I'm using Spring LDAP 1.3.0 library to access an internal LDAP server, with Java, but I'm having troubles to do one thing: how can I get an internal attribute of any structure of LDAP? For example, how can I get the memberOf attribute of an user?
I ever searched a lot but don't find anything about that using Spring LDAP.
Any ideas will be very welcome. Thanks.
As you said in comment UserAttributeMapper is your friend !
If the user has more than one 'memberof' :
static List<List<String>> getPersonGroupsByAccountName(String accountName){
EqualsFilter filter = new EqualsFilter("sAMAccountName", accountName);
return ldap.search(DistinguishedName.EMPTY_PATH,filter.encode(),new AttributesMapper(){
public Object mapFromAttributes(
javax.naming.directory.Attributes attrs)
throws javax.naming.NamingException {
List<String> memberof = new ArrayList();
for (Enumeration vals = attrs.get("memberOf").getAll(); vals.hasMoreElements();) {
memberof.add((String)vals.nextElement());
}
return memberof;
}
});
I'm sure there is a better way to do this but it works.
I use this to get fields like "createTimestamp" or "pwdChangedTime",
and UserContextMapper you can reference resources: http://docs.spring.io/spring-ldap/docs/1.3.x-SNAPSHOT/reference/htmlsingle/
ldapTemplate.lookup(dn, new String[] {"*", "+"}, new UserContextMapper());
It also works with odmManager. Something like
DistinguishedName dn = new DistinguishedName("The path your are searching in");
SearchControls searchControls = new SearchControls();
searchControls.setReturningObjFlag(true);
searchControls.setReturningAttributes("your attributes, as an array of strings");
return odmManager.findAll(User.class, dn, searchControls);
I use this to get fields like "createTimestamp" ....
Related
I'm trying to query again a particular dns server both in linux shell using digg and using Java.
The dig command works. but the java way doesn't. what's wrong?
dig #dns.nic.it test.it
;; QUESTION SECTION:
;test.it. IN A
;; AUTHORITY SECTION:
test.it. 10800 IN NS dns2.technorail.com.
test.it. 10800 IN NS dns.technorail.com.
test.it. 10800 IN NS dns3.arubadns.net.
test.it. 10800 IN NS dns4.arubadns.cz.
java way
public static void rootDNSLookup(String domainName) throws NamingException{
String server="dns://dns.nic.it";
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
env.put("java.naming.provider.url", server);
DirContext ictx = new InitialDirContext(env);
Attributes attrs = ictx.getAttributes(domainName, new String[] {"A", "AAAA", "NS", "SRV"});
System.out.println(attrs);
NamingEnumeration e = attrs.getAll();
while(e.hasMoreElements()) {
Attribute a = e.next();
System.out.println(a.getID() + " = " + a.get());
}
}
java prints:
No attributes
The best way to go is to use the library dnsjava.
The particular class you are looking for is SimpleResolver. It has two constructors. When used with no parameters it will use the system's DNS settings. If you provide an IP address it will force that as the DNS server.
You can find a great example of usage here: dnsjava Examples.
Don't try and get all attributes at the same time.
Use:
Attributes attrs = ictx.getAttributes(domainName, new String[] {"A"});
Use a String array that contains all attributes you want and iterate over the call passing in the attribute.
String[] attributes = {"A", "AAAA", "NS", "SRV"};
for (String attribute : attributes) {
...
Attributes attrs = ictx.getAttributes(domainName, new String[] {attribute});
...
}
Hi I am a developer but new to ldap programming. I was able to our Ldap server by providing the DN=ou=app1,ou=development,ou=Group and set my search level to subtree_scope and was able to get to on level down which put me at DN=cn=admin,DN=ou=app1,ou=development,ou=Group. By expanding this DN i see Member(4),OU(1), cn(1),and Objectclasses: top and groupOfNames. I am trying to access the 4 users with uid=user entries. I got the below message when i tried to access uid:
UID... class javax.naming.directory.SearchResult
null
Found cn=Admin:
Attributes are.. No attributes
The following is the snippet of my code. I can provide more if needed
controls.setReturningAttributes("uid");
String filter="(objectClass=groupOfNames)";
NamingEnumeration objs = ctx.search("",filter, controls);
while (objs.hasMoreElements())
{
SearchResult match = (SearchResult)objs.nextElement();
System.out.println(" UID...\t"+ match.getClass());
System.out.println(match.getClassName());
System.out.println("Found "+match.getName()+":");
System.out.println("Attributes are..\t"+match.getAttributes());
Attributes attrs = match.getAttributes();
NamingEnumeration e = attrs.getAll();
while (e.hasMoreElements())
{
Attribute attr = (Attribute) e.nextElement();
System.out.println("Attribute and its class..\t"+attr.getClass());
}
System.out.println("---------------------------------------");
}
}
The SearchControls define the attributes to be returned by the search. You must have set its 'returningAttributes' property to 'new String[0]'. Leave it at null to get all attributes, or specify the ones you want.
I'm trying to run:
Map<String, String> environmentProperties = new HashMap<String, String>();
environmentProperties.put("java.naming.security.authentication", "simple");
environmentProperties.put("java.naming.ldap.attributes.binary", "tokenGroups objectSid");
LdapContextSource contextSource = new LdapContextSource();
contextSource.setAnonymousReadOnly(false);
contextSource.setPooled(false);
contextSource.setUserDn("CN=Administrator,CN=Users,DC=someDomain,DC=com");
contextSource.setPassword("password");
contextSource.setUrls(new String[]{"ldap://url.goes.here"});
contextSource.setBaseEnvironmentProperties(environmentProperties);
contextSource.setDirObjectFactory(null);
contextSource.afterPropertiesSet();
final SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
ContextExecutor contextExecutor = new ContextExecutor() {
public Object executeWithContext(DirContext ctx) throws NamingException {
EventDirContext ectx = (EventDirContext) ctx.lookup("CN=Users,,DC=someDomain,DC=com");
ectx.addNamingListener("", "(cn=*)", searchControls, new LDAPChangeListener());
return null;
}
};
LdapTemplate ldapTemplate = new LdapTemplate(contextSource);
ldapTemplate.setIgnorePartialResultException(true);
ldapTemplate.executeReadOnly(contextExecutor);
but, the first message my listener gets is:
javax.naming.OperationNotSupportedException: [LDAP: error code 12 - 00000057: LdapErr: DSID-0C090753, comment: Error processing control, data 0, v1db1 ]; remaining name ''
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3127)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3013)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2820)
at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:129)
I also ran this code I found here that's supposed to verify that my AD supports persistent search, and the result was true.
static boolean isPersistentSearchSupported(LdapContext rootContext)
throws NamingException {
SearchResult rootDSE;
NamingEnumeration searchResults;
Attributes attrs;
NamingEnumeration attrEnum;
Attribute attr;
NamingEnumeration values;
String value;
String[] attrNames = { "supportedControl" };
SearchControls searchControls = new SearchControls();
searchControls.setCountLimit(0); // 0 means no limit
searchControls.setReturningAttributes(attrNames);
searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
// search for the rootDSE object
searchResults = rootContext.search("", "(objectClass=*)",
searchControls);
while (searchResults.hasMore()) {
rootDSE = (SearchResult) searchResults.next();
attrs = rootDSE.getAttributes();
attrEnum = attrs.getAll();
while (attrEnum.hasMore()) {
attr = (Attribute) attrEnum.next();
values = attr.getAll();
while (values.hasMore()) {
value = (String) values.next();
if (value.equals("1.2.840.113556.1.4.528"))
return true;
}
}
}
return false;
}
what do I need to do to start getting events from AD?
According to the documentation, the scope can't be Subtree and the search filter must be (objectClass=*) for a persistent search.
UPDATE:
I found this: https://forums.oracle.com/thread/1157474?tstart=0
It basically says that AD does not support this, and that there’s no way I can make the above code work.
However, it does give out 2 different ways of getting such notifications from AD:
Using DirSync- I tried the attached code, and it did not work, but did not continue investigating from the reasons that will be listed in the end of this post.
Using LDAP Notifications (https://forums.oracle.com/message/4698114 )- this code worked, however, it only returns results for created / changed events, it will not notify once an object gets deleted, and there’s no way of getting it with this method since the search filter cannot be changed, because any other filter will not work. So it did not fit my purposes, but maybe someone else finds it useful.
I thought DirSync might be the only solution possible for me, if any.
However, it should be noted that DirSync has the following limitations:
The DirSync control can only be used by a highly privileged account, such as a domain administrator.
The DirSync control can only monitor an entire naming context. You cannot limit the scope of a DirSync search to monitor only a specific subtree, container, or object in a naming context.
I hope this information will help someone else in the future.
I would like to add some additional information on this topic since I have done research on this topic couple years ago.
The NamingListener capability provided by JNDI. If you try to register a NamingListener on any LDAP server, that particularly server must support the 'Persistent Search' extension. The Persistent Search extension has always been in IETF draft stage therefore there's no official RFC# associate with it.
Not a lot of LDAP server support this extension. The last time I researched on this topic was 2008 and the LDAP servers that support persistent search extension were 389 Directory Server, Oracle Internet Directory (OID) and OpenDS (now known as OpenDJ).
http://www-archive.mozilla.org/directory/ietf-docs/draft-smith-psearch-ldap-01.txt
http://www.redhat.com/archives/fedora-directory-users/2008-May/msg00120.html
I am trying to fetch LDAP User internal attributes, but couldn't find how to fetch them
DirContext ctx = this.getDirContext();
List<Employee> list = new ArrayList<Employee>();
NamingEnumeration<SearchResult> results = null;
try {
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
results = ctx.search("", "(objectclass=person)", controls);
while (results.hasMore()) {
SearchResult searchResult = results.next();
Attributes attributes = searchResult.getAttributes();
String fullName = this.getValue(attributes.get("cn"));
//so on...
}
// so on
from LDAP, I want to fetch each employee/person internal attributes too.
By Default, it's not returning the internal attributes [ex: createTimestamp]
You won't get any operational attributes unless you ask for them. At present you aren't asking for any attributes, which is equivalent to constructing the SearchControls, or calling SearchControls.setReturningAttributes(String[]) afterwards, using the argument new String[]{"*"}:this gives you all the non-operational attributes.
To get the operational attributes as well, use the argument new String[]{"*","+"}.
if you could please explain to me one piece of the following code that I don't quite understand I would be grateful:
What does (&(cn=*)({0}={1})) mean in the filter field?
I know that cn means search for the cn attribute and then ADD the result to ({0}={1}).
What is the meaning of ({0}={1})?
Here's the code:
try {
// Create initial context
ctx = new InitialDirContext(env);
Attributes matchAttrs = new BasicAttributes(true);
matchAttrs.put(new BasicAttribute(ldap_id_field, netid));
String attlist[] = {ldap_email_field, ldap_givenname_field,
ldap_surname_field, ldap_phone_field};
// look up attributes
try {
SearchControls ctls = new SearchControls();
ctls.setReturningAttributes(attlist);
NamingEnumeration answer =
ctx.search(ldap_search_context, "(&(cn=*)({0}={1}))", new Object[] {ldap_id_field,netid},ctls);
}
...
It looks wrong to me. All that filter does is find entries which have any CN and which match an attribute name/value pair specified as arguments to the search, in ldap_id_field and netid respectively. There is no 'adding' going on: the & means that both filter-expressions must match.