18.3. Login Modules
18.3.1. Using Modules
18.3.1.1. Password Stacking
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.
password-stacking
option is set to useFirstPass
, this module first looks for a shared user name 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.
Note
Example 18.5. Password Stacking Sample
/subsystem=security/security-domain=pwdStack/authentication=classic/login-module=Ldap:add( \ code=Ldap, \ flag=required, \ module-options=[ \ ("password-stacking"=>"useFirstPass"), \ ... Ldap login module configuration ]) /subsystem=security/security-domain=pwdStack/authentication=classic/login-module=Database:add( \ code=Database, \ flag=required, \ module-options=[ \ ("password-stacking"=>"useFirstPass"), \ ... Database login module configuration ])
18.3.1.2. Password Hashing
Important
Example 18.6. Password Hashing
nobody
and contains based64-encoded, SHA-256 hashes of the passwords in a usersb64.properties
file. The usersb64.properties
file is part of the deployment classpath.
/subsystem=security/security-domain=testUsersRoles:add /subsystem=security/security-domain=testUsersRoles/authentication=classic:add /subsystem=security/security-domain=testUsersRoles/authentication=classic/login-module=UsersRoles:add( \ code=UsersRoles, \ flag=required, \ module-options=[ \ ("usersProperties"=>"usersb64.properties"), \ ("rolesProperties"=>"test-users-roles.properties"), \ ("unauthenticatedIdentity"=>"nobody"), \ ("hashAlgorithm"=>"SHA-256"), \ ("hashEncoding"=>"base64") \ ])
- hashAlgorithm
- 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 areSHA-256
,SHA-1
andMD5
. - hashEncoding
- String that specifies one of three encoding types:
base64
,hex
orrfc2617
. The default isbase64
. - hashCharset
- Encoding character set used to convert the clear text password to a byte array. The platform default encoding is the default.
- hashUserPassword
- 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
. - hashStorePassword
- 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.
org.jboss.security.auth.spi.Util
class provides a static helper method that will hash a password using the specified encoding. The following example produces a base64-encoded, MD5 hashed password.
String hashedPassword = Util.createPasswordHash("SHA-256", Util.BASE64_ENCODING, null, null, "password");
password
- is piped into the OpenSSL digest function then piped into another OpenSSL function to convert into base64-encoded format.
echo -n password | openssl dgst -sha256 -binary | openssl base64
XohImNooBHFR0OVvjcYpJ3NgPQ1qq73WKhHvch0VQtg=
. This value must be stored in the users' properties file specified in the security domain - usersb64.properties
- in the example above.
18.3.1.3. Unauthenticated Identity
unauthenticatedIdentity
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.
18.3.1.4. Ldap Login Module
Ldap
login module is a LoginModule
implementation that authenticates against a Lightweight Directory Access Protocol (LDAP) server. Use the Ldap
login module if your user name and credentials are stored in an LDAP server that is accessible using a Java Naming and Directory Interface (JNDI) LDAP provider.
Note
AdvancedLdap
login module chained with the SPNEGO login module or only the AdvancedLdap
login module.
- Distinguished Name (DN)
- In Lightweight Directory Access Protocol (LDAP), the distinguished name uniquely identifies an object in a directory. Each distinguished name must have a unique name and location from all other objects, which is achieved using a number of attribute-value pairs (AVPs). The AVPs define information such as common names, organization unit, among others. The combination of these values results in a unique string required by the LDAP.
Note
- java.naming.factory.initial
InitialContextFactory
implementation class name. This defaults to the Sun LDAP provider implementationcom.sun.jndi.ldap.LdapCtxFactory
.- java.naming.provider.url
- LDAP URL for the LDAP server.
- java.naming.security.authentication
- Security protocol level to use. The available values include
none
,simple
, andstrong
. If the property is undefined, the behavior is determined by the service provider. - java.naming.security.protocol
- Transport protocol to use for secure access. Set this configuration option to the type of service provider (for example, SSL). If the property is undefined, the behavior is determined by the service provider.
- java.naming.security.principal
- Specifies the identity of the Principal for authenticating the caller to the service. This is built from other properties as described below.
- java.naming.security.credentials
- Specifies the credentials of the Principal for authenticating the caller to the service. Credentials can take the form of a hashed password, a clear-text password, a key, or a certificate. If the property is undefined, the behavior is determined by the service provider.
Note
true
.
InitialLdapContext
with an environment composed of the LDAP JNDI properties described previously in this section.
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 18.7. LDAP Login Module Security Domain
/subsystem=security/security-domain=testLDAP:add(cache-type=default) /subsystem=security/security-domain=testLDAP/authentication=classic:add /subsystem=security/security-domain=testLDAP/authentication=classic/login-module=Ldap:add( \ code=Ldap, \ flag=required, \ module-options=[ \ ("java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory"), \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org:1389/"), \ ("java.naming.security.authentication"=>"simple"), \ ("principalDNPrefix"=>"uid="), \ ("principalDNSuffix"=>",ou=People,dc=jboss,dc=org"), \ ("rolesCtxDN"=>"ou=Roles,dc=jboss,dc=org"), \ ("uidAttributeID"=>"member"), \ ("matchOnUserDN"=>true), \ ("roleAttributeID"=>"cn"), \ ("roleAttributeIsDN"=>false) \ ])
java.naming.factory.initial
, java.naming.factory.url
and java.naming.security
options in the testLDAP security domain 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.
jsmith
would map to uid=jsmith,ou=People,dc=jboss,dc=org
.
Note
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.
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=jsmith,ou=People,dc=jboss,dc=org
. The search would locate cn=JBossAdmin
under the roles entry.
cn
. The value returned would be JBossAdmin
, so the jsmith
user is assigned to the JBossAdmin
role.
- LDAP Data Interchange Format (LDIF)
- Plain text data interchange format used to represent LDAP directory content and update requests. Directory content is represented as one record for each object or update request. Content consists of add, modify, delete, and rename requests.
Example 18.8. 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=jsmith,ou=People,dc=jboss,dc=org objectclass: top objectclass: uidObject objectclass: person uid: jsmith cn: John sn: Smith 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=jsmith,ou=People,dc=jboss,dc=org description: the JBossAdmin group
18.3.1.5. LdapExtended Login Module
- Distinguished Name (DN)
- In Lightweight Directory Access Protocol (LDAP), the distinguished name uniquely identifies an object in a directory. Each distinguished name must have a unique name and location from all other objects, which is achieved using a number of attribute-value pairs (AVPs). The AVPs define information such as common names, organization unit, among others. The combination of these values results in a unique string required by the LDAP.
org.jboss.security.auth.spi.LdapExtLoginModule)
searches for the user to bind, as well as the associated roles, for authentication. The roles query recursively follows DNs to navigate a hierarchical role structure.
- 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 initial LDAP server bind is authenticated using the bindDN and bindCredential properties. The bindDN is a user with permissions 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 property.
- The resulting userDN is authenticated by binding to the LDAP server using the userDN 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.
Note
- The top level role is queried only for roleAttributeID and not for roleNameAttributeID.
- When the roleAttributeIsDN module property is set to false, the recursive role search is disabled even if the recurseRoles module option is set to true.

Figure 18.1. LDAP Structure Example
Example 18.9. Example 2 LDAP Configuration
version: 1 dn: o=example2,dc=jboss,dc=org objectClass: top objectClass: organization o: example2 dn: ou=People,o=example2,dc=jboss,dc=org objectClass: top objectClass: organizationalUnit ou: People dn: uid=jduke,ou=People,o=example2,dc=jboss,dc=org objectClass: top objectClass: uidObject objectClass: person objectClass: inetOrgPerson cn: Java Duke employeeNumber: judke-123 sn: Duke uid: jduke userPassword:: dGhlZHVrZQ== dn: uid=jduke2,ou=People,o=example2,dc=jboss,dc=org objectClass: top objectClass: uidObject objectClass: person objectClass: inetOrgPerson cn: Java Duke2 employeeNumber: judke2-123 sn: Duke2 uid: jduke2 userPassword:: dGhlZHVrZTI= dn: ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: organizationalUnit ou: Roles dn: uid=jduke,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupUserEx memberOf: cn=Echo,ou=Roles,o=example2,dc=jboss,dc=org memberOf: cn=TheDuke,ou=Roles,o=example2,dc=jboss,dc=org uid: jduke dn: uid=jduke2,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupUserEx memberOf: cn=Echo2,ou=Roles,o=example2,dc=jboss,dc=org memberOf: cn=TheDuke2,ou=Roles,o=example2,dc=jboss,dc=org uid: jduke2 dn: cn=Echo,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupOfNames cn: Echo description: the echo role member: uid=jduke,ou=People,dc=jboss,dc=org dn: cn=TheDuke,ou=Roles,o=example2,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: TheDuke description: the duke role member: uid=jduke,ou=People,o=example2,dc=jboss,dc=org dn: cn=Echo2,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupOfNames cn: Echo2 description: the Echo2 role member: uid=jduke2,ou=People,dc=jboss,dc=org dn: cn=TheDuke2,ou=Roles,o=example2,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: TheDuke2 description: the duke2 role member: uid=jduke2,ou=People,o=example2,dc=jboss,dc=org dn: cn=JBossAdmin,ou=Roles,o=example2,dc=jboss,dc=org objectClass: top objectClass: groupOfNames cn: JBossAdmin description: the JBossAdmin group member: uid=jduke,ou=People,dc=jboss,dc=org
/subsystem=security/security-domain=testLdapExample2/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory"), \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("java.naming.security.authentication"=>"simple"), \ ("bindDN"=>"cn=Root,dc=jboss,dc=org"), \ ("bindCredential"=>"secret1"), \ ("baseCtxDN"=>"ou=People,o=example2,dc=jboss,dc=org"), \ ("baseFilter"=>"(uid={0})"), \ ("rolesCtxDN"=>"ou=Roles,o=example2,dc=jboss,dc=org"), \ ("roleFilter"=>"(uid={0})"), \ ("roleAttributeIsDN"=>"true"), \ ("roleAttributeID"=>"memberOf"), \ ("roleNameAttributeID"=>"cn") \ ])
Example 18.10. Example 3 LDAP Configuration
dn: o=example3,dc=jboss,dc=org objectclass: top objectclass: organization o: example3 dn: ou=People,o=example3,dc=jboss,dc=org objectclass: top objectclass: organizationalUnit ou: People dn: uid=jduke,ou=People,o=example3,dc=jboss,dc=org objectclass: top objectclass: uidObject objectclass: person objectClass: inetOrgPerson uid: jduke employeeNumber: judke-123 cn: Java Duke sn: Duke userPassword: theduke dn: ou=Roles,o=example3,dc=jboss,dc=org objectClass: top objectClass: organizationalUnit ou: Roles dn: uid=jduke,ou=Roles,o=example3,dc=jboss,dc=org objectClass: top objectClass: groupUserEx memberOf: cn=Echo,ou=Roles,o=example3,dc=jboss,dc=org memberOf: cn=TheDuke,ou=Roles,o=example3,dc=jboss,dc=org uid: jduke dn: cn=Echo,ou=Roles,o=example3,dc=jboss,dc=org objectClass: top objectClass: groupOfNames cn: Echo description: the JBossAdmin group member: uid=jduke,ou=People,o=example3,dc=jboss,dc=org dn: cn=TheDuke,ou=Roles,o=example3,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: TheDuke member: uid=jduke,ou=People,o=example3,dc=jboss,dc=org
/subsystem=security/security-domain=testLdapExample3/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory"), \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("java.naming.security.authentication"=>"simple"), \ ("bindDN"=>"cn=Root,dc=jboss,dc=org"), \ ("bindCredential"=>"secret1"), \ ("baseCtxDN"=>"ou=People,o=example3,dc=jboss,dc=org"), \ ("baseFilter"=>"(cn={0})"), \ ("rolesCtxDN"=>"ou=Roles,o=example3,dc=jboss,dc=org"), \ ("roleFilter"=>"(member={1})"), \ ("roleAttributeID"=>"cn") \ ])
Example 18.11. Example 4 LDAP Configuration
dn: o=example4,dc=jboss,dc=org objectclass: top objectclass: organization o: example4 dn: ou=People,o=example4,dc=jboss,dc=org objectclass: top objectclass: organizationalUnit ou: People dn: uid=jduke,ou=People,o=example4,dc=jboss,dc=org objectClass: top objectClass: uidObject objectClass: person objectClass: inetOrgPerson cn: Java Duke employeeNumber: jduke-123 sn: Duke uid: jduke userPassword:: dGhlZHVrZQ== dn: ou=Roles,o=example4,dc=jboss,dc=org objectClass: top objectClass: organizationalUnit ou: Roles dn: cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: RG1 member: cn=empty dn: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: RG2 member: cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org member: uid=jduke,ou=People,o=example4,dc=jboss,dc=org dn: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: RG3 member: cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R1,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R1 member: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R2,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R2 member: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R3,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R3 member: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org member: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R4,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R4 member: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org dn: cn=R5,ou=Roles,o=example4,dc=jboss,dc=org objectClass: groupOfNames objectClass: top cn: R5 member: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org member: uid=jduke,ou=People,o=example4,dc=jboss,dc=org
/subsystem=security/security-domain=testLdapExample4/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory"), \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("java.naming.security.authentication"=>"simple"), \ ("bindDN"=>"cn=Root,dc=jboss,dc=org"), \ ("bindCredential"=>"secret1"), \ ("baseCtxDN"=>"ou=People,o=example4,dc=jboss,dc=org"), \ ("baseFilter"=>"(cn={0})"), \ ("rolesCtxDN"=>"ou=Roles,o=example4,dc=jboss,dc=org"), \ ("roleFilter"=>"(member={1})"), \ ("roleRecursion"=>"1"), \ ("roleAttributeID"=>"memberOf") \ ])
Example 18.12. Default Active Directory Configuration
/subsystem=security/security-domain=AD_Default/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("bindDN"=>"JBOSS\searchuser"), \ ("bindCredential"=>"password"), \ ("baseCtxDN"=>"CN=Users,DC=jboss,DC=org"), \ ("baseFilter"=>"(sAMAccountName={0})"), \ ("rolesCtxDN"=>"CN=Users,DC=jboss,DC=org"), \ ("roleFilter"=>"(sAMAccountName={0})"), \ ("roleAttributeID"=>"memberOf"), \ ("roleAttributeIsDN"=>"true"), \ ("roleNameAttributeID"=>"cn"), \ ("searchScope"=>"ONELEVEL_SCOPE"), \ ("allowEmptyPasswords"=>"false") \ ])
Example 18.13. Recursive Roles Active Directory Configuration
/subsystem=security/security-domain=AD_Recursive/authentication=classic/login-module=LdapExtended:add( \ code=LdapExtended, \ flag=required, \ module-options=[ \ ("java.naming.provider.url"=>"ldap://ldaphost.jboss.org"), \ ("java.naming.referral"=>"follow"), \ ("bindDN"=>"JBOSS\searchuser"), \ ("bindCredential"=>"password"), \ ("baseCtxDN"=>"CN=Users,DC=jboss,DC=org"), \ ("baseFilter"=>"(sAMAccountName={0})"), \ ("rolesCtxDN"=>"CN=Users,DC=jboss,DC=org"), \ ("roleFilter"=>"(member={1})"), \ ("roleAttributeID"=>"cn"), \ ("roleAttributeIsDN"=>"false"), \ ("roleRecursion"=>"2"), \ ("searchScope"=>"ONELEVEL_SCOPE"), \ ("allowEmptyPasswords"=>"false") \ ])
18.3.1.6. UsersRoles Login Module
UsersRoles
login module is a simple login module that supports multiple users and user roles loaded from Java properties files. The default username-to-password mapping filename is users.properties
and the default username-to-roles mapping filename is roles.properties
.
WEB-INF/classes
folder in the WAR
archive), or into any directory on the server 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 18.14. UsersRoles Login Module
/subsystem=security/security-domain=ejb3-sampleapp/authentication=classic/login-module=UsersRoles:add( \ code=UsersRoles, \ flag=required, \ module-options=[ \ ("usersProperties"=>"ejb3-sampleapp-users.properties"), \ ("rolesProperties"=>"ejb3-sampleapp-roles.properties") \ ])
ejb3-sampleapp-users.properties
file uses a username=password
format with each user entry on a separate line:
username1=password1 username2=password2 ...
ejb3-sampleapp-roles.properties
file referenced in Example 18.14, “UsersRoles Login Module” uses the pattern username=role1,role2,
with an optional group name value. For example:
username1=role1,role2,... username1.RoleGroup1=role3,role4,... username2=role1,role3,...
ejb3-sampleapp-roles.properties
is used to assign the user name roles to a particular named group of roles where the XXX
portion of the property name is the group name. The user name=... form is an abbreviation for user name.Roles=..., where the Roles
group name is the standard name the JBossAuthorizationManager
expects to contain the roles which define the permissions of users.
jduke
user name:
jduke=TheDuke,AnimatedCharacter jduke.Roles=TheDuke,AnimatedCharacter
18.3.1.7. Database Login Module
Database
login module is a Java Database Connectivity-based (JDBC) login module that supports authentication and role mapping. Use this login module if you have your user name, password and role information stored in a relational database.
Note
Database
login module is based on two logical tables:
Table Principals(PrincipalID text, Password text) Table Roles(PrincipalID text, Role text, RoleGroup text)
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
.
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.
Principals
and Roles
, as already declared. The following statements populate the tables with the following data:
PrincipalID
java
with aPassword
ofechoman
in thePrincipals
tablePrincipalID
java
with a role namedEcho
in theRoles
RoleGroup
in theRoles
tablePrincipalID
java
with a role namedcaller_java
in theCallerPrincipal
RoleGroup
in theRoles
table
INSERT INTO Principals VALUES('java', 'echoman') INSERT INTO Roles VALUES('java', 'Echo', 'Roles') INSERT INTO Roles VALUES('java', 'caller_java', 'CallerPrincipal')
Database login module
configuration could be constructed as follows:
CREATE TABLE Users(username VARCHAR(64) PRIMARY KEY, passwd VARCHAR(64)) CREATE TABLE UserRoles(username VARCHAR(64), role VARCHAR(32))
/subsystem=security/security-domain=testDB/authentication=classic/login-module=Database:add( \ code=Database, \ flag=required, \ module-options=[ \ ("dsJndiName"=>"java:/MyDatabaseDS"), \ ("principalsQuery"=>"select passwd from Users where username=?"), \ ("rolesQuery"=>"select role, 'Roles' from UserRoles where username=?") \ ])
18.3.1.8. Certificate Login Module
Certificate
login module authenticates users based on X509 certificates. A typical use case for this login module is CLIENT-CERT
authentication in the web tier.
CertRolesLoginModule
and DatabaseCertLoginModule
extend the behavior to obtain the authorization roles from either a properties file or database.
Certificate
login module options, see the Included Authentication Modules reference in the Security Guide for JBoss EAP.
Certificate
login module needs a KeyStore
to perform user validation. This is obtained from a JSSE configuration of linked security domain as shown in the following configuration fragment:
/subsystem=security/security-domain=trust-domain:add /subsystem=security/security-domain=trust-domain/jsse=classic:add( \ truststore={ \ password=>pass1234, \ url=>/home/jbosseap/trusted-clients.jks \ }) /subsystem=security/security-domain=testCert:add /subsystem=security/security-domain=testCert/authentication=classic:add /subsystem=security/security-domain=testCert/authentication=classic/login-module=Certificate:add( \ code=Certificate, \ flag=required, \ module-options=[ \ ("securityDomain"=>"trust-domain"), \ ])
Procedure 18.4. Secure Web Applications with Certificates and Role-based Authorization
user-app.war
, using client certificates and role-based authorization. In this example the CertificateRoles
login module is used for authentication and authorization. Both the trusted-clients.keystore
and the app-roles.properties
require an entry that maps to the principal associated with the client certificate.
Declare Resources and Roles
Modifyweb.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" encoding="UTF-8"?> <web-app 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_3_0.xsd" version="3.0"> <security-constraint> <web-resource-collection> <web-resource-name>Protect App</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>Admin</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>CLIENT-CERT</auth-method> <realm-name>Secured area</realm-name> </login-config> <security-role> <role-name>Admin</role-name> </security-role> </web-app>
Specify the Security Domain
In thejboss-web.xml
file, specify the required security domain.<jboss-web> <security-domain>app-sec-domain</security-domain> </jboss-web>
Configure Login Module
Define the login module configuration for theapp-sec-domain
domain you just specified using the management CLI.[ /subsystem=security/security-domain=trust-domain:add /subsystem=security/security-domain=trust-domain/jsse=classic:add( \ truststore={ \ password=>pass1234, \ url=>/home/jbosseap/trusted-clients.jks \ }) /subsystem=security/security-domain=app-sec-domain:add /subsystem=security/security-domain=app-sec-domain/authentication=classic:add /subsystem=security/security-domain=app-sec-domain/authentication=classic/login-module=CertificateRoles:add( \ code=CertificateRoles, \ flag=required, \ module-options=[ \ ("securityDomain"=>"trust-domain"), \ ("rolesProperties"=>"app-roles.properties") \ ])
Example 18.15. Certificate Example
[conf]$ keytool -printcert -file valid-client-cert.crt Owner: CN=valid-client, OU=Security QE, OU=JBoss, O=Red Hat, C=CZ Issuer: CN=EAP Certification Authority, OU=Security QE, OU=JBoss, O=Red Hat, C=CZ Serial number: 2 Valid from: Mon Mar 24 18:21:55 CET 2014 until: Tue Mar 24 18:21:55 CET 2015 Certificate fingerprints: MD5: 0C:54:AE:6E:29:ED:E4:EF:46:B5:14:30:F2:E0:2A:CB SHA1: D6:FB:19:E7:11:28:6C:DE:01:F2:92:2F:22:EF:BB:5D:BF:73:25:3D SHA256: CD:B7:B1:72:A3:02:42:55:A3:1C:30:E1:A6:F0:20:B0:2C:0F:23:4F:7A:8E:2F:2D:FA:AF:55:3E:A7:9B:2B:F4 Signature algorithm name: SHA1withRSA Version: 3
trusted-clients.keystore
would need the certificate in Example 18.15, “Certificate Example” stored with an alias of CN=valid-client, OU=Security QE, OU=JBoss, O=Red Hat, C=CZ
. The app-roles.properties
must have 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 app-roles.properties file CN\=valid-client,\ OU\=Security\ QE,\ OU\=JBoss,\ O\=Red\ Hat,\ C\=CZ
18.3.1.9. Identity Login Module
Identity
login module 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.
Note
jduke
and assigns role names of TheDuke
, and AnimatedCharacter
:.
/subsystem=security/security-domain=testIdentity:add /subsystem=security/security-domain=testIdentity/authentication=classic:add /subsystem=security/security-domain=testIdentity/authentication=classic/login-module=Identity:add( \ code=Identity, \ flag=required, \ module-options=[ \ ("principal"=>"jduke"), \ ("roles"=>"TheDuke,AnimatedCharacter") \ ])
18.3.1.10. RunAs Login Module
RunAs
login module is a helper module that pushes a run as
role onto the stack for the duration of the login phase of authentication, then pops the run as
role from the stack in either the commit or abort phase.
RunAs
login module must be configured ahead of the login modules that require a run as
role established.
18.3.1.10.1. RunAsIdentity Creation
javax.security.auth.Subject
instance or an org.jboss.security.RunAsIdentity
instance. Both these classes store one or more principals that represent the identity and a list of roles that the identity possesses. In the case of the javax.security.auth.Subject
a list of credentials is also stored.
ejb-jar.xml
deployment descriptor, you specify one or more roles that a user must have to access the various EJB methods. A comparison of these lists reveals whether the user has one of the roles necessary to access the EJB method.
Example 18.16. org.jboss.security.RunAsIdentity Creation
ejb-jar.xml
file, you specify a <security-identity> element with a <run-as> role defined as a child of the <session> element.
<session> ... <security-identity> <run-as> <role-name>Admin</role-name> </run-as> </security-identity> ... </session>
Admin
RunAsIdentity role must be created.
Admin
role, you define a <run-as-principal>
element in the jboss-ejb3.xml
file.
<jboss:ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns:s="urn:security:1.1" version="3.1" impl-version="2.0"> <assembly-descriptor> <s:security> <ejb-name>WhoAmIBean</ejb-name> <s:run-as-principal>John</s:run-as-principal> </s:security> </assembly-descriptor> </jboss:ejb-jar>
<security-identity>
element in both the ejb-jar.xml
and <security>
element in the jboss-ejb3.xml
files are parsed at deployment time. The <run-as>
role name and the <run-as-principal>
name are then stored in the org.jboss.metadata.ejb.spec.SecurityIdentityMetaData
class.
Example 18.17. Assigning multiple roles to a RunAsIdentity
jboss-ejb3.xml
deployment descriptor <assembly-descriptor>
element group.
<jboss:ejb-jar xmlns:sr="urn:security-role" ...> <assembly-descriptor> ... <sr:security-role> <sr:role-name>Support</sr:role-name> <sr:principal-name>John</sr:principal-name> <sr:principal-name>Jill</sr:principal-name> <sr:principal-name>Tony</sr:principal-name> </sr:security-role> </assembly-descriptor> </jboss:ejb-jar>
<run-as-principal>
of John
was created. The configuration in this example extends the Admin
role, by adding the Support
role. The new role contains extra principals, including the originally defined principal John
.
<security-role>
element in both the ejb-jar.xml
and jboss-ejb3.xml
files are parsed at deployment time. The <role-name>
and the <principal-name>
data is stored in the org.jboss.metadata.ejb.spec.SecurityIdentityMetaData
class.
18.3.1.11. Client Login Module
Client
login module (org.jboss.security.ClientLoginModule
) is an implementation of LoginModule
for use by JBoss clients when establishing caller identity and credentials. This creates a new SecurityContext
assigns it a principal and a credential and sets the SecurityContext
to the ThreadLocal
security context.
Client
login module 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 the EAP security subsystem transparently) must use Client
login module.
Client
login module.
18.3.1.12. SPNEGO Login Module
SPNEGO
login module (org.jboss.security.negotiation.spnego.SPNEGOLoginModule
) is an implementation of LoginModule
that establishes caller identity and credentials with a KDC. The module implements SPNEGO (Simple and Protected GSSAPI Negotiation mechanism) and is a part of the JBoss Negotiation project. This authentication can be used in the chained configuration with the AdvancedLdap
login module to allow cooperation with an LDAP server.
SPNEGO
or AdvancedLdap
login modules in your project, you must add the dependency manually by editing the META-INF/jboss-deployment-structure.xml
deployment descriptor file.
Example 18.18. Add JBoss Negotiation Module as a Dependency
<jboss-deployment-structure> <deployment> <dependencies> <module name="org.jboss.security.negotiation" /> </dependencies> </deployment> </jboss-deployment-structure>
18.3.1.13. RoleMapping Login Module
RoleMapping
login module supports mapping roles, that are the end result of the authentication process, to one or more declarative roles. For example, if the authentication process has determined that the user "A" has the roles "ldapAdmin" and "testAdmin", and the declarative role defined in the web.xml
or ejb-jar.xml
file for access is admin
, then this login module maps the admin
roles to the user A
.
RoleMapping
login module options, see the Included Authentication Modules reference in the Security Guide for JBoss EAP.
RoleMapping
login module must be defined as an optional module to a login module configuration as it alters mapping of the previously mapped roles.
Example 18.19. Defining mapped roles
/subsystem=security/security-domain=test-domain-2/:add /subsystem=security/security-domain=test-domain-2/authentication=classic:add /subsystem=security/security-domain=test-domain-2/authentication=classic/login-module=test-2-lm/:add(\ flag=required,\ code=UsersRoles,\ module-options=[("usersProperties"=>"users.properties"),("rolesProperties"=>"roles.properties")]\ ) /subsystem=security/security-domain=test-domain-2/authentication=classic/login-module=test2-map/:add(\ flag=optional,\ code=RoleMapping,\ module-options=[("rolesProperties"=>"rolesMapping-roles.properties")]\ )
Example 18.20. Preferred method of defining mapped roles
/subsystem=security/security-domain=test-domain-2/:add /subsystem=security/security-domain=test-domain-2/authentication=classic:add /subsystem=security/security-domain=test-domain-2/authentication=classic/login-module=test-2-lm/:add(\ flag=required,\ code=UsersRoles,\ module-options=[("usersProperties"=>"users.properties"),("rolesProperties"=>"roles.properties")]\ ) /subsystem=security/security-domain=test-domain-2/mapping=classic/mapping-module=test2-map/:add(\ code=PropertiesRoles,type=role,\ module-options=[("rolesProperties"=>"rolesMapping-roles.properties")]\ )
Example 18.21. Properties File used by a RoleMappingLoginModule
ldapAdmin=admin, testAdmin
ldapAdmin
, then the roles admin
and testAdmin
are added to or substitute the authenticated subject depending on the replaceRole property value.
18.3.1.14. bindCredential Module Option
bindCredential
module option is used to store the credentials for the DN and can be used by several login and mapping modules. There are several methods for obtaining the password.
- Plaintext in a management CLI command.
- The password for the
bindCredential
module may be provided in plaintext, in a management CLI command. For example:("bindCredential"=>"secret1")
. For security reasons, the password should be encrypted using the JBoss EAP vault mechanism. - Use an external command.
- To obtain the password from the output of an external command, use the format
{EXT}...
where the...
is the external command. The first line of the command output is used as the password.To improve performance, the{EXTC[:expiration_in_millis]}
variant caches the password for a specified number of milliseconds. By default the cached password does not expire. If the value0
(zero) is specified, the cached credentials do not expire.TheEXTC
variant is only supported by theLdapExtended
login module.
Example 18.22. Obtain a password from an external command
{EXT}cat /mysecretpasswordfile
Example 18.23. Obtain a password from an external file and cache it for 500 milliseconds
{EXTC:500}cat /mysecretpasswordfile
18.3.2. Custom Modules
AuthenticationManager
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 AuthenticationManager
.
LoginModule
implementations that can help you implement custom login modules.
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)
Subject
identities and roles, EAP 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; user name, social security number, employee ID) are stored as
java.security.Principal
objects in theSubject
Principals
set. ThePrincipal
implementation that represents the user identity must base comparisons and equality on the name of the principal. A suitable implementation is available as theorg.jboss.security.SimplePrincipal
class. OtherPrincipal
instances may be added to theSubject
Principals
set as needed. - Assigned user roles are also stored in the
Principals
set, and are grouped in named role sets usingjava.security.acl.Group
instances. TheGroup
interface defines a collection ofPrincipal
s and/orGroup
s, and is a subinterface ofjava.security.Principal
. - Any number of role sets can be assigned to a
Subject
.
- The EAP security framework uses two well-known role sets with the names
Roles
andCallerPrincipal
.- The
Roles
group is the collection ofPrincipal
s for the named roles as known in the application domain under which theSubject
has been authenticated. This role set is used by methods like theEJBContext.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 singlePrincipal
identity assigned to the user in the application domain. TheEJBContext.getCallerPrincipal()
method uses theCallerPrincipal
to allow the application domain to map from the operation environment identity to a user identity suitable for the application. If aSubject
does not have aCallerPrincipal
Group
, the application identity is the same as operational environment identity.
18.3.2.1. Subject Usage Pattern Support
Subject
usage patterns described in Section 18.3.2, “Custom Modules”, EAP includes login modules that populate the authenticated Subject
with a template pattern that enforces correct Subject
usage.
The most generic of the two is the org.jboss.security.auth.spi.AbstractServerLoginModule
class.
javax.security.auth.spi.LoginModule
interface and offers abstract methods for the key tasks specific to an operation environment security infrastructure. The key details of the class are highlighted in Example 18.24, “AbstractServerLoginModule Class Fragment”. The JavaDoc comments detail the responsibilities of subclasses.
Important
loginOk
instance variable is pivotal. This must be set to true
if the log in succeeds, or false
by any subclasses that override the log in method. If this variable is incorrectly set, the commit method will not correctly update the subject.
Example 18.24. AbstractServerLoginModule Class Fragment
package org.jboss.security.auth.spi; /** * This class implements the common functionality required for a JAAS * server-side LoginModule and implements the PicketBox standard * Subject usage pattern of storing identities and roles. Subclass * this module to create your own custom LoginModule and override the * login(), getRoleSets(), and getIdentity() methods. */ public abstract class AbstractServerLoginModule implements javax.security.auth.spi.LoginModule { protected Subject subject; protected CallbackHandler callbackHandler; protected Map sharedState; protected Map options; protected Logger log; /** Flag indicating if the shared credential should be used */ protected boolean useFirstPass; /** * Flag indicating if the login phase succeeded. Subclasses that * override the login method must set this to true on successful * completion of login */ protected boolean loginOk; // ... /** * Initialize the login module. This stores the subject, * callbackHandler and sharedState and options for the login * session. Subclasses should override if they need to process * their own options. A call to super.initialize(...) must be * made in the case of an override. * * <p> * The options are checked for the <em>password-stacking</em> parameter. * If this is set to "useFirstPass", the login identity will be taken from the * <code>javax.security.auth.login.name</code> value of the sharedState map, * and the proof of identity from the * <code>javax.security.auth.login.password</code> value of the sharedState map. * * @param subject the Subject to update after a successful login. * @param callbackHandler the CallbackHandler that will be used to obtain the * the user identity and credentials. * @param sharedState a Map shared between all configured login module instances * @param options the parameters passed to the login module. */ public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { // ... } /** * Looks for javax.security.auth.login.name and * javax.security.auth.login.password values in the sharedState * map if the useFirstPass option was true and returns true if * they exist. If they do not or are null this method returns * false. * Note that subclasses that override the login method * must set the loginOk var to true if the login succeeds in * order for the commit phase to populate the Subject. This * implementation sets loginOk to true if the login() method * returns true, otherwise, it sets loginOk to false. */ public boolean login() throws LoginException { // ... } /** * Overridden by subclasses to return the Principal that * corresponds to the user primary identity. */ abstract protected Principal getIdentity(); /** * Overridden by subclasses to return the Groups that correspond * to the role sets assigned to the user. Subclasses should * create at least a Group named "Roles" that contains the roles * assigned to the user. A second common group is * "CallerPrincipal," which provides the application identity of * the user rather than the security domain identity. * * @return Group[] containing the sets of roles */ abstract protected Group[] getRoleSets() throws LoginException; }
The second abstract base login module suitable for custom login modules is the org.jboss.security.auth.spi.UsernamePasswordLoginModule
.
char[]
password as the authentication credentials. It also supports the mapping of anonymous users (indicated by a null user name and password) to a principal with no roles. The key details of the class are highlighted in the following class fragment. The JavaDoc comments detail the responsibilities of subclasses.
Example 18.25. UsernamePasswordLoginModule Class Fragment
package org.jboss.security.auth.spi; /** * An abstract subclass of AbstractServerLoginModule that imposes a * an identity == String username, credentials == String password * view on the login process. Subclasses override the * getUsersPassword() and getUsersRoles() methods to return the * expected password and roles for the user. */ public abstract class UsernamePasswordLoginModule extends AbstractServerLoginModule { /** The login identity */ private Principal identity; /** The proof of login identity */ private char[] credential; /** The principal to use when a null username and password are seen */ private Principal unauthenticatedIdentity; /** * The message digest algorithm used to hash passwords. If null then * plain passwords will be used. */ private String hashAlgorithm = null; /** * The name of the charset/encoding to use when converting the * password String to a byte array. Default is the platform's * default encoding. */ private String hashCharset = null; /** The string encoding format to use. Defaults to base64. */ private String hashEncoding = null; // ... /** * Override the superclass method to look for an * unauthenticatedIdentity property. This method first invokes * the super version. * * @param options, * @option unauthenticatedIdentity: the name of the principal to * assign and authenticate when a null username and password are * seen. */ public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { super.initialize(subject, callbackHandler, sharedState, options); // Check for unauthenticatedIdentity option. Object option = options.get("unauthenticatedIdentity"); String name = (String) option; if (name != null) { unauthenticatedIdentity = new SimplePrincipal(name); } } // ... /** * A hook that allows subclasses to change the validation of the * input password against the expected password. This version * checks that neither inputPassword or expectedPassword are null * and that inputPassword.equals(expectedPassword) is true; * * @return true if the inputPassword is valid, false otherwise. */ protected boolean validatePassword(String inputPassword, String expectedPassword) { if (inputPassword == null || expectedPassword == null) { return false; } return inputPassword.equals(expectedPassword); } /** * Get the expected password for the current username available * via the getUsername() method. This is called from within the * login() method after the CallbackHandler has returned the * username and candidate password. * * @return the valid password String */ abstract protected String getUsersPassword() throws LoginException; }
The choice of sub-classing the AbstractServerLoginModule
versus UsernamePasswordLoginModule
is based on whether a string-based user name and credentials are usable for the authentication technology you are writing the login module for. If the string-based semantic is valid, then subclass UsernamePasswordLoginModule
, otherwise subclass AbstractServerLoginModule
.
The steps your custom login module must execute depend on which base login module class you choose. When writing a custom login module that integrates with your security infrastructure, you should start by sub-classing AbstractServerLoginModule
or UsernamePasswordLoginModule
to ensure that your login module provides the authenticated Principal
information in the form expected by the EAP security manager.
AbstractServerLoginModule
, you must override the following:
void initialize(Subject, CallbackHandler, Map, Map)
: if you have custom options to parse.boolean login()
: to perform the authentication activity. Be sure to set theloginOk
instance variable to true if log in succeeds, false if it fails.Principal getIdentity()
: to return thePrincipal
object for the user authenticated by thelog()
step.Group[] getRoleSets()
: to return at least oneGroup
namedRoles
that contains the roles assigned to thePrincipal
authenticated duringlogin()
. A second commonGroup
is namedCallerPrincipal
and provides the user's application identity rather than the security domain identity.
UsernamePasswordLoginModule
, you must override the following:
void initialize(Subject, CallbackHandler, Map, Map)
: if you have custom options to parse.Group[] getRoleSets()
: to return at least oneGroup
namedRoles
that contains the roles assigned to thePrincipal
authenticated duringlogin()
. A second commonGroup
is namedCallerPrincipal
and provides the user's application identity rather than the security domain identity.String getUsersPassword()
: to return the expected password for the current user name available via thegetUsername()
method. ThegetUsersPassword()
method is called from withinlogin()
after thecallbackhandler
returns the user name and candidate password.
18.3.2.2. Custom LoginModule Example
UsernamePasswordLoginModule
and obtains a user's password and role names from a JNDI lookup.
password/<username>
(where <username>
is the current user being authenticated). Similarly, a lookup of the form roles/<username>
returns the requested user's roles. In Example 18.26, “JndiUserAndPassLoginModule Custom Login Module” is the source code for the JndiUserAndPassLoginModule
custom login module.
UsernamePasswordLoginModule
, the JndiUserAndPassLoginModule
obtains the user's password and roles from the JNDI store. The JndiUserAndPassLoginModule
does not interact with the JAAS LoginModule operations.
Example 18.26. JndiUserAndPassLoginModule 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.logging.Logger; 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 */ public class JndiUserAndPassLoginModule 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; private static Logger log = Logger.getLogger(JndiUserAndPassLoginModule.class); /** * Override to obtain the userPathPrefix and rolesPathPrefix options. */ @Override 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. */ @Override 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. */ @Override 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)); } } }
Example 18.27. Definition of security-ex2 security domain with the newly-created custom login module
/subsystem=security/security-domain=security-ex2/:add /subsystem=security/security-domain=security-ex2/authentication=classic:add /subsystem=security/security-domain=security-ex2/authentication=classic/login-module=ex2/:add(\ flag=required,\ code=org.jboss.book.security.ex2.JndiUserAndPassLoginModule,\ module-options=[("userPathPrefix"=>"/security/store/password"),\ ("rolesPathPrefix"=>"/security/store/roles")]\ )
JndiUserAndPassLoginModule
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-ejb3.xml
descriptor sets the security domain. For a web application it is part of the WEB-INF/jboss-web.xml
file.
Example 18.28. jboss-ejb3.xml
Example
<?xml version="1.0"?> <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:s="urn:security" version="3.1" impl-version="2.0"> <assembly-descriptor> <s:security> <ejb-name>*</ejb-name> <s:security-domain>security-ex2</s:security-domain> </s:security> </assembly-descriptor> </jboss:ejb-jar>
Example 18.29. jboss-web.xml example
<?xml version="1.0"?> <jboss-web> <security-domain>security-ex2</security-domain> </jboss-web>