This post is the sixth in a series of blog posts about customizing for Clearspace 2.x. The previous posts covered:

  1. Customizations in Clearspace 2.x

  2. Upgrading Themes and FTL Files.

  3. Widgets in Clearspace 2.x

  4. Macros for Clearspace 2.0

  5. Web Services

 

As in the Clearspace 1.x series, in Clearspace 2.x versions you can write your own components to manage user information and provide custom authentication.

 

Upgrading a User Data Provider

In version 1 you created a custom user provider by implementing the com.jivesoftware.spi.user.UserProvider interface to interact with your user data source and implementing the com.jivesoftware.base.User interface to represent a user. In version 2, you implement UserProvider and User, but the interfaces have changed a bit. The version 2 model is more streamlined, removing the need to implement the lifecycle methods that the SPI framework requires. Here's a summary of the changes:

 

  • Because you no longer implement the ServiceProvider interface, you don't implement support for its life cycle methods. Clearspace handles provider life cycle through Spring.

  • The com.jivesoftware.base.User interface is read-only (lacks setters) in version 2. Your implementation now provides the interface and logic for updating user information and returning it to Clearspace.

  • The User.authenticate method has been removed. Use an authentication provider to authenticate a user.

  • The User interface includes several new methods for retrieving information about the user.

  • You now connect your custom provider to Clearspace using Spring conventions rather than by setting a Jive property.

 

Here's a high level view of the upgrade steps you'll need to consider.

 

  • Implement the User interface to support whatever setters it needs. You'll also want to implement the is*Supported methods that indicate to Clearspace which user data is supported for setting.

  • For UserProvider methods in which your code receives and returns a User instance, you'll need to rewrite a bit to return your own User implementation. In version 1 the UserProvider instance received a UserTemplate with setters. Because you can no longer simply call setters on the User instance you receive (it might not have any), you'll instead copy data from the received instance into an instance of your own implementation and return your own (such as by constructing your instance from the User your code receives). The methods you'll need to change include create(User) and getUser(User).

  • Implement UserProvider.supportsUpdate to return true if your data store supports creating or updating users from Clearspace. If you return false from this method, be sure to also throw an UnsupportedOperationException from the create and update methods.

 

Upgrading an Authentication Provider

Authentication is substantially changed in version 2. For example, you no longer need to pass an AuthToken instance with method calls. Every request is guaranteed to have an authentication context. In version 2, Clearspace uses Acegi security, which is designed to fit well with the Spring framework. If you're implementing your own authentication provider, your components are based on Acegi; in some cases you might be able to use the classes included with Acegi, such as Authentication implementations.

 

Be sure to read the Acegi documentation, which includes information you'll find useful.

 

What Your Implementation Should Include

 

  • Implement org.acegisecurity.AuthenticationProvider to provide the service that authenticates users for Clearspace. This interface includes two methods: authenticate(Authentication) and supports(Class). Your supports method is called by Clearspace to determine whether the Authentication approach is supported by your provider. You should return true if the Authentication class it receives is one your authenticate method supports.

public boolean supports(Class authentication) {
    return authentication == UsernamePasswordAuthenticationToken.class;
}


The authenticate method receives an Authentication instance containing information identifying the user. Your implementation knows how to authenticate the user and should return an Authentication instance that indicates whether the user is authenticated. Here's a simple authenticate method example in which the checkAuth method (not shown) communicates with the data source and returns true if the user is authentic:

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
    String username = String.valueOf(auth.getPrincipal());
    String password = String.valueOf(auth.getCredentials());
    if(!checkAuth(username, password)){
        throw new BadCredentialsException("Username:" + username + " was not authenticated");
    }
    return new UsernamePasswordAuthenticationToken(username, password, new GrantedAuthority[]{});
}


  • Implement org.acegisecurity.Authentication to contain details of the authentication request (you can also use an existing class that implements Authentication ). An Authentication class represents the user in the context of a particular authentication approach -- such as basic authentication, LDAP, X.509 certificate, and so on. An instance includes details such as principal (something identifying the user, such as a username) and credentials (such as a password). Your isAuthenticated method should return true if the user is authentic.
     
    The Authentication class includes a getAuthorities method that is not currently supported by Clearspace. Your implementation should return an empty array:

public GrantedAuthority[] getAuthorities() {
    return new GrantedAuthority[0];
}]


  • Connect your authentication provider to Clearspace by adding a Spring configuration XML file to the jiveHome/etc directory.

 

<?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /upgrade/**=httpSessionContextIntegrationFilter, upgradeAuthenticationFilter, upgradeExceptionTranslationFilter
    /post-upgrade/**=httpSessionContextIntegrationFilter, postUpgradeAuthenticationFilter, postUpgradeExceptionTranslationFilter
    /admin/**=httpSessionContextIntegrationFilter, adminAuthenticationFilter, adminExceptionTranslationFilter
    /rpc/xmlrpc=httpSessionContextIntegrationFilter, basicAuthenticationFilter, wsExceptionTranslator
    /rpc/rest/**=httpSessionContextIntegrationFilter, basicAuthenticationFilter, wsExceptionTranslator
    /**=httpSessionContextIntegrationFilter, formAuthenticationFilter, rememberMeProcessingFilter, anonymousProcessingFilter, exceptionTranslationFilter
    .... add your implementation ...
</value>
</property>
</bean>

The following stanza lists the authentication providers that Clearspace tries to use. When trying to authenticate a user, Clearspace tries with each in turn, top to bottom. Each of the beans listed here

 

<!-- A list of authentication sources that will be consulted when attempting to
    authenticate the user. Each is consulted in order until a provider does
    *not* return null. This chains multiple providers together
    until one decides it can handle the user. -->
<bean id="authenticationManager" 
    class="org.acegisecurity.providers.ProviderManager">
    <property name="providers">
    <list>
        <ref bean="jiveLdapAuthenticationProvider"/>
        <ref bean="jiveLegacyAuthenticationProvider"/>
        <ref bean="daoAuthenticationProvider" />
        <ref bean="rememberMeAuthenticationProvider"/>
        <ref bean="anonymousAuthenticationProvider"/>
    </list>
    </property>
</bean>

 

The information above along with more details can be found in the Upgrading Extensions to 2.0 documentation.

 

If you are working on authentication for SSO, you might also be interested in reading Fred's post about Quick SSO on Clearspace 2.0