Question Java LDAP - Détermine si l'utilisateur dans un groupe donné?


Nous connectons les utilisateurs à Active Directory via LDAP à l'aide de l'API Java LDAP. Nous souhaitons améliorer notre fonctionnalité d'ouverture de session afin de vérifier si l'utilisateur se trouve dans un groupe AD donné. Est-ce que quelqu'un sait comment faire ça?

Code actuel:

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

Mettre à jour: Voir la solution ci-dessous.


24
2018-02-20 17:18


origine


Réponses:


Nous avons résolu ce problème avec la classe ci-dessous. Il suffit d'appeler la méthode d'authentification:

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

18
2017-10-13 17:09



Aucun des extraits de code ci-dessus n'a fonctionné pour moi. Après une journée passée sur Google et sur le code source de Tomcat, le code a bien fonctionné pour trouver des groupes d'utilisateurs.

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

12
2017-08-05 09:54



Le moyen le plus simple est d'utiliser "lookup": (pour ouvrir un contexte Ldap: regardez les exemples ci-dessus)

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

5
2018-01-11 13:15



Les méthodes de recherche LDAP pour déterminer si un utilisateur est membre d'un groupe ne sont pas correctes, surtout si vous parlez d'un utilisateur connecté. Pour un utilisateur actuellement connecté, la liste des groupes varie selon l'ordinateur sur lequel l'utilisateur s'est connecté. Cette liste doit inclure des groupes provenant d'approbations de domaines, de groupes imbriqués et de groupes locaux.

Si vous recherchez des appartenances à un groupe d'utilisateurs actuellement connectés ou d'un utilisateur avec un nom d'utilisateur et un mot de passe en Java, essayez Gaufre.

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

3
2018-04-08 13:02



Vous n'êtes pas sûr des spécificités de l'API Java, mais la méthode générique consiste à ajouter une vérification de groupe à la requête / à la liaison.


2
2018-02-20 17:29



Malheureusement, la réponse varie selon les installations d'AD et d'autres types de serveur LDAP.

Nous avons dû résoudre le même problème. En fin de compte, nous avons permis à l'administrateur système de nous fournir un modèle de requête LDAP dans lequel nous substituons le nom d'utilisateur (et le nom du groupe si cela doit également être variable) au modèle.


1
2018-02-20 17:23



Je ne peux pas vous donner un code de travail en utilisant java naming ldap. J'ai utilisé Spring LDAP et la façon dont vous le faites: Obtenez l'objet utilisateur, effectuez une recherche sur le nom d'utilisateur quelque chose comme sAMAccountName = USERNAME

Une fois que vous obtenez l'objet que vous récupérez, la propriété memberOf -> ce sera une liste et recherchez un objet spécifique en Java.

C'est la seule façon de penser.


1
2018-02-20 17:27



J'ai trouvé cela utile:

récupère l'appartenance à un groupe pour Active Directory

Et j'ai ce morceau de code de travail:

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

}

0
2018-02-26 16:58



Vous pouvez également modifier la réponse acceptée ici: Authentification contre Active Directory avec Java sous Linux avec les éléments suivants:

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

0
2018-03-13 12:27