trying to solve IT problems

How I tried to fix certain programming problems, mostly in the java, JEE, JBoss scene, web area and using Ubuntu or Debian linux.

  • Home
  • Geomajas / GIS
  • About
Twitter RSS

Using UnboundID to authenticate against an LDAP server

Posted on December 7, 2011 by joachim
1 CommentLeave a comment

UnboundID is an open source project which provides an SDK for connecting to an LDAP server. Compared with other solutions, UnboundID has two advantages. For starters UnboundId includes an in-memory server which is very practical for unit testing. Secondly (and useful in my practical case) is that the UnboundId API makes it easy to deal with the complexities of an SSL connection.

My use case was to authenticate using LDAP for Geomajas. The easiest solution there is to provide an implementation of the AuthenticationService in the Geomajas staticsecurity plug-in.

Let’s start with the interesting bits, setting up a in-memory server for testing. The server needs to be created. We use a null schema to assure all attributes are allowed. Bind credentials are added for the user we add and a base data is added to the server.

protected InMemoryDirectoryServer server;

@Before
public void before() throws Exception {
  InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=org");
  config.addAdditionalBindCredentials("cn=test,dc=staticsecurity,dc=geomajas,dc=org", "cred");
  InMemoryListenerConfig listenerConfig = new InMemoryListenerConfig("test", null, PORT, null, null, null);
  config.setListenerConfigs(listenerConfig);
  config.setSchema(null); // do not check (attribute) schema
  server = new InMemoryDirectoryServer(config);
  server.startListening();

  server.add("dn: dc=org", "objectClass: top", "objectClass: domain", "dc: org");
  server.add("dn: dc=geomajas,dc=org", "objectClass: top", "objectClass: domain", "dc: geomajas");
  server.add("dn: dc=roles,dc=geomajas,dc=org", "objectClass: top", "objectClass: domain", "dc: roles");
  server.add("dn: dc=staticsecurity,dc=geomajas,dc=org", "objectClass: top", "objectClass: domain",
      "dc: staticsecurity");
  server.add("dn: cn=testgroup,dc=roles,dc=geomajas,dc=org", "objectClass: groupOfUniqueNames",
      "cn: testgroup");
  server.add("dn: cn=test,dc=staticsecurity,dc=geomajas,dc=org", "objectClass: person", "locale: nl_BE",
      "sn: Tester", "givenName: Joe", "cn: test", "memberOf: cn=testgroup,dc=roles,dc=geomajas,dc=org");
}

@After
public void shutdown() {
  server.shutDown(true);
}

In true TDD style, let’s look at the test for our authentication service before we look at the actual code. The main test (excluding initialization) look like this. For the fluent asserts, the FEST-assert library is used.

@Test
public void testLdapAuthenticationService() throws Exception {
  String password = "bladibla";
  assertThat(service.convertPassword("me", password)).isEqualTo(password);

  assertThat(service.isAuthenticated("wrong", "wrong")).isNull();

  String userId = "test";
  UserInfo authResult = service.isAuthenticated(userId, "cred");
  assertThat(authResult).isNotNull();
  assertThat(authResult.getUserId()).isEqualTo(userId);
  assertThat(authResult.getUserName()).isEqualTo("Joe Tester");
  assertThat(authResult.getUserLocale()).isEqualTo(new Locale("nl_BE"));
  assertThat(authResult.getUserOrganization()).isEqualTo("test");
  assertThat(authResult.getUserDivision()).isEqualTo("person");
  List<AuthorizationInfo> auths = authResult.getAuthorizations();
  assertThat(auths).hasSize(1);
}

On to the actual authentication. On a login request, we connect with the LDAP server and send a bind request to see whether the credentials are valid.

There is a special handling for the case when SSL certificate checks should be ignored. This can be particularly useful for testing. It is not recommended in production as this reduces security (and makes you vulnerable to man-in-the-middle attacks and and attacks using DNS, redirecting to a different server).

public UserInfo isAuthenticated(String user, String password) {
  String userDn = userDnTemplate.replace("{}", user);
  LDAPConnection connection = null;
  try {
    if (allowAllSocketFactory) {
      SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
      connection = new LDAPConnection(sslUtil.createSSLSocketFactory(), serverHost, serverPort);
    } else {
      connection = new LDAPConnection(serverHost, serverPort);
    }

    BindResult auth = connection.bind(userDn, password);
    if (auth.getResultCode().isConnectionUsable()) {
      List<String> attributes = new ArrayList<String>();
      attributes.add("cn");
      addAttribute(attributes, givenNameAttribute);
      addAttribute(attributes, surNameAttribute);
      addAttribute(attributes, localeAttribute);
      addAttribute(attributes, organizationAttribute);
      addAttribute(attributes, divisionAttribute);
      addAttribute(attributes, rolesAttribute);
      SearchRequest request = new SearchRequest(userDn, SearchScope.SUB,
          Filter.createEqualityFilter("objectclass", "person"),
          attributes.toArray(new String[attributes.size()]));
      return getUserInfo(user, connection.search(request));
    }
  } catch (LDAPException le) {
    String message = le.getMessage();
    if (!message.startsWith("Unable to bind as user ")) {
      log.error(le.getMessage(), le);
    }
  } catch (GeneralSecurityException gse) {
    log.error(gse.getMessage(), gse);
  } finally {
    if (null != connection) {
      connection.close();
    }
  }
  return null;  // not logged in
}

The information about the logged in user and the roles is built from the configured attributes in the getUserInfo method.

private UserInfo getUserInfo(String userId, SearchResult search) {
  if (search.getEntryCount() > 0) {
    SearchResultEntry entry = search.getSearchEntries().get(0);
    UserInfo result = new UserInfo();
    result.setUserId(userId);
    String name = entry.getAttributeValue(givenNameAttribute);
    String name2 = entry.getAttributeValue(surNameAttribute);
    if (null != name) {
      if (null != name2) {
        name += " " + name2;
      }
    } else {
      name = name2;
    }
    result.setUserName(name);
    result.setUserLocale(entry.getAttributeValue(localeAttribute));
    result.setUserOrganization(entry.getAttributeValue(organizationAttribute));
    result.setUserDivision(entry.getAttributeValue(divisionAttribute));
    result.setAuthorizations(getAuthorizations(entry));
    return result;
  }
  return null;
}

The full source code can be found here.

Categories: geomajas / GIS, java
Routing demo at FOSS4G Denver
Let’s make this test suite run faster, BeJUG session

One Response to “Using UnboundID to authenticate against an LDAP server”

  1. Terry says:
    December 7, 2011 at 12:15

    Good information, thanks. For some more information, see my LDAP blog at http://ff1959.wordpress.com/2011/11/01/ldap-in-memory-directory-server-using-unboundid-ldap-sdk/

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

*

*


question razz sad evil exclaim smile redface biggrin surprised eek confused cool lol mad twisted rolleyes wink idea arrow neutral cry mrgreen

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

  • Recent Posts

    • December BeJUG notes: Let’s make this test suite run faster
    • MagdaGeo sample
    • Geomajas GIS framework 2011 roundup
    • Routing demo at FOSS4G Denver
    • Using UnboundID to authenticate against an LDAP server
  • Recent Comments

    • javaLearner on CXF ws client, dynamic endpoint and loading WSDL from the classpath
    • Geomajas GIS framework 2011 roundup « trying to solve IT problems on Routing demo at FOSS4G Denver
    • Sumant on delete windows service account
    • asme standards on Using Infinispan for high availability, extreme performance, Manik Surtani & Galder ZamarreƱo
    • Terry on Using UnboundID to authenticate against an LDAP server
  • Categories

    • architecture
    • competencies
    • equanda
    • geomajas / GIS
    • java
    • jboss
    • maven
    • semantics
    • tapestry5
    • ubuntu / debian / linux
    • Uncategorized
    • web development
    • web services
© trying to solve IT problems. Proudly Powered by WordPress | Nest Theme by YChong