简体   繁体   中英

Programmatically connect LDAP and authenticate credentials in AEM

I want to connect to LDAP programmatically in AEM using maven dependency which resolves in OSGi

Approaches and subsequent issues faced:-

1. Cannot use

@Reference
private ExternalIdentityProviderManager externalIdentityProviderManager;

final String externalId = request.getParameter("externalId");
final String externalPassword = request.getParameter("externalPassword");

final ExternalIdentityProvider idap = externalIdentityProviderManager.getProvider("ldap");
final SimpleCredentials credentials = new SimpleCredentials(externalId, externalPassword.toCharArray());
final ExternalUser externalUser = idap.authenticate(credentials);

as this Identity provider config is only present in author environment and not in publish servers(as per req).

2. Trying to use

<dependency>
    <groupId>org.apache.directory.api</groupId>
    <artifactId>api-ldap-client-api</artifactId>
    <version>2.0.0.AM4</version>
</dependency>

to resolve dependencies. It resolve my compile time errors but this is not an 'osgi ready' library, hence couldn't be installed in OSGi . If done so manually it has further unresolved dependencies .

Code reference for this approach - https://directory.apache.org/api/user-guide/2.1-connection-disconnection.html & https://directory.apache.org/api/user-guide/2.10-ldap-connection-template.html

3. I've also tried to use

String rootDN = "uid=admin,ou=system";
String rootPWD = "secret";
Hashtable < String, String > environment = new Hashtable < String, String > ();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL, "ldap://localhost:10389");
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, rootDN);
environment.put(Context.SECURITY_CREDENTIALS, rootPWD);
DirContext dirContext = null;
NamingEnumeration < ? > results = null;
dirContext = new InitialDirContext(environment);
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String userId = "abhishek";
String userPwd = "{SSHA}ip/DD+zUhv22NH3wE1dvJN7oauYE4TYQ3ziRtg=="; //"apple";
String filter = "(&(objectclass=person)(uid=" + userId + ")(userPassword=" + userPwd + "))";
results = dirContext.search("", filter, controls);
if(results.hasMore()) {
   System.out.println("User found");
} else {
   System.out.println("User not found");
}

It has 2 issues - a) It works fine when tested as plain Java class in main method on class load, but when attempted to integrate in AEM/osgi service class, it throws -

javax.naming.NotContextException: Not an instance of DirContext at javax.naming.directory.InitialDirContext.getURLOrDefaultInitDirCtx(InitialDirContext.java:111) at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:267)

b) Even in plain Java class, i had to provide the hashed password to validate, which would be difficult to integrate.

String userPwd = "{SSHA}ip/DD+zUhv22NH3wE1dvJN7oauYE4TYQ3ziRtg==";//"apple";

Can someone provide me any maven dependency/library that can integrate with osgi and resolve dependency as well as i don't need to provide hashed password to validate user credentials? Any approach that may resolve these issues?

Step 1: Add these dependencies in project pom

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.6.2</version>
</dependency>
<dependency>
    <groupId>org.apache.directory.api</groupId>
    <artifactId>api-all</artifactId>
    <version>1.0.0-RC2</version>
</dependency>
<dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-core</artifactId>
    <version>2.1.3</version>
</dependency>
<dependency>
    <groupId>commons-pool</groupId>
    <artifactId>commons-pool</artifactId>
    <version>1.6</version>
</dependency>
<dependency>
    <groupId>antlr</groupId>
    <artifactId>antlr</artifactId>
    <version>2.7.7</version>
</dependency>

Step 2: Add them to bundle pom

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.directory.api</groupId>
    <artifactId>api-all</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-core</artifactId>
</dependency>
<dependency>
    <groupId>commons-pool</groupId>
    <artifactId>commons-pool</artifactId>
</dependency>
<dependency>
    <groupId>antlr</groupId>
    <artifactId>antlr</artifactId>
</dependency>

Step 3: In bundle pom at the plugin description

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
    <configuration>
        <instructions>
            <Import-Package>!net.sf.cglib.proxy, javax.inject;version=0.0.0,*</Import-Package>
            <Export-Package />
            <Sling-Model-Packages></Sling-Model-Packages>
            <Bundle-SymbolicName></Bundle-SymbolicName>
             <Embed-Dependency>antlr, mina-core, api-all, commons-pool, commons-pool2</Embed-Dependency>
        </instructions>
    </configuration>
</plugin>

Use these for the above mentioned plugin

<Import-Package>!net.sf.cglib.proxy</Import-Package>
<Embed-Dependency>antlr, mina-core, api-all, commons-pool, commons-pool2</Embed-Dependency>

Step 4: Imports are specifics and works only when

<dependency>
    <groupId>org.apache.directory.api</groupId>
    <artifactId>api-all</artifactId>
    <version>1.0.0-RC2</version>
</dependency>

is used. As there are some other dependencies which provides packages/class but they don't work at some point or the other.

import org.apache.directory.api.ldap.model.message.SearchScope;
import org.apache.directory.ldap.client.api.DefaultPoolableLdapConnectionFactory;
import org.apache.directory.ldap.client.api.LdapConnectionConfig;
import org.apache.directory.ldap.client.api.LdapConnectionPool;
import org.apache.directory.ldap.client.template.LdapConnectionTemplate;
import org.apache.directory.ldap.client.template.PasswordWarning;
import org.apache.directory.ldap.client.template.exception.PasswordException;

private String ldapAuthenticationApacheDsFlow(final SlingHttpServletRequest request) {
    String status = "";
    try {
        LdapConnectionConfig config = new LdapConnectionConfig();
        config.setLdapHost("localhost");
        config.setLdapPort(10389);
        config.setName("uid=admin,ou=system");
        config.setCredentials("secret");
        final DefaultPoolableLdapConnectionFactory factory = new DefaultPoolableLdapConnectionFactory(config);
        final LdapConnectionPool pool = new LdapConnectionPool(factory);
        pool.setTestOnBorrow(true);
        final LdapConnectionTemplate ldapConnectionTemplate = new LdapConnectionTemplate(pool);
        final String uid = request.getParameter("externalId");
        final String password = request.getParameter("externalPassword");
        final PasswordWarning warning = ldapConnectionTemplate.authenticate(
                "ou=Users,dc=example,dc=com", "(uid=" + uid +")", SearchScope.SUBTREE,  password.toCharArray());
        status = "User credentials authenticated";
        if(warning != null) {
            status = status + " \n Warning!!" +warning.toString();
        }
    } catch(final PasswordException e) {
        status = e.toString();
        e.printStackTrace();
    }
    return status;
}

If no error is thrown at final PasswordWarning warning = user credentials are successfully validated.

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