2009-02-20 5 views
23

Java LDAP APIを使用してLDAP経由でユーザーをActive Directoryにログオンします。ユーザーが特定のADグループにいるかどうかをさらに確認するために、ログオン機能を強化したいと考えています。誰もこれを行う方法を知っていますか?Java LDAP - 特定のグループのユーザを判別しますか?

現在のコード:

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

更新:以下のソリューションを参照してください。

答えて

18

以下のクラスでこれを解決しました。あなたはログオンしたユーザーの話をしている場合は特に、正しくないユーザーがグループのメンバーであるかどうかを見つけるの

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

グループはActive Directoryにネストすることができるので、これは完全ではないので、別のグループのメンバーであるためにグループに所属するユーザーは取得できません。これを行う正しい方法は、SIDのリストとしてグループを含むユーザーのtokenGroups属性を取得することですが、これはデコードする必要があるバイナリ属性です。参照:http://blogs.msdn.com/alextch/archive/2007/06/18/sample-java-application-that-retrieves-group-membership-of-an-active-directory-user-account.aspx –

1

回答は、ADのインストールや他のタイプのLDAPサーバーによって異なります。

私たちは同じ問題を解決しなければなりませんでした。最終的に、システム管理者はLDAPクエリーパターンを提供しました。ここで、ユーザー名(および変数が必要な場合はグループ名)をパターンに置き換えます。

+0

ありがとう。なぜ答えが変わるのですか?かなり標準的なクエリと思われます。LDAPクエリを利用するコードサンプルがありますか? –

+0

私はそれがどのようにADがmemberOfを扱うかによってADのバージョンが異なると思われます。ユーザーオブジェクトではなくグループにグループメンバーシップを格納します。ユーザーのmemberOf属性は実際には存在せず、オンザフライで計算されます。より良いLDAPサーバーは期待どおりに両方の場所に格納します – geoffc

1

java naming ldapを使用して作業コードを与えることはできません。 私は春のLDAPを使用して、あなたがそれを行う方法: Userオブジェクトを取得し、sAMAccountNameのようなユーザ名の何かに検索を行う= USERNAME

あなたは、プロパティのmemberOfを盗んオブジェクトを取得した後に - >これはとなりますJavaで特定のものを一覧表示して確認します。

これは私が考えることができる唯一の方法です。

2

ないのJava APIの仕様について確認してください、しかし、これを行うための一般的な方法は、クエリ/結合するグループのチェックを追加しています。

3

LDAP検索の方法:ちょうどauthenticateメソッドを呼び出します。グループのリストに実際にログオンしているユーザーは、ユーザーがログオンしたコンピューターによって異なります。そのリストには、ドメインの信頼、ネストされたグループ、ローカルグループのグループが含まれている必要があります。

現在ログインしているユーザーのグループメンバーシップまたは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() + ")"); 
} 
+0

これは私に有望に見えます。しかし、ここで一つの問題が見つかりました。ローカルグループ「テスト」を作成しました。この下で、私は現在のユーザーを手動で追加しました。上記のコードを実行したとき、私には "テスト"グループが表示されませんでした。どんなポインタであれ、これは本当に助けになるでしょう。 –

+0

セキュリティグループであることを確認してください(https://technet.microsoft.com/en-us/library/cc781446%28v=ws.10%29.aspx)。 –

12

上記のコードスニペットは私のためには機能しませんでした。 1日後、GoogleとTomcatのソースコードを使って、ユーザーグループを見つけるのにうまくいきました。

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); 
     } 
    } 
} 
+1

Marcusのソリューションには未知のクラス/ライブラリ(インポートするまで)と他の無関係なコードが含まれていますが、このソリューションはシンプルで機能的です。ありがとう! – elady

5

'ルック' である最も簡単な方法:(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; 
} 
0

は、私は、これは有用であることが判明:

retrieves-group-membership for Active Directory

そしてI作業コードのこの部分を持っている:

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

} 
+0

以下のコードは十分ですか? – ajayfn

関連する問題