SASL LDAP Proxy Authentication in OpenLDAP and Java

SASL is a way for handling authentication and “act-as” issues in protocol. LDAP is using it in an alternative way to direct simple binds.

This article will show how to use a SASL LDAP proxy authentication by adding it to OpenLDAP and using it through Java Naming and Directory Interface.

First, set up a OpenLDAP directory with fully functional SASL settings. Build or use an OpenLDAP directory that is linked to libsasl2 : you can check that libsasl2 is used :

$ ldd /usr/sbin/slapd |grep sasl
libsasl2.so.2 => /usr/lib/libsasl2.so.2 (0x00007fac2e546000)

If you want to build your own version of OpenLDAP, the required option is –with-cyrus-sasl.

Then suppose a directory with the following entries :

dc=foo,dc=bar
  |-cn=proxy
  |-ou=People
    |-uid=user1

We suppose you want to use the proxy account to act-as users (i.e. user1 in our sample) to search, read and write to the directory without using their passwords.

You need to understand the main SASL concepts :

  • the authentication id : this is the account used to connect to the directory, i.e. cn=proxy
  • the authorization id : the account authorized (or not) to act, i.e. uid=user1
  • the authentication credentials : a user password or any way to authenticate

In OpenLDAP, SASL is handle natively (by OpenLDAP itself) without the need of third-party configuration (no need of /usr/lib/sasl2/slapd.conf, this was the old way 🙂 !). So let’s explain how it will handle SASL bind requests :

  • the initial messages are exchanged between the client and the server to check for the authentication method (PLAIN, DIGEST-MD5, …) and will provide server general information (realm, server name, supported ciphers, level for quality of protection, charset, …) and session shared secret
  • on the server side, the second step will use the provided authentication id by passing it to the ‘authz-regexp’ regular expression to get a authentication DN. This will be in the form uid=<authentication_id>,cn=<auth_method>,cn=auth where authentication_id will be replaced by the authentication id you have provided (username or full dn) and auth_method will be the SASL authentication method used (DIGEST-MD5, EXTERNAL, …). So if you plan to use the proxy username, you will require a regex such as
    authz-regexp
        "uid=([^,]*),cn=digest-md5,cn=auth"
        "ldap:///dc=foo,dc=bar??one?cn=$1"

    Then the authentication DN is used to check the password, which must be stored in a clear text format inside the userPassword attribute (take care that an “auth” access right is required). Therefore, you must ensure that password changes for the proxy account must always be stored in a clear text format (see password-hash OpenLDAP directive) and that the userPassword attribute is fully protected from an unauthorized retrieve
  • the second step is also a pattern matching from the authorization id against the same authz-regexp rules. Then you need the corresponding regexp :
    authz-regexp
        "uid=([^,]*),ou=People,dc=foo,dc=bar"
        "ldap:///ou=People,dc=foo,dc=bar??one?uid=$1"
  • the last step is to check if the authentication id is authorized to “act as” the authorization id. The way OpenLDAP check for that is against the authzTo and/or authzFrom attributes. These attributes define if the authentication id can be “authorized to” act as the authorization id and/or if the authorization id can be “authorized from” to act as the authentication id. An “auth” access right is also required on these attributes. Thus you need the following attribute inside the cn=proxy entry :
    authzTo: dn.regex: uid=[^,]+,ou=People,dc=foo,dc=bar

If all previous items are correct, you would be able to achieve successfully the following commands :

  • a sasl bind through a LDAP who am i extended operation :
    ldapwhoami -Y DIGEST-MD5 -U proxy
  • a sasl proxied bind :
    ldapwhoami -Y DIGEST-MD5 -U proxy -X "dn:uid=user1,ou=People,dc=foo,dc=bar"

You are now ready to get ride of the Java part.

First of all, check that the following requirements are fully satisfied :

  • a Sun JRE with Java Cryptographic Extension (JCE) deployed

Then create a new class, for example, SaslClientTest :

public class SaslClientTest {
}

Add a constructor and force Sun SASL Security Provider load :

  public SaslClientTest() {
    Security.addProvider(new com.sun.security.sasl.Provider());
  }

Inside the test method, create a property map and put required settings (that you may need to adapt to fit hostname, port, …)

  public void testSaslBind {
    Properties env = new Properties();
    env.put(InitialLdapContext.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(InitialLdapContext.PROVIDER_URL, "ldap://localhost:389/dc=foo,dc=bar");
    env.put(InitialLdapContext.LDAP_VERSION, "3");
    env.put(InitialLdapContext.SECURITY_AUTHENTICATION, "DIGEST-MD5");
    env.put(InitialLdapContext.SECURITY_PRINCIPAL, "proxy");
    env.put(InitialLdapContext.SECURITY_CREDENTIALS, "proxy");
  }

Now put the proxied authorization id :

    env.put("java.naming.security.sasl.authorizationId","dn:uid=user1,ou=People,dc=foo,dc=bar");

Then you only need to create your LDAP context with the standard method :

    LdapContext lc = new InitialLdapContext(env, null);

That’s it : your connection will be established with the proxy account but will be recognized and authorized as user1 directory entry. With a OpenLDAP 2.4, you may have the following type of log :

conn=4 fd=17 ACCEPT from IP=[::1]:34084 (IP=[::]:389)
conn=4 op=0 BIND dn=”” method=163
conn=4 op=0 RESULT tag=97 err=14 text=SASL(0): successful result:
conn=4 op=1 BIND dn=”” method=163
conn=4 op=1 BIND authcid=”proxy” authzid=”dn:uid=user1,ou=people,dc=foo,dc=bar”
conn=4 op=1 BIND dn=”cn=proxy,dc=foo,dc=bar” mech=DIGEST-MD5 sasl_ssf=128 ssf=128
conn=4 op=1 RESULT tag=97 err=0 text=
conn=4 op=2 SRCH base=”uid=user1,ou=people,dc=foo,dc=bar” scope=2 deref=0 filter=”(objectClass=*)”
conn=4 op=2 SRCH attr=*
conn=4 op=2 SEARCH RESULT tag=101 err=0 nentries=1 text=
conn=4 op=3 UNBIND
conn=4 fd=17 closed

Troubleshooting

  1. you can encountered errors in the first step (arround OpenLDAP). If you have follow instructions, launch OpenLDAP with a great loglevel (launch slapd with -d -1) and take a look at ACL messages : if at any moment, an attribute is not well authorized, your SASL bind will fail
  2. If you encountered an error in the second step, try to look at the messages exchanged with the server through the following complementary setting :
    env.put("com.sun.jndi.ldap.trace.ber", System.err);
Posted in Identity, OpenSource | Leave a comment

LSC 2.0 in preparation

Ldap Synchronization Connector is near from a next generation version. Designed during the FOSDEM 2010, 2.0 version will include full of cool new features :

  • Web administrative interface : start/stop, follow tasks run, configure, plan, … do everything through a friendly web interface
  • Write anywere : initially designed to write only to a directory, LSC now supports writing to other data source
  • Scheduler : an quartz scheduler is embedded to support planned execution of tasks
  • Connectors architecture : it allows LSC to support data source as Java archive provided at runtime
  • NIS source connector : it allows reading from a NIS directory any map stored (passwd, group, automount, …)
  • Executable writable connector : it provides capabilities of writing through scripts and reading either through an LDAP connection or also through scripts
  • XML configuration file format : a new configuration file format has been introduced to support automatic analysis and generation

You can see the preview at the following location : http://build.lsc-project.org/lsc-webai-snapshot/

This version will be able to read existing lsc.properties 1.X configuration file format to allow smooth transition from 1.X to 2.0.

Estimated delivery time is about 3 to 6 months depending on Q/A efforts and feedback on the first release client that will be published near April 2011.

My personal goal for the next major version (3.0) will be to redesign synchronization process arround a data bus, and will require arround 1 or 2 years.

Posted in Identity, OpenSource | Leave a comment

Voyages-sncf.fr : Biggest French ecommerce website now fully Open Source

I’m pleased to see that tests I’ve contributed to achieve to demonstrate functions and high performance level of Open Source components have been enough successful to help the biggest french ecommerce website to move on a fully Open Source architecture : Drupal, Tomcat, …

See the original news, news on lemonde.fr and the new web site : Voyages-sncf.com

Posted in OpenSource | Leave a comment

Rebirth of this blog

After 6 months of downtime, I’m pleased to restart my blog to post info and links about OSS IAM and Security. I’ll repost lastest news that were on my previous blog soon (thanks to Internet Archive 🙂

Posted in General | Leave a comment