Spring 3.1 RESTful Authentication

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.

3. Signature

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.

Whats Involved

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.

Advertisements

Hash based Message Authentication Code hashing in Spring MVC

Hash based Message Authentication Code(HMAC) is used in scenarios where you need to validate the validity and authenticity of a message. Recently I was implementing some security aspects for our REST service, and I noticed that Spring Security currently supports SHA hashing for password, but no HMAC SHA hashing.

Now firstly, this is really for informational sakes, and I’m in no position to advise which way is better, but instead, I’m providing what I think I’d rather have implemented, and its purely a personal preference – for me anyway.

So, now back to the point. Firstly, below is a sample of a security configuration(in xml) using one of the many Spring Security provided implementations of the PasswordEncoder interface – namely the ShaPasswordEncoder.

.....
<authentication-manager>
   <authentication-provider>
      <password-encoder hash="sha"/>
      <user-service>
         <user name="jimi" password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f" authorities="ROLE_USER, ROLE_ADMIN" />
         <user name="bob" password="4e7421b1b8765d8f9406d87e7cc6aa784c4ab97f" authorities="ROLE_USER" />
      </user-service>
   </authentication-provider>
</authentication-manager>
.....

Now in this simple contrived sample config, we’re telling Spring Security to use their implementation of the ShaPasswordEncoder. Upon inspection of this implementation, you’re also able to specify the field responsible for holding the salt value if you so choose to provide one. In the REST service I have, I have defintely opted to provide a salt in which to further secure the hash.

In this ShaPasswordEncoder implementation provided by Spring, it performs a hash on the raw concatenated string in the format of “password{salt}” . This surprised me somewhat, because I had actually expected Spring to provide an implementation of HMacSHA when providing a salt, not just an implementation of SHA! And believe me theres a difference! So the purist in me came out, and I couldn’t let this rest (see what I did there? rest….REST?.. ok I know, perhaps a little lame, but I digress.)

The main difference between the two implementations, is that the way Spring have done it, they have just effectively hashed a string. With HMac, the salt actively plays a role in the encryption of the raw string. Some might argue that they arrive at the same end result, which is a hashed string based on the salt. I’d tend to agree, but the purist in me wanted to do it properly, so I wrote my own implementation of what the HMacSha should have been. Below is a simple snippet of what the code looks like when just using a normal SHA hash, and when using a HMacSHA. In these samples below I’ve only shown the code which actually does the hashing so you can see what the difference is. Also bear in mind, that my custom rolled hashing class extends the PasswordEncoder class so that I can include it in the security config xml.

SHA Implementation

public String encodePassword(String rawPass, Object salt) {
 String saltedPass = mergePasswordAndSalt(rawPass, salt, false);

MessageDigest messageDigest = getMessageDigest();

byte[] digest = messageDigest.digest(Utf8.encode(saltedPass));

// "stretch" the encoded value if configured to do so
 for (int i = 1; i < iterations; i++) {
 digest = messageDigest.digest(digest);
 }

if (getEncodeHashAsBase64()) {
 return Utf8.decode(Base64.encode(digest));
 } else {
 return new String(Hex.encode(digest));
 }
 }

protected final MessageDigest getMessageDigest() throws IllegalArgumentException {
 try {
 return MessageDigest.getInstance(algorithm);
 } catch (NoSuchAlgorithmException e) {
 throw new IllegalArgumentException("No such algorithm [" + algorithm + "]");
 }
 }

protected String mergePasswordAndSalt(String password, Object salt, boolean strict) {
 if (password == null) {
 password = "";
 }

if (strict && (salt != null)) {
 if ((salt.toString().lastIndexOf("{") != -1) || (salt.toString().lastIndexOf("}") != -1)) {
 throw new IllegalArgumentException("Cannot use { or } in salt.toString()");
 }
 }

if ((salt == null) || "".equals(salt)) {
 return password;
 } else {
 return password + "{" + salt.toString() + "}";
 }
 }

HMac Implementation

protected final Mac getMac() throws IllegalArgumentException {
 try {
 return Mac.getInstance(algorithm);
 } catch (NoSuchAlgorithmException e) {
 throw new IllegalArgumentException("No such algorithm [" + algorithm + "]");
 }
 }
 public String encodePassword(String rawDataToBeEncrypted, Object salt) {
 byte[] hmacData = null;
 if(rawDataToBeEncrypted != null){
 try {
 SecretKeySpec secretKey = new SecretKeySpec(rawDataToBeEncrypted.getBytes(ENCODING_FOR_ENCRYPTION), this.algorithm);
 Mac mac = getMac();
 mac.init(secretKey);
 hmacData = mac.doFinal(salt.toString().getBytes(ENCODING_FOR_ENCRYPTION));

if (isEncodeHashAsBas64()) {
 return new String(Base64.encode(hmacData), ENCODING_FOR_ENCRYPTION);
 } else {
 return new String(hmacData, ENCODING_FOR_ENCRYPTION);
 }

}
 catch(InvalidKeyException ike){
 throw new RuntimeException("Invalid Key while encrypting.", ike);
 }
 catch (UnsupportedEncodingException e) {
 throw new RuntimeException("Unsupported Encoding while encrypting.",e);
 }
 }
 return "";

}

I am using this version of the hashing algorithm for my sample REST service which I have up on Github. You can check out the java file itself here, but I’ll give a more detailed run down of the sample project in my next blog post, which is about supporting stateless authentication in a Spring REST application, and how I went about rolling my own security filter/mechanism to support this. Watch this space!