Tuesday, February 1, 2011

@Value!; How do I inject you, you little $#%@!!



Spring 3 introduces a new annotation, @Value, for injecting values into properties. This is especially useful if you're using the <component-scan/> of spring's context namespace.

I recently need to access tomcat's "webapp.root" variable in a @Controller stereotype class, which was conveniently managed via Spring.

Our webapp's log files are stored in the root directory, and I needed to access this property in order to read the data in the file. The simplest way to get that value injected into the controller's property would be to inject it using this new value.

After some digging, bashing, and cursing, I finally got it to work...(drumroll)...

@Value("#{systemProperties['webapp.root']}/bookin-synchronizer.log}")

I certainly wish that this was more properly documented in Spring's documentation, as it would have saved me some time...oh well, can't have everything.

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...