Showing posts with label filters. Show all posts
Showing posts with label filters. Show all posts

Wednesday, February 17, 2010

Extending UsernamePasswordAuthenticationFilter in Spring Security

So, you are using Spring security, and you want to process some information after a user has logged in (say, load something in session) or after failed login attempts (such as lock an account after a set number of failed logins.. ), here's how it can be done.. Hope this helps.

Before I go on to describe what goes into it, thanks to the following. These links are a bit dated, but they did help me along.

Custom AuthenticationProcessingFilter for spring security to perform actions on login
An example of the security config for a custom auth filter (see last post)
Spring's documentation on adding own filters

Now, here we go. What is described below works for Spring Security 3.0.0.RELEASE.

1. We need to extend UsernamePasswordAuthenticationFilter

It used to be AuthenticationProcessingFilter, which is depricated.

In this example, we just write to the console. You would do something more important.

public class CustomUsernamePasswordAuthenticationFilter extends
UsernamePasswordAuthenticationFilter {

@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, Authentication authResult)
throws IOException, ServletException {
super.successfulAuthentication(request, response, authResult);

System.out.println("==successful login==");
}

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
super.unsuccessfulAuthentication(request, response, failed);

System.out.println("==failed login==");
}

}

2. In spring security context, we will be overriding the form login filter FORM_LOGIN_FILTER.

This used to be AUTHENTICATION_PROCESSING_FILTER, which is not used now.

<http ...
<custom-filter position="FORM_LOGIN_FILTER" ref="customUsernamePasswordAuthenticationFilter">

Note: Since we are replacing the default FORM_LOGIN_FILTER, we should not use <form-login login-page... , as that will try to create the default filter and you would get an exception (that there are two filters defined at the same position).

3. Since we are using the custom FORM_LOGIN_FILTER, we need to set the following property on <http ..

<http auto-config="false"

4. Another thing to set at <http is entry-point-ref

Again, since we are altering the default behavior, we need to tell what is the entry point for the form login.

<http entry-point-ref="loginUrlAuthenticationEntryPoint"

And, correspondingly, define the loginUrlAuthenticationEntryPoint bean. Note that LoginUrlAuthenticationEntryPoint used to be AuthenticationProcessingFilterEntry which is depricated.

<beans:bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/login.html">
</beans:bean>

5. Remember the filter 'customUsernamePasswordAuthenticationFilter ' we used in in step 2 and extended in step 1, we have to define it.
<beans:bean id="customUsernamePasswordAuthenticationFilter"
class="com.yourapp.web.security.CustomUsernamePasswordAuthenticationFilter" >
<beans:property name="authenticationManager" ref="authenticationManager">
<beans:property name="authenticationFailureHandler" ref="failureHandler">
<beans:property name="authenticationSuccessHandler" ref="successHandler">
</beans:bean>

<beans:bean id="successHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/login.html">
</beans:bean>
<beans:bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login.html?login_error=true">
</beans:bean>

6. In the definition of 'customUsernamePasswordAuthenticationFilter' we are identifying the 'authenticationManager', so when you define your authentication manager provide an 'alias' for it:

<authentication-manager alias="authenticationManager">
...
</authentication-manager>

There you have it. Share and enjoy.