Help SiteVision 4

JAAS module example

SiteVision is dependent of a LDAP directory for fetching user information and adding credentials. Though, sometimes login information are stored elsewhere than in a directory (e.g. in a database) or you need to authenticate against something else than a LDAP directory service (e.g. a Web Service). Such custom authentication can be implemented in a JAAS module.

Disclaimer! This fictitious example is for the SiteVision 3 series. Currently there are no explicit example for the SiteVision 4 series. Classes and interfaces in the SiteVision JAAS API has been moved in the 4 series, so the code example needs a SiteVision 4 API jar and imports might differ!

Fictitious use case description

You have a source other that a LDAP directory where the username and password for a lot of users are stored. These users should have access to a specific part of your website that requires authentication. No personal information about each user is required, all you really need is that they can be authenticated in SiteVision so they can access the protected area. This area is accessible for all users that has a SiteVision role that contains the 'read' permission.

Solution description

Since SiteVision only handles LDAP users, a possible solution is to add all users in a LDAP directory. This is not a viable solution in this case since many applications uses the same source. This specific problem can be solved with just one LDAP user. The downside with this is that all users are 'mapped' to one LDAP user, but in this case it doesn't matter.

1. Setting up a LDAP user and give the user read permissions

We start solving our problem by creating a LDAP user in a directory SiteVision has access to. In this case, let us call the user 'customer' (the username of the user is 'customer'). Then we adds this user to the protected area of our web site and assigns 'customer' to a role that contains read permission.

Example of READ config for customer user (UI might differ in SiteVision versions)

2. Implementing a JAAS module

Now we need to map each user we authenticate to the LDAP user 'customer'. This is done by implementing a JAAS module that authenticates to the specific non-LDAP source an set the subject for the authenticated user to 'customer'.

To keep this example as simple and easy to understand as possible, let us skip any real connections to a source where the username and password can be found (e.g. probably in a database). For simplicity, let us instead stipulate two simple rules that allows the JAAS module to determine if a specific login (username + password) should be authentication or not.

  • The first rule is that the username and the password must be identical.
  • The second rule is that the username/password must contain 10 characters or more.

The JAAS login module will authenticate all users that fulfills these two simple rules.

Here is a link to the complete code for the sample JAAS module (PatternLoginModule) Zip, 114.9 kB.

3. Build and deploy the JAAS module

Use ANT to create a jar file containing the code for our JAAS module and a proper manifest that describes that it is actually is a JAAS module.

Deploy the JAAS module by putting the jar file in the custom/lib folder of your SiteVision installation. Then restart SiteVision.

4. Configure SiteVision to use the JAAS module

Log on to SiteVision and go to the Authentication Configuration tab in the Security category on the Website settings. When you press the Add button for JAAS modules the JAAS module should be in the list of possible JAAS modules.

Example of JAAS module selection (UI might differ in SiteVision versions)

Select the JAAS module and set the Control flag to 'Sufficient' and ensure that the JAAS module are the first item in the JAAS module list (i.e. this JAAS module should be the first one used whenever a user tries to authenticate to this website).

Example of JAAS module order (UI might differ in SiteVision versions)

Some implementation details

The implementation of the JAAS module illustrates some details that are good to know when implementing a JAAS module:

First of all, the module implements the javax.security.auth.spi.LoginModule interface and to be compiled at all, a SiteVision API jar must be on your classpath but it must NOT be included in the JAAS module jar file.

Note how a NameCallback and a PasswordCallback are used to tell SiteVision what information the JAAS module are interested in.

// Prompt for a user name and password
callbacks = new Callback[2];
callbacks[0] = new NameCallback(bundle.getString("username"));
callbacks[1] = new PasswordCallback(bundle.getString("password"), false);

// Do callback
callbackHandler.handle(callbacks);

// Handle callback result
username = ((NameCallback) callbacks[0]).getName();
char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
...

Note! When using an array and executing a callback - make sure the array has a proper size. Null array elements are not allowed.

The logic for determining if the user should be authenticated or not is quite simple in this particular example:

// verify the username/password
if (username != null && username.length() > 9
     && username.equals(new String(password)))
{
  // => authentication succeeded !!!
  ...
} else
{
  // => authentication failed !!!
  ...
}

Also note how a UserPrincipalCallback is used to add the 'customer' LDAP user as the subject for the authenticated user.

// Convert username to a Principal by looking up a known LDAP user
// All authenticated users use the same LDAP user (with user name 'customer')
UserPrincipalCallback principalCallback = new UserPrincipalCallback("customer");
try
{
  callbackHandler.handle(new Callback[]{principalCallback});

  userPrincipal = principalCallback.getPrincipal();
} catch (Exception e)
{
  throw new FailedLoginException(bundle.getString("loginFailed"));
}

// Found no such user in LDAP
if (userPrincipal == null)
{
  throw new FailedLoginException(bundle.getString("loginFailed"));
}

Note! If there are more than one LDAP user that has the username 'customer', you must explicitly specify the path to  your customer user (e.g cn=customer,ou=yyy,o=xx).

The UserPrincipalCallback class is not defined in the public JAAS API, that's why you need the SiteVision API jar when you compile your project.

Note how property files are used for i18n and note that a LanguageCallback is used for proper property file handling.

LanguageCallback languageCallback = new LanguageCallback();
Callback[] callbacks = new Callback[]{languageCallback};

callbackHandler.handle(callbacks);

bundle = ResourceBundle.getBundle(getClass().getName(),
                                                     languageCallback.getLocale());

The property files are used for two different purposes:

1. The keys 'username', 'password' and 'loginFailed' are used for the actual login form that SiteVision renders (as you can see this JAAS module is available in swedish and in english):

PatternLoginModule_sv.properties:

## Used in login form
loginFailed = Felaktigt användarnamn ...
username = Ange användarnamn
password = Ange lösenord

PatternLoginModule.properties:

## Used in login form
loginFailed = Invalid username ...
username = Your username
password = Your password

Note! In this particular case, the PatternLoginModule is the first one in the JAAS module list (see 4 above). If another JAAS module has been the first one in the list, then that module would have precedence and should determine how the login form should be rendered.

2. The keys 'title' and 'description' are predefined keys that are used for displaying texts in the SiteVision UI whenever an administrator adds the JAAS module or checks the properties of the JAAS module.

PatternLoginModule_sv.properties:

## Predefined keys that ...
title = Mönsterbaserad loginmodul
description = Autenticerar användare ...

PatternLoginModule.properties:

## Predefined keys that ...
title = Pattern login module
description = Authenticates users ...

Example of JAAS module texts (UI might differ in SiteVision versions)

Note! Always specify a 'title' or a 'description' key and give them proper values. If not, the JAAS module will be given the same name as the class name of the JAAS module (i.e. PatternLoginModule in this example).

Note that the PatternLoginModule has a helper method called cleanUpLoginState() that ensures that the password is blanked out. This is a small but important security issue that always should be performed when handling passwords that no longer are needed.

private void cleanUpLoginState()
{
   username = null;

   // Ensure password chars are blanked out in allocated memory
   if (password != null)
   {
      for (int i = 0; i < password.length; i++)
         password[i] = ' ';
      password = null;
   }
}

The page published:

Find us!

SiteVision AB (Headquarter)
Vasagatan 10
702 10 Orebro
Sweden


Info: +46 19-17 30 30
Support: +46 19-17 30 39