Spring 3 and Spring Security: Setting your Own Custom /j_spring_security_check Filter Processes URL

| No TrackBacks
While working on a new personal project, I decided to pick up and dig into Spring 3 MVC and Spring Security.  I've touched both of these technologies here and there in a number of other projects, but this new opportunity has really opened the door for a deep dive into Spring.  I know the Ruby fanatics out there would say I'm crazy, but once I got all of the awful XML configuration mess out of the way, I'm really enjoying Spring's stability and reliability.  I know Ruby and Rails is hip and what not, but Spring 3 has really made an impression on me.  It's hard to beat such a mature enterprise framework.

I setup a few Spring 3 controllers, and integrated Spring Security into my web-app.  All went great and so I added a simple form-based login to my Spring Security XML configuration.


Problem: Overriding UsernamePasswordAuthenticationFilter

When setting up a form-based login via a default Spring Security <http:security> configuration, Spring auto generates and configures a UsernamePasswordAuthenticationFilter bean.  This filter, by default, responds to the URL /j_spring_security_check when processing a login POST from your web-form.  First, I want to override Spring Security's default login process URL to /login instead of /j_spring_security_check.  Second, I've configured a Spring 3 controller to display my login web-form when a user visits /login.

That said, here's the underlying problem with Spring Security's default UsernamePasswordAuthenticationFilter: I want it to accept and process POST's to /login, but a GET or any HTTP method to /login should be forwarded to the next filter in the chain.  Not surprisingly, you cannot do this with Spring Security's default UsernamePasswordAuthenticationFilter because it does not @Override the doFilter() method of AbstractAuthenticationProcessingFilter.  In short, there's no way to get and check the incoming HTTP request method and re-route it using the default UsernamePasswordAuthenticationFilter.


Solution: Write your own Spring Security Authentication Filter

If you want a Spring controller to process GET requests to /login, but Spring Security to intercept and process a POST to /login, then you'll need to write your own Spring Security authentication filter.  Here's the idea:

public class MyFilter extends AbstractAuthenticationProcessingFilter {

private static final String DEFAULT_FILTER_PROCESSES_URL = "/login";
private static final String POST = "POST";

public MyFilter () {
super(DEFAULT_FILTER_PROCESSES_URL);
}

@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException,
IOException, ServletException {
// You'll need to fill in the gaps here. See the source of
// UsernamePasswordAuthenticationFilter for a working implementation
// you can leverage.
}

@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
if(request.getMethod().equals(POST)) {
// If the incoming request is a POST, then we send it up
// to the AbstractAuthenticationProcessingFilter.
super.doFilter(request, response, chain);
} else {
// If it's a GET, we ignore this request and send it
// to the next filter in the chain. In this case, that
// pretty much means the request will hit the /login
// controller which will process the request to show the
// login page.
chain.doFilter(request, response);
}
}

}

Note the good stuff inside of doFilter().  If the incoming request method is a POST, then we send it up to our AbstractAuthenticationProcessingFilter to actually process the login.  If it's a GET, or any other HTTP request method for that matter, we simply send it to the next filter in the chain.

Finally, remember that you'll need to define your own FORM_LOGIN_FILTER inside of your <security:http> Spring Security XML configuration to override the default /j_spring_security_check URL:

<security:http auto-config="false" use-expressions="true"
entry-point-ref="LoginUrlAuthenticationEntryPoint">
<security:custom-filter position="FORM_LOGIN_FILTER" ref="MyFilter" />
</security:http>

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

Enjoy!

Did You Find this Helpful?

Did you find this post helpful, or at least, interesting?

  

Send Mark a Direct Message

If you'd like to send me a direct message, please do so below. However, I do not publicly post comments or messages submitted directly to me. So, if you're going to try to SPAM me, or my blog, you're pretty much wasting your time.

400 characters remaining

Error

About Mark

A Silicon Valley native, Mark Kolich is a full-time Software Engineer, a casual entrepreneur, and a consultant for hire. A web technologies expert, his current focus is on building powerful and robust cloud-driven web-applications using Java, PHP, Perl, AJAX, DHTML, CSS, and JavaScript. His favorite programming languages are PHP, Java and JavaScript. He uses Linux, enjoys biking to work, loves building great software, and always writes elegant, readable, and maintainable code.

No TrackBacks

No trackbacks attached to this entry.

Twitter (@markkolich)

Translate

About this Entry

This page contains a single entry by Mark Kolich published on July 24, 2010 7:20 PM.

Extended Thoughts on Custom Tiny URL Engines was the previous entry in this blog.

Integrating Ant and Google's Closure Compiler is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.