Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Meta-annotation Parameter Support #14480

Closed
Tracked by #14595
jzheaux opened this issue Jan 22, 2024 · 8 comments · Fixed by #14494
Closed
Tracked by #14595

Add Meta-annotation Parameter Support #14480

jzheaux opened this issue Jan 22, 2024 · 8 comments · Fixed by #14494
Assignees
Labels
in: core An issue in spring-security-core theme: partner-use-cases Use cases we identified with a partner (an established contributor) type: enhancement A general enhancement

Comments

@jzheaux
Copy link
Contributor

jzheaux commented Jan 22, 2024

It would be nice if Spring Security's method security meta-annotation support allowed for parameters.

For example, it would be nice to be able to do:

@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasAuthority('{value}')")
public @interface HasAuthority {
    String value();
}

Then, an application could do:

@HasAuthority("message:read")
public String method(...) {
}

The annotation expression should be able to handle method parameters, like @PreAuthorize already does:

@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("@myAuthzBean.authorizeParameter(#object)")
public @interface AuthorizeObject {
}

allowing an application to do:

@AuthorizeObject
public String method(Object object) {
}

Also, it should support passing method parameters through the custom annotation where:

@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("@openfga.check({user}, {relation}, {_object})")
public @interface Check {
    String user() default "authentication.name";
    String relation();
    String _object();
}

supports:

@GetMapping("/resource/{id}")
@Check(relation="'reader'", _object="'#id'")
public String method(String id) {
}
@jzheaux jzheaux added in: core An issue in spring-security-core type: enhancement A general enhancement labels Jan 22, 2024
@jzheaux jzheaux self-assigned this Jan 22, 2024
@kse-music
Copy link
Contributor

@jzheaux Can I do it?

@jzheaux
Copy link
Contributor Author

jzheaux commented Jan 25, 2024

Hi, @kse-music, thanks for the offer. I'm going to take care of this one for the moment since it is in a bit of flux (notice the recent changes in the description).

Please feel free to try out this branch to suggest improvements: https://github.com/jzheaux/spring-security/tree/gh-14480

@jzheaux jzheaux added the theme: partner-use-cases Use cases we identified with a partner (an established contributor) label Jan 25, 2024
@kse-music
Copy link
Contributor

Oh, according to the previous description, I thought that the meta-annotation parameter was used as an SPEL expression variable, but I didn't expect it used as a placeholder parsed property sources. @jzheaux

@jzheaux
Copy link
Contributor Author

jzheaux commented Jan 30, 2024

That's right, @kse-music. As I was doing some of my own research, I found that approach to be easier. The reason is that SpEL does not support nested variables, which would be needed in some setups.

Sorry for the confusion. If you are still interested, I'd love to have your help on this PR: #14494 once I have it out of draft.

@sbrannen
Copy link
Member

Very interesting idea! 👍

The reason is that SpEL does not support nested variables, which would be needed in some setups.

Would you mind providing a concrete example just for the sake of clarity?

@jzheaux
Copy link
Contributor Author

jzheaux commented Feb 5, 2024

Sure, @sbrannen. In the following arrangement:

@PreAuthorize("hasAuthority(#authority)")
public @interface HasAuthority {
    String authority();
}

// ...

@HasAuthority("#parameter")
public String method(String parameter) { // an existing Spring Security annotation feature 
   // ...
}

what happens is if method("value") is invoked, the set of variables handed to the evaluation context looks something like:

{ "#parameter" : value, "#authority" : "#parameter" }

I couldn't quite unravel how to get SpEL to resolve #authority by first resolving #parameter.

@efenderbosch-atg
Copy link

efenderbosch-atg commented Feb 21, 2024

Will this enhancement let me do something like this?

@PreAuthorize(
    """
    hasAuthority('PERM_FOO') and
    (#checkTenantId == false or #tenantId == authentication.principal.tenantId)
    """
)
annotation class HasFooPermission(val checkTenantId: Boolean = true)
@RestController
@SecurityRequirement(name = "Bearer Authentication")
@RequestMapping(value = "/foo", produces = [MediaType.APPLICATION_JSON_VALUE])
class FooController(private val service: FooService) {
    @HasFooPermission(checkTenantId = false)
    @GetMapping
    fun findAll(): ResponseEntity<List<Foo>> = service.findAll().ok()

    @HasFooPermission
    @GetMapping("{tenantId}")
    fun findAllByTenantId(tenantId: UUID): ResponseEntity<List<Foo>> = service.findAllByTenantId(tenantId).ok()
}

@kse-music
Copy link
Contributor

@efenderbosch-atg According to the current implementation, attribute method variables in custom annotations need to be quoted through curly braces like so:

@PreAuthorize(
    """
    hasAuthority('PERM_FOO') and
    ({checkTenantId} == false or #tenantId == authentication.principal.tenantId)
    """
)
annotation class HasFooPermission(val checkTenantId: Boolean = true)

jzheaux added a commit to jzheaux/spring-security that referenced this issue Feb 22, 2024
jzheaux added a commit to jzheaux/spring-security that referenced this issue Feb 23, 2024
jzheaux added a commit that referenced this issue Feb 23, 2024
jzheaux added a commit to jzheaux/spring-security that referenced this issue Feb 23, 2024
jzheaux added a commit that referenced this issue Feb 26, 2024
jzheaux added a commit that referenced this issue Apr 4, 2024
@jzheaux jzheaux moved this to Done in Spring Security Team Jul 23, 2024
jzheaux added a commit to jzheaux/spring-security that referenced this issue Sep 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core An issue in spring-security-core theme: partner-use-cases Use cases we identified with a partner (an established contributor) type: enhancement A general enhancement
Projects
Status: Done
4 participants