9/25/10

Karaf's JAAS modules in action

Prologue
Karaf 2.1.0 has been just released! Among other new features, it includes a major revamp in the JAAS module support:
  1. Encryption support
  2. Database Login Module
  3. Role Policies
This post will use all 3 features, in order to create a secured Wicket application on Karaf, using Karaf's JAAS modules and Wicket's auth-roles module.

Introduction
The application that we are going to build is a simple wicket application. It will be deployed on Karaf and the user credentials will be stored in a mysql database. For encrypting the password we will use Karaf's Jasypt encryption service implementation, to encrypt passwords using MD5 algorithm in hexadecimal format.

Step 1: Creating the database
The database that we are going to create will the simplest possible. We need a table that will hold username and password for each user. Each user may have one or more roles, so we will need a new table to hold the roles of the users.


We are going to create a user named "iocanel", that will have the roles "manager" and "admin" and password "koala" (stored in MD5 with hex output).

Note, for cases that a schema for user credentials already exists, Karaf's database login module offer's customization by allowing the user to provide custom queries for password and role retrieval.

Step 2: Creating a data source
In order to create a data source we will use the blueprint to create a DataSource as an OSGi service.
Before we do that we will need to install the mysql bundle and its prerequisite.
They can be easily installed from karaf shell.


osgi:install wrap:mvn:javax.xml.stream/stax-api/1.0
osgi:install wrap:mvn:mysql/mysql-connector-java/5.1.13 

Once all prerequisites are meet the datasource can be created by dropping the following xml under karaf deploy folder or by adding it under OSGI-INF/blueprint folder of our bundle.


Step 3: Creating a JAAS realm
In the same manner the new JAAS realm can be created by dropping the blueprint xml under the deploy folder or by adding it under OSGI-INF/blueprint folder of our bundle.

The new realm will make use of Karaf's JDBCLoginModule, and will also use MD5 encryption with hexadecimal output. Finally, it will be passed a role policy, that will add the "ROLE_" prefix on all role principals. This way our application can identify the role principals, without depending to the Karaf implementation.

If this isn't that clear, note that JAAS specifies interface Principal and its implementations provide User & Role principals (as implementing classes), making it impossible to distinguish between these two without having a dependency to the JAAS implementation or by having a common convention. This is what Role Policies is about.


Step 4: Creating the wicket application
Everything is set and all we need is to create the wicket application that will make use of our new JAAS realm in order to authenticate.

The first step is to create a Wicket Authenticated Session:

Now we need to tell our application to create such sessions and also where the location of our sign in page will be. For this purpose we will extend Wicket's AuthenticatedWebApplication class:
Now that everything is set up, we can restrict access to the HomePage to "admins" and "managers" by making use of Wickets

Final Words
I hope you found it useful. The source of this example will be added to this post soon, so stay tuned.

9 comments:

  1. PRIMARY KEY (username,#role#)
    I guess?

    ReplyDelete
  2. #
    #
    #
    I guess, there are a lot of typo.

    ReplyDelete
  3. And again, why do we need ROLES_PREFIX at all?

    Can you just pull out ready maven-enabled application? Thanks

    ReplyDelete
  4. @Alex Shubert:

    We are using ROLES_PREFIX in order to be able to distinguish User from Role principals, without having to depend on the Karaf implementation. We could add as a maven dependency the karaf jaas module, but then we would be coupled with karaf and we want to avoid that.

    Feel free to send feedback for any typo you might find. Thanks!

    ReplyDelete
  5. OSGI-INF/blueprint last 3 rows

    again, that code you posted in article full of typos. I suggest you to make it maven-based as a really portable example. During that you will find that nor you sql query, nor you confs do not work.

    But I believe, as in many another cases there will be no runnable sources at all....


    Anyway you article is good enough to make a vision how that things work and I am very gratitude you wrote it. Thanks!

    ReplyDelete
  6. @Alex: Thanks for your feedback. I updated the post with fixes for some of the "typos". Unfortunately, the Syntax Highlighter that is used, messes a bit with the XML. I will try to provide a running example soon.

    ReplyDelete
  7. Thank you very much for your post! Was a great help!

    btw

    @AuthorizeInstantiation("admin","manager")

    have to be

    @AuthorizeInstantiation({"admin","manager"})

    ReplyDelete
  8. Even if the blog is already a bit 'outdated' it is still very useful!

    Just to note that it might be also useful having the code of the login form, e.g. somewhat similar to:

    @Override
    protected void onSubmit() {
    String username = (String) usernameField.getDefaultModelObject();
    String password = (String) passwordField.getDefaultModelObject();

    WicketJaasSession wicketJaasSession = getWicketJaasSession();

    if (null == username || null == password) {
    loginStatus.setDefaultModelObject("Both, username and password must contain values!");
    } else if (username.equals("") || password.equals("")) {
    loginStatus.setDefaultModelObject("Both, username and password may not be empty!");
    } else {
    if (wicketJaasSession.signIn(username, password)) {
    loginStatus.setDefaultModelObject("Congratulations!");
    continueToOriginalDestination();
    } else {
    loginStatus.setDefaultModelObject("Unable to sign you in!");
    }
    }
    }

    ReplyDelete