cancel
Showing results for 
Search instead for 
Did you mean: 

Programmatically LDAP configuration

matutano6
Champ in-the-making
Champ in-the-making
Hi,
I'm trying to configure LDAP on a ProcessEngine by doing it programmatically on Activiti 5.14. First, I want to use the default configuration resource (i.e. activiti.cf.xml) and then configure the LDAP properties. Everythings seems to work until the engine tries to do queries to the LDAP server; then I get the following exception:


java.lang.NullPointerException
   at org.activiti.ldap.LDAPQueryBuilder$1.executeInContext(LDAPQueryBuilder.java:62)
   at org.activiti.ldap.LDAPQueryBuilder$1.executeInContext(LDAPQueryBuilder.java:55)
   at org.activiti.ldap.LDAPTemplate.execute(LDAPTemplate.java:44)
   at org.activiti.ldap.LDAPQueryBuilder.buildQueryGroupsForUser(LDAPQueryBuilder.java:55)
   at org.activiti.ldap.LDAPGroupManager$1.executeInContext(LDAPGroupManager.java:115)
   at org.activiti.ldap.LDAPGroupManager$1.executeInContext(LDAPGroupManager.java:111)
   at org.activiti.ldap.LDAPTemplate.execute(LDAPTemplate.java:44)
   at org.activiti.ldap.LDAPGroupManager.findGroupsByUser(LDAPGroupManager.java:111)
   at org.activiti.engine.impl.TaskQueryImpl.getGroupsForCandidateUser(TaskQueryImpl.java:477)
(not relevant stacktrace follows)


This is the code I'm using:


/* Create default configuration */
ProcessEngineConfigurationImpl engineConfiguration = (ProcessEngineConfigurationImpl)
   ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();

/* Populate configuration */
LDAPConfigurator ldapConfigurator = new LDAPConfigurator();
ldapConfigurator.setServer("actual value was removed");
ldapConfigurator.setPort(10389);
ldapConfigurator.setUser("actual value was removed");
ldapConfigurator.setPassword("actual value was removed");
      
ldapConfigurator.setUserBaseDn("actual value was removed");
ldapConfigurator.setGroupBaseDn("actual value was removed");

ldapConfigurator.setQueryUserByUserId("actual value was removed");
ldapConfigurator.setQueryUserByFullNameLike("actual value was removed");
ldapConfigurator.setQueryGroupsForUser("actual value was removed");
      
ldapConfigurator.setUserIdAttribute("actual value was removed");
ldapConfigurator.setUserFirstNameAttribute("actual value was removed");
ldapConfigurator.setUserLastNameAttribute("actual value was removed");
      
ldapConfigurator.setGroupIdAttribute("actual value was removed");
ldapConfigurator.setGroupNameAttribute("actual value was removed");
      
ldapConfigurator.setInitialContextFactory("com.sun.jndi.ldap.LdapCtxFactory");
ldapConfigurator.setSecurityAuthentication("simple");

/* Build process engine */
engineConfiguration.getConfigurators().add(ldapConfigurator);
ProcessEngine processEngine = engineConfiguration.buildProcessEngine();


I browse the code (5.14) and found that the exception is raised at this line (LDAPQueryBuilder.java:62):

NamingEnumeration< ? > namingEnum = initialDirContext.search(baseDn, userDnSearch, createSearchControls(ldapConfigurator));


If I'm not missing anything, the only way to have a NPE at that line is by having initialDirContext null. So, browsing up the origin of that object I arrived to LDAPConnectionUtil.createDirectoryContext:


public static InitialDirContext createDirectoryContext(LDAPConfigurator ldapConfigurator, String principal, String credentials) {
    Properties properties = new Properties();
    properties.put(Context.INITIAL_CONTEXT_FACTORY, ldapConfigurator.getInitialContextFactory());
    properties.put(Context.PROVIDER_URL, ldapConfigurator.getServer() + ":" + ldapConfigurator.getPort());
    properties.put(Context.SECURITY_AUTHENTICATION, ldapConfigurator.getSecurityAuthentication());
    properties.put(Context.SECURITY_PRINCIPAL, principal);
    properties.put(Context.SECURITY_CREDENTIALS, credentials);
   
    if (ldapConfigurator.getCustomConnectionParameters() != null) {
      for (String customParameter : ldapConfigurator.getCustomConnectionParameters().keySet()) {
        properties.put(customParameter, ldapConfigurator.getCustomConnectionParameters().get(customParameter));
      }
    }

    InitialDirContext context;
    try {
      context = new InitialDirContext(properties);
    } catch (NamingException e) {
      throw new ActivitiException("Could not create InitialDirContext for LDAP connection : " + e.getMessage(), e);
    }
    return context;
  }


Once again, the only way to get a null InitialDirContext is by leaving that method from the catch block, but I'm not getting that exception (at least, it's not beign shown in the log).

I think theres something missing when I populate the LDAPConfigurator, but I couldn't realize what it is yet. Maybe, the way I'm doing it is totally wrong and there has to be another approach to do what I'm trying to do. ¿Could please anyone tell me if I'm taking the right path or what's missing in my code?

Thanks in advance!
Regards,
M.
3 REPLIES 3

matutano6
Champ in-the-making
Champ in-the-making
Hi everyone,
I found the problem and I want to share the experience.

Effectively, the problem was that the InitialDirContext could not be created, but the exception was not logged due to the configuration of the logger. The exception thrown was:

<code>
Caused by: javax.naming.NamingException: Cannot parse url: 1xx.2xx.3xx.4xx:10389 [Root exception is java.net.MalformedURLException: Not an LDAP URL: 1xx.2xx.3xx.4xx:10389]
at com.sun.jndi.ldap.LdapURL.<init>(LdapURL.java:95)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:164)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:211)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:154)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:84)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
at javax.naming.InitialContext.init(InitialContext.java:240)
at javax.naming.InitialContext.<init>(InitialContext.java:214)
at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:99)
at org.activiti.ldap.LDAPConnectionUtil.createDirectoryContext(LDAPConnectionUtil.java:54)
… 204 more
Caused by: java.net.MalformedURLException: Not an LDAP URL: 1xx.2xx.3xx.4xx:10389
at com.sun.jndi.ldap.LdapURL.<init>(LdapURL.java:89)
… 214 more
</code>

After looking at the code, the LDAPConnectionUtil does the following:
<code>
properties.put(Context.PROVIDER_URL, ldapConfigurator.getServer() + ":" + ldapConfigurator.getPort());
</code>

It means that the resulting string after the concatenation of <em>ldapConfigurator.getServer() + ":" + ldapConfigurator.getPort()</em> should contain the URL's scheme (i.e. ldap:// or ldaps://). Immediatelly, a looked into the activiti.cfg.cml and remember that the scheme must be part of the server element:
<code>
<property name="server" value="ldap://1xx.2xx.3xx.4xx" />
</code>

So, the short story: remember to add the scheme!

And finally, I would like to suggest a tweak here. The LDAP could be cofigured using an URL instead of an IP (with scheme) and a TCP port. If I'm not wrong, software that use LDAP are tending to configure the connection through an URL.

Regards,
M.

jbarrez
Star Contributor
Star Contributor
Thanks for sharing the solution to your problem!

I'ù not following the remark about the URL. Do you mean that we should not use 'ldapConfigurator.getServer() + ":" + ldapConfigurator.getPort()', but pass a URl directly?

matutano6
Champ in-the-making
Champ in-the-making
Hi Joram,
IMHO, I think there should be two possible ways of configuring the LDAP server:

1. Scheme, server and port as three separate properties
<code>
properties.put(Context.PROVIDER_URL, ldapConfigurator.getScheme() + "://" + ldapConfigurator.getServer() + ":" + ldapConfigurator.getPort());
</code>

2. A complete URL including scheme, server and port, and possibly some other connection options (sometimes, LDAP server specific ones)
<code>
properties.put(Context.PROVIDER_URL, ldapConfigurator.getConnectionURL());
</code>

Without the addition of other parameters, the first options will not have the possibility of specifying other options, like root o partition in URLs like this:
ldap://localhost:389/ou=employees,dc=company,dc=org

That kind of connection options are not currently supported with the LDAPConfigurator, are they?

I'm really not an expert with LDAP, but an experienced user. May be the best answers could be found at the source: http://www.ietf.org/rfc/rfc2255.txt

Thanks for considering my suggestions!

Regards,
M.