Taylor Identity
From Taylor
Taylor Identity is a reusable component for user and group maintenance.
Contents |
Model
Taylor Identity has a basic model made up of users and groups and a many2many association between them.
Group represents two concepts:
- Roles - defined at design time
- Organizational Units - defined at run time
Roles
Roles are defined at design time as you model your application and determine the actors and stories.
Two base roles are defined:
- User - The root role used for all users
- Admin - The role used for administrators
Two initial users are created if these roles have not already been created:
- user/user
- admin/admin
Use a Seam postInitialization listener to initialize your application's roles.
@Observer("org.jboss.seam.postInitialization")
@Transactional
public void initRoles() {
IdentityUtil.addGroup(identityEntityManager,
"Reviewer", "Reviewers",
"The role for users who review tickets.");
}
Profile
Several facelets are provided in addition to the User and Group maintenance screens.
- Profile - For the current user to maintain their information
- Register - For a new user to create a profile
- Provisioning (future) - a business process triggered by registration to task administrators with assigning additional roles
- Initial/Reset Password - set to changeme
- Obviously there is room for improvement here...
- However, you will typically use Ldap in production...
Jaas
- Seam security is leveraged and pointed at the taylor jaas configuration
<security:identity authenticate-method="#{authenticator.authenticate}"
jaas-config-name="taylor"/>
- By default a Database Login Module is used and pointed at the taylor-identity tables
<application-policy name="taylor"> <authentication> <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required"> <module-option name="dsJndiName">java:/TaylorDS</module-option> <module-option name="principalsQuery"> select password from TUser where id=? </module-option> <module-option name="rolesQuery"> select membership_id,'Roles' from TGroup_TUser where members_id=? </module-option> <module-option name="hashAlgorithm">MD5</module-option> <module-option name="hashEncoding">base64</module-option> </login-module> </authentication> </application-policy>
Ldap
Using a database identity store is great for development and small applications. However, for enterprise applications you will want to use Ldap.
The following shows how to configure the Taylor Identity Ldap implementation.
Login Module
Of course we want to leverage the existing Ldap Login Module to perform authentication.
<!-- http://jboss.org/community/docs/DOC-11251 -->
<login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required" >
<module-option name="password-stacking">useFirstPass</module-option>
<module-option name="java.naming.provider.url">ldap://localhost:10389</module-option>
<module-option name="bindDN">uid=admin,ou=system</module-option>
<module-option name="bindCredential">secret</module-option>
<module-option name="baseCtxDN">ou=People,ou=system</module-option>
<module-option name="baseFilter">(uid={0})</module-option>
<module-option name="allowEmptyPasswords">false</module-option>
<module-option name="rolesCtxDN">ou=Groups,ou=system</module-option>
<module-option name="roleFilter">(member={1})</module-option>
<module-option name="roleAttributeID">cn</module-option>
<module-option name="roleRecursion">-1</module-option>
<module-option name="searchScope">SUBTREE_SCOPE</module-option>
</login-module>
Application Specific Roles
It is often the case that you will not be allowed to manage all of your application specific roles in the enterprise Ldap store. For example, a typically approach is to have one role per application stored in Ldap to retrict overall authorization and then perform fine-grained authorization in each application.
If this is the case then we can leverage login module stacking to combine local roles into the Jaas Subject.
Here the taylor-identity database store is used just to access application specific roles.
<login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required" > ... </login-module> <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="sufficient"> <module-option name="password-stacking">useFirstPass</module-option> <module-option name="dsJndiName">java:/TaylorDS</module-option> <module-option name="rolesQuery">select membership_id,'Roles' from TGroup_TUser where members_id=?</module-option> </login-module>
Programmatic Ldap Access
There is more to Ldap the just authentication and authorization. We also need access to Ldap with in applications to access user information such as email addresses. Two key components are provided to facilitate this:
- LoginModuleOptions - provides access to the login module configuration to avoid duplicate configuration
- ManagedLdapContext - manages the lifecycle of the ldap context
- Note the assignment of the provider url
<component name="ldapLoginModule" class="net.taylor.jaas.LoginModuleOptions"
appConfigurationEntryName="taylor"
loginModuleName="org.jboss.security.auth.spi.LdapExtLoginModule" />
<ldap:ManagedLdapContext providerUrl = "#{ldapLoginModule['java.naming.provider.url']}"/>
Identity Service
Taylor provides an Identity Service that is used to access user and group information with in an application and encapsulates the source of the data.
Use the following to turn on the Ldap implementation.
<ldap:LdapDao /> <component class="net.taylor.identity.ldap.IdentityServiceLdapImpl" />
Schema Mapping
Not all Ldap schema are created equal. To account for these variations a schema mapping feature is provided. The mapping uses a combination of annotations and xml configuration.
NOTE: You can use this feature to map your own entities as well, such as an Employee entity which contains address and contact information.
The User and Groups entities have already been implemented with the necessary annotations.
@Entity
public class User {
@Id
@Attribute
public String getId() {...}
@Attribute("cn")
public String getName() {...}
@Attribute("mail")
public String getEmail() {...}
}
@Entity
public class Group {
@Id
@Attribute("cn")
public String getId() {...}
@Attribute
public String getName() {...}
@Attribute
public String getDescription() {...}
@ManyToMany
@Attribute
public Set<User> getMembers() {...}
}
These annotations are then merged with the metadata in the components.xml file.
<ldap:Metadata name="net.taylor.identity.entity.UserLdapMetadata"
dnAttribute="uid"
contextDN="#{ldapLoginModule['baseCtxDN']}"
filterObjectClass="person"
searchScope="SubTree">
<attributes>
<key>id</key><value>uid</value>
<key>membership</key><value>businessCategory</value>
</attributes>
</ldap:Metadata>
<ldap:Metadata name="net.taylor.identity.entity.GroupLdapMetadata"
dnAttribute="cn"
contextDN="#{ldapLoginModule['rolesCtxDN']}"
filterObjectClass="groupOfNames">
<attributes>
<key>description</key><value>description</value>
<key>members</key><value>member</value>
</attributes>
</ldap:Metadata>
Synchronization
Synchronization is often necessary, because identity data will usually be spread across Ldap and the application database.
Users will need to be partially synchronized when Users are stored in Ldap and Roles are stored in the application, so that the roles can be assigned to users.
The LoginObserver will add new users to the database when they login the first time.
<sync:LoginObserver />
The Synchronizer will sync users on startup that have the required role in Ldap.
<sync:Synchronizer requiredRole="MyApp" />
Jpa Listeners can be used for real-time sync.
<entity-listener class="net.taylor.ldap.jpa.LoadCallbackListener"/> <entity class="net.taylor.identity.entity.User"> <entity-listeners> <entity-listener class="net.taylor.ldap.jpa.UpdateCallbackListener"/> </entity-listeners> </entity>
components.xml
These various configurations need to be placed in a components.xml. Any components.xml will do, but we need to consider different environment configurations.
For example, all of the connection information is stored outside the Ear in the server\all\conf\login-config.xml and accessed with in the Ear via the LoginModuleOptions component. This facilitates deploying the Ear to different ldap-enabled environments.
However, not all environments will use ldap.
One option is to use WEB-INF\classes\META-INF\components.xml.
But a better option is to create a separate jar with just a components.xml file for your ldap configuration. Then use a profile in your maven build to control the dependency on this jar.
Unit Testing
To facilitate unit testing with Ldap, taylor-identity provides a component to startup ApacheDS.
<ldap:ApacheDS />
- import.ldif - load data
Seam Security
The User and Group entities have the seam security annotations applied and the jpa-identity-store is configured in the taylor-identity/META-INF/components.xml file.
<security:jpa-identity-store user-class="net.taylor.identity.entity.User" role-class="net.taylor.identity.entity.Group"/>


