23

I'm looking to use Spring Security for a Spring MVC application which will strictly be a JSON web service. I've done some research and read a few articles but haven't really found anything complete. I want the application to be completely stateless and use token based authentication. I don't want the Spring MVC application to have any forms, or used forms to authenticate. It should strictly take requests and data in JSON, and return JSON responses.

There will be an Angular JS client application which will need to send the username and password and get the token from the application to be used in sequential requests. At some point there may be Android clients that access this web service as well.

I'm assuming Spring Security has its way internally to mapping a token to a user session, meaning it knows token XXXXXXXXXXXX is admin user Bob and token AAAAAAAAAA is standard user Joe. However I don't have much experience with Spring Security so I don't know how this all comes together. I still want to be able to use secured annotations on controller and service methods.

Is there a way to accomplish this in Spring Security?

This question seems to be a good place to start but I'm not sure this will work as I envisioned it RESTful Authentication via Spring.

Community
  • 1
  • 1
greyfox
  • 6,426
  • 23
  • 68
  • 114
  • check this url it may be useful https://github.com/srinivas1918/spring-rest-security. additionally you need add form based login also to the configuration. – Nalla Srinivas Dec 16 '16 at 08:48

3 Answers3

19

This will be a good place to start with Spring-Rest-Boilerplate.

  1. For the first time you have to use http basic authentication and then login (send username/password) and this will return the token.
  2. In subsequent request you will use this token for authentication.
  3. You will have to add a filter to the chain that will do that authentication based on a token.

You have to come up with a token format and encryption for same. You ideally need to keep an expiry for the token too, expiry along with username could be a part of the token.Use an encryption algorithm a cryptographic hash function like MD5 and get hash of the whole Token.

Edit : As pointed out by Maciej Stępyra MD5 seems to be broken and its advised to use a Stronger hash functions like SHA-256.

Spring security by default will redirect you to a login page, but this does not make sense in case of REST so use a custom AuthenticationEntryPoint in config(Ref sample github code).

I was using this format for my Token: token:username:hash:expiry

hash=MD5(username+magickey)

expiry=current_timestamp+mins_to_expiry

 <security:http realm="Protected API" use-expressions="true" auto-config="false" create-session="always" entry-point-ref="**CustomAuthenticationEntryPoint**">
        <security:custom-filter ref="**authenticationTokenProcessingFilter**" position="PRE_AUTH_FILTER" />
        <security:intercept-url pattern="/**" access="isAuthenticated()" />
 </security:http>

NB:Thanks dhavaln for the code. I have used this as a reference and developed similar thing.

M4ver1k
  • 1,505
  • 1
  • 15
  • 26
  • This looks like a good starting point. Thanks! Does Spring Security internally map the token to a session so you can still do things such as @Secured(value={"ROLE_ADMIN"})? – greyfox Jun 12 '14 at 18:55
  • Yes you can use, but no need session REST should be stateless and configure `create-session="stateless "` . In your `TokenAuthenticationFilter` look up userdetails and create a `UsernamePasswordAuthenticationToken` and use `SecurityContextHolder.getContext().setAuthentication(authentication);` – M4ver1k Jun 13 '14 at 09:20
  • How do you renew your token? Like if you set it so it expires after 15 minutos and you've been sending requests the whole 15 minutes, do you force the user to relogin again? – M Rajoy Nov 01 '14 at 11:54
  • You can achieve this in multiple ways, for the first auth request we sent back a refresh token and expiration time so the client-sdk makes a call automatically with the refresh token to get a new access token when token is expired. – M4ver1k Nov 01 '14 at 14:59
  • MD5 is a hashing algorithm, not encryption ;) Better use stronger algorithms such SHA256 – Maciej Stępyra Sep 22 '15 at 10:16
  • @MaciejStępyra thanks for pointing that out, I have updated the answer. – M4ver1k Sep 22 '15 at 11:18
  • @M4ver1k i like ur concept,but i didn't know to implement this.Please help me to implement this as per ur concept.I am using rest request so there is no HttpServlet request,response service.I need this for my android application authentication which is same like authentication for a desktop application. – KJEjava48 Feb 08 '16 at 12:53
1

"I want the application to be completely stateless"

I'd reconsider what you're trying to do. There's a reason why you can't find good examples of your solution: You simply can't have an application that's both stateless and secure. Also if you're storing the tokens somewhere, you're not being stateless. Even if you aren't storing the tokens (like using JWT to encode them), you have to protect against CSRF attacks if users will be accessing this in a web browser. If you do go your route, expect to be writing a lot of customized security code (which is a bad thing). See a discussion of this here: https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii

user64141
  • 5,141
  • 4
  • 37
  • 34
1

In my case I found it easier to replace the org.springframework.security.web.context.SecurityContextRepository in org.springframework.security.web.context.SecurityContextPersistenceFilter with an implementation that shares the SecurityContext among several tomcat nodes. The client keeps sending a token jsessionid-like but I can do a simple round-robin load balancing and don't have to worry about session replication.

wpercy
  • 9,636
  • 4
  • 33
  • 45
user2560528
  • 105
  • 6