Skip to content

Commit

Permalink
Merge pull request #54 from michalvavrik/feature/change-default-permi…
Browse files Browse the repository at this point in the history
…ssions-allowed-behavior

Detect permission constructor parameters based on formal method names match with a method secured by the @PermissionsAllowed annotation
  • Loading branch information
cescoffier authored Sep 23, 2024
2 parents 5be9ed6 + e96f1dd commit 8e9154b
Showing 1 changed file with 72 additions and 21 deletions.
93 changes: 72 additions & 21 deletions src/main/java/io/quarkus/security/PermissionsAllowed.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,50 @@

/**
* Constant value for {@link #params()} indicating that the constructor parameters of the {@link #permission()}
* should be autodetected. That is, each constructor argument data type must exactly match a data type of at least
* one argument of the secured method.
*
* For example consider following permission:
*
* should be autodetected based on formal parameter names. For example, consider following method secured with this
* annotation:
* <pre>
* {@code
* &#64;PermissionsAllowed(value = "resource:retrieve", permission = UserPermission.class)
* public Resource getResource(String param1, String param2, String param3) {
* // business logic
* }
* }
* </pre>
* The {@code getResource} method parameters {@code param1} and {@code param3} will be
* matched with the {@code UserPermission} constructor parameters {@code param1} and {@code param3}.
* <pre>
* {@code
* public class UserPermission extends Permission {
*
* private final User user;
*
* public UserPermission(String name, User user) {
* super(name);
* this.user = user;
* public UserPermission(String name, String param3, String param1) {
* ...
* }
*
* ...
* }
* </pre>
* }
* If no method parameter name matches the constructor parameter name, Quarkus checks names of fields and methods
* declared on the method parameter type.
* For example:
* <pre>
* {@code
* record BeanParam2(String param1, String param2) {}
* record BeanParam3(String param3) {}
* record BeanParam1(BeanParam2 beanParam2, BeanParam3 beanParam3) {
*
* Constructor parameter {@code user} is in fact object passed to a secured method.
* In the example below, {@code user1} parameter of the 'getResource' method is passed to the constructor.
* }
*
* <pre>
* &#64;PermissionsAllowed(permission = UserPermission.class, value = "resource")
* public Resource getResource(User user1) {
* // business logic
* &#64;PermissionsAllowed(value = "resource:retrieve", permission = UserPermission.class)
* public Resource getResource(BeanParam1 beanParam) {
* // business logic
* }
* </pre>
*
* Constructor parameters are always selected as the first secured method parameter with exactly matching data type.
* There is no limit to a reasonable number of parameters passed to the permission constructor this way.
* Please see {@link #params()} for more complex matching.
* }
* }
* </pre>
* In this example, resolution of the {@code param1} and {@code param3} formal parameters is unambiguous.
* For more complex scenarios, we suggest to specify {@link #params()} explicitly.
*/
String AUTODETECTED = "<<autodetected>>";

Expand Down Expand Up @@ -204,6 +216,45 @@
* <b>WARNING:</b> "params" attribute is only supported in the scenarios explicitly named in the Quarkus documentation.
* </p>
*
* Method parameter fields or methods can be passed to a Permission constructor as well.
* Consider the following secured method and its parameters:
* <pre>
* {@code
* &#64;PermissionsAllowed(permission = UserPermission.class, value = "resource", params = {"admin1.param1", "user1.param3"})
* public Resource getResource(User user, User user1, Admin admin, Admin admin1) {
* // business logic
* }
* class ResourceIdentity {
* private final String param1;
*
* public String getParam1() {
* return param1;
* }
* }
* class User extends ResourceIdentity {
* public String getParam3() {
* return "param3";
* }
* }
* class Admin extends ResourceIdentity { }
* }
* </pre>
*
* The corresponding {@code UserPermission} constructor would look like this:
*
* <pre>
* public class UserPermission extends Permission {
*
* public UserPermission(String name, String param1, String param3) {
* }
*
* ...
* }
* </pre>
*
* Here, the constructor parameter {@code param1} refers to the {@code admin1#param1} secured method parameter
* and the constructor parameter {@code param3} to the {@code user1#getParam3} secured method parameter.
*
* @see #AUTODETECTED
*
* @return constructor parameters passed to the {@link #permission()}
Expand Down

0 comments on commit 8e9154b

Please sign in to comment.