UsersRolesLoginModule

UsersRolesLoginModule

 

A simple properties file based login module that consults two Java Properties formatted text files for username to password (users.properties) and username to roles (roles.properties) mapping. The names of the properties files may be overriden by the usersProperties and rolesProperties options.

The properties files are loaded during initialization using the thread context class loader. This means that these files can be placed into the J2EE deployment jar or the JBoss config directory. Don't forget to restart JBoss aufter changing these files.

 

The users.properties file uses a format:

username1=password1
username2=password2
...

 

to define all valid usernames and their corresponding passwords.

 

The roles.properties file uses a format:

username1=role1,role2,...
username1.RoleGroup1=role3,role4,...
username2=role1,role3,...

 

to define the sets of roles for valid usernames. The username.XXX form of property name is used to assign the username roles to a particular named group of roles where the XXX portion of the property name is the group name.

The username=... form is an abbreviation for username.Roles=...

 

The following are therefore equivalent:

jduke=TheDuke,AnimatedCharacter
jduke.Roles=TheDuke,AnimatedCharacter

 

The supported login module configuration options include the following:

 

  • unauthenticatedIdentity=name, Defines the principal name that should be assigned to requests that contain no authentication information. This can be used to allow unprotected servlets to invoke methods on EJBs that do not require a specific role. Such a principal has no associated roles and so can only access either unsecured EJBs or EJB methods that are associated with the unchecked permission constraint.

  • password-stacking=useFirstPass, When password-stacking option is set, this module first looks for a shared username and password under the property names "javax.security.auth.login.name" and "javax.security.auth.login.password" respectively in the login module shared state Map. If found these are used as the principal name and password. If not found the principal name and password are set by this login module and stored under the property names "javax.security.auth.login.name" and "javax.security.auth.login.password" respectively.

  • hashAlgorithm=string: The name of the java.security.MessageDigest algorithm to use to hash the password. There is no default so this option must be specified to enable hashing. When hashAlgorithm is specified, the clear text password obtained from the CallbackHandler is hashed before it is passed to UsernamePasswordLoginModule.validatePassword as the inputPassword argument. The expectedPassword as stored in the users.properties file must be comparably hashed.

  • hashEncoding=base64|hex: The string format for the hashed pass and must be either "base64" or "hex". Base64 is the default.

  • hashCharset=string: The encoding used to convert the clear text password to a byte array. The platform default encoding is the default.

  • usersProperties=string: (2.4.5+) The name of the properties resource containing the username to password mappings. This defaults to users.properties.

  • rolesProperties=string: (2.4.5+) The name of the properties resource containing the username to roles mappings. This defaults to roles.properties.

  • ignorePasswordCase=true|false: (3.2.3+) A boolean  flag indicating if the password comparison should ignore case. This can be useful for hashed password encoding where the case of the hashed password is not significant.

  • principalClass: (3.2.4+) An option that specifies a Principal implementation class. This must support a ctor taking a String argument for the princpal name.

  • roleGroupSeperator: (3.2.6+) The character used to seperate the role group name from the username e.g., '.' in jduke.CallerPrincipal=... . The default is '.'.

  • defaultUsersProperties=string: (4.0.2, 3.2.8) The name of the properties resource containing the username to password mappings that will be used as the defaults Properties passed to the usersProperties Properties. This defaults to defaultUsers.properties.

  • defaultRolesProperties=string: (4.0.2, 3.2.8) The name of the properties resource containing the username to roles mappings that will be used as the defaults Properties passed to the usersProperties Properties. This defaults to defaultRoles.properties.

  • hashUserPassword (4.0.3+) - A flag indicating if the user entered password should be hashed when a hashAlgorithm is specified. Defaults to true.

  • hashStorePassword (4.0.3+) - A flag indicating if the store password returned from  getUsersPassword() should be hashed. Defaults to false.

  • digestCallback (4.0.3+) - The class name of the org.jboss.crypto.digest.DigestCallback implementation that includes pre/post digest content like salts. Only used if hashAlgorithm has been specified.

  • storeDigestCallback (4.0.3+) - The class name of the org.jboss.crypto.digest.DigestCallback implementation that includes pre/post digest content like salts for hashing the store/expected password. Only used if hashStorePassword is true and hashAlgorithm has been specified.

  • callback.option. - all options prefixed with callback.option. are passed to the DigestCallback.init(Map) method. The input username is always passed in via the javax.security.auth.login.name option, and the input/store password is passed in via the javax.security.auth.login.password option to the digestCallback/storeDigestCallback.

 

The digestCallback and storeDigestCallback specify and implementation of the org.jboss.crypto.digest.DigestCallback interface:

package org.jboss.crypto.digest;

import java.util.Map;
import java.security.MessageDigest;

/**
 * An interface that can be used to augment the behavior of a digest hash.
 * One example usecase is with the password based login modules to
 * modify the behavior of the hashing to introduce prefix/suffix salts.
 */
public interface DigestCallback
{
   /** Pass through access to the login module options. When coming from a
    * login module this includes the following keys:
    * javax.security.auth.login.name - for the username
    * javax.security.auth.login.password - for the String password
    */
   public void init(Map options);
   /**
    * Pre-hash callout to allow for content before the password. Any content
    * should be added using the MessageDigest update methods.
    * @param digest - the security digest being used for the one-way hash
    */ 
   public void preDigest(MessageDigest digest);
   /** Post-hash callout afer the password has been added to allow for content
    * after the password has been added. Any content should be added using the
    * MessageDigest update methods.
    * @param digest - the security digest being used for the one-way hash
    */
   public void postDigest(MessageDigest digest);
}

 

A sample legacy Sun format login configuration entry that assigned unauthenticated users the principal name "nobody" and contains based64 encoded, MD5 hashes of the passwords in a "usersb64.properties" file is:

 

testUsersRoles {

org.jboss.security.auth.spi.UsersRolesLoginModule required
   usersProperties=usersb64.properties
   hashAlgorithm=MD5
   hashEncoding=base64
   unauthenticatedIdentity=nobody
;
};

 

The corresponding XMLLoginConfig format is:

 

<policy>
   <application-policy name="testUsersRoles">
      <authentication>
      <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
         <module-option name="usersProperties">usersb64.properties
         </module-option>
         <module-option name="hashAlgorithm">MD5</module-option>
         <module-option name="hashEncoding">base64</module-option>
         <module-option name="unauthenticatedIdentity">nobody</module-option>
      </login-module>
   </application-policy>
</policy>

 

An example of using the default users and roles properties files is:

    <application-policy name = "other">
       <authentication>
          <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule"
             flag = "required">
             <module-option name="defaultUsersProperties">jacc-users.properties</module-option>
             <module-option name="defaultRolesProperties">jacc-roles.properties</module-option>
             <module-option name="usersProperties">users.properties</module-option>
             <module-option name="rolesProperties">roles.properties</module-option>
             <module-option name="roleGroupSeperator">.</module-option>
          </login-module>
       </authentication>
    </application-policy>

 

There is no generic tool for creating the password hash. A simple example for creating md5 hashes with base64 encoding is:

 

import java.security.MessageDigest;
import org.jboss.security.Util;

class HashPassword
{
   public static void main(String[] args)
   {
      String password = args[0];
      MessageDigest md = null;
      try
      {
         md = MessageDigest.getInstance("MD5");
      }
      catch(Exception e)
      {
         e.printStackTrace();
      }
      byte[] passwordBytes = password.getBytes();
      byte[] hash = md.digest(passwordBytes);
      String passwordHash = Util.encodeBase64(hash);
      System.out.println("password hash: "+passwordHash);
   }
}

 

Another example for a MD5 with hex(base16) encoding:

 

/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
import java.security.MessageDigest;
import org.jboss.security.Util;

/**
 * @author Scott.Stark@jboss.org
 * @version $Revision:$
 */
public class HashHexPassword
{
   public static void main(String[] args)
   {
      String password = args[0];
      MessageDigest md = null;
      try
      {
         md = MessageDigest.getInstance("MD5");
      }
      catch(Exception e)
      {
         e.printStackTrace();
      }
      byte[] passwordBytes = password.getBytes();
      byte[] hash = md.digest(passwordBytes);
      String passwordHash = Util.encodeBase16(hash);
      System.out.println("password hash: "+passwordHash);
   }
}

 

 

Subclassing UsersRolesLoginModule

As of 4.0.3, the following two methods exist to allow subclasses to create the users/roles Properties maps as needed. These methods are called from the initialize method to set the users/roles instance variables.

 

   /**
    * A hook to allow subclasses to create the users Properties map. This
    * implementation simply calls loadUsers() and returns the users ivar.
    * Subclasses can override to obtain the users Properties map in a different
    * way.
    * 
    * @param options - the login module options passed to initialize
    * @return Properties map used for the username/password mapping.
    * @throws IOException - thrown on failure to load the properties
    */ 
   protected Properties createUsers(Map options) throws IOException

   /**
    * A hook to allow subclasses to create the roles Properties map. This
    * implementation simply calls loadRoles() and returns the roles ivar.
    * Subclasses can override to obtain the roles Properties map in a different
    * way.
    * 
    * @param options - the login module options passed to initialize
    * @return Properties map used for the username/roles mapping.
    * @throws IOException - thrown on failure to load the properties
    */ 
   protected Properties createRoles(Map options) throws IOException