2.2. Authentication API - The Identity Bean
The
Identity
bean (which can be found in the org.picketlink
package) is central to PicketLink's security API. This bean represents the authenticated user for the current session, and provides many useful methods for controlling the authentication process and querying the user's assigned privileges. In terms of authentication, the Identity
bean provides the following methods:
AuthenticationResult login(); void logout(); boolean isLoggedIn(); Account getAccount();
The
login()
method is the primary point of entry for the authentication process. Invoking this method will cause PicketLink to attempt to authenticate the user based on the credentials that they have provided. The AuthenticationResult
type returned by the login()
method is a simple enum that defines the following two values:
public enum AuthenticationResult { SUCCESS, FAILED }
If the authentication process is successful, the
login()
method returns a result of SUCCESS
, otherwise it returns a result of FAILED
. The default implementation of the Identity
bean is a @SessionScoped
CDI bean, which means that once a user is authenticated they will stay authenticated for the duration of the session.
Note
One significant point to note is the presence of the
@Named
annotation on the Identity
bean, which means that its methods may be invoked directly from the view layer (if the view layer, such as JSF, supports it) via an EL expression.
One possible way to control the authentication process is by using an action bean, for example the following code might be used in a JSF application:
public @RequestScoped @Named class LoginAction { @Inject Identity identity; public void login() { AuthenticationResult result = identity.login(); if (AuthenticationResult.FAILED.equals(result)) { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage( "Authentication was unsuccessful. Please check your username and password " + "before trying again.")); } } }
In the above code, the
Identity
bean is injected into the action bean via the CDI @Inject
annotation. The login()
method is essentially a wrapper method that delegates to Identity.login()
and stores the authentication result in a variable. If authentication was unsuccessful, a FacesMessage
is created to let the user know that their login failed. Also, since the bean is @Named
it can be invoked directly from a JSF control like so:
<h:commandButton value="LOGIN" action="#{loginAction.login}"/>
The
Identity.isLoggedIn()
method may be used to determine whether there is a user logged in for the current session. It is typically used as an authorization check to control either an aspect of the user interface (for example, not displaying a menu item if the user isn't logged in), or to restrict certain business logic. While logged in, the getAccount()
method can be used to retrieve the currently authenticated account (i.e. the user). If the current session is not authenticated, then getAccount()
will return null
. The following example shows both the isLoggedIn()
and getAccount()
methods being used inside a JSF page:
<ui:fragment rendered="#{identity.loggedIn}">Welcome, #{identity.account.loginName}
Note
If you're wondering what an
Account
is, it is simply a representation of the external entity that is interacting and authenticating with your application. The Account
interface is actually the superclass of the User
and Agent
- see Chapter 5, Identity Management - Basic Identity Model for more details.
The
logout()
method allows the user to log out, thereby clearing the authentication state for their session. Also, if the user's session expires (for example due to inactivity) their authentication state will also be lost requiring the user to authenticate again.
The following JSF code example demonstrates how to render a log out button when the current user is logged in:
<ui:fragment rendered="#{identity.loggedIn}"> <h:form> <h:commandButton value="Log out" action="#{identity.logout}"/> </h:form> </ui:fragment>
While it is the
Identity
bean that controls the overall authentication process, the actual authentication "business logic" is defined by the Authenticator
interface:
public interface Authenticator { public enum AuthenticationStatus { SUCCESS, FAILURE, DEFERRED } void authenticate(); void postAuthenticate(); AuthenticationStatus getStatus(); Account getAccount(); }
During the authentication process, the
Identity
bean will invoke the methods of the active Authenticator
(more on this in a moment) to perform user authentication. The authenticate()
method is the most important of these, as it defines the actual authentication logic. After authenticate()
has been invoked by the Identity
bean, the getStatus()
method will reflect the authentication status (either SUCCESS
, FAILURE
or DEFERRED
). If the authentication process was a success, the getAccount()
method will return the authenticated Account
object and the postAuthenticate()
method will be invoked also. If the authentication was not a success, getAccount()
will return null
.
Note
By default, the
Identity
bean uses a Authenticator
fully integrated with the Identity Management API. You don't need to provide your own authenticator to start using PicketLink and authenticate your users! Check Section 3.1, “Introduction” for more details about how to manage users and credentials.
2.2.1. Stateful or Stateless Authentication
The
Identity
bean is stateful by default, using the session scope to share user's authentication state between different requests and interactions. Once the user is authenticated, the Identity
bean will hold user's data until the session is invalidated.
When you inject the
Identity
bean as follows:
@Inject private Identity identity;
You're using the stateful version of the
Identity
bean.
While this is the desired behavior for most applications, this may not be the case if you're exposing the
Identity
bean as a service, with a high load of authentication requests. A good example is a RESTful endpoint that issues a token to represent user's information after a successful authentication, using that token in subsequent invocations to other services to check if the user was previously authenticated, check the token validity or even provide some authorization. Pretty common scenario for mobile and HTML5 applications.
In those cases, you're not interested in wasting server resources to manage users sessions. You want a stateless behavior, where once the authentication finishes all data produced during the process is lost after the request processing is done.
To configure the
Identity
bean as stateless you need to provide the following configuration:
public class SecurityConfiguration { public void init(@Observes SecurityConfigurationEvent event) { SecurityConfigurationBuilder securityConfigurationBuilder = event.getBuilder(); securityConfigurationBuilder .identity() .stateless(); // enable stateless authentication } }
The
org.picketlink.event.SecurityConfigurationEvent
is an event that lets you configure PicketLink. It provides access to a org.picketlink.config.SecurityConfigurationBuilder
instance from where you can provide all configuration for PicketLink.