1

I would like to have spring security configured so that one specific resource is locked down to a group, the rest are available to any logged in user. My security.xml looks like this

<http auto-config="true" create-session="stateless" use-expressions="true">
    <intercept-url pattern="/server/**" access="hasRole('ROLE_DEV-USER')" method="POST" requires-channel="https"/>

    <intercept-url pattern="/**" access="isFullyAuthenticated()" method="POST" requires-channel="https"/>
    <intercept-url pattern="/**" access="isFullyAuthenticated()" method="PUT" requires-channel="https"/>
    <intercept-url pattern="/**" access="isFullyAuthenticated()" method="DELETE" requires-channel="https"/>

    <intercept-url pattern="/**" access="permitAll" method="GET" requires-channel="any"/>
    <intercept-url pattern="/**" access="permitAll" method="HEAD" requires-channel="any"/>
    <http-basic />
    <logout />
</http>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="admin" password="admin" authorities="ROLE_NOT-DEV-USER" />
            <user name="admin2" password="admin2" authorities="ROLE_DEV-USER" />
        </user-service>
    </authentication-provider>
</authentication-manager>

I would expect the only admin to be able to POST to server/enable and server/disable. What I am actually seeing is both admin and admin2 can POST to the server/enable resource. As though the /server/** is ignored and the next more generic intercept-url is taking its place. The start up logs show all lines being loaded

2013-08-21 15:07:42,124  INFO FilterInvocationSecurityMetadataSourceParser:134 - Creating access control expression attribute 'hasRole('ROLE_DEV-USER')' for /server/**
2013-08-21 15:07:42,125  INFO FilterInvocationSecurityMetadataSourceParser:134 - Creating access control expression attribute 'isFullyAuthenticated()' for /**
2013-08-21 15:07:42,125  INFO FilterInvocationSecurityMetadataSourceParser:134 - Creating access control expression attribute 'isFullyAuthenticated()' for /**
2013-08-21 15:07:42,126  INFO FilterInvocationSecurityMetadataSourceParser:134 - Creating access control expression attribute 'isFullyAuthenticated()' for /**
2013-08-21 15:07:42,126  INFO FilterInvocationSecurityMetadataSourceParser:134 - Creating access control expression attribute 'permitAll' for /**
2013-08-21 15:07:42,127  INFO FilterInvocationSecurityMetadataSourceParser:134 - Creating access control expression attribute 'permitAll' for /**

Currently using spring v3.1.2

t0mmyw
  • 737
  • 3
  • 10
  • 22

2 Answers2

3

Intercept URLs are evaluated in the order they appear. From the docs at http://static.springsource.org/spring-security/site/docs/3.0.x/reference/core-web-filters.html

Patterns are always evaluated in the order they are defined. Thus it is important that more specific patterns are defined higher in the list than less specific patterns. This is reflected in our example above, where the more specific /secure/super/ pattern appears higher than the less specific /secure/ pattern. If they were reversed, the /secure/ pattern would always match and the /secure/super/ pattern would never be evaluated.

..so as long as your more specific URL is at the top it should work. It might be worth debugging to see how spring security is evaluating and trying to match your URLs. Sorry, not really an answer, but too big for a comment.

Qwerky
  • 18,217
  • 6
  • 44
  • 80
  • unfortunately that documentation is what led me to ask the question here. We aren't seeing this behaviour and were a little stumped, hoping there was a setting missing that would enable the ordering – t0mmyw Aug 21 '13 at 15:17
  • This answer is correct. My usage was wrong. I've included my mistake as an unaccepted answer below for reference – t0mmyw Aug 22 '13 at 15:41
1

The pattern needs to be expanded to include the url-pattern used to match the servlet

web.xml

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
    <servlet-name>restServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext-dispatchservlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>restServlet</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

So spring security needs the servlet mapping, plus the request mapping to get to the url and apply the intercept

<http auto-config="true" create-session="stateless" use-expressions="true">
    <intercept-url pattern="/rest/server/**" access="hasRole('ROLE_DEV-USER')" method="POST" requires-channel="https"/>

    <intercept-url pattern="/**" access="isFullyAuthenticated()" method="POST" requires-channel="https"/>
    <intercept-url pattern="/**" access="isFullyAuthenticated()" method="PUT" requires-channel="https"/>
    <intercept-url pattern="/**" access="isFullyAuthenticated()" method="DELETE" requires-channel="https"/>

    <intercept-url pattern="/**" access="permitAll" method="GET" requires-channel="any"/>
    <intercept-url pattern="/**" access="permitAll" method="HEAD" requires-channel="any"/>
    <http-basic />
    <logout />
</http>

Once the missing /rest is added to the pattern it works as expected

t0mmyw
  • 737
  • 3
  • 10
  • 22