简体   繁体   中英

Not able to retrieve users from LDAP AD server

I created LDAP AD server in Windows 2008 server using the steps mentioned in the following link:

https://blogs.msdn.microsoft.com/robert_mcmurray/2011/09/16/ftp-and-ldap-part-2-how-to-set-up-an-active-directory-lightweight-directory-services-ad-lds-server/#01b

The following program has to search for users in LDAP AD. It connects with the LDAP server successfully, but the user search is unsuccessful. I am not sure why.

public class LDAPTest {
String ldapHost = "ldap://hostname:389";
String searchBase = "CN=LDAPServer,DC=SITDomain,DC=local";

public static void main(String[] args) {
    LDAPTest ldapConnect = new LDAPTest();
    ldapConnect.authenticate("john", "****");
}

public Map authenticate(String user, String pass) {
    String returnedAtts[] = { "dintinguishedName" };
    String searchFilter = "(& (userPrincipalName="+user+")(objectClass=user))";

    // Create the search controls
    SearchControls searchCtls = new SearchControls();
    searchCtls.setReturningAttributes(returnedAtts);

    // Specify the search scope
    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

    Hashtable<Object, Object> env = new Hashtable<Object, Object>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, this.ldapHost);
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL,"CN=ryan,CN=grp,CN=LDAPServer,DC=SITDomain,DC=local");
    env.put(Context.SECURITY_CREDENTIALS, pass);

    LdapContext ctxGC = null;
    boolean ldapUser = false;

    try {
        ctxGC = new InitialLdapContext(env, null);
        // Search objects in GC using filters
        NamingEnumeration<SearchResult> answer = ctxGC.search(this.searchBase, searchFilter, searchCtls);
        while (answer.hasMoreElements()) {
            SearchResult sr = answer.next();
            System.out.println(">>>" + sr.getName());
            Attributes attrs = sr.getAttributes();
            Map amap = null;
            if (attrs != null) {
                System.out.println(attrs.size());
                System.out.println(">>>>>>" + attrs.get("dintinguishedName"));
                amap = new HashMap();
                NamingEnumeration<Attribute> ne = (NamingEnumeration<Attribute>) attrs.getAll();
                while (ne.hasMore()) {
                    Attribute attr = ne.next();
                    amap.put(attr.getID(), attr.get());
                    System.out.println(attr.getID()+">>>>>>" + attr.get());
                    ldapUser = true;
                }
                ne.close();
            }
        }

    } catch (NamingException ex) {
        ex.printStackTrace();
        System.out.println(ex.getMessage());
    }

    return null;
}

}

LDAP server dir image

Not sure if it is a copy/paste error or a typo in the code, but the user attribute being returned is spelled incorrectly. The attribute name dintinguishedName should be distinguishedName. I would also expect to see an initial bind with a known good user (eg an account specifically created for the application), a search for the user, retrieval of the distinguishedName, and a second attempt to bind with the returned distinguishedName and user supplied password. Instead I'm seeing a hard-coded ID (ryan) using the user-supplied password. Which may work if the two accounts happen to have the same password. Below this post, I have included the code I use to authenticate against my LDAP servers, including Active Directory.

I wanted universal code, and most other LDAP servers require you use the distinguishedName in the bind operation. But for Active Directory, specifically, you can bind without knowing the distinguishedName of the user -- LDAP bind to AD can be performed with sAMAccountName (domain\\user) and userPrincipalName (user@domain.TLD). If you have a single tree in a single forest (ie you know the value to append to the user ID to form sAMAccountName or userPrincipalName), you can perform a bind operation as the user. Should you need additional information about the person beyond their authentication validation, on return code 0 (successful authentication), search for the user & retrieve the information.

 // Editable variables -- ensure you change these to your application's details
String strSysUID = "uid=YOURSYSTEMIDGOESHERE,ou=OrgUnitName,dc=Org,dc=Name";
String strSysPassword = "YourSystemPasswordGoesHere";
String strAuthorizationGroup = "LJL_Test";
String strTrustStorePassword = "YourTrustStorePassword"

String trustStoreFile = ".\\ADTrust";

String sLDAPServer = "ldaps://ldap.domain.gTLD:636";
String strUserBaseDN = "ou=UserOU,dc=Org,dc=Name";
String strGroupBaseDN = "ou=GroupOU,dc=Org,dc=Name";
String strUserIDSchemaAttribute = "sAMAccountName=";            // attribute that holds user logon name
String strGroupMembershipSchemaAttribute = "member";            // attribute that holds member list in group object
// End of editable variables

System.setProperty("javax.net.ssl.trustStore", trustStoreFile);
System.setProperty("javax.net.ssl.trustStorePassword", strTrustStorePassword);

// Obtain UID and PWD from user
String sUserUID = "";
String sUserPwd = "";

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

System.out.print("Please enter your username: ");

try{
    sUserUID = in.readLine();
}catch(Exception er) { er.printStackTrace(); }

System.out.print("Please enter your password: ");
try{
    sUserPwd = in.readLine();
}catch(Exception er) { er.printStackTrace(); }

// Initial context for system bind
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, sLDAPServer);
env.put(Context.SECURITY_PROTOCOL, "ssl");

// Authenticate as system ID and password
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, strSysUID);
env.put(Context.SECURITY_CREDENTIALS, strSysPassword);

try {
    DirContext ctx = new InitialDirContext(env);

    // Using the system credentials, search for a user matching the logon ID provided by the user
    String sFilter = strUserIDSchemaAttribute + sUserUID;
    NamingEnumeration UserDNAnswer = ctx.search(strUserBaseDN, sFilter, null);

    String sReturnedFQDN = "";
    // If only one record should be returns, validate that exactly one record is located and throw an error otherwise
    while (UserDNAnswer.hasMore()) {
        SearchResult sr = (SearchResult) UserDNAnswer.next();
        // Store the DN of the user re have found
        sReturnedFQDN = sr.getNameInNamespace();
    }

    // Check group membership, can be done after the password is validated if you wish
    // Example LDAP filter is "(&(cn=NameOfGroupToCheck)(uniqueMember=FQDNOfUserBeingTested))"
    String sGroupFilter = "(&(cn=" + strAuthorizationGroup + ")(" + strGroupMembershipSchemaAttribute + "=" + sReturnedFQDN + "))";
    NamingEnumeration GroupMembershipAnswer = ctx.search(strGroupBaseDN, sGroupFilter, null);

    String sReturnedGroupDN = "";
    while (GroupMembershipAnswer.hasMore()) {
        SearchResult srGroup = (SearchResult) GroupMembershipAnswer.next();
        sReturnedGroupDN = srGroup.getNameInNamespace();
    }

    ctx.close();
    // If an entry was returned, then the user is a member of the group. We should validate the user's password
    if(sReturnedGroupDN.equals("cn=" + strAuthorizationGroup+ "," + strGroupBaseDN)){
        System.out.println(sReturnedFQDN + " is a member of " + sReturnedGroupDN + " and now we will validate the password.");

        // Now establish a new LDAP connection to validate the credentials supplied
        Hashtable envUser = new Hashtable(11);
        envUser.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        envUser.put(Context.PROVIDER_URL, sLDAPServer);

        // Authenticate using the searched FQDN for the user and the password provided by the user
        envUser.put(Context.SECURITY_AUTHENTICATION, "simple");
        envUser.put(Context.SECURITY_PRINCIPAL, sReturnedFQDN);
        envUser.put(Context.SECURITY_CREDENTIALS, sUserPwd);

        // Doing this so a login failure throws a code
        try{
            DirContext ctxUser = new InitialDirContext(envUser);
            System.out.println("Successfully authenticated as " + sUserUID);
            ctxUser .close;
        }
        // User credentials failure
        catch (NamingException e) {
            e.printStackTrace();
        }
    }
    // If no group matched the filter, the user is not a group member and an authorisation failure can be returned
    else{
        System.out.println(sReturnedFQDN + " is NOT a member of " + sReturnedGroupDN + " and there is no need to verify the password.");
    }
}
// System credentials failure
catch (NamingException e) {
    e.printStackTrace();
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM