11

I have spring-security configured using basic and form based authentication as per auto-config='true'.

I would like the endpoints under /api/** to NOT use form based security. Other endpoints outside of /api/** should use form based login. I would like a 401 response sent to any call for these endpoints who did not provide credentials under /api/**.

UPDATE: Thanks to Luke Taylor's comment below I have come up with the following solution.

NOTE: This technique can only be applied as of spring-security 3.1.

First I single out /api/**. We never create a session though use one if available, this is handled by create-session="never" and the use of <session-management/>.

<http pattern="/api/**" create-session="never" use-expressions="true">
    <http-basic />
    <session-management />
    <intercept-url pattern="/api/**" access="hasRole('API_ACCESS')"/>
</http>

<http auto-config="true" use-expressions="true">
    <intercept-url pattern="/" access="permitAll"/>
    <intercept-url pattern="/**" access="isAuthenticated()"/>
</http>
Brett Ryan
  • 26,937
  • 30
  • 128
  • 163
  • 1
    Look here http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security-3-1-part-3/. In this tutorial you can find some answers on your questions. – dimas Aug 14 '12 at 06:59
  • 1
    See my answer to [this question](http://stackoverflow.com/questions/9302795/handling-both-form-and-http-basic-authentication-with-different-sources) which is essentially asking the same thing. – Shaun the Sheep Aug 14 '12 at 11:36
  • Hi Luke, in theory this looks like what I'm after and will investigate applying it. In having multiple `` tags could they accidentally both handle the request? Maybe I can use SpEL to match anything other than `/api`. I was not aware that in spring-security 3.1 they now allow multiple `` tags, this is a good thing. – Brett Ryan Aug 15 '12 at 01:19
  • @LukeTaylor, please post an answer so I may accept it, I've adapted your other answer to work thusly. First `` I've also added `` to this as it will allow a web user access if they have a session already but NOT request one. I only need the one `authentication-manager`. I'll update my question with what I have done. – Brett Ryan Aug 15 '12 at 01:47
  • @BrettRyan post your solution as an answer, please, and accept it if you want. In this way people will see immediately that it is a solution. ;) – bluish Jan 15 '15 at 15:23

1 Answers1

19

With Spring Security 3.1, your best option is to split the restful and non-restful parts of your application into separate filter chains by using two separate <http> elements. The restful API chain can then be configured to be stateless and use basic authentication, while the default chain can use a normal form-login configuration.

You would then have something like:

<http pattern="/api/**" create-session="stateless">
    <intercept-url pattern="/api/**" access="ROLE_API_USER" />
    <http-basic />        
</http>

<!-- No pattern attribute, so defaults to matching any request -->
<http>
    <intercept-url pattern="/**" access="ROLE_USER" />
    <form-login />        
</http>

The chain definitions must be ordered from most specific pattern to most general, so the default chain comes last.

Shaun the Sheep
  • 22,353
  • 1
  • 72
  • 100
  • Excellent Luke, thank you very much for posting the answer. I should have read the docs for 3.1 to discover this as it's a small but powerful new feature. :) – Brett Ryan Aug 15 '12 at 12:47
  • I think the create-session attribute must be set to `create-session="never"` as per this post: http://stackoverflow.com/questions/16914985/spring-security-either-http-basic-or-form-login-authentication – lanoxx Sep 30 '13 at 13:02
  • @lanoxx not if you want your application to be completely stateless and never have a session. – Shaun the Sheep Oct 02 '13 at 14:57