3

We have following secured controller:

@RestController
@RequestMapping("/api/employee")
public class EmployeeController {

    @GetMapping
    @PreAuthorize("#oauth2.hasScope('edit') OR hasRole('ADMIN')")
    public String getForAdmin(@AuthenticationPrincipal Principal principal) {
        return employeeService.getForAdmin(principal)
    }
}

Security works as expected. I received jwt access token from authorization server, and with request with header "Authorization bearer xxxx.yyyy.zzzz" I am able to call this controller.

Resource server has configured pretty basic authentication

@Override
public void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests(httpSecurity -> httpSecurity
            .anyRequest().authenticated()
        );
}

Next I tried write integration test for employee controller to ensure security works fine like this:

// configure mock mvc with security
    mockMvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply(springSecurity())
            .build();

    // call secured endpoint and with specific authentication
    mockMvc.perform(get("/api/employee")
            .with(jwt())
            .accept(MediaType.APPLICATION_JSON))
            .andDo(print())
            .andExpect(status().isOk());

I found out that exists JwtRequestPostProcessor as I appointed in sample but I have no idea how to tell this mocked jwt scope and role. I tried at least role like this: jwt().authorities(new SimpleGrantedAuthority("ROLE_ADMIN")) but it didn't work and I always get 401 error.

EDIT: this is logs which I found after enabling debug level to security:

2020-02-14 11:42:18.167 DEBUG 2094 --- [           main] o.s.security.web.FilterChainProxy        : /api/employee at position 5 of 11 in additional filter chain; firing Filter: 'OAuth2AuthenticationProcessingFilter'
2020-02-14 11:42:18.167 DEBUG 2094 --- [           main] o.s.s.o.p.a.BearerTokenExtractor         : Token not found in headers. Trying request parameters.
2020-02-14 11:42:18.167 DEBUG 2094 --- [           main] o.s.s.o.p.a.BearerTokenExtractor         : Token not found in request parameters.  Not an OAuth2 request.
2020-02-14 11:42:18.167 DEBUG 2094 --- [           main] p.a.OAuth2AuthenticationProcessingFilter : Clearing security context.
2020-02-14 11:42:18.167 DEBUG 2094 --- [           main] p.a.OAuth2AuthenticationProcessingFilter : No token in request, will continue chain.
2020-02-14 11:42:18.167 DEBUG 2094 --- [           main] o.s.security.web.FilterChainProxy        : /api/employee at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2020-02-14 11:42:18.167 DEBUG 2094 --- [           main] o.s.security.web.FilterChainProxy        : /api/employee at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-02-14 11:42:18.168 DEBUG 2094 --- [           main] o.s.security.web.FilterChainProxy        : /api/employee at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2020-02-14 11:42:18.168 DEBUG 2094 --- [           main] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@94907bf0: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2020-02-14 11:42:18.168 DEBUG 2094 --- [           main] o.s.security.web.FilterChainProxy        : /api/employee at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-02-14 11:42:18.169 DEBUG 2094 --- [           main] o.s.security.web.FilterChainProxy        : /api/employee at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-02-14 11:42:18.169 DEBUG 2094 --- [           main] o.s.security.web.FilterChainProxy        : /api/employee at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-02-14 11:42:18.169 DEBUG 2094 --- [           main] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /api/employee; Attributes: [#oauth2.throwOnError(authenticated)]
2020-02-14 11:42:18.169 DEBUG 2094 --- [           main] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@94907bf0: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2020-02-14 11:42:18.173 DEBUG 2094 --- [           main] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@2f6e92ca, returned: -1
2020-02-14 11:42:18.176 DEBUG 2094 --- [           main] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is anonymous); redirecting to authentication entry point

org.springframework.security.access.AccessDeniedException: Access is denied

dependencies:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
        <version>2.2.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
        <version>2.2.0.RELEASE</version>
    </dependency>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        <version>2.2.2.RELEASE</version>
    </dependency>
Denis Stephanov
  • 4,563
  • 24
  • 78
  • 174
  • Two things come to mind, but you really should turn on Spring Security debug logging to see what it is complaining about. It might be that you need to set a ROLE_USER too, it might also be that you are being blocked by a CSRF check. As said - need the debug logging to know what the truth is. – Gimby Feb 14 '20 at 10:39
  • @Gimby I tried enable debug to security and I've updated question with log which I found. Due to logs my request is passed still as annonymous. – Denis Stephanov Feb 14 '20 at 10:47
  • So this is an integration test? as in you're using `@SpringBootTest` ? – Gimby Feb 14 '20 at 11:50
  • @Gimby yes I did, and also @ExtendWith(SpringExtension.class) for junit5 – Denis Stephanov Feb 14 '20 at 12:30
  • Hm I'm not too familiar with combining SpringBootTest and MockMVC, I tend to use TestRestTemplate in integration tests and make everything as real as possible. But perhaps it is as simple as adding a `@WithMockUser(roles = {"USER", "ADMIN"})` to your test method? – Gimby Feb 14 '20 at 13:05
  • @Gimby but how to test if security works for scope – Denis Stephanov Feb 14 '20 at 13:07
  • The documentation points to the fact that the [jwt()](https://docs.spring.io/spring-security/site/docs/current/reference/html/test.html#literal-jwt-requestpostprocessor-literal) post processor is indeed the answer to *that* question. So perhaps you were on the right track already in your attempt to use it, but you didn't actually put the right scope. – Gimby Feb 14 '20 at 13:26
  • @Gimby I am sure I wrote it correct :/ – Denis Stephanov Feb 14 '20 at 13:35
  • Based on the logs, it looks like you are using the deprecated spring-security-oauth project. You should instead use the core spring-security project. Can you share your dependencies? If you are indeed using spring-security-oauth, I can help you figure out what the equivalent dependency is in core Spring Security. – Eleftheria Stein-Kousathana Feb 19 '20 at 15:47
  • @EleftheriaStein-Kousathana hello, thank you for effort. I added security related dependencies. – Denis Stephanov Feb 19 '20 at 17:31
  • What are you using from the `spring-cloud-starter-oauth2` dependency? This is what is bringing in the deprecated Spring Security OAuth project. – Eleftheria Stein-Kousathana Feb 20 '20 at 21:28

0 Answers0