I would like to list or search the root context(s) in a LDAP tree. I use Apache Directory Server and Java:
Hashtable<String, String> contextParams = new Hashtable<String, String>();
contextParams.put("java.naming.provider.url", "ldap://localhost:10389");
contextParams.put("java.naming.security.principal", "uid=admin,ou=system");
contextParams.put("java.naming.security.credentials", "secret");
contextParams.put("java.naming.security.authentication", "simple");
contextParams.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
DirContext dirContext = new InitialDirContext(contextParams);
NamingEnumeration<NameClassPair> resultList;
//Works
resultList = dirContext.list("ou=system");
while (resultList.hasMore()) {
NameClassPair result = resultList.next();
System.out.println(result.getName());
}
//Does not work
resultList = dirContext.list("");
while (resultList.hasMore()) {
NameClassPair result = resultList.next();
System.out.println(result.getName());
}
I can list the sub nodes of ou=system. But I cannot list the sub nodes of the actual root node. I would like to have this list just like Apache Directory Studio can:
alt text http://lesc.se/stackoverflow/ldap_root_contexts.png
The base DNs can be obtained from the namingContexts attribute of the root node (RootDSE). The code should look like this:
Attributes attributes = dirContext.getAttributes( "", new String[]{"namingContexts"} );
Attribute attribute = attributes.get( "namingContexts" );
NamingEnumeration<?> all = attribute.getAll();
while(all.hasMore())
{
String next = (String)all.next();
System.out.println(next);
}
Related
At the same time of providing authentication to the user in LDAP within Microsoft Active Directory, I'm trying to get all groups that specific user belongs to. The following code is in Java.
What I'm doing at the moment is the following:
public static List authenticate(String username, String password) throws Exception {
String LDAPURL = MY_LDAP_URL;
String userBase = MY_USERBASE; //format "dc=***,dc=com"
ArrayList<String> groups = new ArrayList<String>();
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL, LDAPURL);
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, username);
environment.put(Context.SECURITY_CREDENTIALS, password);
DirContext ctx =
new InitialDirContext(environment);
SearchControls ctls = new SearchControls();
String[] attributes = {"cn", "memberOf"};
ctls.setReturningAttributes(attributes);
ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
String searchFilters = "{sAMAccountName="+username+"}";
NamingEnumeration<?> answer = ctx.search(userBase, searchFilters, ctls);
if(answer == null || !answer.hasMore()) {
logger.info("No result found");
}
else {
SearchResult result = (SearchResult) answer.next();
Attributes attrs = result.getAttributes();
Attribute memberAttr = attrs.get("memberOf");
NamingEnumeration e = memberAttr.getAll();
while(e.hasMore()) {
String group = (String) e.next();
groups.add(group);
logger.info(group);
}
}
return groups;
}
I have tried several ways of doing my query, for example:
String searchFilters = "(&(uid="+username+"),(ou=users),(memberOf=*))"
Or
String searchFilters = "(&(objectClass=groupOfNames)(member=cn=" + username + ")(memberOf=*))"
Or
String searchFilters = "(&(userPrincipalName=" + username + ")(memberOf=*))"
In none of the cases any groups were retrieved. In some of the cases the login itself failed as well (in some cases it worked but still no groups returned).
What is the correct way to retrieve the groups?
Although you can bind with "username" and some other attributes, using ANR, ONLY when using Microsoft Active Directory, you will need to obtain the Fully Distinguished Name for the user to perform many LDAP Searches.
Assuming username is the samAccountName, which is always Unique within a AD Forrest, your Authentication should work.
After Authentication you can obtain the DN of the entry and then perform a search for Groups the user is a member.
For all groups the user is a member, including nested groups this will usually work.
(member:1.2.840.113556.1.4.1941:=(CN=UserName,CN=Users,DC=YOURDOMAIN,DC=NET))
We have several JNDI Examples in a code repository.
I am going mad over a LDAP attribute modification.
Be aware, I am very beginner so my code might contain mistakes and loads of issues but here is what I am trying to do.
I need to change the following attribute of a AD user givenName, samAccountName, displayName to the one of my choice.
I have 2 classes, one that searches for AD user (and works perfectly), and one that should modify the above attribute. However I keep getting error InvocationTargetException
This is Class 2, the one that does not work:
public void modify() {
try {
//connecting to the domain
Hashtable<String, String> ldapEnv = new Hashtable<String, String>(11);
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
ldapEnv.put(Context.SECURITY_PROTOCOL,"TLSv1.2");
ldapEnv.put(Context.PROVIDER_URL,"ldap://10.61.0.6:389");
ldapEnv.put(Context.SECURITY_PRINCIPAL,"CN=ldapadmin,OU=Users,OU=Dublin,OU=Europe,OU=Offices,DC=vmtech,DC=com");
ldapEnv.put(Context.SECURITY_CREDENTIALS,"Password1");
InitialDirContext ldapContext = new InitialDirContext(ldapEnv);
DirContext ctx = new InitialDirContext(ldapEnv);
System.out.println(NameObject);
ModificationItem[] mods = new ModificationItem[3];
//replace the GivenName
Attribute A0 = new BasicAttribute("givenName", modgivenName);
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, A0);
// replace the sAMAccountName
Attribute A1 = new BasicAttribute("samAccountName", ModsAMAccountName);
mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, A1);
// Replace the displayname
Attribute A2 = new BasicAttribute("displayName",ModdisplayName);
mods[2] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, A2);
for(int i =0; i <= mods.length; i++){
System.out.println(mods[i]);
}
// apply the modification to the object
ctx.modifyAttributes(NameObject, mods);
}
catch (NamingException ex) {
Logger.getLogger(LdapSearch.class.getName()).log(Level.SEVERE, null, ex);
}
}
I want to get user DN with the username provided.
What I think is that I want to retrieve all the user data and compare with the username.
And now, I have added objectclass in my search filter and I have no idea why is the data is not retrieving.
Here are the codes that I currently have.
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=admin,ou=sa,o=system");
env.put(Context.SECURITY_CREDENTIALS, "P#ssw0rd");
try{
DirContext context = new InitialDirContext(env);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration result = context.search("", "(objectclass=Person)", constraints);
while(result.hasMore())
{
SearchResult searchResult = (SearchResult) result.next();
Attributes attrs = searchResult.getAttributes();
request.setEmail(attrs.get("mail").toString());
request.setPhoneNumber(attrs.get("personalMobile").toString());
Attribute ldapattr = attrs.get("photo");
if(ldapattr != null){
byte[] photo = (byte[])ldapattr.get();
request.setPhoto(photo);
}
}
}catch(Exception e){
System.out.println("can't initialized");
}
list.add(request);
//Specific URL of LDAP with the host and :port
return list;
}
Provide a base DN to search. e.g. ou=users below and add username to filter for faster search
Don't get all the user data as you are unnecessarily increasing network traffic and doing additional computational work on the client.
LDAP server excels at this kind of searching. CN is indexed by default but givenName may not be indexed; so you might want to add an index for this attribute.
NamingEnumeration result = context.search("ou=users",
"(&(objectClass=person)(sAMAccountName=" + userId + "))", constraints);
If you have givenName
NamingEnumeration result = context.search("ou=users",
"(&(objectClass=person)(givenName=" + givenName + "))", constraints);
I am currently maintaining some library scanning software at a company, and I am at a coop for (I am in high school). I have to be able to pass an employeeID value from the scanner to the LDAP lookup to return a "CN" value.
Unfortunately, I am not getting any results returned in the Java program. I am able to search using the Active Directory program in Windows, but it takes 6 to 10 seconds to display any results from employeeID. I attempted to solve this issue by using a very large timeout limit on the query, but I think I must be doing something wrong.
Anyone with database experience have any ideas?
try
{
System.out.println("Début du test Active Directory");
Hashtable<String, String> env = new Hashtable<String, String>(11);
env.put(INSERT CREDENTIALS HERE);
env.put("com.sun.jndi.ldap.timeout", "80000");
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put(Context.SECURITY_PROTOCOL, "simple");
ldapContext = new InitialDirContext(env);
// Create the search controls
SearchControls searchCtls = new SearchControls();
//Specify the attributes to return
String returnedAtts[]={"cn","givenName", "samAccountName"};
searchCtls.setReturningAttributes(returnedAtts);
//Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
//specify the LDAP search filter
id = "********";
String searchFilter = "(&(employeeID="+id+"))";
//Specify the Base for the search
String searchBase = "dc=ericsson,dc=se";
//initialize counter to total the results
SearchResult sr = null;
int totalResults = 0;
NamingEnumeration<SearchResult> answer = ldapContext.search(searchBase, searchFilter, searchCtls);
// Search for objects using the filter
while (totalResults == 0){
answer = ldapContext.search(searchBase, searchFilter, searchCtls);
System.out.println("Total results: " + totalResults);
while (answer.hasMoreElements())
{
sr = answer.next();
System.out.println(sr);
totalResults++;
System.out.println(">>>" + sr.getName());
Attributes attrs = sr.getAttributes();
cn = (">>>>>>>>>" + attrs.get("cn"));
signum = cn.substring(13,20);
System.out.println("Total results: " + totalResults);
}
}
//Loop through the search results
You need to ensure that the employeeID attribute is indexed.
You should also qualify your filter further. I would add at least an objectClass filter, set to whatever object class you're using for people.
I am able to run following search query successfully on openldap commandline tool:
ldapsearch -h 1.11.1.1 -b "DC=ff2,DC=in" -s subtree -D "CN=Ldap Bind,OU=Service Accounts,OU=BA,DC=ff2,DC=in" -w G00Pass# sBAAccountName=testAccount
Now I have to execute it in java class. I have done the following:
Hashtable env = new Hashtable();
env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.PROVIDER_URL, "ldap://1.11.1.1:389");
env.put(Context.SECURITY_PRINCIPAL, "CN=Ldap Bind,OU=Service Accounts,OU=TECH,DC=ff2,DC=in");
env.put(Context.SECURITY_CREDENTIALS, "H00Pass#");
LdapContext context = new InitialLdapContext(env, null);
// To get only 1000 results at a time.
context.setRequestControls(
new Control[]{new PagedResultsControl(1000, Control.CRITICAL)});
String[] attrs={"CN=Ldap Bind,OU=Service Accounts,OU=TECH,DC=ff2,DC=in"};
String base = "DC=ff2,DC=in";
String filter = "(&(objectClass=user)(sAMAccountName=testAccount))";
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
controls.setReturningAttributes(attrs);
SearchResult searchResults;
NamingEnumeration<SearchResult> results = context.search(base, filter, controls);
if (results.hasMoreElements()) {
SearchResult searchResult = (SearchResult) results.nextElement();
if(results.hasMoreElements()){
System.err.println("Matched multiple groups for the group with SID: ");
}else{
System.out.println( (String)searchResult.getAttributes().get("sAMAccountName").get());
}
}
This is giving me Null Pointer Exception at searchResult.getAttributes(). Here I am not sure how to include sBAAccountName filter?
You have to search with that criteria as follows:
env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.PROVIDER_URL, "<LDAP HOST>");
env.put(Context.SECURITY_PRINCIPAL, "<LDAP USER LOGIN>");
env.put(Context.SECURITY_CREDENTIALS, "<LDAP USER PASSWORD>");
LdapContext context = new InitialLdapContext(env);
// To get only 1000 results at a time.
context.setRequestControls(
new Control[]{new PagedResultsControl(1000, Control.CRITICAL))});
String attrs = "<List of attrs to be retrieved for each matching LDAP entry>";
String base = "<Base of the search tree>";
String filter = "<Your filter>";
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
controls.setReturningAttributes(attrs);
SearchResults searchResults;
do {
searchResults = ctx.search(base, filter, controls);
while (searchResults.hasMoreElements()) {
// Process result.
}
// Process response controls to get the cookie
// and keep searching until it is null.
}
while (cookie is not null);
You must have declared searchResult elsewhere as a member variable. Remove that. You will then discover via a compile error that you are using it in a place where it isn't even declared and therefore has no value. Remove that too.