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:
PasswordCredential
implementationCredentialPasswordEncoder
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
.
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.
InternalCredential
lifecycle eventsDefaultCredentialHandler
is provided with an
InternalPasswordCredentialInterceptor
, it will invoke this interceptor (or an arbirary
set if
InternalPasswordCredentialInterceptorsProxy
is used) on:
ValidatePasswordOnLoadInterceptor
CredentialPasswordValidator
of the PasswordCredentialProvider
, the same as used when a password is changed.
EncodePasswordOnFirstLoadInterceptor
CredentialPasswordEncoder
from the PasswordCredentialProvider
PasswordExpirationInterceptor
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.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
DefaultCredentialHandler
.
PasswordHistoryInterceptor
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.
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.
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.
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):
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>
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>
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.
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:
Action | Expires |
---|---|
Expired | today |
Extend | today + maxLifeSpanInDays as configured for the PasswordExpirationInterceptor |
Extend Unlimited | January 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!
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.