Search code examples
spring-bootspring-securityspring-authorization-serverspring-resource-server

Spring boot resource server @PreAuthorize("hasAuthority('SCOPE_xxx')") does not work


I am working with spring boot resource server and trying to use @PreAuthorize("hasAuthority('SCOPE_xxx')") for authorization but no matter what scope is used in generating the token, access is always allowed to protected resource.

Here is what I am doing:

My pom.xml has following dependencies:

    <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Resource server bring spring security with it, so no need to specify starter security -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

and my resource method in controller has following code:

   @PostMapping("/with-role-security")
   @PreAuthorize("hasAuthority('SCOPE_items.write')")
   public ResponseEntity<Order> placeOrderWithRoleBasedSecurity(@RequestBody Order order) 
   {

    var jwt = (Jwt)SecurityContextHolder.getContext().getAuthentication().getPrincipal();

    System.out.println("User : " + jwt.getSubject());
    System.out.println("SecurityContextHolder = " + SecurityContextHolder.getContext().getAuthentication());
    System.out.println("Received Order For " + order.getItems().size() + " Items");
    order.getItems().forEach((lineItem) -> System.out.println("Item: " + lineItem.getItemCode() +
            " Quantity: " + lineItem.getQuantity()));

    String orderId = UUID.randomUUID().toString();
    order.setOrderId(orderId);
    orders.put(orderId, order);
    return new ResponseEntity<>(order, HttpStatus.CREATED);
}

I am using scope "items.write" in PreAuthorize but access is allowed to method even if i generate token with scope "items.read"

Here is the log from 2 different token generated with different scope:

SecurityContextHolder = JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@25490a6c, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[SCOPE_items.write]]

SecurityContextHolder = JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@d3f0f246, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[SCOPE_items.read]]

As you can see scope is different in each token but access to above method is allowed with both token even when I specified that access to allowed to scope "items.write"

I have spend good amount of time in resolving this without any luck.

Any idea where things are going wrong?


Solution

  • You did not show your security configuration, so it's hard to tell with certainty, but you most probably forgot @EnableMethodSecurity.