6

I am trying to create a webapplication, which will use a js front end and invoke Spring WS in the backend. Let's say this is a shopping site kind of website. So, I could have services like OrderService InventoryService ShippingService and so on. The only thing that needs session is the shopping cart of the user. Now, just for this shopping cart, does it make sense to use a servlet container for session management? Or, should I have CartService that persists session information to the database?

What is the best practice when it comes to session management with WebServices? I guess, the best practice really is to keep the service stateless, but how can I authorize users if I have stateless webservices?

Is it a good practice at all to use a servlet container just to do session management and then have different controllers acting as proxies to the webservices?

I am attaching a picture to make you understand the context better. enter image description here

Jay
  • 2,394
  • 11
  • 54
  • 98
  • Well I guess you can use a kind of client access key in HTTP request header; I mean: from browser (after login attempt) a client access-code is passed in a custom http header; on server side in servlet container you can get this client access token and check if it's valid token; then you cna use it in order to invoke web services – Angelo Immediata Aug 14 '15 at 06:27
  • So should a single servlet/filter act as an authorizer for all web services? – Jay Aug 14 '15 at 06:31
  • Yes I0d definitively use a single servlet or filter – Angelo Immediata Aug 14 '15 at 06:32
  • if I am going to use a servlet/filter, then it would have access to the session, wouldn't it? And if it has access to session and can check if user is qualified to access the webservice, then I wouldn't need any sort of security at my WS? Is this (using a servlet as security gate) the best practice to secure your webservices from ajax requests? – Jay Aug 14 '15 at 06:37
  • Nope... you wouldn't; you must acces to the request and get the http header cotaining the client access key. Something like request.getHeader("CUST-KEY"); and then check if this key is valid or less (according to some well defined rules). This means that browser MUST pass this http header in every call – Angelo Immediata Aug 14 '15 at 06:39
  • @AngeloImmediata do you have any links to any tutorial that implements such an access key concept? – Jay Aug 14 '15 at 06:41
  • I guess that the best approach you may use is the OAuth 2.0; here few links you may see: 1) http://oauth.net/2/ 2) https://en.wikipedia.org/wiki/OAuth 3) https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified 4) https://developers.google.com/identity/protocols/OAuth2 – Angelo Immediata Aug 14 '15 at 06:47
  • @AngeloImmediata here's the situation, I have say, http://myapp.com/testapp1 and http://myapp.com/testapp2. Two different applications that would have different set of users. And some users from app1 can access my web service and some users from app2 cannot. In both cases, what you are suggesting is that I should not have no protection at WS, but have app1 and app2 authorize users and make internal calls (from app1 and app2's server side) to WS? – Jay Aug 14 '15 at 06:51
  • Nope; i'm saying that you can use this approach to generate a client code; then pass this code to the WS too and there check if the code is valid or not – Angelo Immediata Aug 14 '15 at 07:26

3 Answers3

5

How can I authorize users if I have stateless webservices?

  1. If you app uses external ws, then rather common approach is described here.

  2. If all the ws are part of your delivery, you can surely use spring-security.

  3. A very common approach is also to have an (apache) http server as a proxy with something like ldap for both, authentication and authorization.

Is it a good practice at all to use a servlet container just to do session management and then have different controllers acting as proxies to the webservices?

I would think it is not. As also discussed here you can only benefit from keeping your Web Services stateless and if you need to maintain state between requests, use cookies.

If the state (cart) should survive the logout, something like CartService sounds like a good idea to me.

Community
  • 1
  • 1
Milos Gregor
  • 940
  • 8
  • 14
  • on your point 3 - do you mean I should use basic authentication? if its http server, how will I store session specific information? – Jay Aug 18 '15 at 12:54
  • We currently use basic authentication (so it works) but I would not call it a _best practice_. Anyway, apache can do a form authentication and manage sessions : check [this](http://httpd.apache.org/docs/2.4/mod/mod_auth_form.html). – Milos Gregor Aug 18 '15 at 15:42
  • Ok, I guess it will require usernames to be on file for it to authenticate. – Jay Aug 18 '15 at 21:51
  • Maybe I'm reading it wrong but leaving the servlet container handle sessions while the web services are stateless IS a good practice. – lpezet Aug 19 '15 at 13:59
  • There might be a misunderstanding. - stateless ws is indeed a good practice - having an additional servlet container with controllers as proxies to the real web services sounds not a good practice to me. – Milos Gregor Aug 19 '15 at 15:24
  • @MilosGregor ok. if webservice is stateless, how do I know that an ajax request is authorized? Let's say my service is supposed to be accessed from two different apps and only certain kind of users from these two different apps are authorized to access. How do I know that ajax request is coming from user1 of webapp1, who is authorized? and not from user2 of webapp2, who is not authorized to access the service? – Jay Aug 19 '15 at 19:33
  • @Jay: please, see my new answer. – Milos Gregor Aug 20 '15 at 08:14
2

You could refer to the Spring-WS security

Check here, for a sample that uses WS-Security in a Spring Boot app. Specifically, see WebServiceServerConfig.

Nassim MOUALEK
  • 4,702
  • 4
  • 25
  • 44
  • ok this link was helpful. But from this code here - https://github.com/gregturn/learning-spring-ws/blob/security/learning-spring-ws-server/src/main/java/com/greglturnquist/learningspringws/WebServiceServerConfig.java I couldn't tell why a dispatcherServlet needs to be mentioned as part of configuration. Does this mean that a dispatcher servlet will manage all query requests and we need to specify the path for this webservice in that callback? – Jay Aug 18 '15 at 21:59
  • Sorry i am not an expert of SpringWS, if you want give me your mail, i will send you a very good Project Exemple developed by my self for a Job Test, with Spring-Boot and Swing Interface – Nassim MOUALEK Aug 19 '15 at 08:18
2

If webservice is stateless, how do I know that an ajax request is authorized? How do I know that ajax request is coming from user1 of webapp1, who is authorized? and not from user2 of webapp2, who is not authorized to access the service?

Good question. Quick answer would be :

  1. For Basic Authentication : username:password is base64 encoded and stored in the Authorization http header for each request that the client sends. See this wiki entry. The header looks like this:

    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

    With spring security, configuration can be like this:

    <http pattern="/api/**" create-session="stateless">
        <intercept-url pattern='/**' access="hasRole('REMOTE')" />
        <http-basic />
    </http>
  1. For form based authentication of WS, take a look on this article.

    • First you sent a post request to /j_spring_security_check. This request will return the Cookie which will then be used by any subsequent request against the Web Service. Here they store it in a text file:

      curl -i -X POST -d j_username=user -d j_password=userPass -c /tmp/cookies.txt http://localhost:8080/app/j_spring_security_check

    • Then you can use the cookie from the file to do further authenticated requests:

      curl -i --header "Accept:application/json" -X GET -b /tmp/cookies.txt http://localhost:8080/app/api/foos

    The xml spring security configuration can look like this:

    <http pattern="/api/**" create-session="stateless">
        <intercept-url pattern='/**' access="hasRole('REMOTE')" />
        <form-login />
    </http>
Milos Gregor
  • 940
  • 8
  • 14