Spring security: How to make annotation based role specifications have precedence over pattern-based role specifications

Viewed 421

I want to combine role-based annotations and pattern-based authorization configuration.

I want the the pattern-based authorization to be the "fallback in case no annotation is specified".

An example of an annotated method endpoint:

@PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_USER')")
@RequestMapping(
  method = RequestMethod.POST,
  headers = "Accept=application/json",
  path="publicApi/doWork" )
public void doWork() {
  ...
}

And my pattern-based authorization configuration looks like:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
// specifies actuator endpoints should be secured by this config
@Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  private void configureEndpointRoles(HttpSecurity http) throws Exception {
    http.authorizeRequests().
      antMatchers(anonymousUrlPatterns()).permitAll().
      antMatchers("/publicApi/**").access("hasAnyRole('ROLE_ADMIN')").
      anyRequest().denyAll();
    ;
  }
}

Here's how I want the to work:

  • If an endpoint URL matches any of the "anonymousUrlPatterns" - permit.
  • If an endpoint matches the "publicApi" pattern and is annotated with @PreAuthorize, use the definition in the annotation to decide if the user can access it (in this case the user needs either ADMIN or USER role).
  • If an endpoint matches the "publicApi" pattern but is not annotated, then the user must have ADMIN role in order to access it.
  • If the endpoint matches none of the above - deny.

How would I go about defining this behaviour?

With the above setup as specified, the pattern-based configuration takes precedence and the endpoint invocation is denied (I'm not sure if the pattern-based configuration is taking precedence or if Spring is combining them somehow?)

Spring version - 4.2.3


Update: I've tried updating the EnableGlobalMethodSecurity to:

@EnableGlobalMethodSecurity(
  prePostEnabled = true,
  order = Ordered.HIGHEST_PRECEDENCE)

But that didn't seem to change the behaviour.

1 Answers

As per comment from @dur, it looks like you can't do this with a basic configuration.

Under the default Spring Security AccessDecisionManager strategy, the "No" vote from the pattern-based rule will cause the overall invocation to be denied.

It looks like the behaviour I want will involve writing some custom decision manager logic, something like: http://www.baeldung.com/spring-security-custom-voter

Related