Product SiteDocumentation Site

4.3. Credential Handlers

For IdentityStore implementations that support multiple credential types, PicketLink provides an optional SPI to allow the default credential handling logic to be easily customized and extended. To get a better picture of the overall workings of the Credential Handler SPI, let's take a look at the sequence of events during the credential validation process when validating a username and password against JPAIdentityStore:
  • 1 - The user (or some other code) first invokes the validateCredentials() method on IdentityManager, passing in the Credentials instance to validate.
  • 1.1 - After looking up the correct IdentityStore (i.e. the one that has been configured to validate credentials) the IdentityManager invokes the store's validateCredentials() method, passing in the IdentityContext and the credentials to validate.
  • 1.1.1 - In JPAIdentityStore's implementation of the validateCredentials() method, the IdentityContext is used to look up the CredentialHandler implementation that has been configured to process validation requests for usernames and passwords, which is then stored in a local variable called handler.
  • 1.1.2 - The validate() method is invoked on the CredentialHandler, passing in the security context, the credentials value and a reference back to the identity store. The reference to the identity store is important as the credential handler may require it to invoke certain methods upon the store to validate the credentials.
The CredentialHandler interface declares three methods, as follows:
public interface CredentialHandler {
    void setup(IdentityStore<?> identityStore);

    void validate(IdentityContext context, Credentials credentials,
                  IdentityStore<?> identityStore);

    void update(IdentityContext context, Account account, Object credential,
                IdentityStore<?> identityStore, Date effectiveDate, Date expiryDate);

}
The setup() method is called once, when the CredentialHandler instance is first created. Credential handler instantiation is controlled by the CredentialHandlerFactory, which creates a single instance of each CredentialHandler implementation to service all credential requests for that handler. Each CredentialHandler implementation must declare the types of credentials that it is capable of supporting, which is done by annotating the implementation class with the @SupportsCredentials annotation like so:
@SupportsCredentials(
  credentialClass = { UsernamePasswordCredentials.class, Password.class },
  credentialStorage = EncodedPasswordStorage.class
)
public class PasswordCredentialHandler implements CredentialHandler {
Since the validate() and update() methods receive different parameter types (validate() takes a Credentials parameter value while update() takes an Object that represents a single credential value), the @SupportsCredentials annotation must contain a complete list of all types supported by that handler.
Similarly, if the IdentityStore implementation makes use of the credential handler SPI then it also must declare which credential handlers support that identity store. This is done using the @CredentialHandlers annotation; for example, the following code shows how JPAIdentityStore is configured to be capable of handling credential requests for usernames and passwords, X509 certificates and digest-based authentication:
@CredentialHandlers({ PasswordCredentialHandler.class,
          X509CertificateCredentialHandler.class, DigestCredentialHandler.class })
public class JPAIdentityStore implements IdentityStore<JPAIdentityStoreConfiguration>, 
                                         CredentialStore {

4.3.1. The CredentialStore interface

For IdentityStore implementations that support multiple credential types (such as JPAIdentityStore and FileBasedIdentityStore), the implementation may choose to also implement the CredentialStore interface to simplify the interaction between the CredentialHandler and the IdentityStore. The CredentialStore interface declares methods for storing and retrieving credential values within an identity store, as follows:
public interface CredentialStore {
   /**
     * Stores the specified credential state.
     *
     * @param context The contextual invocation context.
     * @param account The account which credentials should be removed.
     * @param storage The credential storage instance to be stored.
     */
    void storeCredential(IdentityContext context, Account account, CredentialStorage storage);

    /**
     * Returns the currently active credential state of the specified {@link T}, for the specified {@link org.picketlink.idm.model.Account}.
     *
     * @param context The contextual invocation context.
     * @param account The account which credentials should be removed.
     * @param storageClass The credential storage type specifying which credential types should be removed.
     *
     * @return
     */
    <T extends CredentialStorage> T retrieveCurrentCredential(IdentityContext context, Account account, Class<T> storageClass);

    /**
     * Returns a list of all credential state of the specified {@link T}, for the specified {@link org.picketlink.idm.model.Account}.
     *
     * @param context The contextual invocation context.
     * @param account The account which credentials should be removed.
     * @param storageClass The credential storage type specifying which credential types should be removed.
     *
     * @return
     */
    <T extends CredentialStorage> List<T> retrieveCredentials(IdentityContext context, Account account, Class<T> storageClass);

    /**
     * <p>Removes all credentials stored by a certain {@link org.picketlink.idm.credential.storage.CredentialStorage} associated
     * with the given {@link org.picketlink.idm.model.Account}.</p>
     *
     * @param context The contextual invocation context.
     * @param account The account which credentials should be removed.
     * @param storageClass The credential storage type specifying which credential types should be removed.
     */
    void removeCredential(IdentityContext context, Account account, Class<? extends CredentialStorage> storageClass);
}