connect Java to Active Directory - java

I try to connect to Active Directory with my Java code, but I get this error message :
Début du test Active Directory
Search error: javax.naming.AuthenticationException: [LDAP: error code 49 - 8009030C:
LdapErr: DSID-0C0904DC, comment: AcceptSecurityContext error, data 52e, v1db1
I use JNDI,the DIGEST-MD5 authentication method and no encryption method
this is my code:
public class TestAD {
static DirContext ldapContext;
public static void main (String[] args) throws NamingException
{
try
{
System.out.println("Début du test Active Directory");
Hashtable<String, String> ldapEnv = new Hashtable<String, String>(11);
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
ldapEnv.put(Context.PROVIDER_URL, "ldap://societe.fr:389");
ldapEnv.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5");
ldapEnv.put("java.naming.security.sasl.realm","myRealm");
ldapEnv.put("javax.security.sasl.qop", "auth");
ldapEnv.put("javax.security.sasl.strength","high");
ldapEnv.put(Context.SECURITY_PRINCIPAL, "dn:cn=administrateur,ou=users,o=societe.fr");
ldapEnv.put(Context.SECURITY_CREDENTIALS,"myPassword");
ldapContext = new InitialDirContext(ldapEnv);
// Create the search controls
SearchControls searchCtls = new SearchControls();
// Specify the attributes to return
String returnedAtts[]={"sn","givenName", "samAccountName"};
searchCtls.setReturningAttributes(returnedAtts);
// Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// specify the LDAP search filter
String searchFilter = "(&(objectClass=user))";
// Specify the Base for the search
String searchBase = "dc=societe,dc=fr";
// initialize counter to total the results
int totalResults = 0;
// Search for objects using the filter
NamingEnumeration<SearchResult> answer = ldapContext.search(searchBase, searchFilter, searchCtls);
// Loop through the search results
while (answer.hasMoreElements())
{
SearchResult sr = (SearchResult)answer.next();
totalResults++;
System.out.println(">>>" + sr.getName());
Attributes attrs = sr.getAttributes();
System.out.println(">>>>>>" + attrs.get("samAccountName"));
}
System.out.println("Total results: " + totalResults);
ldapContext.close();
}
catch (Exception e)
{
System.out.println(" Search error: " + e);
e.printStackTrace();
System.exit(-1);
}
}
}
P.S.:I can connect to my Active Directory with the same parameter with Apache Directory Studio

Related

Not able to retrieve users from LDAP AD server

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();
}
}

How to get all users from specific ou in active directory using java?

Here is the method which i have used to fetch but nothing is being populated.
public void doSearch() throws NamingException {
String searchFilter = "(&(ou=Example,ou=Examples_ou)(objectClass=person))";
String domain = "DC=mydom,DC=com";
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> answer = ctx.search(domain, searchFilter, searchControls);
int ttl = 0;
while (answer.hasMoreElements()) {
SearchResult sr = (SearchResult) answer.next();
ttl++;
System.out.println(">>>" + sr.getName());
Attributes attrs = sr.getAttributes();
System.out.println(">>>>>>" + attrs.get("samAccountName"));
}
System.out.println("Total results: " + ttl);
}
Your filter is invalid, thus returns no data. In
ctx.search(domain, searchFilter, searchControls);
domain is being passed as the base DN for the search. If you want to restrict your search to users within ou=Example,ou=Examples_ou of dc=example,dc=com, then your search base DN should be "ou=Example,ou=Examples_ou,dc=example,dc=com" and searchFilter would be simply "(&(objectClass=person))"

JNDI: How to use Logical not query to search LDAP

I am facing problem while applying logical not query.
For example,
NamingEnumeration<SearchResult> results =
context.search("ou=people,dc=example,dc=com", "sn=Kumaran", searcCon);
Above statement is working absolutely fine, it is returning all the person entries whose sn is Kumaran.
Suppose that I change the statement to get all the person entries whose sn is not Kumaran.
NamingEnumeration<SearchResult> results =
context.search("ou=people,dc=example,dc=com", "(!sn=Kumaran)", searcCon);
I am getting following error:
Exception in thread "main" javax.naming.directory.InvalidSearchFilterException: Unbalanced parenthesis; remaining name 'ou=people,dc=example,dc=com'
at com.sun.jndi.ldap.Filter.findRightParen(Filter.java:694)
at com.sun.jndi.ldap.Filter.encodeFilterList(Filter.java:733)
at com.sun.jndi.ldap.Filter.encodeComplexFilter(Filter.java:657)
at com.sun.jndi.ldap.Filter.encodeFilter(Filter.java:118)
at com.sun.jndi.ldap.Filter.encodeFilterString(Filter.java:74)
at com.sun.jndi.ldap.LdapClient.search(LdapClient.java:548)
at com.sun.jndi.ldap.LdapCtx.doSearch(LdapCtx.java:1985)
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1844)
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1769)
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:392)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:358)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:341)
at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:267)
at jndi_tutorial.Test.getPeopleSnIsKumaran(Test.java:34)
at jndi_tutorial.Test.main(Test.java:62)
Following is my code
public static void printResults(NamingEnumeration<SearchResult> results)
throws NamingException {
while (results.hasMoreElements()) {
SearchResult res = results.next();
Attributes atbs = res.getAttributes();
Attribute nameAttr = atbs.get("cn");
String name = (String) nameAttr.get();
Attribute descriptionAtr = atbs.get("description");
String description = (String) descriptionAtr.get();
System.out.println(description);
System.out.println("Name is :" + name + ",description is :"
+ description);
}
}
/* Get all people whose sn is not equal to Kumaran */
public static void getAllExcludeKumaran() throws NamingException {
SearchControls searcCon = new SearchControls();
searcCon.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> results = context.search(
"ou=people,dc=example,dc=com", "(!(sn=Kumaran))", searcCon);
printResults(results);
}
Reference
https://technet.microsoft.com/en-us/library/aa996205(v=exchg.65).aspx
Try to add parenthesis (!(sn=Kumaran))
UPDATE:
Try this
...
SearchControls searcCon = new SearchControls();
String[] attributeFilter = { "cn", "description" };
searcCon.setReturningAttributes(attributeFilter);
searcCon.setSearchScope(SearchControls.SUBTREE_SCOPE);
...
See RFC 2254:
filter ::= "(" filtercomp ")"
not ::= "!" filter
Your code should be like
context.search("ou=people,dc=example,dc=com", "((!sn=Kumaran))", searcCon);
It should work for you.

LDAP Query Accessing a Slow Response Attribute from Java (employeeID)

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.

Find user with specific value in employeeID attribute

I'm trying to find the CN of a username by searching for the employeeID attribute (which is unique for each employee). I already got it to return a string with all attributes, but I want it to return only the CN of a user (ex: 'John Doe' or 'cn=John Doe'; both are fine)
public void getEmployeeId(String id) {
// TODO stuff
String groupName = "ou=Accounts,DC=PORTAL,DC=COMPANY,DC=BE";
try {
System.out.println("Creating initial directory context...");
LdapContext ctx = new InitialLdapContext(env, null);
// Create default search controls
SearchControls ctls = new SearchControls();
// Search for user with 'id' as value for employeeID attribute
String filter = "(&(employeeID=" +id + "))";
// Search for objects using filter
NamingEnumeration answer = ctx.search(groupName, filter, ctls);
// Print the answer
// Search.printSearchEnumeration(answer);
System.out.println("-----------------");
System.out.println(answer.next());
System.out.println("-----------------");
// Close the context when we're done
ctx.close();
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
note: I know you can just cut parts from a string, but I want it to return only the value I need.
The search request should contain a list of attributes. Some APIs will return all attributes from matching entries. Specify cn in the list of attributes to return, and be prepared to handle a multi-valued cn attribute.
see also
LDAP: Mastering Search Filters
LDAP: Search best practices
LDAP: Programming practices
For example:
DirContext ctx = new InitialDirContext(env);
/***/
NamingEnumeration<?> namingEnum = ctx.search(
"dc=stackoverflow,dc=com, "employeeID=" +id,
ctls);
while (namingEnum.hasMoreElements()) {
SearchResult result = (SearchResult) namingEnum.next();
Attributes attrs = result.getAttributes();
System.out.println(attrs.get("cn"));
System.out.println(attrs.get("name"));
System.out.println(attrs.get("userPrincipalName"));
}
/***/
the result:
CN: Andres Montejo
NAME: Andres Montejo
userPrincipalName: andresmontejo#stackoverflow.com

Categories