Expired Password Integration

A password usually expires in a set period of time. For this example lets say my password will expire on April 1st 2007.

When I login using CAS during the last week of March, I would like to see a warning page informing me that my password will expire in the next seven days. If I choose I can click on a link that will bring me into my Account Management System ( AMS ). Here I can change my password. Or I can just go to the service I requested.

If I login on April 1st 2007, I am forced to change my password in the AMS. I will not be granted any access to any system until I do so.

It is possible that an account gets locked for some reason, abuse of service or violation of Terms of Use. When a user account is locked, I would like to provide a page informing them to contact the Administrator and receive their punishment.

---------------------------------------------------- 

Use case for attached classes (by Velpi):

There 5 distinct states for an account and one error status that may occur while processing (defined by the Spring action that is configured in the webflow). 

  • activate: every account is in the activate status at first. This means the user still needs to activate its account at the AMS. At this point the user cannot log in yet. Since the user is unable to authenticate itself using a password at this point, this status may be obsolete to the login system. However x509 logins may be allowed (company policy). Activation is usually done using a special one-time activation code that the user physically receives at the administration of the organisation. (this procedure can be done again at any time, which is useful when the user loses its password). An activation code should be seen as a random initial password that can only be used to activate the account. The main reason for this state is so the user can create its own password without anyone else ever having to know its (temporary or initial) password.
  • active: normal account state. User can just pass the login system without any further interaction.
  • changepwd: user is near to account expiry. He should be bothered with a warning screen (preferably once, at initial login) that contains a link to the AMS-changepwd. The user can choose to follow the link or ignore the message for now and continue.
  • locked: the user account's password has expired since he did not change its password on time. In order to use the system the password needs to be changed immediately (or re-activate the account; depending on company policy). So there should be a warning screen that cannot be bypassed. The screen will inform the user what to do next (probably contains some links).
  • blocked: the user has been detected with illegal/unwanted behaviour. All further access is blocked immediately. He/she can only re-activate its account after visiting the administration office which will ask the user for an explanation of its conduct.
  • error: an error occurred while looking up the account status. Access should probably be blocked, depending on company policy.

If this check is implemented as a Spring action, then the login-webflow can easily be configured so redirecting/blocking behaves according to company policy.

The status information of the account may be one of the following (implementation of an AccountStatusGetter):

  • direct attribute from a data-store (eg: SimpleLDAPAccountStatusGetter: information is pushed from external source)
  • calculation based on a (combination of) attributes from data-store, eg: AD accountExpiry (and...)
  • a (combination of) locally calculated/retrieved attributes, eg: client IP, time-of-day, ...

    

-------------------------

Questions asked by Chris Roffler 

  • Q:It is not clear to me if you are going to provide the screens to change the password ?
    (Velpi) Forms to actually change the password should be a separate project, most campuses have such a page at the moment so it is less urgent.
  • Q: If I understand this right, you will base the error conditions on an attribute in LDAP ?
    (Velpi) Using error conditions may be a good, standard implementation strategy. However it prevents authenticating the user before fetching THIS user's attributes and using them for the correct response.
  • Q: Are you going to let me set the LdapAccountStatusGetter like you do with the authenticationHandler and how do you guys plan to use this StatusGetter class within CAS ?
    For example, I am using Sun One Directory Server, I can set all those parameters ( Password expiration, length, reuse etc )system wide and when I try to authenticate on the connection I get an error. from there I could map the error to the cas pre defined errors.
    (Velpi) The interpreter needs to be configurable. But I'm not sure it is wise to connect it to the authenticationHandler. This would also limit its use only at authentication time and to the same backend.

-------------------------

Questions and remarks added by marc-antoine garrigue

We had (nearly) the same requirements :

  • We needed to deal with and distinguishes account and password status
    • Account locked, disabled
    • Password expired, must change.
  • We needed to handle and distinguishes both Active Directory and SUNOne LDAP as authentication source
  • We do not need to provide 'near expiration date' status
  • We need to redirect to a request password webflow when password expiration status arrise from the LDAP source (but not from AD)

But our implementation strategy was very different :

  • We customize our ldap authentication handler in order to get the backend exception during the bind or search.
  • We develop custom exception handlers for AD and SUNOne
  • We customize the login web flow in oder to deal with our ExpiredPasswordException extending AuthenticationException

Questions :

  • How do the AccountStatusGetter integrate in the login flow : before or after the authentication?
    (Velpi) The AccountStatusAction is a standard Spring action that can be configured anywhere in the login flow. It seems reasonable to put it right AFTER authentication but before setting the TGT cookie. Else you could start "mining" account statusses. Optionally you may want to configure this action to be triggered also when a user passes by while having a TGT.
    Please also consider multiple authentication sources, eg: LDAP and x509 at the same time. Both sources need to result in the account being checked for validity (though x509 does not require a password  expiry check, it may need the blocked check). Spring webflow makes this all possible.
  • Wouldn't it be groovy to add the AccountStatusGetter as a service available in the AuthenticationHandler?
    (Velpi) It may limit its flexibility. The PrincipalResolver is also separate from the AuthenticationHandler, and it works great.

 My2c

  • Adding an AccountStatusGetter to the AuthenticationHandler may provide the benefit of re-using connections. However

-------------------------

Summary so far (please edit this!):

Common:

  • account statusses: active, locked, must change
  • configurable backend, preferrably depending on the authN (all LDAP clones up to now, SQL may be interesting to)
  • optional, forced redirection to a password change form OR showing page that has a link to such a page [can both be implemented as a view]
    Mentioned specific functionality:
  • statusses: activation, near to expiration date, blocked
    Implementation strategies:
  • direct access to a predefined status identifier as attribute
  • interpreting exceptions returned when authenticating to AD or SUNOne LDAP as the user (=connecting it to the authenticationHandler)
  • calculated from a list of attributes

-------------------------------------------------------------------------------

24-03-2009

By Bart Ophelders & Johan Peeters

We worked out the password expiration problem, starting from the code Jan van der Velpen wrote a few years back.

There are 5 different states, calculated from a pwLastChanged value (yyyy-MM-dd) fetched out of LDAP:

  • activate --> set pwLastChanged to 1900-01-01
  • active
  • changepwd --> warning page displayed a configurable amount of time before the password expiration date
  • locked --> expiration date has passed
  • blocked --> set pwLastChanged to a date before 1950

The activate and blocked states are defined in this way for convenience, but you can easily adapt the code to check i.e. for another value in LDAP.

The expiration check happens after the creation of the TGT but before the setting of the TGT cookie. (Thus after the action-state submit and before the action-state sendTicketGrantingTicket)

To use the code, add the following beans to deployerConfigContext.xml: 

deployerConfigContext.xml
<bean
                id="accountStatusAction"
                class="org.jasig.cas.web.flow.AccountStatusAction"
                p:accountStatusGetter-ref="accountStatusGetter"
        />
       
  <bean
                id="accountStatusGetter"
                class="org.jasig.cas.web.support.ExtendedLdapAccountStatusGetter"
                p:filter="cn=%u"
                p:statusAttributeName="description"
                p:searchBase="ou=People,dc=example,dc=be"
                p:contextSource-ref="contextSource"
                p:daysTillLocked="365"
                p:warningDays="30"
        />
                
<bean
                id="contextSource"
                class="org.jasig.cas.adaptors.ldap.util.AuthenticatedLdapContextSource"
                p:url="ldap://test.example.be:389"
                p:userDn="cn=IDP,dc=example,dc=be"
                p:password="secret">
                <property name="baseEnvironmentProperties">
                        <map>
                                <entry>
                                        <key>
                                                <value>java.naming.security.authentication</value>
                                        </key>
                                        <value>simple</value>
                                </entry>
                        </map>
                </property>
        </bean>
        <bean
                id="chooseChangepwdViaFormAction"
                class="org.jasig.cas.web.flow.ChooseChangepwdViaFormAction"
                />
</beans>


The code and login-webflow is added as an attachement.