이 콘텐츠는 선택한 언어로 제공되지 않습니다.
Authorization of web endpoints
Abstract
Providing feedback on Red Hat build of Quarkus documentation 링크 복사링크가 클립보드에 복사되었습니다!
To report an error or to improve our documentation, log in to your Red Hat Jira account and submit an issue. If you do not have a Red Hat Jira account, then you will be prompted to create an account.
Procedure
- Click the following link to create a ticket.
- Enter a brief description of the issue in the Summary.
- Provide a detailed description of the issue or enhancement in the Description. Include a URL to where the issue occurs in the documentation.
- Clicking Submit creates and routes the issue to the appropriate documentation team.
Making open source more inclusive 링크 복사링크가 클립보드에 복사되었습니다!
Red Hat is committed to replacing problematic language in our code, documentation, and web properties. We are beginning with these four terms: master, slave, blacklist, and whitelist. Because of the enormity of this endeavor, these changes will be implemented gradually over several upcoming releases. For more details, see our CTO Chris Wright’s message.
Chapter 1. Authorization of web endpoints 링크 복사링크가 클립보드에 복사되었습니다!
Quarkus incorporates a pluggable web security layer. When security is active, the system performs a permission check on all HTTP requests to determine if they should proceed.
Using @PermitAll will not open a path if the path is restricted by the quarkus.http.auth. configuration. To ensure specific paths are accessible, appropriate configurations must be made within the Quarkus security settings.
If you use Jakarta RESTful Web Services, consider using quarkus.security.jaxrs.deny-unannotated-endpoints or quarkus.security.jaxrs.default-roles-allowed to set default security requirements instead of HTTP path-level matching because annotations can override these properties on an individual endpoint.
Authorization is based on user roles that the security provider provides. To customize these roles, a SecurityIdentityAugmentor can be created, see Security Identity Customization.
1.1. Authorization using configuration 링크 복사링크가 클립보드에 복사되었습니다!
Permissions are defined in the Quarkus configuration by permission sets, each specifying a policy for access control.
| Built-in policy | Description |
|---|---|
|
| This policy denies all users. |
|
| This policy permits all users. |
|
| This policy permits only authenticated users. |
You can define role-based policies that allow users with specific roles to access the resources.
Example of a role-based policy
quarkus.http.auth.policy.role-policy1.roles-allowed=user,admin
quarkus.http.auth.policy.role-policy1.roles-allowed=user,admin
- 1
- This defines a role-based policy that allows users with the
userandadminroles.
You can reference a custom policy by configuring the built-in permission sets that are defined in the application.properties file, as outlined in the following configuration example:
Example of policy configuration
- 1
- This permission references the default built-in
permitpolicy to allowGETmethods to/public. In this case, the demonstrated setting would not affect this example because this request is allowed anyway. - 2
- This permission references the built-in
denypolicy for/forbidden. It is an exact path match because it does not end with*. - 3
- This permission set references the previously defined policy.
roles1is an example name; you can call the permission sets whatever you want.
The exact path /forbidden in the example will not secure the /forbidden/ path. It is necessary to add a new exact path for the /forbidden/ path to ensure proper security coverage.
1.1.1. Custom HttpSecurityPolicy 링크 복사링크가 클립보드에 복사되었습니다!
Sometimes it might be useful to register your own named policy. You can get it done by creating application scoped CDI bean that implements the io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy interface like in the example below:
- 1
- Named HTTP Security policy will only be applied to requests matched by the
application.propertiespath matching rules.
Example of custom named HttpSecurityPolicy referenced from configuration file
quarkus.http.auth.permission.custom1.paths=/custom/* quarkus.http.auth.permission.custom1.policy=custom
quarkus.http.auth.permission.custom1.paths=/custom/*
quarkus.http.auth.permission.custom1.policy=custom
- 1
- Custom policy name must match the value returned by the
io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy.namemethod.
You can also create global HttpSecurityPolicy invoked on every request. Just do not implement the io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy.name method and leave the policy nameless.
1.1.2. Matching on paths and methods 링크 복사링크가 클립보드에 복사되었습니다!
Permission sets can also specify paths and methods as a comma-separated list. If a path ends with the * wildcard, the query it generates matches all sub-paths. Otherwise, it queries for an exact match and only matches that specific path:
quarkus.http.auth.permission.permit1.paths=/public*,/css/*,/js/*,/robots.txt quarkus.http.auth.permission.permit1.policy=permit quarkus.http.auth.permission.permit1.methods=GET,HEAD
quarkus.http.auth.permission.permit1.paths=/public*,/css/*,/js/*,/robots.txt
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD
- 1
- The
*wildcard at the end of the path matches zero or more path segments, but never any word starting from the/publicpath. For that reason, a path like/public-infois not matched by this pattern.
1.1.3. Matching a path but not a method 링크 복사링크가 클립보드에 복사되었습니다!
The request is rejected if it matches one or more permission sets based on the path but none of the required methods.
Given the preceding permission set, GET /public/foo would match both the path and method and therefore be allowed. In contrast, POST /public/foo would match the path but not the method, and, therefore, be rejected.
1.1.4. Matching multiple paths: longest path wins 링크 복사링크가 클립보드에 복사되었습니다!
Matching is always done on the "longest path wins" basis. Less specific permission sets are not considered if a more specific one has been matched:
Given the preceding permission set, GET /public/forbidden-folder/foo would match both permission sets' paths. However, because the longer path matches the path of the deny1 permission set, deny1 is chosen, and the request is rejected.
Subpath permissions precede root path permissions, as the deny1 versus permit1 permission example previously illustrated.
This rule is further exemplified by a scenario where subpath permission allows access to a public resource while the root path permission necessitates authorization.
1.1.5. Matching multiple sub-paths: longest path to the * wildcard wins 링크 복사링크가 클립보드에 복사되었습니다!
Previous examples demonstrated matching all sub-paths when a path concludes with the * wildcard.
This wildcard also applies in the middle of a path, representing a single path segment. It cannot be mixed with other path segment characters; thus, path separators always enclose the * wildcard, as seen in the /public/*/about-us path.
When several path patterns correspond to the same request path, the system selects the longest sub-path leading to the * wildcard. In this context, every path segment character is more specific than the * wildcard.
Here is a simple example:
quarkus.http.auth.permission.secured.paths=/api/*/detail quarkus.http.auth.permission.secured.policy=authenticated quarkus.http.auth.permission.public.paths=/api/public-product/detail quarkus.http.auth.permission.public.policy=permit
quarkus.http.auth.permission.secured.paths=/api/*/detail
quarkus.http.auth.permission.secured.policy=authenticated
quarkus.http.auth.permission.public.paths=/api/public-product/detail
quarkus.http.auth.permission.public.policy=permit
All paths secured with the authorization using configuration should be tested. Writing path patterns with multiple wildcards can be cumbersome. Please make sure paths are authorized as you intended.
In the following example, paths are ordered from the most specific to the least specific one:
Request path /one/two/three/four/five matches ordered from the most specific to the least specific path
The * wildcard at the end of the path matches zero or more path segments. The * wildcard placed anywhere else matches exactly one path segment.
1.1.6. Matching multiple paths: most specific method wins 링크 복사링크가 클립보드에 복사되었습니다!
When a path is registered with multiple permission sets, the permission sets explicitly specifying an HTTP method that matches the request take precedence. In this instance, the permission sets without methods only come into effect if the request method does not match permission sets with the method specification.
The preceding permission set shows that GET /public/foo matches the paths of both permission sets.However, it specifically aligns with the explicit method of the permit1 permission set.Therefore, permit1 is selected, and the request is accepted.
In contrast, PUT /public/foo does not match the method permissions of permit1. As a result, deny1 is activated, leading to the rejection of the request.
1.1.7. Matching multiple paths and methods: both win 링크 복사링크가 클립보드에 복사되었습니다!
Sometimes, the previously described rules allow multiple permission sets to win simultaneously. In that case, for the request to proceed, all the permissions must allow access. For this to happen, both must either have specified the method or have no method. Method-specific matches take precedence.
Given the preceding permission set, GET /api/foo would match both permission sets' paths, requiring both the user and admin roles.
1.1.8. Configuration properties to deny access 링크 복사링크가 클립보드에 복사되었습니다!
The following configuration settings alter the role-based access control (RBAC) denying behavior:
quarkus.security.jaxrs.deny-unannotated-endpoints=true|false-
If set to true, access is denied for all Jakarta REST endpoints by default. If a Jakarta REST endpoint has no security annotations, it defaults to the
@DenyAllbehavior. This helps you to avoid accidentally exposing an endpoint that is supposed to be secured. Defaults tofalse. quarkus.security.jaxrs.default-roles-allowed=role1,role2-
Defines the default role requirements for unannotated endpoints. The
**role is a special role that means any authenticated user. This cannot be combined withdeny-unannotated-endpointsbecausedenytakes effect instead. quarkus.security.deny-unannotated-members=true|false-
If set to true, the access is denied to all CDI methods and Jakarta REST endpoints that do not have security annotations but are defined in classes that contain methods with security annotations. Defaults to
false.
1.1.9. Disabling permissions 링크 복사링크가 클립보드에 복사되었습니다!
Permissions can be disabled at build time with an enabled property for each declared permission, such as:
quarkus.http.auth.permission.permit1.enabled=false quarkus.http.auth.permission.permit1.paths=/public/*,/css/*,/js/*,/robots.txt quarkus.http.auth.permission.permit1.policy=permit quarkus.http.auth.permission.permit1.methods=GET,HEAD
quarkus.http.auth.permission.permit1.enabled=false
quarkus.http.auth.permission.permit1.paths=/public/*,/css/*,/js/*,/robots.txt
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD
Permissions can be reenabled at runtime with a system property or environment variable, such as: -Dquarkus.http.auth.permission.permit1.enabled=true.
1.1.10. Permission paths and HTTP root path 링크 복사링크가 클립보드에 복사되었습니다!
The quarkus.http.root-path configuration property changes the http endpoint context path.
By default, quarkus.http.root-path is prepended automatically to configured permission paths then do not use a forward slash, for example:
quarkus.http.auth.permission.permit1.paths=public/*,css/*,js/*,robots.txt
quarkus.http.auth.permission.permit1.paths=public/*,css/*,js/*,robots.txt
This configuration is equivalent to the following:
quarkus.http.auth.permission.permit1.paths=${quarkus.http.root-path}/public/*,${quarkus.http.root-path}/css/*,${quarkus.http.root-path}/js/*,${quarkus.http.root-path}/robots.txt
quarkus.http.auth.permission.permit1.paths=${quarkus.http.root-path}/public/*,${quarkus.http.root-path}/css/*,${quarkus.http.root-path}/js/*,${quarkus.http.root-path}/robots.txt
A leading slash changes how the configured permission path is interpreted. The configured URL is used as-is, and paths are not adjusted if the value of quarkus.http.root-path changes.
Example:
quarkus.http.auth.permission.permit1.paths=/public/*,css/*,js/*,robots.txt
quarkus.http.auth.permission.permit1.paths=/public/*,css/*,js/*,robots.txt
This configuration only impacts resources served from the fixed or static URL, /public, which might not match your application resources if quarkus.http.root-path has been set to something other than /.
For more information, see Path Resolution in Quarkus.
1.1.11. Map SecurityIdentity roles 링크 복사링크가 클립보드에 복사되었습니다!
Winning role-based policy can map the SecurityIdentity roles to the deployment-specific roles. These roles are then applicable for endpoint authorization by using the @RolesAllowed annotation.
quarkus.http.auth.policy.admin-policy1.roles.admin=Admin1 quarkus.http.auth.permission.roles1.paths=/* quarkus.http.auth.permission.roles1.policy=admin-policy1
quarkus.http.auth.policy.admin-policy1.roles.admin=Admin1
quarkus.http.auth.permission.roles1.paths=/*
quarkus.http.auth.permission.roles1.policy=admin-policy1
- 1
- Map the
adminrole toAdmin1role. TheSecurityIdentitywill have bothadminandAdmin1roles.
1.2. Authorization using annotations 링크 복사링크가 클립보드에 복사되었습니다!
Red Hat build of Quarkus includes built-in security to allow for Role-Based Access Control (RBAC) based on the common security annotations @RolesAllowed, @DenyAll, @PermitAll on REST endpoints and CDI beans.
| Annotation type | Description |
|---|---|
|
| Specifies that no security roles are allowed to invoke the specified methods. |
|
| Specifies that all security roles are allowed to invoke the specified methods.
|
|
| Specifies the list of security roles allowed to access methods in an application.
As an equivalent to |
The following SubjectExposingResource example demonstrates an endpoint that uses both Jakarta REST and Common Security annotations to describe and secure its endpoints.
SubjectExposingResource example
- 1
- The
/subject/securedendpoint requires an authenticated user with the granted "Tester" role through the use of the@RolesAllowed("Tester")annotation. - 2
- The endpoint obtains the user principal from the Jakarta REST
SecurityContext. This returnsnon-nullfor a secured endpoint. - 3
- The
/subject/unsecuredendpoint allows for unauthenticated access by specifying the@PermitAllannotation. - 4
- The call to obtain the user principal returns
nullif the caller is unauthenticated andnon-nullif the caller is authenticated. - 5
- The
/subject/deniedendpoint declares the@DenyAllannotation, disallowing all direct access to it as a REST method, regardless of the user calling it. The method is still invokable internally by other methods in this class.
If you plan to use standard security annotations on the IO thread, review the information in Proactive Authentication.
The @RolesAllowed annotation value supports property expressions including default values and nested property expressions. Configuration properties used with the annotation are resolved at runtime.
| Annotation | Value explanation |
|---|---|
|
|
The endpoint allows users with the role denoted by the value of the |
|
| An example showing that the value can contain multiple variables. |
|
|
A default value demonstration. The required role is denoted by the value of the |
Example of a property expressions usage in the @RolesAllowed annotation
Subject access control example
- 1
- The
@RolesAllowedannotation value is set to the value ofAdministrator. - 2
- This
/subject/software-testerendpoint requires an authenticated user that has been granted the role of "Software-Tester". It is possible to use multiple expressions in the role definition. - 3
- This
/subject/userendpoint requires an authenticated user that has been granted the role "User" through the use of the@RolesAllowed("${customer:User}")annotation because we did not set the configuration propertycustomer. - 4
- In production, this
/subject/securedendpoint requires an authenticated user with theUserrole. In development mode, it allows any authenticated user. - 5
- Property expression
all-roleswill be treated as a collection typeList, therefore, the endpoint will be accessible for rolesAdministrator,Software,TesterandUser.
1.2.1. Permission annotation 링크 복사링크가 클립보드에 복사되었습니다!
Quarkus also provides the io.quarkus.security.PermissionsAllowed annotation, which authorizes any authenticated user with the given permission to access the resource. This annotation is an extension of the common security annotations and checks the permissions granted to a SecurityIdentity instance.
Example of endpoints secured with the @PermissionsAllowed annotation
- 1
- The resource method
createOrUpdateis only accessible for a user with bothcreateandupdatepermissions. - 2
- By default, at least one of the permissions specified through one annotation instance is required. You can require all permissions by setting
inclusive=true. Both resource methodscreateOrUpdatehave equal authorization requirements. - 3
- Access is granted to
getItemifSecurityIdentityhas eitherreadpermission orseepermission and one of theallordetailactions. - 4
- You can use your preferred
java.security.Permissionimplementation. By default, string-based permission is performed byio.quarkus.security.StringPermission. - 5
- Permissions are not beans, therefore the only way to obtain bean instances is programmatically by using
Arc.container().
If you plan to use the @PermissionsAllowed on the IO thread, review the information in Proactive Authentication.
@PermissionsAllowed is not repeatable on the class level due to a limitation with Quarkus interceptors. For more information, see the Repeatable interceptor bindings section of the Quarkus "CDI reference" guide.
The easiest way to add permissions to a role-enabled SecurityIdentity instance is to map roles to permissions. Use Authorization using configuration to grant the required SecurityIdentity permissions for CRUDResource endpoints to authenticated requests, as outlined in the following example:
- 1
- Add the permission
seeand the actionallto theSecurityIdentityinstance of theuserrole. Similarly, for the@PermissionsAllowedannotation,io.quarkus.security.StringPermissionis used by default. - 2
- Permissions
create,update, andreadare mapped to the roleadmin. - 3
- The role policy
role-policy1allows only authenticated requests to access/crud/modifyand/crud/idsub-paths. For more information about the path-matching algorithm, see Matching multiple paths: longest path wins later in this guide. - 4
- You can specify a custom implementation of the
java.security.Permissionclass. Your custom class must define exactly one constructor that accepts the permission name and optionally some actions, for example,Stringarray. In this scenario, the permissionlistis added to theSecurityIdentityinstance asnew CustomPermission("list").
You can also create a custom java.security.Permission class with additional constructor parameters. These additional parameters get matched with arguments of the method annotated with the @PermissionsAllowed annotation. Later, Quarkus instantiates your custom permission with actual arguments, with which the method annotated with the @PermissionsAllowed has been invoked.
Example of a custom java.security.Permission class that accepts additional arguments
- 1
- There must be exactly one constructor of a custom
Permissionclass. The first parameter is always considered to be a permission name and must be of typeString. Quarkus can optionally pass permission actions to the constructor. For this to happen, declare the second parameter asString[].
The LibraryPermission class permits access to the current or parent library if SecurityIdentity is allowed to perform one of the required actions, for example, read, write, or list.
The following example shows how the LibraryPermission class can be used:
- 1
- The formal parameter
updateis identified as the firstLibraryparameter and gets passed to theLibraryPermissionclass. However, theLibraryPermissionmust be instantiated each time theupdateLibrarymethod is invoked. - 2
- Here, the first
Libraryparameter ismigrate; therefore, thelibraryparameter gets marked explicitly throughPermissionsAllowed#params. The permission constructor and the annotated method must have the parameterlibraryset; otherwise, validation fails.
Example of a resource secured with the LibraryPermission
Similarly to the CRUDResource example, the following example shows how you can grant a user with the admin role permissions to update MediaLibrary:
quarkus.http.auth.policy.role-policy3.permissions.admin=media-library:list,media-library:read,media-library:write quarkus.http.auth.policy.role-policy3.permission-class=org.acme.library.MediaLibraryPermission quarkus.http.auth.permission.roles3.paths=/library/* quarkus.http.auth.permission.roles3.policy=role-policy3
quarkus.http.auth.policy.role-policy3.permissions.admin=media-library:list,media-library:read,media-library:write
quarkus.http.auth.policy.role-policy3.permission-class=org.acme.library.MediaLibraryPermission
quarkus.http.auth.permission.roles3.paths=/library/*
quarkus.http.auth.permission.roles3.policy=role-policy3
- 1
- Grants the permission
media-library, which permitsread,write, andlistactions. BecauseMediaLibraryis theTvLibraryclass parent, a user with theadminrole is also permitted to modifyTvLibrary.
The /library/* path can be tested from a Keycloak provider Dev UI page, because the user alice which is created automatically by the Dev Services for Keycloak has an admin role.
The examples provided so far demonstrate role-to-permission mapping. It is also possible to programmatically add permissions to the SecurityIdentity instance. In the following example, SecurityIdentity is customized to add the same permission that was previously granted with the HTTP role-based policy.
Example of adding the LibraryPermission programmatically to SecurityIdentity
- 1
- The permission
media-librarythat was created can performread,write, andlistactions. BecauseMediaLibraryis theTvLibraryclass parent, a user with theadminrole is also permitted to modifyTvLibrary. - 2
- You can add a permission checker through
io.quarkus.security.runtime.QuarkusSecurityIdentity.Builder#addPermissionChecker.
Annotation-based permissions do not work with custom Jakarta REST SecurityContexts because there are no permissions in jakarta.ws.rs.core.SecurityContext.