1

Currently I am writing my own custom @PreAuthorize annotation. My case is as follows,

  1. I am running my authorization KeyCloak server that holds the user details, roles and permission
  2. After Validation, I have stored the permission details in GrantedAuthority as follows "{rsname}:GET", "{rsname}:POST" ...

KeyCloak JWT permission structure:

"authorization": {
    "permissions": [
      {
        "scopes": [
          "GET",
          "DELETE",
          "POST"
        ],
        "rsid": "6ae9895f-3766-464f-82c4-44f598ec2a93",
        "rsname": "record"
      }
    ]
  }
  1. while using @PreAuthorize annotation in controller instead of hardcoding the resource name and scopes, we have to generalize it by getting the details from application.property we have achieved it as follows,

application.property:

auth:
  data:
    name1: record
    name2: device 

Property Detail Component class:

@ConfigurationProperties(prefix = "auth")
@Component
public class SecurityProperty {
    private Map<String, String> data;
    ....
}

Controller:

@RequestMapping (method = RequestMethod.GET,value = "/api/records",
        produces = {"application/json"})
@PreAuthorize ("hasAuthority (@securityProperty.getData(). get('name1') "
    + "+ ': GET')")
ResponseEntity<List<SomeDTO>> getRecords() {
        ...Some Logic
}


@RequestMapping(method = RequestMethod.GET,value = "/api/devices",
        produces = { "application/json" })
@PreAuthorize("hasAuthority(@securityProperty.getResources().get('name2') "
    + "+ ':GET')")
ResponseEntity<List<SomeDTO>> getDevices() {
        ...Some Logic
}
  1. So far this is working fine. Since we are creating big project we don't want to write this lengthy @PreAuthorize(XXXX) annotation so decided to create custom annotation that uses the @PreAuthorize. We have created @CustomPreAuthorize as below
@Retention(RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@PreAuthorize("hasAuthority(@securityProperty.getResources().get(#resource)"
        + ".concat(':GET'))")
public @interface CustomPreAuthorize {
    String resource();
}

And used this in controller

@RequestMapping (method = RequestMethod.GET,value = "/api/devices",
        produces = {"application/json"})
@CustomPreAuthorize (resource = "name2")
ResponseEntity<List<SomeDTO>> getDevices() {
        ...Some Logic
}

Issue:

  1. When I used like this when the API is called I am getting the following error
Failed to evaluate expression 'hasAuthority(@securityProperty.getResources().get(#resource).concat(':GET'))"
  1. So far what I understood is like the resource and scope are not getting recognized in the @PreAuthorize annotation level. Is it possible to read the values like this or is there any alternatives available?
Sri hari
  • 9
  • 4
  • I hope you get answer to this question, i saw it on Spring security forum as well where they just closed it instead of answering it. I have also tried the exact scenario where reading the properties from within the annotation is not working. May be there are other alternatives which somebody someday will post here, till then have to proceed with ugly code repetition at each method – Hashir Labs Dec 06 '22 at 09:40

1 Answers1

0

Since there is no reply yet for the required fix, for now we have fixed this by adding the Aspect for the annotation and proceed with manual authority check using the SecurityContextHolder.

@Before("@annotation(CustomPreAuthorize)")
void annotationPointcut() {
    //business logic
}

We will check for the other solutions actively and post if we achieve it in more better way.

Sri hari
  • 9
  • 4