javaldapapache-directory

How to implement authentication with Apache Directory Server and Client Java API


I am trying to build an application in which the users and groups will be managed in a Apache Directory Server and its client API.

This is an example of the ldif file being executed against the server when the app is starting:

dn: o=koosserydesk objectclass: extensibleObject objectclass: top objectclass: domain dc: koosserydesk o: koosserydesk
dn: ou=desks,o=koosserydesk objectClass: organizationalUnit objectClass: top ou: desks
dn: ou=users,o=koosserydesk objectClass: organizationalUnit objectClass: top ou: users
dn: cn=John Milton,ou=users,o=koosserydesk objectClass: organizationalPerson objectClass: person objectClass: inetOrgPerson objectClass: top cn: John Milton sn: jmilton uid: jmilton userPassword:: e1NIQTUxMn1lQThmcUQzOVgva2xxSm1jOGlZK2JoWitUVFhzWElFRmZHeWJ1b

I want to let John Milton being recognized as an authenticated user of my app when he enters the corresponding uid/userPassword. Something like:

Boolean authenticate(String uid){
//should i use connection.bind("uid="+uid, userPassword);??
return something; }

Note that John Milton being authenticated against ApacheDS (for acting on entries) is not the most important for me. I just want ApacheDs to act as DB for my users ie take the uid of my user, check the password, if it matches return true, either return false.
May be this is not the way i should try to handle this, but i am pretty new to Ldap Protocol and stuffs around, so do not wonder if my problem is kind of weird!
Waiting for propositions!


Solution

  • This may not be a duplicate, but the second answer (by Nikolay Antipov) on the following question might answer your question: How to check user password in ldap whith java with given LdapContext?


    This is a solution that can be used to authenticate a user with something else than the DN, for example with a uid or sAMAccountName.

    The steps to do are:

    1. Connect to the LDAP server
    2. Authenticate with a service user of whom we know the DN and credentials
    3. Search for the user you want to authenticate, search him with some attribute (for example sAMAccountName)
    4. Get the DN of the user we found
    5. Open another connection to the LDAP server with the found DN and the password
    6. If the user is found and authentication works, you are fine

    Code example:

    public static boolean performAuthentication() {
    
        // service user
        String serviceUserDN = "cn=Mister Service,ou=Users,dc=example,dc=com";
        String serviceUserPassword = "abc123#!$";
    
        // user to authenticate
        String identifyingAttribute = "uid";
        String identifier = "maxdev";
        String password = "jkl987.,-";
        String base = "ou=Users,dc=example,dc=com";
    
        // LDAP connection info
        String ldap = "localhost";
        int port = 10389;
        String ldapUrl = "ldap://" + ldap + ":" + port;
    
        // first create the service context
        DirContext serviceCtx = null;
        try {
            // use the service user to authenticate
            Properties serviceEnv = new Properties();
            serviceEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            serviceEnv.put(Context.PROVIDER_URL, ldapUrl);
            serviceEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
            serviceEnv.put(Context.SECURITY_PRINCIPAL, serviceUserDN);
            serviceEnv.put(Context.SECURITY_CREDENTIALS, serviceUserPassword);
            serviceCtx = new InitialDirContext(serviceEnv);
    
            // we don't need all attributes, just let it get the identifying one
            String[] attributeFilter = { identifyingAttribute };
            SearchControls sc = new SearchControls();
            sc.setReturningAttributes(attributeFilter);
            sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
    
            // use a search filter to find only the user we want to authenticate
            String searchFilter = "(" + identifyingAttribute + "=" + identifier + ")";
            NamingEnumeration<SearchResult> results = serviceCtx.search(base, searchFilter, sc);
    
            if (results.hasMore()) {
                // get the users DN (distinguishedName) from the result
                SearchResult result = results.next();
                String distinguishedName = result.getNameInNamespace();
    
                // attempt another authentication, now with the user
                Properties authEnv = new Properties();
                authEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
                authEnv.put(Context.PROVIDER_URL, ldapUrl);
                authEnv.put(Context.SECURITY_PRINCIPAL, distinguishedName);
                authEnv.put(Context.SECURITY_CREDENTIALS, password);
                new InitialDirContext(authEnv);
    
                System.out.println("Authentication successful");
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (serviceCtx != null) {
                try {
                    serviceCtx.close();
                } catch (NamingException e) {
                    e.printStackTrace();
                }
            }
        }
        System.err.println("Authentication failed");
        return false;
    }