Java LDAP – 确定给定组中的用户是否?

我们使用Java LDAP API通过LDAP将用户登录到Active Directory。 我们希望增强登录function,以进一步检查用户是否在给定的AD组中。 有谁知道如何做到这一点?

当前代码:

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 { ... } 

更新 :请参阅下面的解决方案。

我们用下面的课程解决了这个问题。 只需调用authenticate方法:

 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 * eg 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; } } 

以上代码片段中没有一个对我不起作用。 在Google和tomcat源代码上花费1天后,代码运行良好,可以找到用户组。

 import java.util.Hashtable; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.Name; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; public class MemberOfTest{ private static final String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory"; private static final String connectionURL = "ldap://HOST:PORT"; private static final String connectionName = "CN=Query,CN=Users,DC=XXX,DC=XX"; private static final String connectionPassword = "XXX"; // Optioanl private static final String authentication = null; private static final String protocol = null; private static String username = "XXXX"; private static final String MEMBER_OF = "memberOf"; private static final String[] attrIdsToSearch = new String[] { MEMBER_OF }; public static final String SEARCH_BY_SAM_ACCOUNT_NAME = "(sAMAccountName=%s)"; public static final String SEARCH_GROUP_BY_GROUP_CN = "(&(objectCategory=group)(cn={0}))"; private static String userBase = "DC=XXX,DC=XXX"; public static void main(String[] args) throws NamingException { Hashtable env = new Hashtable(); // Configure our directory context environment. env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory); env.put(Context.PROVIDER_URL, connectionURL); env.put(Context.SECURITY_PRINCIPAL, connectionName); env.put(Context.SECURITY_CREDENTIALS, connectionPassword); if (authentication != null) env.put(Context.SECURITY_AUTHENTICATION, authentication); if (protocol != null) env.put(Context.SECURITY_PROTOCOL, protocol); InitialDirContext context = new InitialDirContext(env); String filter = String.format(SEARCH_BY_SAM_ACCOUNT_NAME, username); SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); constraints.setReturningAttributes(attrIdsToSearch); NamingEnumeration results = context.search(userBase, filter,constraints); // Fail if no entries found if (results == null || !results.hasMore()) { System.out.println("No result found"); return; } // Get result for the first entry found SearchResult result = (SearchResult) results.next(); // Get the entry's distinguished name NameParser parser = context.getNameParser(""); Name contextName = parser.parse(context.getNameInNamespace()); Name baseName = parser.parse(userBase); Name entryName = parser.parse(new CompositeName(result.getName()) .get(0)); // Get the entry's attributes Attributes attrs = result.getAttributes(); Attribute attr = attrs.get(attrIdsToSearch[0]); NamingEnumeration e = attr.getAll(); System.out.println("Member of"); while (e.hasMore()) { String value = (String) e.next(); System.out.println(value); } } } 

最简单的方法是使用’lookup’:(打开Ldap Context:看上面的例子)

  /** * Tests if an Active Directory user exists in an Active Directory group. * @param ctx LDAP Context. * @param dnADGroup distinguishedName of group. * @param dnADUser distinguishedName of user. * @return True if user is member of group. */ public static boolean isMemberOfADGroup(LdapContext ctx, String dnADGroup, String dnADUser) { try { DirContext lookedContext = (DirContext) (ctx.lookup(dnADGroup)); Attribute attrs = lookedContext.getAttributes("").get("member"); for (int i = 0; i < attrs.size(); i++) { String foundMember = (String) attrs.get(i); if(foundMember.equals(dnADUser)) { return true; } } } catch (NamingException ex) { String msg = "There has been an error trying to determin a group membership for AD user with distinguishedName: "+dnADUser; System.out.println(msg); ex.printStackTrace(); } return false; } 

查找用户是否是组成员的LDAP查找方法不正确,尤其是在您谈论登录用户时。 对于实际登录组的用户,根据用户登录的计算机而不同。 该列表需要包含来自域信任,嵌套组和本地组的组。

如果您正在寻找当前登录用户或您使用Java用户名和密码登录的用户的组成员身份,请尝试Waffle 。

 IWindowsAuthProvider prov = new WindowsAuthProviderImpl(); IWindowsIdentity identity = prov.logonUser("username", "password"); System.out.println("User identity: " + identity.getFqn()); for(IWindowsAccount group : identity.getGroups()) { System.out.println(" " + group.getFqn() + " (" + group.getSidString() + ")"); } 

不确定Java API的具体细节,但这样做的一般方法是在查询/绑定中添加组检查。

不幸的是,答案因AD的安装以及其他类型的LDAP服务器而异。

我们必须解决同样的问题。 最后,我们允许系统管理员向我们提供LDAP查询模式,我们将用户名(以及组名称,如果需要也是变量)替换为模式。

我无法使用java命名ldap为您提供工作代码。 我使用Spring LDAP,以及你的方式:获取User对象,搜索用户名,如sAMAccountName = USERNAME

获得对象后,您将检索属性memberOf – >这将是一个列表并检查Java中的特定列表。

这是我能想到的唯一方法。

我发现这很有用:

检索Active Directory的组成员身份

我有这段工作代码:

 import java.util.Hashtable; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.Name; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapContext; public class TestAD1 { private static String userBase = "DC=SomeName,DC=SomeName,DC=SomeName,DC=SomeName,DC=COM,DC=US"; public static void main(String[] args) { TestAD1 tad = new TestAD1(); try { // Create a LDAP Context Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, "ldap.serviceaccount@domain.com"); env.put(Context.SECURITY_CREDENTIALS, "drowssap"); env.put(Context.PROVIDER_URL, "ldap://fully.qualified.server.name:389"); LdapContext ctx = new InitialLdapContext(env, null); InitialDirContext inidircontext = new InitialDirContext(env); DirContext dirctx = new InitialLdapContext(env, null); System.out.println("Connection Successful."); // Print all attributes of the name in namespace SearchControls sctls = new SearchControls(); String retatts[] = {"sn", "mail", "displayName", "sAMAccountName"}; sctls.setReturningAttributes(retatts); sctls.setSearchScope(SearchControls.SUBTREE_SCOPE); String srchfilter = "(&(objectClass=user)(mail=*))"; String srchbase = userBase; int totalresults = 0; NamingEnumeration answer = dirctx.search(srchbase, srchfilter, sctls); while (answer.hasMoreElements()) { SearchResult sr = (SearchResult) answer.next(); totalresults++; System.out.println(">>> " + sr.getName()); Attributes attrs = sr.getAttributes(); if (answer == null || !answer.hasMore()) { System.out.println("No result found"); return; } if (attrs != null) { try { System.out.println(" surname: " + attrs.get("sn").get()); System.out.println(" Email - ID: " + attrs.get("mail").get()); System.out.println(" User - ID: " + attrs.get("displayName").get()); System.out.println(" Account Name: " + attrs.get("sAMAccountName").get()); tad.GetGroups(inidircontext, attrs.get("sAMAccountName").get().toString()); } catch (NullPointerException e) { System.out.println("Error listing attributes..." + e); } } System.out.println("Total Results : " + totalresults); // close dir context dirctx.close(); } ctx.close(); } catch (NamingException e) { System.out.println("Problem Search Active Directory..." + e); //e.printStackTrace(); } } // Get all the groups. public void GetGroups(InitialDirContext context, String username) throws NamingException { String[] attrIdsToSearch = new String[]{"memberOf"}; String SEARCH_BY_SAM_ACCOUNT_NAME = "(sAMAccountName=%s)"; String filter = String.format(SEARCH_BY_SAM_ACCOUNT_NAME, username); SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); constraints.setReturningAttributes(attrIdsToSearch); NamingEnumeration results = context.search(userBase, filter, constraints); // Fail if no entries found if (results == null || !results.hasMore()) { System.out.println("No result found"); return; } SearchResult result = (SearchResult) results.next(); Attributes attrs = result.getAttributes(); Attribute attr = attrs.get(attrIdsToSearch[0]); NamingEnumeration e = attr.getAll(); System.out.println(username + " is Member of the following groups : \n"); while (e.hasMore()) { String value = (String) e.next(); System.out.println(value); } } } 

此外,您可以从此处修改接受的答案:使用以下内容在Linux上使用Java对Active Directory进行身份validation :

 String group="name of the group"; Iterator ig = groups.iterator(); Boolean bool=false; while (ig.hasNext()) { String a=ig.next().toString(); if (a.equals(group)) { JOptionPane.showMessageDialog(this, "Authentication succeeded!"); bool=true; // here you can do smth in case of success } } if (bool==false){ JOptionPane.showMessageDialog(this, "Permission denied"); }