JBoss.orgCommunity Documentation
JBoss AS includes several bundled login modules suitable for most user management needs. JBoss AS can read user information from a relational database, a LDAP server or flat files. In addition to these core login modules, JBoss provides several other login modules that provide user information for very customized needs in JBoss. Before we explore the individual login modules, let's take a look at a few login module configuration options that are common to multiple modules.
Multiple login modules can be chained together in a stack, with each login module providing both the authentication and authorization components. This works for many use cases, but sometimes authentication and authorization are split across multiple user management stores.
Section 10.1.7, “LdapLoginModule”describes how to combine LDAP and a relational database, allowing a user to be authenticated by either system. However, consider the case where users are managed in a central LDAP server but application-specific roles are stored in the application's relational database. The password-stacking module option captures this relationship.
To use password stacking, each login module should set the <module-option> password-stacking
attribute to useFirstPass
. If a previous module configured for password stacking has authenticated the user, all the other stacking modules will consider the user authenticated and only attempt to provide a set of roles for the authorization step.
When password-stacking
option is set to useFirstPass
, 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 properties 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.
When using password stacking, set all modules to be required. This ensures that all modules are considered, and have the chance to contribute roles to the authorization process.
Example 10.1. Password Stacking Sample
This example shows how password stacking could be used.
<application-policy name="todo">
<authentication>
<login-module code="org.jboss.security.auth.spi.LdapLoginModule"
flag="required">
<!-- LDAP configuration -->
<module-option name="password-stacking">useFirstPass</module-option>
</login-module>
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule"
flag="required">
<!-- database configuration -->
<module-option name="password-stacking">useFirstPass</module-option>
</login-module>
</authentication>
</application-policy>
Most login modules must compare a client-supplied password to a password stored in a user management system. These modules generally work with plain text passwords, but can be configured to support hashed passwords to prevent plain text passwords from being stored on the server side.
Example 10.2. Password Hashing
The following is a login module configuration that assigns unauthenticated users the principal name nobody
and contains based64-encoded, MD5 hashes of the passwords in a usersb64.properties
file. The usersb64.properties
file can be part of the deployment classpath, or be saved in the /conf
directory.
<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="rolesProperties">test-users-roles.properties</module-option>
<module-option name="unauthenticatedIdentity">nobody</module-option>
<module-option name="hashAlgorithm">MD5</module-option>
<module-option name="hashEncoding">base64</module-option>
</login-module>
</authentication>
</application-policy>
</policy>
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. Typical values are MD5
and SHA
.
String that specifies one of three encoding types: base64
, hex
or rfc2617
. The default is base64
.
Encoding character set used to convert the clear text password to a byte array. The platform default encoding is the default.
Specifies the hashing algorithm must be applied to the password the user submits. The hashed user password is compared against the value in the login module, which is expected to be a hash of the password. The default is true
.
Specifies the hashing algorithm must be applied to the password stored on the server side. This is used for digest authentication, where the user submits a hash of the user password along with a request-specific tokens from the server to be compare. The hash algorithm (for digest, this would be rfc2617
) is utilized to compute a server-side hash, which should match the hashed value sent from the client.
If you must generate passwords in code, the org.jboss.security.Util
class provides a static helper method that will hash a password using the specified encoding.
String hashedPassword = Util.createPasswordHash("MD5", Util.BASE64_ENCODING, null, null, "password");
OpenSSL provides an alternative way to quickly generate hashed passwords.
echo -n password | openssl dgst -md5 -binary | openssl base64
In both cases, the text password should hash to X03MO1qnZdYdgyfeuILPmQ==
. This value must be stored in the user store.
Not all requests are received in an authenticated format. unauthenticated identity
is a login module configuration option that assigns a specific identity (guest, for example) to requests that are made with no associated 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.
unauthenticatedIdentity: This defines the principal name that should be assigned to requests that contain no authentication information.
Sometimes the implementation of the Principal
interface provided by JBoss is not enough for the applications needs. In this case customers can use a custom implementation.
principalClass: An option that specifies a Principal
implementation class. This must support a constructor taking a string argument for the principal name.
UsersRolesLoginModule
is a simple login module that supports multiple users and user roles loaded from Java properties files. The username-to-password mapping file is called users.properties
and the username-to-roles mapping file is called roles.properties
.
The supported login module configuration options include the following:
Name of the properties resource (file) containing the username to password mappings. This defaults to <filename_prefix>-users.properties
.
Name of the properties resource (file) containing the username to roles mappings. This defaults to <filename_prefix>-roles.properties
.
This login module supports password stacking, password hashing, and unauthenticated identity.
The properties files are loaded during initialization using the initialize method thread context class loader. This means that these files can be placed into the Java EE deployment JAR, the JBoss configuration directory, or any directory on the JBoss server or system classpath. The primary purpose of this login module is to easily test the security settings of multiple users and roles using properties files deployed with the application.
Example 10.3. UserRolesLoginModule
<deployment xmlns="urn:jboss:bean-deployer:2.0"> <!-- ejb3 test application-policy definition --> <application-policy xmlns="urn:jboss:security-beans:1.0" name="ejb3-sampleapp"> <authentication> <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required"> <module-option name="usersProperties">ejb3-sampleapp-users.properties</module-option> <module-option name="rolesProperties">ejb3-sampleapp-roles.properties</module-option> </login-module> </authentication> </application-policy> </deployment>
In Example 10.3, “UserRolesLoginModule”, the ejb3-sampleapp-users.properties
file uses a username=password
format with each user entry on a separate line:
username1=password1 username2=password2 ...
The ejb3-sampleapp-roles.properties
file referenced in Example 10.3, “UserRolesLoginModule” uses the pattern username=role1,role2,
with an optional group name value. For example:
username1=role1,role2,... username1.RoleGroup1=role3,role4,... username2=role1,role3,...
The username.XXX property name pattern present in ejb3-sampleapp-roles.properties
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=..., where the Roles
group name is the standard name the JaasSecurityManager
expects to contain the roles which define the users permissions.
The following would be equivalent definitions for the jduke
username:
jduke=TheDuke,AnimatedCharacter jduke.Roles=TheDuke,AnimatedCharacter
The DatabaseServerLoginModule
is a Java Database Connectivity-based (JDBC) login module that supports authentication and role mapping. Use this login module if you have your username, password and role information stored in a relational database.
This module supports password stacking, password hashing and unauthenticated identity.
The DatabaseServerLoginModule
is based on two logical tables:
Table Principals(PrincipalID text, Password text) Table Roles(PrincipalID text, Role text, RoleGroup text)
The Principals
table associates the user PrincipalID
with the valid password and the Roles
table associates the user PrincipalID
with its role sets. The roles used for user permissions must be contained in rows with a RoleGroup
column value of Roles
.
The tables are logical in that you can specify the SQL query that the login module uses. The only requirement is that the java.sql.ResultSet
has the same logical structure as the Principals
and Roles
tables described previously. The actual names of the tables and columns are not relevant as the results are accessed based on the column index.
To clarify this notion, consider a database with two tables, Principals
and Roles
, as already declared. The following statements populate the tables with the following data:
PrincipalID
java
with a Password
of echoman
in the Principals
table
PrincipalID
java
with a role named Echo
in the Roles
RoleGroup
in the Roles
table
PrincipalID
java
with a role named caller_java
in the CallerPrincipal
RoleGroup
in the Roles
table
INSERT INTO Principals VALUES('java', 'echoman') INSERT INTO Roles VALUES('java', 'Echo', 'Roles') INSERT INTO Roles VALUES('java', 'caller_java', 'CallerPrincipal')
The supported login module configuration options include the following:
The JNDI name for the DataSource
of the database containing the logical Principals
and Roles
tables. If not specified this defaults to java:/DefaultDS
.
The prepared statement query equivalent to: select Password from Principals where PrincipalID=?
. If not specified this is the exact prepared statement that will be used.
The prepared statement query equivalent to: select Role, RoleGroup from Roles where PrincipalID=?
. If not specified this is the exact prepared statement that will be used.
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.
An example DatabaseServerLoginModule
configuration could be constructed as follows:
CREATE TABLE Users(username VARCHAR(64) PRIMARY KEY, passwd VARCHAR(64)) CREATE TABLE UserRoles(username VARCHAR(64), userRoles VARCHAR(32))
A corresponding login-config.xml
entry would be:
<policy>
<application-policy name="testDB">
<authentication>
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule"
flag="required">
<module-option name="dsJndiName">java:/MyDatabaseDS</module-option>
<module-option name="principalsQuery">
select passwd from Users username where username=?</module-option>
<module-option name="rolesQuery">
select userRoles, 'Roles' from UserRoles where username=?</module-option>
</login-module>
</authentication>
</application-policy>
</policy>
LdapLoginModule
is a LoginModule
implementation that authenticates against an LDAP server. Use the LdapLoginModule
if your username and credentials are stored in an LDAP server that is accessible using a JNDI LDAP provider.
This login module also supports unauthenticated identity and password stacking.
The LDAP connectivity information is provided as configuration options that are passed through to the environment object used to create JNDI initial context. The standard LDAP JNDI properties used include the following:
InitialContextFactory
implementation class name. This defaults to the Sun LDAP provider implementation com.sun.jndi.ldap.LdapCtxFactory
.
LDAP URL for the LDAP server.
Security level to use. This defaults to simple
.
Transport protocol to use for secure access, such as, SSL.
Principal for authenticating the caller to the service. This is built from other properties as described below.
Authentication scheme to use. For example, hashed password, clear-text password, key, certificate, and so on.
The supported login module configuration options include the following:
Prefix added to the username to form the user distinguished name. See principalDNSuffix
for more info.
Suffix added to the username when forming the user distinguished name. This is useful if you prompt a user for a username and you don't want the user to have to enter the fully distinguished name. Using this property and principalDNSuffix
the userDN
will be formed as principalDNPrefix + username + principalDNSuffix
Value that indicates the credential should be obtained as an opaque Object
using the org.jboss.security.auth.callback.ObjectCallback
type of Callback
rather than as a char[]
password using a JAAS PasswordCallback
. This allows for passing non-char[]
credential information to the LDAP server. The available values are true
and false
.
Fixed, distinguished name to the context to search for user roles.
Name of an attribute in the user object that contains the distinguished name to the context to search for user roles. This differs from rolesCtxDN
in that the context to search for a user's roles can be unique for each user.
Name of the attribute containing the user roles. If not specified, this defaults to roles
.
Flag indicating whether the roleAttributeID
contains the fully distinguished name of a role object, or the role name. The role name is taken from the value of the roleNameAttributeId
attribute of the context name by the distinguished name.
If true, the role attribute represents the distinguished name of a role object. If false, the role name is taken from the value of roleAttributeID
. The default is false
.
In certain directory schemas (e.g., MS ActiveDirectory), role attributes in the user object are stored as DNs to role objects instead of simple names. For implementations that use this schema type, roleAttributeIsDN must be set to true.
Name of the attribute of the context pointed to by the roleCtxDN
distinguished name value which contains the role name. If the roleAttributeIsDN
property is set to true, this property is used to find the role object's name attribute. The default is group
.
Name of the attribute in the object containing the user roles that corresponds to the userid. This is used to locate the user roles. If not specified this defaults to uid
.
Flag that specifies whether the search for user roles should match on the user's fully distinguished name. If true, the full userDN
is used as the match value. If false, only the username is used as the match value against the uidAttributeName
attribute. The default value is false
.
A flag indicating if empty (length 0) passwords should be passed to the LDAP server. An empty password is treated as an anonymous login by some LDAP servers and this may not be a desirable feature. To reject empty passwords, set this to false
. If set to true
, the LDAP server will validate the empty password. The default is true
.
User authentication is performed by connecting to the LDAP server, based on the login module configuration options. Connecting to the LDAP server is done by creating an InitialLdapContext
with an environment composed of the LDAP JNDI properties described previously in this section. The Context.SECURITY_PRINCIPAL is set to the distinguished name of the user as obtained by the callback handler in combination with the principalDNPrefix and principalDNSuffix option values, and the Context.SECURITY_CREDENTIALS property is either set to the String
password or the Object
credential depending on the useObjectCredential option.
Once authentication has succeeded (InitialLdapContext
instance is created), the user's roles are queried by performing a search on the rolesCtxDN
location with search attributes set to the roleAttributeName and uidAttributeName option values. The roles names are obtaining by invoking the toString
method on the role attributes in the search result set.
Example 10.4. login-config.xml Sample
The following is a sample login-config.xml
entry.
<application-policy name="testLDAP">
<authentication>
<login-module code="org.jboss.security.auth.spi.LdapLoginModule"
flag="required">
<module-option name="java.naming.factory.initial">
com.sun.jndi.ldap.LdapCtxFactory
</module-option>
<module-option name="java.naming.provider.url">
ldap://ldaphost.jboss.org:1389/
</module-option>
<module-option name="java.naming.security.authentication">
simple
</module-option>
<module-option name="principalDNPrefix">uid=</module-option>
<module-option name="principalDNSuffix">
,ou=People,dc=jboss,dc=org
</module-option>
<module-option name="rolesCtxDN">
ou=Roles,dc=jboss,dc=org
</module-option>
<module-option name="uidAttributeID">member</module-option>
<module-option name="matchOnUserDN">true</module-option>
<module-option name="roleAttributeID">cn</module-option>
<module-option name="roleAttributeIsDN">false </module-option>
</login-module>
</authentication>
</application-policy>
An LDIF file representing the structure of the directory this data operates against is shown below.
Example 10.5. LDIF File Example
dn: dc=jboss,dc=org objectclass: top objectclass: dcObject objectclass: organization dc: jboss o: JBoss dn: ou=People,dc=jboss,dc=org objectclass: top objectclass: organizationalUnit ou: People dn: uid=jduke,ou=People,dc=jboss,dc=org objectclass: top objectclass: uidObject objectclass: person uid: jduke cn: Java Duke sn: Duke userPassword: theduke dn: ou=Roles,dc=jboss,dc=org objectclass: top objectclass: organizationalUnit ou: Roles dn: cn=JBossAdmin,ou=Roles,dc=jboss,dc=org objectclass: top objectclass: groupOfNames cn: JBossAdmin member: uid=jduke,ou=People,dc=jboss,dc=org description: the JBossAdmin group
The java.naming.factory.initial
, java.naming.factory.url
and java.naming.security
options in the testLDAP
login module configuration indicate the following conditions:
The Sun LDAP JNDI provider implementation will be used
The LDAP server is located on host ldaphost.jboss.org
on port 1389
The LDAP simple authentication method will be use to connect to the LDAP server.
The login module attempts to connect to the LDAP server using a Distinguished Name (DN) representing the user it is trying to authenticate. This DN is constructed from the passed principalDNPrefix
, the username of the user and the principalDNSuffix
as described above. In Example 10.5, “LDIF File Example”, the username jduke
would map to uid=jduke,ou=People,dc=jboss,dc=org
.
The example assumes the LDAP server authenticates users using the userPassword
attribute of the user's entry (theduke
in this example). Most LDAP servers operate in this manner, however if your LDAP server handles authentication differently you must ensure LDAP is configured according to your production environment requirements.
Once authentication succeeds, the roles on which authorization will be based are retrieved by performing a subtree search of the rolesCtxDN
for entries whose uidAttributeID
match the user. If matchOnUserDN
is true, the search will be based on the full DN of the user. Otherwise the search will be based on the actual user name entered. In this example, the search is under ou=Roles,dc=jboss,dc=org
for any entries that have a member
attribute equal to uid=jduke,ou=People,dc=jboss,dc=org
. The search would locate cn=JBossAdmin
under the roles entry.
The search returns the attribute specified in the roleAttributeID
option. In this example, the attribute is cn
. The value returned would be JBossAdmin
, so the jduke user is assigned to the JBossAdmin
role.
A local LDAP server often provides identity and authentication services, but is unable to use authorization services. This is because application roles don't always map well onto LDAP groups, and LDAP administrators are often hesitant to allow external application-specific data in central LDAP servers. For this reason, the LDAP authentication module is often paired with another login module, such as the database login module, that can provide roles more suitable to the application being developed.
The org.jboss.security.auth.spi.LdapExtLoginModule
is an alternate ldap login module implementation that uses searches for locating both the user to bind as for authentication as well as the associated roles. The roles query will recursively follow distinguished names (DNs) to navigate a hierarchical role structure.
The LoginModule
options include whatever options your LDAP JNDI provider supports. Examples of standard property names are:
Context.INITIAL_CONTEXT_FACTORY
= "java.naming.factory.initial"
Context.SECURITY_PROTOCOL
= "java.naming.security.protocol"
Context.PROVIDER_URL
= "java.naming.provider.url"
Context.SECURITY_AUTHENTICATION
= "java.naming.security.authentication"
Context.REFERRAL
= "java.naming.referral"
The authentication happens in 2 steps:
An initial bind to the ldap server is done using the bindDN and bindCredential options. The bindDN
is some user with the ability to search both the baseCtxDN
and rolesCtxDN
trees for the user and roles. The user DN to authenticate against is queried using the filter specified by the baseFilter
attribute (see the baseFilter
option description for its syntax).
The resulting user DN is then authenticated by binding to ldap server using the user DN as the InitialLdapContext
environment Context.SECURITY_PRINCIPAL
. The Context.SECURITY_CREDENTIALS
property is either set to the String password obtained by the callback handler.
If this is successful, the associated user roles are queried using the rolesCtxDN
, roleAttributeID
, roleAttributeIsDN
, roleNameAttributeID
, and roleFilter
options.
The full module properties include:
baseCtxDN
: The fixed DN of the context to start the user search from.
bindDN
: The DN used to bind against the ldap server for the user and roles queries. This is some DN with read/search permissions on the baseCtxDN
and rolesCtxDN
values.
bindCredential
: The password for the bindDN
. This can be encrypted if the jaasSecurityDomain
is specified.
jaasSecurityDomain
: The JMX ObjectName of the JaasSecurityDomain
to use to decrypt the java.naming.security.principal
. The encrypted form of the password is that returned by the JaasSecurityDomain.encrypt64(byte[])
method. The org.jboss.security.plugins.PBEUtils
class can also be used to generate the encrypted form.
baseFilter
: A search filter used to locate the context of the user to authenticate. The input username/userDN as obtained from the login module callback will be substituted into the filter anywhere a {0}
expression is seen. This substitution behavior comes from the standard DirContext.search(Name, String, Object[], SearchControls cons)
method. A common example for the search filter is (uid={0})
.
rolesCtxDN
: The fixed DN of the context to search for user roles. Consider that this is not the Distinguished Name of where the actual roles are; rather, this is the DN of where the objects containing the user roles are (for example, for Active Directory, this is the DN where the user account is).
roleFilter
: A search filter used to locate the roles associated with the authenticated user. The input username/userDN as obtained from the login module callback will be substituted into the filter anywhere a {0}
expression is seen. The authenticated userDN
will be substituted into the filter anywhere a {1}
is seen. An example search filter that matches on the input username is: (member={0})
. An alternative that matches on the authenticated userDN
is: (member={1})
.
roleAttributeIsDN
: A flag indicating whether the user's role attribute contains the fully distinguished name of a role object, or the users's role attribute contains the role name. If false, the role name is taken from the value of the user's role attribute. If true, the role attribute represents the distinguished name of a role object. The role name is taken from the value of the roleNameAttributeId
attribute of the corresponding object. In certain directory schemas (for example, Microsoft Active Directory), role (group)attributes in the user object are stored as DNs to role objects instead of as simple names, in which case, this property should be set to true. The default value of this property is false.
roleAttributeID
: The name of the role attribute of the context which corresponds to the name of the role. If the roleAttributeIsDN
property is set to true, this property is the DN of the context to query for the roleNameAttributeID
attribute. If the roleAttributeIsDN
property is set to false, this property is the attribute name of the role name.
roleNameAttributeID
: The name of the role attribute of the context which corresponds to the name of the role. If the roleAttributeIsDN
property is set to true, this property is used to find the role object's name attribute. If the roleAttributeIsDN
property is set to false, this property is ignored.
distinguishedNameAttribute
: The name of an attribute in the user entry that contains the DN of the user. This may be necessary if the DN of the user itself contains special characters (backslash for example) that may prevent correct user mapping. Defaults to distinguishedName. If there is no such attribute, the entry's DN will be used.
roleRecursion
: How deep the role search will go below a given matching context. Disable with 0, which is the default.
searchTimeLimit
: The timeout in milliseconds for the user/role searches. Defaults to 10000 (10 seconds).
searchScope
: Sets the search scope to one of the strings. The default is SUBTREE_SCOPE
.
OBJECT_SCOPE
: only search the named roles context.
ONELEVEL_SCOPE
: search directly under the named roles context.
SUBTREE_SCOPE
: If the roles context is not a DirContext, search only the object. If the roles context is a DirContext, search the subtree rooted at the named object, including the named object itself
allowEmptyPasswords
: A flag indicating if empty(length==0)
passwords should be passed to the LDAP server. An empty password is treated as an anonymous login by some LDAP servers and this may not be a desirable feature. Set this to false to reject empty passwords, true to have the ldap server validate the empty password. The default is true.
BaseCertLoginModule
authenticates users based on X509 certificates. A typical use case for this login module is CLIENT-CERT
authentication in the web tier.
This login module only performs authentication: you must combine it with another login module capable of acquiring authorization roles to completely define access to a secured web or EJB component. Two subclasses of this login module, CertRolesLoginModule
and DatabaseCertLoginModule
extend the behavior to obtain the authorization roles from either a properties file or database.
The BaseCertLoginModule
needs a KeyStore
to perform user validation. This is obtained through a org.jboss.security.SecurityDomain
implementation. Typically, the SecurityDomain
implementation is configured using the org.jboss.security.plugins.JaasSecurityDomain
MBean as shown in this jboss-service.xml
configuration fragment:
<mbean code="org.jboss.security.plugins.JaasSecurityDomain"
name="jboss.ch8:service=SecurityDomain">
<constructor>
<arg type="java.lang.String" value="jmx-console"/>
</constructor>
<attribute name="KeyStoreURL">resource:localhost.keystore</attribute>
<attribute name="KeyStorePass">unit-tests-server</attribute>
</mbean>
The configuration creates a security domain with the name jmx-console
, with a SecurityDomain
implementation available through JNDI under the name java:/jaas/jmx-console
. The security domain follows the JBossSX security domain naming pattern.
Procedure 10.1. Secure Web Applications with Certificates and Role-based Authorization
This procedure describes how to secure a web application, such as the jmx-console.war
, using client certificates and role-based authorization.
Declare Resources and Roles
Modify web.xml
to declare the resources to be secured along with the allowed roles and security domain to be used for authentication and authorization.
<?xml version="1.0"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
...
<!-- A security constraint that restricts access to the HTML JMX console
to users with the role JBossAdmin. Edit the roles to what you want and
uncomment the WEB-INF/jboss-web.xml/security-domain element to enable
secured access to the HTML JMX console.
-->
<security-constraint>
<web-resource-collection>
<web-resource-name>HtmlAdaptor</web-resource-name>
<description>An example security config that only allows users with the
role JBossAdmin to access the HTML JMX console web application
</description>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>JBossAdmin</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>JBoss JMX Console</realm-name>
</login-config>
<security-role>
<role-name>JBossAdmin</role-name>
</security-role>
</web-app>
Specify the JBoss Security Domain
In the jboss-web.xml
file, specify the required security domain.
<jboss-web>
<security-domain>jmx-console</security-domain>
</jboss-web>
Specify Login Module Configuration
Define the login module configuration for the jmx-console security domain you just specified. This is done in the conf/login-config.xml
file.
<application-policy name="jmx-console">
<authentication>
<login-module code="org.jboss.security.auth.spi.BaseCertLoginModule"
flag="required">
<module-option name="password-stacking">useFirstPass</module-option>
<module-option name="securityDomain">jmx-console</module-option>
</login-module>
<login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule"
flag="required">
<module-option name="password-stacking">useFirstPass</module-option>
<module-option name="usersProperties">jmx-console-users.properties</module-option>
<module-option name="rolesProperties">jmx-console-roles.properties</module-option>
</login-module>
</authentication>
</application-policy>
Secure Web Applications with Certificates and Role-based Authorizationshows the BaseCertLoginModule
is used for authentication of the client cert, and the UsersRolesLoginModule
is only used for authorization due to the password-stacking=useFirstPass
option. Both the localhost.keystore
and the jmx-console-roles.properties
require an entry that maps to the principal associated with the client cert.
By default, the principal is created using the client certificate distinguished name, such as the DN specified in Example 10.6, “Certificate Example”.
Example 10.6. Certificate Example
[conf]$ keytool -printcert -file unit-tests-client.export Owner: CN=unit-tests-client, OU=JBoss Inc., O=JBoss Inc., ST=Washington, C=US Issuer: CN=jboss.com, C=US, ST=Washington, L=Snoqualmie Pass, EMAILADDRESS=admin @jboss.com, OU=QA, O=JBoss Inc. Serial number: 100103 Valid from: Wed May 26 07:34:34 PDT 2004 until: Thu May 26 07:34:34 PDT 2005 Certificate fingerprints: MD5: 4A:9C:2B:CD:1B:50:AA:85:DD:89:F6:1D:F5:AF:9E:AB SHA1: DE:DE:86:59:05:6C:00:E8:CC:C0:16:D3:C2:68:BF:95:B8:83:E9:58
The localhost.keystore
would need the certificate in Example 10.6, “Certificate Example” stored with an alias of CN=unit-tests-client, OU=JBoss Inc., O=JBoss Inc., ST=Washington, C=US
. The jmx-console-roles.properties
would also need an entry for the same entry. Since the DN contains characters that are normally treated as delimiters, you must escape the problem characters using a backslash ('\
') as illustrated below.
# A sample roles.properties file for use with the UsersRolesLoginModule CN\=unit-tests-client,\ OU\=JBoss\ Inc.,\ O\=JBoss\ Inc.,\ ST\=Washington,\ C\=US=JBossAdmin admin=JBossAdmin
IdentityLoginModule
is a simple login module that associates a hard-coded user name to any subject authenticated against the module. It creates a SimplePrincipal
instance using the name specified by the principal
option.
This module supports password stacking.
This login module is useful when you need to provide a fixed identity to a service, and in development environments when you want to test the security associated with a given principal and associated roles.
The supported login module configuration options include:
This is the name to use for the SimplePrincipal
all users are authenticated as. The principal name defaults to guest
if no principal option is specified.
This is a comma-delimited list of roles that will be assigned to the user.
A sample XMLLoginConfig configuration entry is described below. The entry authenticates all users as the principal named jduke
and assign role names of TheDuke
, and AnimatedCharacter
:
<policy>
<application-policy name="testIdentity">
<authentication>
<login-module code="org.jboss.security.auth.spi.IdentityLoginModule"
flag="required">
<module-option name="principal">jduke</module-option>
<module-option name="roles">TheDuke,AnimatedCharacter</module-option>
</login-module>
</authentication>
</application-policy>
</policy>
RunAsLoginModule
(org.jboss.security.auth.spi.RunAsLoginModule
) is a helper module that pushes a run as role onto the stack for the duration of the login phase of authentication, and pops the run as role in either the commit or abort phase.
The purpose of this login module is to provide a role for other login modules that must access secured resources in order to perform their authentication (for example, a login module that accesses a secured EJB). RunAsLoginModule
must be configured ahead of the login modules that require a run as role established.
The only login module configuration option is:
Name of the role to use as the run as role during login phase. If not specified a default of nobody
is used.
ClientLoginModule
(org.jboss.security.ClientLoginModule
) is an implementation of LoginModule
for use by JBoss clients for establishing caller identity and credentials. This simply sets the principal to the value of the NameCallback
filled in by the callbackhandler
, and the credential to the value of the PasswordCallback
filled in by the callbackhandler
in the security context.
ClientLoginModule
is the only supported mechanism for a client to establish the current thread's caller. Both stand-alone client applications, and server environments (acting as JBoss EJB clients where the security environment has not been configured to use JBossSX transparently) must use ClientLoginModule
.
Note that this login module does not perform any authentication. It merely copies the login information provided to it into the JBoss server EJB invocation layer for subsequent authentication on the server. If you need to perform client-side authentication of users you would need to configure another login module in addition to the ClientLoginModule
.
The supported login module configuration options include the following:
Value that specifies the way login threads connect to principal and credential storage sources. When set to true, each login thread has its own principal and credential storage and each separate thread must perform its own login. This is useful in client environments where multiple user identities are active in separate threads. When set to false the login identity and credentials are global variables that apply to all threads in the VM. The default setting is false
.
Value that specifies whether the SecurityAssociation
principal and credential seen on entry to the login()
method are saved and restored on either abort or logout. This is necessary if you must change identities and then restore the original caller identity. If set to true
, the principal and credential information is saved and restored on abort or logout. If set to false
, abort and logout clear the SecurityAssociation
. The default value is false
.
If the login modules bundled with the JBossSX framework do not work with your security environment, you can write your own custom login module implementation. The JaasSecurityManager
requires a particular usage pattern of the Subject
principals set. You must understand the JAAS Subject class's information storage features and the expected usage of these features to write a login module that works with the JaasSecurityManager
.
This section examines this requirement and introduces two abstract base LoginModule
implementations that can help you implement custom login modules.
You can obtain security information associated with a Subject
by using the following methods:
java.util.Set getPrincipals()
java.util.Set getPrincipals(java.lang.Class c)
java.util.Set getPrivateCredentials()
java.util.Set getPrivateCredentials(java.lang.Class c)
java.util.Set getPublicCredentials()
java.util.Set getPublicCredentials(java.lang.Class c)
For Subject
identities and roles, JBossSX has selected the most logical choice: the principals sets obtained via getPrincipals()
and getPrincipals(java.lang.Class)
. The usage pattern is as follows:
User identities (for example; username, social security number, employee ID) are stored as java.security.Principal
objects in the Subject
Principals
set. The Principal
implementation that represents the user identity must base comparisons and equality on the name of the principal. A suitable implementation is available as the org.jboss.security.SimplePrincipal
class. Other Principal
instances may be added to the Subject
Principals
set as needed.
Assigned user roles are also stored in the Principals
set, and are grouped in named role sets using java.security.acl.Group
instances. The Group
interface defines a collection of Principal
s and/or Group
s, and is a subinterface of java.security.Principal
.
Any number of role sets can be assigned to a Subject
.
The JBossSX framework uses two well-known role sets with the names Roles
and CallerPrincipal
.
The Roles
group is the collection of Principal
s for the named roles as known in the application domain under which the Subject
has been authenticated. This role set is used by methods like the EJBContext.isCallerInRole(String)
, which EJBs can use to see if the current caller belongs to the named application domain role. The security interceptor logic that performs method permission checks also uses this role set.
The CallerPrincipal
Group
consists of the single Principal
identity assigned to the user in the application domain. The EJBContext.getCallerPrincipal()
method uses the CallerPrincipal
to allow the application domain to map from the operation environment identity to a user identity suitable for the application. If a Subject
does not have a CallerPrincipal
Group
, the application identity is the same used for login.
The following information will help you to create a custom Login Module example that extends the UsernamePasswordLoginModule
and obtains a user's password and role names from a JNDI lookup.
At the end of this section you will have created a custom JNDI context login module that will return a user's password if you perform a lookup on the context using a name of the form password/<username>
(where <username>
is the current user being authenticated). Similarly, a lookup of the form roles/<username>
returns the requested user's roles.
Example 10.7, “ JndiUserAndPass Custom Login Module” shows the source code for the JndiUserAndPass
custom login module.
Note that because this extends the JBoss UsernamePasswordLoginModule
, all JndiUserAndPass
does is obtain the user's password and roles from the JNDI store. The JndiUserAndPass
does not interact with the JAAS LoginModule
operations.
Example 10.7. JndiUserAndPass Custom Login Module
package org.jboss.book.security.ex2;
import java.security.acl.Group;
import java.util.Map;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.auth.spi.UsernamePasswordLoginModule;
/**
* An example custom login module that obtains passwords and roles
* for a user from a JNDI lookup.
*
* @author Scott.Stark@jboss.org
* @version $Revision: 1.4 $
*/
public class JndiUserAndPass
extends UsernamePasswordLoginModule
{
/** The JNDI name to the context that handles the password/username lookup */
private String userPathPrefix;
/** The JNDI name to the context that handles the roles/ username lookup */
private String rolesPathPrefix;
/**
* Override to obtain the userPathPrefix and rolesPathPrefix options.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options)
{
super.initialize(subject, callbackHandler, sharedState, options);
userPathPrefix = (String) options.get("userPathPrefix");
rolesPathPrefix = (String) options.get("rolesPathPrefix");
}
/**
* Get the roles the current user belongs to by querying the
* rolesPathPrefix + '/' + super.getUsername() JNDI location.
*/
protected Group[] getRoleSets() throws LoginException
{
try {
InitialContext ctx = new InitialContext();
String rolesPath = rolesPathPrefix + '/' + super.getUsername();
String[] roles = (String[]) ctx.lookup(rolesPath);
Group[] groups = {new SimpleGroup("Roles")};
log.info("Getting roles for user="+super.getUsername());
for(int r = 0; r < roles.length; r ++) {
SimplePrincipal role = new SimplePrincipal(roles[r]);
log.info("Found role="+roles[r]);
groups[0].addMember(role);
}
return groups;
} catch(NamingException e) {
log.error("Failed to obtain groups for
user="+super.getUsername(), e);
throw new LoginException(e.toString(true));
}
}
/**
* Get the password of the current user by querying the
* userPathPrefix + '/' + super.getUsername() JNDI location.
*/
protected String getUsersPassword()
throws LoginException
{
try {
InitialContext ctx = new InitialContext();
String userPath = userPathPrefix + '/' + super.getUsername();
log.info("Getting password for user="+super.getUsername());
String passwd = (String) ctx.lookup(userPath);
log.info("Found password="+passwd);
return passwd;
} catch(NamingException e) {
log.error("Failed to obtain password for
user="+super.getUsername(), e);
throw new LoginException(e.toString(true));
}
}
}
The details of the JNDI store are found in the org.jboss.book.security.ex2.service.JndiStore
MBean. This service binds an ObjectFactory
that returns a javax.naming.Context
proxy into JNDI. The proxy handles lookup operations done against it by checking the prefix of the lookup name against password
and roles
.
When the name begins with password
, a user's password is being requested. When the name begins with roles
the user's roles are being requested. The example implementation always returns a password of theduke
and an array of roles names equal to {"TheDuke", "Echo"}
regardless of what the username is. You can experiment with other implementations as you wish.
The example code includes a simple session bean for testing the custom login module. To build, deploy and run the example, execute the following command in the examples directory.
[examples]$ ant -Dchap=security -Dex=2 run-example ... run-example2: [echo] Waiting for 5 seconds for deploy... [java] [INFO,ExClient] Login with username=jduke, password=theduke [java] [INFO,ExClient] Looking up EchoBean2 [java] [INFO,ExClient] Created Echo [java] [INFO,ExClient] Echo.echo('Hello') = Hello
The choice of using the JndiUserAndPass
custom login module for the server side authentication of the user is determined by the login configuration for the example security domain. The EJB JAR META-INF/jboss.xml
descriptor sets the security domain.
<?xml version="1.0"?>
<jboss>
<security-domain>security-ex2</security-domain>
</jboss>
The SAR META-INF/login-config.xml
descriptor defines the login module configuration.
<application-policy name = "security-ex2">
<authentication>
<login-module code="org.jboss.book.security.ex2.JndiUserAndPass"
flag="required">
<module-option name = "userPathPrefix">/security/store/password</module-option>
<module-option name = "rolesPathPrefix">/security/store/roles</module-option>
</login-module>
</authentication>
</application-policy>