Search This Blog

Friday, July 30, 2010

Spring Security 3 and Digest Authentication

This was a tough one so I thought I'd take a few moments and share what I found.  Context: I'm using Spring 3 as the basis for a set of RESTful services.  The new MVC enhancements makes supporting a RESTful API pretty simple.  What I wanted to do what to lock down the API a bit and turned to Spring Security 3 to make that happen.  Not wanting to enable HTTPS, at least not yet, I turned to Digest Authentication which provides a reasonable authentication mechanism without having to hassle with digital certificates.  Getting Spring Security enabled and, at least initially, authenticating with Basic Authentication was a breeze.  Once I tried to enable Digests Authentication, things got weird.

 Luckily, I was able to locate two resources that steered me down the correct path.  One is the book, Spring Security 3 and another was an article on DZone titled "Using Spring Security to Enforce Authentication and Authorization on Spring Remoting Services Invoked From a Java SE Client".   The upshot is that you cannot rely on the simple namespace configuration that is almost always talked about in the Spring Security 3 literature.  It assumes a JSP type of environment with form login screens et al.  In my case, I'm using just enough of the web stack to allow for HTTP based manipulation of the server-side resource -- no gui.  This means you have to configure things by hand so it'll suit your needs.   Here is the Spring context file I used to enable Digest Authentication for my RESTful services.

Since this was a prototype, I'm relying on the in-memory credential store but you should be able to wire up some more suitable for a production environment.  What I wanted to do was to authenticate at the web layer but authorize at the services layer.  The authentication is handled by the Digest Authentication pieces and the authorization is handled by annotations in service interfaces.  For example:
public interface EchoPort
{
    @PreAuthorize( "hasRole( 'ROLE_ADMIN' )" )
    EchoResponse echoMessage( final EchoRequest request ) throws EchoError;
}

I used Apache HttpClient 4.0.1 for testing and was pleasantly surprised to find that it handled both Basic and Digest authentication for me.  All I had to do was to provide the credentials prior to making the call the HttpClient handled the rest.

theClient.getCredentialsProvider().setCredentials( AuthScope.ANY, new UsernamePasswordCredentials( defaultUserName, defaultPassword ) );

I hope this saves you a bit of time.

3 comments:

  1. Your link to the spring context file goes to a dropbox file...and it tells me the file doesn't exist...

    ReplyDelete
    Replies
    1. I'm sorry about that. I'll see if I can dig up the context file for you.

      Delete
    2. The context file is still missing.

      Delete