SeamFramework.orgCommunity Documentation

Chapter 2. Security - Authentication

2.1. Basic Concepts
2.2. Built-in Authenticators
2.3. Which Authenticator will Seam use?
2.4. Writing a custom Authenticator

The majority of the Security API is centered around the Identity bean. This bean represents the identity of the current user, the default implementation of which is a session-scoped, named bean. This means that once logged in, a user's identity is scoped to the lifecycle of their current session. The two most important methods that you need to know about at this stage in regard to authentication are login() and logout(), which as the names suggest are used to log the user in and out, respectively.

As the default implementation of the Identity bean is named, it may be referenced via an EL expression, or be used as the target of an EL action. Take the following JSF code snippet for example:

  <h:commandButton action="#{identity.login}" value="Log in"/>    

This JSF command button would typically be used in a login form (which would also contain inputs for the user's username and password) that allows the user to log into the application.

The other important bean to know about right now is the Credentials bean. Its' purpose is to hold the user's credentials (such as their username and password) before the user logs in. The default implementation of the Credentials bean is also a session-scoped, named bean (just like the Identity bean).

The Credentials bean has two properties, username and credential that are used to hold the current user's username and credential (e.g. a password) values. The default implementation of the Credentials bean provides an additional convenience property called password, which may be used in lieu of the credential property when a simple password is required.

The Seam Security module provides the following built-in Authenticator implementations:

The Identity bean has an authenticatorClass property, which if set will be used to determine which Authenticator bean implementation to invoke during the authentication process. This property may be set by configuring it with a predefined authenticator type, for example by using the Seam Config module. The following XML configuration example shows how you would configure the Identity bean to use the com.acme.MyCustomerAuthenticator bean for authentication:


<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:s="urn:java:ee" 
   xmlns:security="urn:java:org.jboss.seam.security"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd">
       
   <security:IdentityImpl>
      <s:modifies/>      
      <security:authenticatorClass>com.acme.MyCustomAuthenticator</security:authenticatorClass>
   </security:IdentityImpl>      
</beans>

Alternatively, if you wish to be able to select the Authenticator to authenticate with by specifying the name of the Authenticator implementation (i.e. for those annotated with the @Named annotation), the authenticatorName property may be set instead. This might be useful if you wish to offer your users the choice of how they would like to authenticate, whether it be through a local user database, an external OpenID provider, or some other method.

The following example shows how you might configure the authenticatorName property with the Seam Config module:


<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:s="urn:java:ee" 
   xmlns:security="urn:java:org.jboss.seam.security"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd">
   <security:IdentityImpl>
      <s:modifies/>
      <security:authenticatorName>openIdAuthenticator</security:authenticatorName>
   </security:IdentityImpl>      
</beans>

If neither the authenticatorClass or authenticatorName properties are set, then the authentication process with automatically use a custom Authenticator implementation, if the developer has provided one (and only one) within their application.

If neither property is set, and the user has not provided a custom Authenticator, then the authentication process will fall back to the Identity Management API to attempt to authenticate the user.

All Authenticator implementations must implement the org.jboss.seam.security.Authenticator interface. This interface defines the following methods:

public interface Authenticator {

  void authenticate();   
  void postAuthenticate();   
  User getUser();   
  AuthenticationStatus getStatus();
}

The authenticate() method is invoked during the authentication process and is responsible for performing the work necessary to validate whether the current user is who they claim to be.

The postAuthenticate() method is invoked after the authentication process has already completed, and may be used to perform any post-authentication business logic, such as setting session variables, logging, auditing, etc.

The getUser() method should return an instance of org.picketlink.idm.api.User, which is generally determined during the authentication process.

The getStatus() method must return the current status of authentication, represented by the AuthenticationStatus enum. Possible values are SUCCESS, FAILURE and DEFERRED. The DEFERRED value should be used for special circumstances, such as asynchronous authentication as a result of authenticating against a third party as is the case with OpenID, etc.

The easiest way to get started writing your own custom authenticator is to extend the org.jboss.seam.security.BaseAuthenticator abstract class. This class implements the getUser() and getStatus() methods for you, and provides setUser() and setStatus() methods for setting both the user and status values.

To access the user's credentials from within the authenticate() method, you can inject the Credentials bean like so:

@Inject Credentials credentials;

Once the credentials are injected, the authenticate() method is responsible for checking that the provided credentials are valid. Here is a complete example:

public class SimpleAuthenticator extends BaseAuthenticator implements Authenticator {

   @Inject Credentials credentials;
   
   @Override
   public void authenticate() {
      if ("demo".equals(credentials.getUsername()) && 
            credentials.getCredential() instanceof PasswordCredential &&
            "demo".equals(((PasswordCredential) credentials.getCredential()).getValue()))  {
         setStatus(AuthenticationStatus.SUCCESS);
         setUser(new SimpleUser("demo"));
      }
   }
}

In the above code, the authenticate() method checks that the user has provided a username of demo and a password of demo. If so, the authentication is deemed as successful and the status is set to AuthenticationStatus.SUCCESS, and a new SimpleUser instance is created to represent the authenticated user.