Java LDAP - 确定用户是否在给定组中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/570466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java LDAP - Determine if user in a given group?
提问by Marcus Leon
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?
我们使用 Java LDAP API 通过 LDAP 将用户登录到 Active Directory。我们希望增强我们的登录功能,以进一步检查用户是否在给定的 AD 组中。有谁知道如何做到这一点?
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.
更新:请参阅下面的解决方案。
采纳答案by Marcus Leon
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;
}
}
回答by Jason Cohen
Unfortunately the answer varies with installations of AD as well as other types of LDAP server.
不幸的是,答案因 AD 以及其他类型的 LDAP 服务器的安装而异。
We had to solve the same problem. In the end we allowed the system administrator to provide us with an LDAP query-pattern where we substitute the user name (and group name if that needs to be variable too) into the pattern.
我们必须解决同样的问题。最后,我们允许系统管理员为我们提供一个 LDAP 查询模式,我们将用户名(如果也需要可变,则组名)替换到模式中。
回答by Alexandru Luchian
I can't give you a working code using java naming ldap. I used Spring LDAP, and the way you do it: Get the User object, do a search on the username something like sAMAccountName=USERNAME
我不能给你一个使用 java 命名 ldap 的工作代码。我使用了 Spring LDAP,以及你这样做的方式:获取用户对象,对用户名进行搜索,例如 sAMAccountName=USERNAME
After you get the object you retreive the property memberOf -> this will be a list and check for a specific one in Java.
获得对象后,您检索属性 memberOf -> 这将是一个列表,并在 Java 中检查特定的列表。
That is the only way I could think of.
这是我能想到的唯一方法。
回答by Ryan Graham
Not sure about Java API specifics, but the generic way of doing this is adding a group check to the query/binding.
不确定 Java API 细节,但这样做的通用方法是向查询/绑定添加组检查。
回答by dB.
LDAP lookup methods of finding whether a user is a member of a group are not correct, especially if you're talking about a logged on user. For a user that's actually logged on the list of groups varies depending on which computer the user logged on. That list needs to include groups from domain trusts, nested groups and local groups.
用于查找用户是否为组成员的 LDAP 查找方法不正确,尤其是在您谈论已登录用户时。对于实际登录的用户,组列表因用户登录的计算机而异。该列表需要包括来自域信任、嵌套组和本地组的组。
If you're looking for group memberships of the currently logged on user or a user that you're logging on with a username and password in Java, try Waffle.
如果您正在寻找当前登录用户的组成员身份或您使用 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() + ")");
}
回答by Sundaramurthi
None of above code snippets didn't worked for me. After 1 day spending on Google and tomcat source following code worked well to find user groups.
以上代码片段都不适合我。在 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<String, String> env = new Hashtable<String, String>();
// 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);
}
}
}
回答by INTER
The easiest way is with 'lookup': (to open an Ldap Context: look above examples)
最简单的方法是使用“查找”:(打开一个 Ldap 上下文:查看上面的示例)
/**
* 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;
}
回答by Ajay Kumar
I found this useful:
我发现这很有用:
retrieves-group-membership for Active Directory
And I have this piece of working code:
我有这段工作代码:
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, "[email protected]");
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);
}
}
}
回答by Summer256
Also you can modify the accepted answer from here: Authenticating against Active Directory with Java on Linuxwith the following:
您也可以从此处修改已接受的答案:在 Linux上使用 Java 对 Active Directory 进行身份验证,如下所示:
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");
}
回答by Konrad
Following up on Sundaramurthi's answer, it could be done even more straightforward way, where you don't query for all the user's group:
跟进 Sundaramurthi 的回答,它可以以更直接的方式完成,您无需查询所有用户组:
(&(objectClass=user)(sAMAccountName=XXXX)(memberOf=CN=YYY,OU=_Common-Access,OU=Groups,OU=_CORP,DC=XXX,DC=XX))
where XXXX - user name XXX.XX - domain name YYY - group name
其中 XXXX - 用户名 XXX.XX - 域名 YYY - 组名
This lets you to just get an answer whether user is in a group or not.
这让您可以得到用户是否在一个组中的答案。
So just do:
所以只需这样做:
String userBase = "DC=XXX,DC=XX";
String CHECK_IF_USER_IN_GROUP = "(&(objectClass=user)(sAMAccountName=%s)(memberOf=CN=%s,OU=...,OU=...,OU=...,%s))";
String queryFilter = String.format(CHECK_IF_USER_IN_GROUP, user, group, userBase);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration results = context.search(userBase, queryFilter, constraints);
if (results == null) {
throw new Exception("No answer from LDAP");
}
if (!results.hasMore()) {
System.out.println("No result found");
// user is not in the group
}
// user is in the group