1

I was trying to replace some manual authority checking with annotations (@Secured and @PreAuthorize). While debugging why it doesn't work I was surprised to find that the second of these two assertions failed at the top of a @RequestMapping controller method.

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
assert(auth.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_READER"))); // passes
assert(request.isUserInRole("ROLE_READER")); // fails

I assume (as I can't get them to authorise anything) @Secured and hasRole() make use of the latter lookup?

Are the roles not supposed to be automatically populated from the SecurityContext authorities?

Was the filter that set the Authentication supposed to add the roles separately?


Edit:

Cut down the spring security config to spring boot's (1.3.0) default, plus the filter that sets the authentication.

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(new JwtAuthenticationFilter(), FilterSecurityInterceptor.class);
    }
}
OrangeDog
  • 36,653
  • 12
  • 122
  • 207
  • Post your configuration... And which Spring security version you are using. – M. Deinum Jan 25 '16 at 14:08
  • I am far from an MVCE - configuration is spread over many classes in many projects. This isn't a "find my bug" question, it's a "how does this work" question. – OrangeDog Jan 25 '16 at 14:12
  • The only thing needed is the security configuration and an answer to the question which Spring Security version you are using. – M. Deinum Jan 25 '16 at 19:26
  • @M.Deinum If you insist, but I don't see how that helps answer the questions of how spring web security works internally. – OrangeDog Jan 26 '16 at 11:57
  • The Spring Security version is important as it might have or not have setup the servletrequest integration or not for this method. Also your spring security setup might break proper integration. Hence the request. – M. Deinum Jan 26 '16 at 12:02
  • What does the `JwtAuthenticationFilter` do and what is the actual type of the `Authentication` you get returned? Also you shouldn't need `@EnableWebSecurity` as that is already done by Spring Boot and it might (and probably will) interfere with the auto configuration of Spring Boot. – M. Deinum Jan 26 '16 at 12:13
  • It was my understanding that `@EnableWebSecurity` disables boot's config, otherwise I couldn't add my own filter. – OrangeDog Jan 26 '16 at 13:29
  • The Authentication is a custom class, the filter creates an instance and calls `SecurityContextHolder.getContext().setAuthentication` – OrangeDog Jan 26 '16 at 13:30
  • Your assumptions are also wrong btw, `hasRole` doesn't use the servlet stuff but the plain `Authentication` object. Do you have enabled method level security? Else `@Secured` doesn't do anything. Try `request.isUserInRole("READER")` instead. – M. Deinum Jan 26 '16 at 13:40
  • Does `Authentication.getPrincipal()` return anything? – M. Deinum Jan 26 '16 at 13:49

1 Answers1

1

I assume (as I can't get them to authorise anything) @Secured and hasRole() make use of the latter lookup?

My assumption was wrong. Both use the granted authorities, but in different ways.

  • @Secured requires the prefix, so @Secured("ROLE_READER") works.
  • hasRole does not use the prefix, so @PreAuthorize("hasRole('READER')") works.
  • Both require the granted authority to be prefixed, so @Secured("READER") will never work, even if there is an authority named READER.

The prefix can be configured with RoleVoter's rolePrefix property.

HttpServletRequest.isUserInRole uses a completely separate system, unrelated to Spring security. It is not populated by default, and does not need to be. I believe adding a SecurityContextHolderAwareRequestFilter to the chain will populate it

OrangeDog
  • 36,653
  • 12
  • 122
  • 207
  • The assumption for your question was that you had setup proper integration for Spring Security with the servlet API (calling the `servletApi` to configure it). – M. Deinum Jan 26 '16 at 14:03