login templates

equanda uses an internal mechanism to configure the very granular access rights for the user interface. This is based on user information in the database. This module allows you to generate a login module which prevents duplication of user information between the application and the JAAS module. For efficiency this information is stored in a cache.

For integration you have to configure that the login module is included in the jboss security system (as referenced in the project), that the user information is made available in the web layer (for tapestry) and that there is a cache where the login information can be stored.

Integration in the web layer

In your tapestry application module, the following needs to be included


/**
* User management filter, the login method on the user should be called when the user logs in. If the user does not
* yet exist (which is possible when logging in using some SSO solution, then the user should be created).
*
* @param log log
* @param requestGlobals to have access to servlet request
* @param persistentLocale locale to allow chaning to user preference
* @return request filter
*/
public RequestFilter buildLoginFilter( final Logger log,
final RequestGlobals requestGlobals,
final PersistentLocale persistentLocale,
final LoginInfoService loginInfoService )
{
return new RequestFilter()
{
public boolean service( Request request, Response response, RequestHandler handler )
throws IOException
{
// assure we have a user object, make it available on the session, login and set locale

HttpServletRequest servletRequest = requestGlobals.getHTTPServletRequest();
HttpSession session = servletRequest.getSession();
LoginInfo loginInfo = (LoginInfo) session.getAttribute( T5guiModule.SESSION_USER );
if ( null == loginInfo )
{
try
{
LoginCache loginCache = LoginCache.getLoginCache();
String userName = requestGlobals.getHTTPServletRequest().getUserPrincipal().getName();
loginInfo = loginCache.getWithAuth( userName );
if ( loginInfo == null )
{
EquandaUser user = EquandaUser.equandaCreate( EquandaUserConstants.TYPE_User );
user.setUserName( userName );
user.equandaUpdate();
loginInfo = loginCache.getWithAuth( userName );
}
session.setAttribute( T5guiModule.SESSION_USER, loginInfo );
if ( null != loginInfo.getUser() )
{
( (EquandaUser) loginInfo.getUser() ).login();
if ( loginInfo.getUser().getLanguage() != null )
{
persistentLocale.set( new Locale( loginInfo.getUser().getLanguage() ) );
}
}
}
catch ( Exception ex )
{
log.error( "problem while logging in user", ex );
}
}
loginInfoService.setLoginInfo( loginInfo );

// The reponsibility of a filter is to invoke the corresponding method
// in the handler. When you chain multiple filters together, each filter
// received a handler that is a bridge to the next filter.
return handler.service( request, response );
}
};
}

/**
* This is a contribution to the RequestHandler service configuration. This is how we extend Tapestry using the
* timing filter. A common use for this kind of filter is transaction management or security.
*
* @param configuration configuration to add to
* @param loginFilter filter info
*/
public void contributeRequestHandler( OrderedConfiguration<RequestFilter> configuration,
@InjectService( "LoginFilter" )RequestFilter loginFilter )
{
// Each contribution to an ordered configuration has a name, When necessary, you may
// set constraints to precisely control the invocation order of the contributed filter
// within the pipeline.

configuration.add( "Login", loginFilter );
}

This does a couple of things. It assures a LoginInfo object is created which contains the user information to be used by the authorization services and binding prefixes. This is also stored in the session, though this is actually optional.
The EquandaUser record is automatically created if it doesn't exists. In principle this is not needed when the generated LoginModul is used, but can be required when the login credential come from another source (e.g. LDAP, SSO).

The login()_ action is called on the _EquandaUser object. This allows custom definition of the meaning of logging in. It could be used for auditing, billing,...

The locale is set to the locale for the user.

JBoss configuration

The login templates (amongst others) generate a LoginModule which can be integrated in JBoss. This is a login module which checks the existing users and their credentials (password) from the application database (the EquandaUser table).
To allow bootstrapping, this module falls back to a users-passwords login module which gets the username and credentials from properties files.
Configuration can be done by including a fragment like the following in JBoss in server/your-config/conf/login-config.xml.


<application-policy name = "equanda">
<authentication>
<login-module code = "org.equanda.example.login.LoginModule" flag = "required" >
<module-option name="usersProperties">props/default-users.properties</module-option>
<module-option name="rolesProperties">props/default-roles.properties</module-option>
<module-option name="unauthenticatedIdentity">anonymous</module-option>
</login-module>
</authentication>
</application-policy>
  • The package name needs to match the configuration in dm.ini ("login" section, "package" setting).
  • The application-policy name should match the "security-domain" setting in the "extra" section.
  • The referred properties files contain the fallback user definition. These files should probably be empty for a running application as these contain backdoor credentials.

To assure it all works, a cache needs to be made available in jboss for use by equanda. This cache can be shared between several equanda applications (the package names are used to disciminate objects). In your deploy directory, you need a file called "equanda-cache-service.xml" with the following content.


<?xml version="1.0" encoding="UTF-8"?>
<server>

<!-- ============================================================ -->
<!-- Cache which is used by equanda -->
<!-- ============================================================ -->
<mbean code="org.jboss.cache.TreeCache"
name="jboss.cache:service=equandaCache">

<depends>jboss:service=Naming</depends>
<depends>jboss:service=TransactionManager</depends>

<!-- Configure the TransactionManager -->
<attribute name="TransactionManagerLookupClass">org.jboss.cache.JBossTransactionManagerLookup</attribute>

<!--
Node locking level : SERIALIZABLE
REPEATABLE_READ (default)
READ_COMMITTED
READ_UNCOMMITTED
NONE
-->
<attribute name="IsolationLevel">REPEATABLE_READ</attribute>

<!-- Valid modes are LOCAL
REPL_ASYNC
REPL_SYNC
-->
<attribute name="CacheMode">LOCAL</attribute>

<!-- Must be true if any entity deployment uses a scoped classloader -->
<attribute name="UseRegionBasedMarshalling">true</attribute>
<!-- Must match the value of "useRegionBasedMarshalling" -->
<attribute name="InactiveOnStartup">true</attribute>

<!-- The max amount of time (in milliseconds) we wait until the
initial state (ie. the contents of the cache) are retrieved from
existing members.
-->
<attribute name="InitialStateRetrievalTimeout">17500</attribute>

<!-- Number of milliseconds to wait until all responses for a
synchronous call have been received.
-->
<attribute name="SyncReplTimeout">17500</attribute>

<!-- Max number of milliseconds to wait for a lock acquisition -->
<attribute name="LockAcquisitionTimeout">15000</attribute>

<!-- Name of the eviction policy class. -->
<attribute name="EvictionPolicyClass">org.jboss.cache.eviction.LRUPolicy</attribute>

<!-- Specific eviction policy configurations. This is LRU -->
<attribute name="EvictionPolicyConfig">
<config>
<attribute name="wakeUpIntervalSeconds">5</attribute>
<!-- Cache wide default -->
<region name="/_default_">
<attribute name="maxNodes">500</attribute>
<attribute name="timeToLiveSeconds">1800</attribute>
</region>
</config>
</attribute>

</mbean>

</server>