簡體   English   中英

Java LDAP - 確定用戶是否在給定組中?

[英]Java LDAP - Determine if user in a given group?

我們使用 Java LDAP API 通過 LDAP 將用戶登錄到 Active Directory。 我們希望增強我們的登錄功能,以進一步檢查用戶是否在給定的 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 {
    ...
}

更新:請參閱下面的解決方案。

我們用下面的課程解決了這個問題。 只需調用身份驗證方法:

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

以上代碼片段都不適合我。 在 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);
        }
    }
}

最簡單的方法是使用“查找”:(打開一個 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;
 }

用於查找用戶是否為組成員的 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() + ")"); 
} 

跟進 Sundaramurthi 的回答,它可以以更直接的方式完成,您無需查詢所有用戶組:

(&(objectClass=user)(sAMAccountName=XXXX)(memberOf=CN=YYY,OU=_Common-Access,OU=Groups,OU=_CORP,DC=XXX,DC=XX))

其中 XXXX - 用戶名 XXX.XX - 域名 YYY - 組名

這讓您可以得到用戶是否在一個組中的答案。

所以只需這樣做:

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

不確定 Java API 細節,但這樣做的通用方法是向查詢/綁定添加組檢查。

我不能給你一個使用 java 命名 ldap 的工作代碼。 我使用了 Spring LDAP,以及你這樣做的方式:獲取用戶對象,對用戶名進行搜索,例如 sAMAccountName=USERNAME

獲得對象后,您檢索屬性 memberOf -> 這將是一個列表,並在 Java 中檢查特定的列表。

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

要在建立連接后查詢用戶是否屬於給定組,您可以使用 Active Directory 中的 member 或 memberOf 屬性進行查詢。

使用 memberOf 屬性:使用的過濾器 : (&(Group Member Attribute=Group DN)(objectClass=Group Object class)) 例如:(&(memberOf=CN=group,ou=qa_ou,dc=ppma,dc=org)(objectClass =組))

Using member Attribute : filter used : (&(Group Member Attribute=User DN)(objectClass=Group Object class)) 例如:(&(member=CN=user,ou=qa_ou,dc=ppma,dc=org)(objectClass =組))

我發現這很有用:

檢索 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 進行身份驗證,如下所示:

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

不幸的是,答案因 AD 以及其他類型的 LDAP 服務器的安裝而異。

我們必須解決同樣的問題。 最后,我們允許系統管理員為我們提供一個 LDAP 查詢模式,我們將用戶名(如果也需要可變,則組名)替換到模式中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM