Credentials Management Overview

DefaultCredentialHandler Features

With the Jetspeed DefaultCredentialHandler special management of password credentials can easily be configured. Through the provided PasswordCredentialProvider and InternalPasswordCredentialInterceptor components custom logic can be plugged in for:

  • providing a custom PasswordCredential implementation
  • password encoding

    If an CredentialPasswordEncoder is available from the PasswordCredentialProvider passwords will be encoded with it before they are persisted. The provided MessageDigestCredentialPasswordEncoder uses MessageDigest hash algorithms for the password encryption, and can for example be configured to use SHA-1 and Base64.
  • enforcing password value rules

    If an CredentialPasswordValidator is available from the PasswordCredentialProvider, passwords will be validated with it before they are persisted. The DefaultCredentialPasswordValidator for example enforces non-emtpy password. And with the SimpleCredentialPasswordValidator a minimum length and a minum number of numeric characters can be enforced.
  • intercepting InternalCredential lifecycle events

    If the DefaultCredentialHandler is provided with an InternalPasswordCredentialInterceptor, it will invoke this interceptor (or an arbirary set if InternalPasswordCredentialInterceptorsProxy is used) on:
    • after loading a credential from the persistent store
    • after authenticating a user
    • before a new credential is saved to the persistent store
    • before a new password is save for the credential
    Jetspeed already provides a basic set of interceptors, ready to be used:
    • ValidatePasswordOnLoadInterceptor

      This interceptor can be used to validate (pre)set passwords in the persistent store and force a required change by the user if invalid. It uses the configured CredentialPasswordValidator of the PasswordCredentialProvider, the same as used when a password is changed.
    • EncodePasswordOnFirstLoadInterceptor

      This interceptor can be used if passwords needs to be preset in the persistent store or migrated unencoded from a different store. With this interceptor, these cleartext password will automatically be encoded the first time they are loaded from the database, using the CredentialPasswordEncoder from the PasswordCredentialProvider
    • PasswordExpirationInterceptor

      This interceptor can be used to enforce a maximum lifespan for passwords. It manages the expiration_date and is_expired members of the InternalCredential and sets the expired flag when on authentication of a user its (valid) password is expired. The authentication will then fail.

      Note: A Jetspeed pipeline Valve, the PasswordCredentialValveImpl can be used to request or even enforce users to change their password in time to prevent a password expiration (described further below).
    • MaxPasswordAuthenticationFailuresInterceptor

      This interceptor can be used to prevent password hacking by enforcing a maximum number of invalid password attempts in a row. Once this number of authentication failures is reached, the credential will be disabled. On a successful authentication though, this count will automatically be reset to zero again by the DefaultCredentialHandler.
    • PasswordHistoryInterceptor

      This interceptor can be used to enforce usage of unique new passwords in respect to a certain number of previous used passwords. When a new password is set, the current password is saved in a FIFO stack of used passwords. When a user itself changes its password, it must be different from all the onces thus saved, otherwise a PasswordAlreadyUsedException will be thrown. But setting a new password through the administrative interface still allows any password (when otherwise valid) to be set.

    The DefaultCredentialHandler only supports one interceptor to be configured. But, with the InternalPasswordCredentialInterceptorsProxy, a list of interceptors can be configured which then will be invoked sequentially.

    Jetspeed comes out of the box with several of these interceptors configured, and its very easy to change and extend.See the security-spi-atn.xml section in the Security Services Configuration document for a description of the default configuration. Also provided there is an example how to setup the interceptors to restore the "old" (and much more restrict) configuration provided with the 2.0-M3 release and earlier.

Credentials Management Implementation

The class diagram below describes the components used for the DefaultCredentialHandler implementation.

The OJB mappings for the default credentials implementation are described in security_repository.xml:

  • InternalCredential: Maps to the SECURITY_CREDENTIAL table.
The following database schema is used to stored credentials and their associations to principals.

User interaction

Although the DefaultCredentialHandler provides fine-grained management of credentials, it cannot provide direct feedback to the user like presenting a warning that the current password is soon to be expired. But, special request processing pipeline valves provided with jetspeed allow to do just that.

The configuration for these valves can be found and set in the pipelines.xml spring configuration file.

LoginValidationValveImpl

The LoginValidationValveImpl provides feedback to the user about the cause of an failed login attempt.

It retrieves the UserPrincipal and its current PasswordCredential for the specified user name, and (if found) determines an specific error code based on its state. This error code is communicated back to through the session so an appropriate error message can be presented to the user.

The following possible error codes can be returned (all defined in the LoginConstants interface):

  1. ERROR_UNKNOWN_USER
  2. ERROR_INVALID_PASSWORD
  3. ERROR_USER_DISABLED
  4. ERROR_FINAL_LOGIN_ATTEMPT
  5. ERROR_CREDENTIAL_DISABLED
  6. ERROR_CREDENTIAL_EXPIRED

Of the above error codes, the ERROR_FINAL_LOGIN_ATTEMPT will only be reported if the valve is configured with the same maxNumberOfAuthenticationFailures value as used for the related MaxPasswordAuthenticationFailuresInterceptor described above:

  <bean id="loginValidationValve"
        class="org.apache.jetspeed.security.impl.LoginValidationValveImpl"
        init-method="initialize">
    <!-- maxNumberOfAuthenticationFailures
         This value should be in sync with the value for
         org.apache.jetspeed.security.spi.impl.MaxPasswordAuthenticationFailuresInterceptor
         (if used) to make sense.
         Any value < 2 will suppress the LoginConststants.ERROR_FINAL_LOGIN_ATTEMPT
         error code when only one last attempt is possible before the credential
         will be disabled after the next authentication failure.
    -->
    <constructor-arg index="0"><value>3</value></constructor-arg>  
</bean>
                

PasswordCredentialValveImpl

The PasswordCredentialValveImpl is meant to be used together with a special Portlet on a special Portal Page (PSML) to automatically request or even require a user to change its password.

This valve evaluates PasswordCredential.isUpdateRequired() and optionally the expirationDate, lastAuthenticationDate and previousAuthenticationDate fields to determine if a user is required or just be asked to change its password.

This valve can optionally be configured with a list of expirationWarningDays numbers in its constructor:

<bean id="passwordCredentialValve"
      class="org.apache.jetspeed.security.impl.PasswordCredentialValveImpl"
      init-method="initialize">
 <constructor-arg>
   <!-- expirationWarningDays -->
   <list>
     <value>2</value>
     <value>3</value>
     <value>7</value>
   </list>
 </constructor-arg>
</bean>
                
These numbers each represent a day before the current expirationDate of the password credential when a user should be warned its password is soon to expire and be asked to change it. The lastAuthenticationDate and the previousAuthenticationDate are used to determine when this should happen. It will be done only once for each configured expirationWarningDay. If a user logs on for the first time (after several days) with the above example configuration, 6 days before the password expires, he or she will be warned about it. And again when 3 or 2 days are left.

When a user logs on the last day before the password expires or when updateRequired is true, the user will be required to change the password, regardless if expirationWarningDays are configured or not.

To be able to automatically provide the user with this information and allow or require the password to be changed directly after login, a special ProfileLocator SECURITY_LOCATOR is used. The PageProfilerValve (which should be configed after this valve in the pipeline) will then use this enforced locator to be used to find the related portal page to present to the user.

For this to work, a "security" Profiler rule must have been setup like the default one provided by Jetspeed:

As can seen from the above image, the default page which will be presented to the user is the /my-account.psml located in the root.

This default page contains only one portlet, the ChangePasswordPortlet from the security Portlet Application.

The ChangePasswordPortlet works together with the PasswordCredentialValveImpl as it checks for the PASSWORD_CREDENTIAL_DAYS_VALID_REQUEST_ATTR_KEY request parameter which will be set by this valve with the number of days the password is still valid. For a required password change this will be set to Integer(0).

The default my-account.psml page contains only the ChangePasswordPortlet to make sure a user which is required to change the password cannot interact with the portal any other way then after the password is changed.

Although the user might be attempted to select a link to a different page (from a portal menu for exampl), this valve will make sure only the configured "security" locator page is returned if it is required. But, once the password is changed the then targeted page in the url will be navigated to automatically.

Managing Password Expiration

If the PasswordExpirationInterceptor is used, password expiration for a certain user can be directly managed through the UserDetailPortlet provided with the security portlet application.

If enabled, this portlet can display the current expiration date of a password and also allows to change its value:

As you can see, through the radio group, the password expiration date can be changed to:

ActionExpires
Expiredtoday
Extendtoday + maxLifeSpanInDays as configured for the PasswordExpirationInterceptor
Extend UnlimitedJanuary 1, 8099 (the maximum value allowed for java.sql.Date)

This feature can be enabled through the edit/preferences page of the UserDetailsPortlet:

Note: when a new password value is specified selected password expiration action Expired will be ignored!

Setting default 'Change Password required on First Login'

Through the same UserDetailsPortlet preferences as show above, the default updateRequired property of a password credential for a new user can be configured too.

And, if you always need the same setting for all users, you can even suppress the selection box normally displayed on the Add User dialog.

With the preferences set as in the example shown above, the Add User dialog will look like this:

A user added with the example preferences set, will have the updateRequired property set to true, the User role assigned and use the role-fallback profiling rule.