Crowd JAAS Login Module

Name Crowd JAAS Login Module
Version 0.9.2
Product Versions Crowd 1.0.6
Author(s) Brad Harvey
Homepage  
Price Free
License BSD
JavaDocs  
IssueTracking  
Download JAR CrowdJaasLoginModule-0.9.2.jar
Download Source CrowdJaasLoginModule-0.9.2-src.zip

The JAAS Login Module is a Crowd Application Connector for JAAS and Spring Acegi.

Description/Features

Plug straight in to existing applications that use JAAS to take full advantage of Crowd's application provisioning and identity management features.

Enable single sign on in applications using the Spring Acegi security framework.

Usage

JAAS Login Module Options

The Crowd JAAS Login Module is configured via module options. These are set in an application specific manner (often with a Configuration file).

The options you need to set are:

  • crowd.server.url
  • application.name
  • application.password

This will allow you to authenticate against crowd with a user/password and retrieve the user's Crowd groups. These options can be set in the login module configuration, or in a crowd.properties file on the classpath. The remaining options must be set in the login module configuration.

If you want to authenticate with a token instead of password, set useToken.

Module Option Description Default
crowd.server.url URL to Crowd web service Defaulted from crowd.properties file
application.name Crowd application name Defaulted from crowd.properties file
application.password Crowd application password Defaulted from crowd.properties file
useToken if true, treat the password as a token false

If you are chaining login modules, tryFirstPass and friends can be used to share state between them. This is used where interactive callback handlers are employed to prevent the user being asked for their password multiple times.

Module Option Description Default
storePass if true, save shared state if login succeeds (tryFirstPass and useFirstPass do not enable this automatically). false
tryFirstPass if true, attempt authentication from shared state. If this fails, try again with callback handler. false
useFirstPass if true, only attempt authentication from shared state - do not use callbackhandler at all. false
clearPass if true, clear shared state after commit false
storeToken if true and storePass is true, save the token to shared state instead of the password. Automatically true if useToken is true. useToken ? true : false

Finally, if you need specific classes for principals and groups they can be specified with principalClassName and friends.

Module Option Description Default
principalClassName class name of Principal implementation for User Principal com.atlassian.crowd.application.jaas.CrowdPrincipal
roleGroupClassName class name of Group implementation to contain roles com.atlassian.crowd.application.jaas.CrowdGroup
roleGroupName name of role Group Roles
roleClassName class name of Principal implementation for role Principals within the role group value of principalClassName

JAAS in Acegi

See Acegi JAAS for instructions on using a JAAS login module in Acegi. Essentially, you need to configure the login module in a JaasAuthenticationProvider, and provide com.atlassian.crowd.application.acegi.CrowdAuthorityGranter as the AuthorityGranter to return the Crowd groups as granted authorities to Acegi.

Authenticate via Jaas
<bean id="jaasAuthenticationProvider" class="org.acegisecurity.providers.jaas.JaasAuthenticationProvider">
  <property name="loginConfig">
    <value>/WEB-INF/login.conf</value>
  </property>
  <property name="loginContextName">
    <value>crowd</value>
  </property>
  <property name="callbackHandlers">
    <list>
      <bean class="org.acegisecurity.providers.jaas.JaasNameCallbackHandler"/>
      <bean class="org.acegisecurity.providers.jaas.JaasPasswordCallbackHandler"/>
    </list>
  </property>
  <property name="authorityGranters">
    <list>
      <bean class="com.atlassian.crowd.application.acegi.CrowdAuthorityGranter"/>
    </list>
  </property>
</bean>

The login config should look something like this:

/WEB-INF/login.conf
crowd {
	com.atlassian.crowd.application.jaas.CrowdLoginModule required application.name=acegi application.password=acegi crowd.server.url="http://localhost:8095/crowd/services/";
};

If your environment already uses JAAS, the loginConfig property may be ignored in favour of that environment's configuration mechanism. For example, in JBoss the login module has to be configured in conf/login-config.xml

Acegi Single Sign On

Single Sign On is implemented using the RememberMe infrastructure. It does not actually store the token information persistently for true remember me, and is not intended to.

The RememberMeServices implementation is com.atlassian.crowd.application.acegi.CrowdVerifyTokenService. This reads a crowd.properties file from the classpath (see Java Integration Libraries).

<bean id="rememberMeServices" class="com.atlassian.crowd.application.acegi.CrowdVerifyTokenService">
    <constructor-arg value="changeThis"/> <!-- key must be shared with RememberMeAuthenticationProvider -->
</bean>

Place this snippet inside your authentication provider. The key must be shared with the rememberMeServices, but it isn't actually used to validate the cookie - Crowd has already validated it in the CrowdVerifyTokenService.

<bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
    <property name="key" value="changeThis"/>
</bean>

You will also need to add rememberMeServices references to various other beans. Here are the applicable beans in the acegi-tutorial configuration.

<!-- add remember me references to various other beans as per normal -->
	<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
		<constructor-arg value="/index.jsp"/> <!-- URL redirected to after logout -->
		<constructor-arg>
			<list>
				<ref bean="rememberMeServices"/>
				<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
			</list>
		</constructor-arg>
	</bean>

	<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
		<property name="authenticationManager" ref="authenticationManager"/>
		<property name="authenticationFailureUrl" value="/acegilogin.jsp?login_error=1"/>
		<property name="defaultTargetUrl" value="/"/>
		<property name="filterProcessesUrl" value="/j_acegi_security_check"/>
		<property name="rememberMeServices" ref="rememberMeServices"/>
	</bean>
   
	<bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
		<property name="authenticationManager" ref="authenticationManager"/>
		<property name="rememberMeServices" ref="rememberMeServices"/>
	</bean>

Examples

Simple JAAS Client

Here's a sample client. I created an application in Crowd called soapui with a password of soapui. This JAAS module configuration sets the application name, password, and Crowd server url.

crowd.conf
Crowd {
	com.atlassian.crowd.application.jaas.CrowdLoginModule required application.name=soapui application.password=soapui crowd.server.url="http://localhost:8095/crowd/services/";
};

Here's a snippet of code to load this configuration file from the classpath, create a login context, and login.

Sample Client Code to invoke a LoginContext
URL resource = Thread.currentThread().getContextClassLoader().getResource("crowd.conf");
    System.setProperty("java.security.auth.login.config", URLDecoder.decode(resource.getFile()));
    LoginContext loginContext = new LoginContext("Crowd", new UsernamePasswordCallbackHandler("testuser", "password".toCharArray()));
    loginContext.login();
    System.out.println(loginContext.getSubject());
    loginContext.logout();

The UsernamePasswordCallbackHandler class is in the test directory of the source distribution. The output of that snippet is:

Subject:
	Principal: CrowdGroup: Roles [CrowdPrincipal: crowd-administrators, CrowdPrincipal: soapui]
	Principal: CrowdPrincipal: testuser

The user "testuser" has crowd-administrators and soapui groups in Crowd.

JBoss Login Module

To use the CrowdJAASLoginModule in JBoss, you need to change login-config.xml and copy the jar and dependencies into the server lib directory. I have tested with JBoss 4.05GA and JDK 1.5.

Here's an example application policy entry in login-config.xml. Adjust the module options as required.

<application-policy name = "jmx-console">
       <authentication>
          <login-module code="com.atlassian.crowd.application.jaas.CrowdLoginModule" flag = "required">
           <module-option name="application.name">jboss</module-option>
           <module-option name="application.password">jboss</module-option>
           <module-option name="crowd.server.url">http://localhost:8095/crowd/services/</module-option>
          </login-module>
       </authentication>
    </application-policy>

In addition to CrowdJaasLoginModule-0.9.2.jar, the following jars are required in the <jboss home>/server/<context>/lib directory (eg, C:\jboss-4.0.5.GA\server\default\lib). All can be found in the client and client/lib directory under your Crowd installation.

  • crowd-core-1.0.6.jar
  • xfire-all-1.2.1.jar
  • stax-api-1.0.1.jar
  • wstx-asl-2.9.3.jar
  • jdom-1.0.jar
  • commons-httpclient-3.0.jar

This directory already contains a commons-httpclient.jar - this should be removed.

Sample Application

The Application Launchpad uses the JAAS and Acegi single sign on capabilities of the Crowd JAAS Login Module.

Version History

Version Release Date Description
0.9.2 April 29, 2007 Add Acegi support - see release notes in CrowdJaasLoginModule-0.9.2-src.zip
0.9.1 April 26, 2007 Minor bug fix and enhancement - see release notes in CrowdJaasLoginModule-0.9.1.zip
0.9 April 25, 2007 Initial Version.

Dependencies

  • Should be the same as the normal java integration client - crowd-core + jars found in $CROWD_INSTALL/client/lib.
  • I had to use xerces 2.8.1 to fix a class not found error.
  • The maven2 transitive dependencies report is quite scary due to xfire-all.

Known Limitations

The Crowd JAAS Login module uses the SecurityServerClient to communicate with Crowd. This class is implemented in a static manner, which means if you have multiple login modules defined they all share the same details for connecting to Crowd. This may not be suitable in a server environment.

Crowd roles and user attributes are not retrieved by the login module. In theory these could be retrieved and added to the subject as well.

The clearPass option will clear shared state added by other modules.

Logging out doesn't actually invalidate the token. In a single sign on environment this is probably a feature

Building from Source

This project uses maven2. I use the maven2 plugin for eclipse - http://m2eclipse.codehaus.org/.

You may need to add crowd-core to your local repository. Change to the $CROWD_INSTALL/client directory and execute this command:

mvn install:install-file -DgroupId=com.atlassian.crowd -DartifactId=crowd-core -Dversion=1.0.6 -Dpackaging=jar -Dfile=crowd-core-1.0.6.jar

References

JAAS Documentation

Acegi

Labels