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);
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 created LDAP AD server in Windows 2008 server using the steps mentioned in the following link:
https://blogs.msdn.microsoft.com/robert_mcmurray/2011/09/16/ftp-and-ldap-part-2-how-to-set-up-an-active-directory-lightweight-directory-services-ad-lds-server/#01b
The following program has to search for users in LDAP AD. It connects with the LDAP server successfully, but the user search is unsuccessful. I am not sure why.
public class LDAPTest {
String ldapHost = "ldap://hostname:389";
String searchBase = "CN=LDAPServer,DC=SITDomain,DC=local";
public static void main(String[] args) {
LDAPTest ldapConnect = new LDAPTest();
ldapConnect.authenticate("john", "****");
}
public Map authenticate(String user, String pass) {
String returnedAtts[] = { "dintinguishedName" };
String searchFilter = "(& (userPrincipalName="+user+")(objectClass=user))";
// Create the search controls
SearchControls searchCtls = new SearchControls();
searchCtls.setReturningAttributes(returnedAtts);
// Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
Hashtable<Object, Object> env = new Hashtable<Object, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, this.ldapHost);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL,"CN=ryan,CN=grp,CN=LDAPServer,DC=SITDomain,DC=local");
env.put(Context.SECURITY_CREDENTIALS, pass);
LdapContext ctxGC = null;
boolean ldapUser = false;
try {
ctxGC = new InitialLdapContext(env, null);
// Search objects in GC using filters
NamingEnumeration<SearchResult> answer = ctxGC.search(this.searchBase, searchFilter, searchCtls);
while (answer.hasMoreElements()) {
SearchResult sr = answer.next();
System.out.println(">>>" + sr.getName());
Attributes attrs = sr.getAttributes();
Map amap = null;
if (attrs != null) {
System.out.println(attrs.size());
System.out.println(">>>>>>" + attrs.get("dintinguishedName"));
amap = new HashMap();
NamingEnumeration<Attribute> ne = (NamingEnumeration<Attribute>) attrs.getAll();
while (ne.hasMore()) {
Attribute attr = ne.next();
amap.put(attr.getID(), attr.get());
System.out.println(attr.getID()+">>>>>>" + attr.get());
ldapUser = true;
}
ne.close();
}
}
} catch (NamingException ex) {
ex.printStackTrace();
System.out.println(ex.getMessage());
}
return null;
}
}
LDAP server dir image
Not sure if it is a copy/paste error or a typo in the code, but the user attribute being returned is spelled incorrectly. The attribute name dintinguishedName should be distinguishedName. I would also expect to see an initial bind with a known good user (e.g. an account specifically created for the application), a search for the user, retrieval of the distinguishedName, and a second attempt to bind with the returned distinguishedName and user supplied password. Instead I'm seeing a hard-coded ID (ryan) using the user-supplied password. Which may work if the two accounts happen to have the same password. Below this post, I have included the code I use to authenticate against my LDAP servers, including Active Directory.
I wanted universal code, and most other LDAP servers require you use the distinguishedName in the bind operation. But for Active Directory, specifically, you can bind without knowing the distinguishedName of the user -- LDAP bind to AD can be performed with sAMAccountName (domain\user) and userPrincipalName (user#domain.TLD). If you have a single tree in a single forest (i.e. you know the value to append to the user ID to form sAMAccountName or userPrincipalName), you can perform a bind operation as the user. Should you need additional information about the person beyond their authentication validation, on return code 0 (successful authentication), search for the user & retrieve the information.
// Editable variables -- ensure you change these to your application's details
String strSysUID = "uid=YOURSYSTEMIDGOESHERE,ou=OrgUnitName,dc=Org,dc=Name";
String strSysPassword = "YourSystemPasswordGoesHere";
String strAuthorizationGroup = "LJL_Test";
String strTrustStorePassword = "YourTrustStorePassword"
String trustStoreFile = ".\\ADTrust";
String sLDAPServer = "ldaps://ldap.domain.gTLD:636";
String strUserBaseDN = "ou=UserOU,dc=Org,dc=Name";
String strGroupBaseDN = "ou=GroupOU,dc=Org,dc=Name";
String strUserIDSchemaAttribute = "sAMAccountName="; // attribute that holds user logon name
String strGroupMembershipSchemaAttribute = "member"; // attribute that holds member list in group object
// End of editable variables
System.setProperty("javax.net.ssl.trustStore", trustStoreFile);
System.setProperty("javax.net.ssl.trustStorePassword", strTrustStorePassword);
// Obtain UID and PWD from user
String sUserUID = "";
String sUserPwd = "";
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Please enter your username: ");
try{
sUserUID = in.readLine();
}catch(Exception er) { er.printStackTrace(); }
System.out.print("Please enter your password: ");
try{
sUserPwd = in.readLine();
}catch(Exception er) { er.printStackTrace(); }
// Initial context for system bind
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, sLDAPServer);
env.put(Context.SECURITY_PROTOCOL, "ssl");
// Authenticate as system ID and password
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, strSysUID);
env.put(Context.SECURITY_CREDENTIALS, strSysPassword);
try {
DirContext ctx = new InitialDirContext(env);
// Using the system credentials, search for a user matching the logon ID provided by the user
String sFilter = strUserIDSchemaAttribute + sUserUID;
NamingEnumeration UserDNAnswer = ctx.search(strUserBaseDN, sFilter, null);
String sReturnedFQDN = "";
// If only one record should be returns, validate that exactly one record is located and throw an error otherwise
while (UserDNAnswer.hasMore()) {
SearchResult sr = (SearchResult) UserDNAnswer.next();
// Store the DN of the user re have found
sReturnedFQDN = sr.getNameInNamespace();
}
// Check group membership, can be done after the password is validated if you wish
// Example LDAP filter is "(&(cn=NameOfGroupToCheck)(uniqueMember=FQDNOfUserBeingTested))"
String sGroupFilter = "(&(cn=" + strAuthorizationGroup + ")(" + strGroupMembershipSchemaAttribute + "=" + sReturnedFQDN + "))";
NamingEnumeration GroupMembershipAnswer = ctx.search(strGroupBaseDN, sGroupFilter, null);
String sReturnedGroupDN = "";
while (GroupMembershipAnswer.hasMore()) {
SearchResult srGroup = (SearchResult) GroupMembershipAnswer.next();
sReturnedGroupDN = srGroup.getNameInNamespace();
}
ctx.close();
// If an entry was returned, then the user is a member of the group. We should validate the user's password
if(sReturnedGroupDN.equals("cn=" + strAuthorizationGroup+ "," + strGroupBaseDN)){
System.out.println(sReturnedFQDN + " is a member of " + sReturnedGroupDN + " and now we will validate the password.");
// Now establish a new LDAP connection to validate the credentials supplied
Hashtable envUser = new Hashtable(11);
envUser.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
envUser.put(Context.PROVIDER_URL, sLDAPServer);
// Authenticate using the searched FQDN for the user and the password provided by the user
envUser.put(Context.SECURITY_AUTHENTICATION, "simple");
envUser.put(Context.SECURITY_PRINCIPAL, sReturnedFQDN);
envUser.put(Context.SECURITY_CREDENTIALS, sUserPwd);
// Doing this so a login failure throws a code
try{
DirContext ctxUser = new InitialDirContext(envUser);
System.out.println("Successfully authenticated as " + sUserUID);
ctxUser .close;
}
// User credentials failure
catch (NamingException e) {
e.printStackTrace();
}
}
// If no group matched the filter, the user is not a group member and an authorisation failure can be returned
else{
System.out.println(sReturnedFQDN + " is NOT a member of " + sReturnedGroupDN + " and there is no need to verify the password.");
}
}
// System credentials failure
catch (NamingException e) {
e.printStackTrace();
}
}
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 looking for a query, when entered a name it should check whether there are any sub employees reporting to that entered name. If there are any, then it should return all the list of child users(employees) and sub child users reporting to that employee.
I wrote a query, when entered a username, it gets all the data associated with him, but I am confused now how to get only the users & sub-users & sub-sub users names that report to that search term.
Is there a way to do it with AD or do I need to implement DFS search? If either option, then please give me some hints to do it.
try {
// Create Initial Context
LdapContext ctxGC = new InitialLdapContext(env, null);
// ctxGC.setRequestControls(null);
String searchFilter = "(&(objectClass=user)(sAMAccountName=" + searchTerm + ")(!(displayName=ADM*)))";
NamingEnumeration<?> namingEnum = ctxGC.search("OU=User,DC=emea,DC=xyz,DC=biz", searchFilter, getSearchControls());
Deque<Node> stack = new ArrayDeque<Node>(); // Do I need to implement tree here or is there any other way to get sub users info from LDAP search??
while (namingEnum.hasMoreElements()) {
SearchResult result = (SearchResult) namingEnum.next();
Attributes attrs = result.getAttributes();
if (attrs != null) {
NamingEnumeration ne = attrs.getAll();
while (ne.hasMore()) {
Attribute attr = (Attribute) ne.next();
}
}
}
namingEnum.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static SearchControls getSearchControls() {
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchCtls.setReturningAttributes(new String[]{"*"});
return searchCtls;
}
To get the list of users reporting to a manager, I just need to change the search filter query and retrieve the manager credentials, then it returns the list of all users that are reporting to that person. If there are no users reporting to him, then it returns nothing.
So, the searchFilter need to be changed like the following.
String searchFilter = "(&(objectClass=user)(manager=CN=Its\\\\, Zaif,OU=xx,OU=xx,OU=StandardUser,OU=xx,DC=emea,DC=xyz,DC=biz) (!(displayName=ADM*)))";
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.