Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java LDAP - Determine if user in a given group?

We logon users to Active Directory via LDAP using the Java LDAP API. We want to enhance our logon functionality to further check if the user is in a given AD group. Does anyone know how to do this?

Current code:

import javax.naming.*; import javax.naming.ldap.*;  LdapContext ctx = null; Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.SECURITY_AUTHENTICATION,"simple"); env.put(Context.PROVIDER_URL, Config.get("ldap-url"));  try {     Control[] connCtls = new Control[] {new FastBindConnectionControl()};     ctx = new InitialLdapContext(env, connCtls);     ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, "DOMAIN\\" + username);     ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);     ctx.reconnect(connCtls);     /* TODO: Only return true if user is in group "ABC" */     return true; //User authenticated } catch (Exception e) {     return false; //User could NOT be authenticated } finally {     ... } 

Update: See the solution below.

like image 424
Marcus Leon Avatar asked Feb 20 '09 17:02

Marcus Leon


1 Answers

We solved this with the class below. Just call the authenticate method:

import java.text.MessageFormat; import java.util.*;     import javax.naming.*;     import org.apache.log4j.Level;  public class LdapGroupAuthenticator {     public static final String DISTINGUISHED_NAME = "distinguishedName";     public static final String CN = "cn";     public static final String MEMBER = "member";     public static final String MEMBER_OF = "memberOf";     public static final String SEARCH_BY_SAM_ACCOUNT_NAME = "(SAMAccountName={0})";     public static final String SEARCH_GROUP_BY_GROUP_CN = "(&(objectCategory=group)(cn={0}))";      /*      * Prepares and returns CN that can be used for AD query      * e.g. Converts "CN=**Dev - Test Group" to "**Dev - Test Group"      * Converts CN=**Dev - Test Group,OU=Distribution Lists,DC=DOMAIN,DC=com to "**Dev - Test Group"      */     public static String getCN(String cnName) {         if (cnName != null && cnName.toUpperCase().startsWith("CN=")) {             cnName = cnName.substring(3);         }         int position = cnName.indexOf(',');         if (position == -1) {             return cnName;         } else {             return cnName.substring(0, position);         }     }     public static boolean isSame(String target, String candidate) {         if (target != null && target.equalsIgnoreCase(candidate)) {             return true;         }         return false;     }      public static boolean authenticate(String domain, String username, String password) {         Hashtable env = new Hashtable();         env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");         env.put(Context.PROVIDER_URL, "ldap://1.2.3.4:389");         env.put(Context.SECURITY_AUTHENTICATION, "simple");         env.put(Context.SECURITY_PRINCIPAL, domain + "\\" + username);         env.put(Context.SECURITY_CREDENTIALS, password);         DirContext ctx = null;         String defaultSearchBase = "DC=DOMAIN,DC=com";         String groupDistinguishedName = "DN=CN=DLS-APP-MyAdmin-C,OU=DLS File Permissions,DC=DOMAIN,DC=com";          try {             ctx = new InitialDirContext(env);              // userName is SAMAccountName             SearchResult sr = executeSearchSingleResult(ctx, SearchControls.SUBTREE_SCOPE, defaultSearchBase,                     MessageFormat.format( SEARCH_BY_SAM_ACCOUNT_NAME, new Object[] {username}),                     new String[] {DISTINGUISHED_NAME, CN, MEMBER_OF}                     );              String groupCN = getCN(groupDistinguishedName);             HashMap processedUserGroups = new HashMap();             HashMap unProcessedUserGroups = new HashMap();              // Look for and process memberOf             Attribute memberOf = sr.getAttributes().get(MEMBER_OF);             if (memberOf != null) {                 for ( Enumeration e1 = memberOf.getAll() ; e1.hasMoreElements() ; ) {                     String unprocessedGroupDN = e1.nextElement().toString();                     String unprocessedGroupCN = getCN(unprocessedGroupDN);                     // Quick check for direct membership                     if (isSame (groupCN, unprocessedGroupCN) && isSame (groupDistinguishedName, unprocessedGroupDN)) {                         Log.info(username + " is authorized.");                         return true;                     } else {                         unProcessedUserGroups.put(unprocessedGroupDN, unprocessedGroupCN);                     }                 }                 if (userMemberOf(ctx, defaultSearchBase, processedUserGroups, unProcessedUserGroups, groupCN, groupDistinguishedName)) {                     Log.info(username + " is authorized.");                     return true;                 }             }              Log.info(username + " is NOT authorized.");             return false;         } catch (AuthenticationException e) {             Log.info(username + " is NOT authenticated");             return false;         } catch (NamingException e) {             throw new SystemException(e);         } finally {             if (ctx != null) {                 try {                     ctx.close();                 } catch (NamingException e) {                     throw new SystemException(e);                 }             }         }     }      public static boolean userMemberOf(DirContext ctx, String searchBase, HashMap processedUserGroups, HashMap unProcessedUserGroups, String groupCN, String groupDistinguishedName) throws NamingException {         HashMap newUnProcessedGroups = new HashMap();         for (Iterator entry = unProcessedUserGroups.keySet().iterator(); entry.hasNext();) {             String  unprocessedGroupDistinguishedName = (String) entry.next();             String unprocessedGroupCN = (String)unProcessedUserGroups.get(unprocessedGroupDistinguishedName);             if ( processedUserGroups.get(unprocessedGroupDistinguishedName) != null) {                 Log.info("Found  : " + unprocessedGroupDistinguishedName +" in processedGroups. skipping further processing of it..." );                 // We already traversed this.                 continue;             }             if (isSame (groupCN, unprocessedGroupCN) && isSame (groupDistinguishedName, unprocessedGroupDistinguishedName)) {                 Log.info("Found Match DistinguishedName : " + unprocessedGroupDistinguishedName +", CN : " + unprocessedGroupCN );                 return true;             }         }          for (Iterator entry = unProcessedUserGroups.keySet().iterator(); entry.hasNext();) {             String  unprocessedGroupDistinguishedName = (String) entry.next();             String unprocessedGroupCN = (String)unProcessedUserGroups.get(unprocessedGroupDistinguishedName);              processedUserGroups.put(unprocessedGroupDistinguishedName, unprocessedGroupCN);              // Fetch Groups in unprocessedGroupCN and put them in newUnProcessedGroups             NamingEnumeration ns = executeSearch(ctx, SearchControls.SUBTREE_SCOPE, searchBase,                     MessageFormat.format( SEARCH_GROUP_BY_GROUP_CN, new Object[] {unprocessedGroupCN}),                     new String[] {CN, DISTINGUISHED_NAME, MEMBER_OF});              // Loop through the search results             while (ns.hasMoreElements()) {                 SearchResult sr = (SearchResult) ns.next();                  // Make sure we're looking at correct distinguishedName, because we're querying by CN                 String userDistinguishedName = sr.getAttributes().get(DISTINGUISHED_NAME).get().toString();                 if (!isSame(unprocessedGroupDistinguishedName, userDistinguishedName)) {                     Log.info("Processing CN : " + unprocessedGroupCN + ", DN : " + unprocessedGroupDistinguishedName +", Got DN : " + userDistinguishedName +", Ignoring...");                     continue;                 }                  Log.info("Processing for memberOf CN : " + unprocessedGroupCN + ", DN : " + unprocessedGroupDistinguishedName);                 // Look for and process memberOf                 Attribute memberOf = sr.getAttributes().get(MEMBER_OF);                 if (memberOf != null) {                     for ( Enumeration e1 = memberOf.getAll() ; e1.hasMoreElements() ; ) {                         String unprocessedChildGroupDN = e1.nextElement().toString();                         String unprocessedChildGroupCN = getCN(unprocessedChildGroupDN);                         Log.info("Adding to List of un-processed groups : " + unprocessedChildGroupDN +", CN : " + unprocessedChildGroupCN);                         newUnProcessedGroups.put(unprocessedChildGroupDN, unprocessedChildGroupCN);                     }                 }             }         }         if (newUnProcessedGroups.size() == 0) {             Log.info("newUnProcessedGroups.size() is 0. returning false...");             return false;         }          //  process unProcessedUserGroups         return userMemberOf(ctx, searchBase, processedUserGroups, newUnProcessedGroups, groupCN, groupDistinguishedName);     }      private static NamingEnumeration executeSearch(DirContext ctx, int searchScope,  String searchBase, String searchFilter, String[] attributes) throws NamingException {         // Create the search controls         SearchControls searchCtls = new SearchControls();          // Specify the attributes to return         if (attributes != null) {             searchCtls.setReturningAttributes(attributes);         }          // Specify the search scope         searchCtls.setSearchScope(searchScope);          // Search for objects using the filter         NamingEnumeration result = ctx.search(searchBase, searchFilter,searchCtls);         return result;     }      private static SearchResult executeSearchSingleResult(DirContext ctx, int searchScope,  String searchBase, String searchFilter, String[] attributes) throws NamingException {         NamingEnumeration result = executeSearch(ctx, searchScope,  searchBase, searchFilter, attributes);          SearchResult sr = null;         // Loop through the search results         while (result.hasMoreElements()) {             sr = (SearchResult) result.next();             break;         }         return sr;     } } 
like image 194
Marcus Leon Avatar answered Sep 21 '22 16:09

Marcus Leon