Friday, January 28, 2011

Expired Password??? No problem with Spring Security!


I've got a user story which requires a feature that lets a user change their expired password. We've already got the views defined/written, and they'll work pretty much right away, so I'd like to leverage Spring Security's authentication framework to detect when a user's password has expired, and redirect them to the view that will allow them to change their password.

Spending some time on the forum, didn't yield a whole lot of answers that were directly relevant to 3.0.x, but after digging through the API's I found that I could swap the <form-login >'s authentication-failure-handler with Spring Security's own org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler, which will let me provide separate views for each type of exception that is thrown during authentication. In my particular case, I'm concerned with org.springframework.security.authentication.AccountExpiredException.

So, I need to change the <form-login > namespace a bit:
   

Next, I configure the authenticationFailureHandler bean above, and provide it with the appropriate mappings:


  
  
   
    /login.jsp?login_error=1
    
    /expiredPassword.htm
    
    /expiredPassword.htm
    
   
  
 

Before I can load the view, I need to populate the backing bean (or form) for the view, which requires that I populate it with a valid Users' object...I can find a user based on their username, and luckily, Spring puts the username into the requests' session scope, so I can handle the request like so
 @RequestMapping(value="/expiredPassword.htm", method=RequestMethod.GET)
 public ModelAndView goToChangePassword(HttpServletRequest request,
   HttpServletResponse response) throws Exception {
     String username = (String) request.getSession().getAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY);
     
     
     Users user = userService.getUserByUsername(username);
     if (user == null){
      return new ModelAndView( new RedirectView("/home.htm"));
     }
     
     PasswordForm form = new PasswordForm(user);
  ModelAndView mav = new ModelAndView(CHANGE_PASSWORD);
  mav.addObject(form);
  return mav;
 }

I can do whatever I want in the case I can't load the username, but for now, I'll just redirect the user to the login page (ambiguously through the home.htm mapping).

Everything else behaves the way it did before; other exceptions get mapped to the default view (login.jsp?login_error=1); I can change this in the future, if I need to handle any other special cases. Thank you Spring Security team for a really easy implementation...

2 comments:

  1. I am not getting any username from session
    String username = (String) request.getSession().getAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY);

    i am using spring security 3.1, so i changed key,

    String username = (String) request.getSession().getAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY);

    ReplyDelete
  2. I am getting null value while trying to do in either way suggested by Pradeep.

    How can i retrieve username from session for CredentialsExpiredException...

    Please guys help...

    ReplyDelete