Wicket, JBoss, JAAS, LDAP

Serge Beaumont

Call me old-skool, but I don't like pulling in huge frameworks like Acegi for some simple authentication and authorization stuff. This post will show you how I connected Wicket security to an LDAP through JAAS. This leverages the LDAP configuration and access on the appserver level and keeps the application clean. This was done on JBoss, so YMMV on another server, but this post should help you along when you need to tweak the solution.

Caveat: this solution does NOT get you logged in as far as the appserver is concerned, so you'll not be able to use container calls like isUserInRole(). If you find out how, let me know. For our purposes we didn't need it, but it's nice to know anyway.

Step one: Set up the LDAP server

Download OpenLDAP and install it. You'll need to tweak the slapd.conf a bit. Things to set are the suffix, rootdn (this user will be used by JBoss to connect), rootpw, and optionally the directory.

(..snip..)

#######################################################################
# ldbm database definitions
#######################################################################

database	bdb
suffix		"dc=example,dc=com"
rootdn        	"cn=Manager,dc=example,dc=com"
# Cleartext passwords, especially for the rootdn, should
# be avoid.  See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw       	secret
# The database directory MUST exist prior to running slapd AND 
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory	/my/custom/openldap/data/directory
# Indices to maintain
index	objectClass	eq

(..snip..)

When you run OpenLDAP, it can be handy to use a port higher than 1024 (don't need root privileges) and reference your custom slapd.conf file:

/path/to/slapd -h "ldap://127.0.0.1:10389" -f /path/to/my/custom/slapd.conf

You'll need to have the necessary user and group entries in the LDAP. I've attached the ldap-setup.ldif file that has a structure that corresponds to the configuration we'll set up in JBoss.

Step Two: Connect JBoss to the LDAP

JBoss uses the LdapLoginModule to work with an LDAP. You need to set up an application-policy in the login-config.xml that can be found in the JBOSS_HOME/server/default/conf directory. This will allow JBoss to log in to the LDAP server, and tells it what the structure of your LDAP is so the username, password and roles can be found.

I've attached a JBoss login-config.xml snippet.


	
		[..snip..]
	
	
	[...etcetera...]


After setting this up you will be able to connect to the LDAP in your code through JAAS. The connection with your configuration is through the application policy name that is passed to the LoginContext() constructor (see later).

Step 3: The JAAS connector code

This code has been integrated into the Wicket security model, but it could be used anywhere. It checks the username/password and retrieves the user's roles through JAAS.

I've attached the class that does this and commented it (JAASBasedSession.java), but overall it does the following:

  • Create a handler for callbacks from JAAS. This handler knows the username/password.
  • Create a LoginContext using the name of your application-policy.
  • Call login(), which will lead to callbacks.
  • Retrieve and parse the subject information to get the roles that the user is authorized for.
  • Put the roles where Wicket can get at them.

Step 4: Integration with Wicket

The Wicket model depends on the retrieval of role names that a user is authorized for. Instead of subclassing from WebApplication, you subclass from AuthenticatedWebApplication. You will have two more methods to implement. One returns the class of the login page, the other returns the class of the AuthenticatedWebSession subclass that will be used by the framework. The AuthenticatedWebSession subclass is the one with the JAAS connector code, and it is queried by Wicket to retrieve the logged in user's roles.

package com.example.myapplication.ui;

[..snip..]
import org.apache.wicket.authentication.AuthenticatedWebApplication;
import org.apache.wicket.authentication.AuthenticatedWebSession;
[..snip..]

public class MyWicketApplication extends AuthenticatedWebApplication {

	[...other stuff...]

    @Override
    protected void init() {
        super.init();

		[...other stuff...]

        // setting page that Wicket will display if user has no rights to access a page
        getApplicationSettings().setAccessDeniedPage(LoginPage.class);
        
        mountBookmarkablePage("/login", LoginPage.class);
    }

    protected Class getWebSessionClass() {
        return JAASBasedSession.class;
    }

    protected Class getSignInPageClass() {
        return LoginPage.class;
    }

	[...other stuff...]
}

The commented JAASBasedSession.java is attached. The LoginPage.java I've attached is likely not the most elegant way to log into Wicket. It works, but refactoring it is a bit lower on my to-do list.

Step 5: Annotate your secure pages

Wicket has annotations that check if the user has the roles required for that page. These role names map to the roles as they have been set in the LDAP.

package com.example.myapplication.admin.ui;

import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeInstantiation;
import org.apache.wicket.markup.html.WebPage;

// The AuthorizeInstantiation annotation enforces security based on the roles that have been
// set in the Session and are retrieved with the getRoles() method. In this case both
// admin roles are authorized to use the page. For a single role you don't need the curly braces.

@AuthorizeInstantiation({"TechnicalAdmin","FunctionalAdmin"})
public class AdministrationPage extends WebPage {

	[..snip..]

}

Step 6: World domination!

By now you should have a complete setup. You can authenticate and authorize your Wicket application, while keeping your application free of the specifics of the LDAP setup. All that rests is teaching your users not to use "secret" as their password... 🙂

Comments (3)

  1. Erik Pragt - Reply

    May 8, 2008 at 3:42 pm

    Hi Serge,

    In JBoss 4.2.2, you can get logged into the Application Server by using the WebAuthentication class. It's located in JBoss, in the jbossweb-service.jar file. It's not on a Maven Repository as far as I know, so you have to install it manually.

    You can use it something like:

        private boolean authenticateForContainer(String username, String password) {
            WebAuthentication webAuthentication = new WebAuthentication();
            return webAuthentication.login(username, password);
        }
    

    I have no idea on how to to this in older versions of JBoss!

    You can find more information about it here: http://roneiv.wordpress.com/2008/03/15/using-webauthentication-in-jboss/

  2. Serge Beaumont - Reply

    May 9, 2008 at 1:41 am

    Erik,

    I tried that option, but for some reason it did not work: isUserInRole() calls still failed on everything. This could mean that WebAuthentication does exactly that: authenticate, but no authorization.

  3. Laurent - Reply

    June 15, 2009 at 8:50 am

    Hi,

    Works great. Thanks for posting it.

    Unless I missed something I didn't find a wicket build-in getter for "username"
    So, I've added private variable "username" next to roles and a getUsername().

    Laurent

Add a Comment