Wow! Please! Do it again!: Web Dev: Spring Security - Create custom implementation of RedirectStrategy

Wednesday, August 15, 2012

Web Dev: Spring Security - Create custom implementation of RedirectStrategy

Spring Security has the interface RedirectStrategy for one reason that is pretty obvious, to perform server-side redirects. However, it only comes with one implementation, DefaultRedirectStrategy.

Spring Security may perform server-side redirects for:
  • Session timeout/invalid.
  • Concurrent number of sessions per user exceeded.
  • Authentication success.
  • Authentication failure.
  • Access denied to certain resources.

I have had 2 real life requirements (so far) to create custom implementations for RedirectStrategy:

Case 1:
1. The system I was building had 2 different set of pages (simply put, 2 different sites).
2. One site was for customers and the other for administrators.
3. Each set of pages are protected by their own login page.
4. A different path was used to differentiate which site to display to the user:

  • /contextPath/cust/login.htm
  • /contextPath/admin/login.htm
5. Any redirect from Spring Security should be able to handle both sites (/cust and /admin) gracefully.
6. Session timeout URL is configured to "/login.htm?timeout=1". If configured to "/cust/login.htm?timeout=1" then it won't be able to handle session timeout in the /admin site.
7. Therefore, a custom RedirectStrategy (ServletPathRedirectStrategy) was the ideal place to:
  • From the request URL, detect which site it is coming from. For example, if the original request was "/contextPath/cust/accounts.htm", the site is cust.
  • The ServletPathRedirectStrategy would construct the target URL to be "/contextPath/cust/login.htm?timeout=1".
Case 2:
1. Using Spring Web Flow, JSF 2.1 and PrimeFaces to build a site.
2. More information on JsfRedirectStrategy here.

Steps:
1. Create subclass of DefaultRedirectStrategy, let's say CustomRedirectStrategy.
2. Copy the implementation from DefaultRedirectStrategy.calculateRedirectUrl to CustomRedirectStrategy. Why? Because calculateRedirectUrl was declared as private!
3. Override the sendRedirect method to fulfill your redirect requirements. Be sure to use calculateRedirectUrl as how it's used in DefaultRedirectStrategy for consistency.
4. Declare your CustomRedirectStrategy (bean name "redirectStrategy") in Spring config (XML or Annotations, I won't go there).
5. Inject "redirectStrategy" into the following beans:

  • concurrentSessionFilter - Existing class org.springframework.security.web.session.ConcurrentSessionFilter has setter for redirectStrategy.
  • invalidSessionStrategy - Unable to inject to SimpleRedirectInvalidSessionStrategy because no setter available (setRedirectStrategy). Just clone the entire SimpleRedirectInvalidSessionStrategy and add the setter.
  • authenticationEntryPoint - Existing implementation org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint declares redirectStrategy as a final attribute. Same drill, copy clone entire class and add the setter.
  • authenticationSuccessHandler - Existing implementations SavedRequestAwareAuthenticationSuccessHandler and SimpleUrlAuthenticationSuccessHandler both have the setter.
  • authenticationFailureHandler - Existing implementations ExceptionMappingAuthenticationFailureHandler and SimpleUrlAuthenticationFailureHandler both have the setter.
  • logoutSuccessHandler - Existing implementation SimpleUrlLogoutSuccessHandler has the setter.
  • Any custom bean that does server-side redirections - For example, hdivFilter?

Versions:
1. Spring Security 3.1.2
2. Spring Framework 3.1.2
3. JSF Mojarra 2.1.11
4. PrimeFaces 3.4 RC1
5. Spring Web Flow 2.3.1