Lately I’ve been dabbling in trying to secure a REST service that I’ve built using Spring & Spring Security. I’ve been reading quite a bit about REST of late(and have been for quite some time), and the popular themes around security I’m noticing, is that HTTPS is a good thing, and persisting any sort of session state(even user authentication) is not the best practise. So I decided to take a look at what Spring have provided in the way of authentiction when using web apps, and decided that there wasn’t anything pre-configured that I could use that would require me to provide my security credentials on every request, and effectively re-authenticate, unless of course you were going to use Basic Authentication, or Digest authentication.
Looking around at how others in the industry implement security for their REST services, I came across a pretty neat implementation at Kayako, and thought I’d adopt the same principle. If you’ve not seen how Kayako secure their REST services, its quite simple. You, as a client, need to provide 3 things.
1. The API Key
Something that identifies you as a user. Preferably this should be some “Not so easily guessable” string. I would suggest perhaps some guid. Add this as an additional attribute against the user details you hold in your DB. Allow the user to request a new guid through your web app if they feel that their current one has been compromised.
2. A Salt
This should be a random string that should change on every request. You could calculate and MD5 hash of the content of your request, or you could send any other random string.
This is the Hash(preferably a HMAC SHA, see my previous post about hashing passwords in Spring). This hash is a combination of your password, with the Salt mentioned above. On the server side, it’ll lookup your user details via your API Key, and validate the authenticity of your credentials by performing the same hash against your salt/password in the hope that it’ll arrive at the same signature that you’ve provided in the request. Obviously the password that is stored in the database would be a hashed password anyway, just so that it’s not obviously “guessable”.
I couldn’t find anything in Spring which is provided out of the box support for stateless authentication for REST, where I could provide these credentials in the URL, so I decided it would be fun to try and roll my own, using Kayako as a source of authority on how to provide the details for the secured REST call. Feel free to check out the sample app I’ve put together over on Github.
In order to embark on creating your own mechanism for authentication with Spring, you need to be familiar with how the Spring Security model works. If you’re not familiar with it, I’d suggest a quick read over their documentation.
The main java classes involved in order to make this happen are the following:
1. The Filter (RESTAuthenticationFilter)
I’ve chosen to insert this filter where Spring would have used a Forms Authentication Filter. Below is a snippet where I’ve pointed out where/how I did this.
<sec:http disable-url-rewriting="true" entry-point-ref="forbiddenEntryPoint" use-expressions="true" create-session="never"> <sec:anonymous enabled="false"/> <sec:session-management session-fixation-protection="none"/> <sec:custom-filter ref="restAuthenticationFilter" position="FORM_LOGIN_FILTER"/> <sec:intercept-url pattern="/**" access="isFullyAuthenticated()"/> </sec:http>
Notice how I’ve chosen specifically to not create a session, disabled anonymous access, and replaced the Forms Login Filter with my own.
2. The Authentication Provider (RESTDaoAuthenticationProvider)
This is essentially responsible for looking up the user, and validating their credentials. I’ve tried to use as much of already existing functionliaty so I’ve extended from the
AbstractUserDetailsAuthenticationProvider, and the most important method here is the
additionalAuthenticationChecks(...). This method is actually where the check is done to see if the password the user has supplied is in fact correct.
So thats the guts of it! There are obviously a few other supporting classes, but if you can get your head around this, then you’re well on your way to customising your authentication for REST Services in Spring.