Standalone Tomcat with jBoss plus authentication against LDAP

There is a 2nd edition of this post: Standalone Tomcat with jBoss (2nd Edition)!
This tutorial desribes, how to install and configure a standalone Tomcat, so that a deployed webapp can authenticate against LDAP and connect to a jBoss passing the credentials in every call of an EJB via remote interface , so that the business application can authenticate against the same LDAP, too. The configuration of the jBoss seems to be a more common and better documented task and will be covered in another tutorial, which I will link here later, as soon as I have written it.

WARNING: Please don’t use this solution in a productive system, but for testing purpose only. The custom LdapExtLoginModule presented here exposes the credentials of all online users to all classes using the same class loader! I will add a blog post, as I find a solution for production systems.

The tutorial has been successfully tested with the following versions of third party libraries:

  • Tomcat 6.0.20
  • jBoss 5.0.1.GA

The following steps are sufficient advices  for the impatient reader, in order to run the tomcat standalone with a connection to jboss. A more detailed description about what is going on here can be found in using JAAS login modules from jboss in tomcat. Here are the instructions:

  • download tomcat:
http://www.internet.bs/apache.org/tomcat/tomcat-6/v6.0.20/bin/apache-tomcat-6.0.20.tar.gz
  • decompress the file
  • edit $CATALINA_HOME/bin/catalina.sh:
export JAVA_OPTS="$JAVA_OPTS -Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.config
    -Djava.naming.provider.url=localhost:1399"
  • We’re using JAAS for authentication. We declare two login modules. The ClientLoginModule builds the security context for EJB calls, so that the application server gets the credentials for authentication. The LdapExtLoginModule authenticates the user with LDAP and builds  the subject for Tomcat. In order to configure JAAS create/edit the file $CATALINA_HOME/conf/jaas.config:
someapp {
 // create security context for jboss
 org.jboss.security.ClientLoginModule required;
     multi-threaded="true";
 // Login module for tomcat
 org.someorg.security.LdapExtLoginModule required
     java.naming.factory.initial="com.sun.jndi.ldap.LdapCtxFactory"
     java.naming.security.authentication="simple"
     java.naming.provider.url="ldap://<your_ldap_host>:<your_ldap_port>"
     //We use anonymous authentication to our LDAP here
     bindDN=""
     bindCredential=""
     // Base DN, where we search our users
     baseCtxDN="ou=people,dc=someorg,dc=org"
     // Our users log in via uid
     baseFilter="(uid={0})"
     // Our roles are situated in the following subtree
     rolesCtxDN="ou=Roles,dc=someorg,dc=org"
     // A member of a group is identified/referenced by its full DN here
     roleFilter="(member={1})"
     roleAttributeID="cn"
     // We assume flat roles
     roleRecursion="-1";
};
  • edit $CATALINA_HOME/conf/server.xml:
    • comment out all existing <Realm>-tags
    • add the following block:
<Realm className="org.apache.catalina.realm.JAASRealm"
       appName="someapp"
       useContextClassLoader="false"
       userClassNames="org.jboss.security.SimplePrincipal"
       roleClassNames="org.jboss.security.SimpleGroup"
/>
  • Above we used a class called org.someorg.security.LdapExtLoginModule. This class must be on the class path of tomcat and jboss ($CATALINA_HOME/lib and $JBOSS_SERVER_CONFIG_HOME/lib). Here is an implementation of the class:
package org.someorg.security;
public class LdapExtLoginModule
        extends org.jboss.security.auth.spi.LdapExtLoginModule {
 private String credential;
 private Principal identity;
 private static Map<string, Object> credentials = new HashMap<string, Object>();

 public static Object getCredential(String username) {
   return credentials.get(username);
 }

 @Override
 protected Group[] getRoleSets() throws LoginException {
     List<group> groups = new LinkedList<group>();
     Enumeration<? extends Principal> roles = super.getRoleSets()[0].members();
     while(roles.hasMoreElements()) {
     groups.add(new SimpleGroup(roles.nextElement().getName()));
   }
   return groups.toArray(new Group[0]);
 }

 @Override
 @SuppressWarnings("unchecked")
 public boolean login() throws LoginException {
   // See if shared credentials exist
   if( super.login() == true ) {
     String[] info = getUsernameAndPassword();
     this.identity = new SimplePrincipal(info[0]);
     this.credential = info[1];
     return true;
   }
   return false;
 }

 @Override
 public boolean commit() throws LoginException {
   // SecurityAssociationActions.setPrincipalInfo(identity, credential);
   boolean success = super.commit();
   if(success) {
     credentials.put(identity.getName(), credential);
   }
   return success;
 }

 @Override
 public boolean logout() throws LoginException {
   credentials.remove(identity.getName());
 }
}
  • We can load a session bean in a servlet like this (the login has to be done at least once per request, because a new request might run in another thread, so a call to a session bean would be done with the user anonymous):
String user = httpRequest.getRemoteUser();
String credential = (String)LdapExtLoginModule.getCredential(user);
Properties env = new Properties();
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory");
env.setProperty(Context.SECURITY_PRINCIPAL, user);
env.setProperty(Context.SECURITY_CREDENTIALS, credential);
env.setProperty("java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");
InitialContext ctx = new InitialContext(env);
MySessionBean sb = (MySessionBean)ctx.lookup("myapp/MySessionBean/remote");
...
  • In order to get everything running jbosssx.jar and jbossall-client.jar (part of the jboss package) has to be on the classpath. So get it and put it into the $CATALINA_HOME/lib folder.

5 thoughts to “Standalone Tomcat with jBoss plus authentication against LDAP”

  1. “Please don’t use this solution in a productive system,”

    HI… Did you wrotte a “productive simple” ? Where is the link ?
    Regards.

    1. I don’t have a solution for a productive system by now. But I’m working out a solution using REST-services to access a jboss from an external tomcat. I will write a concept post soon.

  2. Hi Jonny
    I realy didn’t undertands how standalone web container propagates JAAS autentication to ejb container !!!! I’ve read a lot of stuff and I realized that I must config and duplicate roles inside war and ejb xmls….and duplicate the specific way how this container will autenticate and authorized (XML, JDBC, LDAP etc….)
    I’m right ??
    Best Regards

  3. There is no propagation. The Login name and credential is stored in a static class member (of the login module) and later reused for a login during creation of the InitialContext initializing the connection to the JNDI of the jboss.

Leave a Reply

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