diff --git a/_generated-doc/main/config/quarkus-all-config.adoc b/_generated-doc/main/config/quarkus-all-config.adoc index 3e50d37b2a..fec5abdb8d 100644 --- a/_generated-doc/main/config/quarkus-all-config.adoc +++ b/_generated-doc/main/config/quarkus-all-config.adoc @@ -62865,6 +62865,8 @@ a| [[quarkus-quartz_quarkus-quartz-thread-count]] [.property-path]##link:#quarku -- The size of scheduler thread pool. This will initialize the number of worker threads in the pool. +It's important to bear in mind that Quartz threads are not used to execute scheduled methods, instead the regular Quarkus thread pool is used by default. See also `quarkus.quartz.run-blocking-scheduled-method-on-quartz-thread`. + ifdef::add-copy-button-to-env-var[] Environment variable: env_var_with_copy_button:+++QUARKUS_QUARTZ_THREAD_COUNT+++[] @@ -62874,7 +62876,7 @@ Environment variable: `+++QUARKUS_QUARTZ_THREAD_COUNT+++` endif::add-copy-button-to-env-var[] -- |int -|`25` +|`10` a| [[quarkus-quartz_quarkus-quartz-thread-priority]] [.property-path]##link:#quarkus-quartz_quarkus-quartz-thread-priority[`quarkus.quartz.thread-priority`]## @@ -72399,6 +72401,23 @@ endif::add-copy-button-to-env-var[] |boolean |`true` +a|icon:lock[title=Fixed at build time] [[quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-operation-summary]] [.property-path]##link:#quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-operation-summary[`quarkus.smallrye-openapi.auto-add-operation-summary`]## + +[.description] +-- +This will automatically add a summary to operations based on the Java method name. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_SMALLRYE_OPENAPI_AUTO_ADD_OPERATION_SUMMARY+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_SMALLRYE_OPENAPI_AUTO_ADD_OPERATION_SUMMARY+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`true` + a|icon:lock[title=Fixed at build time] [[quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-server]] [.property-path]##link:#quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-server[`quarkus.smallrye-openapi.auto-add-server`]## [.description] diff --git a/_generated-doc/main/config/quarkus-quartz.adoc b/_generated-doc/main/config/quarkus-quartz.adoc index 7030b2a79d..bd14b32c16 100644 --- a/_generated-doc/main/config/quarkus-quartz.adoc +++ b/_generated-doc/main/config/quarkus-quartz.adoc @@ -247,6 +247,8 @@ a| [[quarkus-quartz_quarkus-quartz-thread-count]] [.property-path]##link:#quarku -- The size of scheduler thread pool. This will initialize the number of worker threads in the pool. +It's important to bear in mind that Quartz threads are not used to execute scheduled methods, instead the regular Quarkus thread pool is used by default. See also `quarkus.quartz.run-blocking-scheduled-method-on-quartz-thread`. + ifdef::add-copy-button-to-env-var[] Environment variable: env_var_with_copy_button:+++QUARKUS_QUARTZ_THREAD_COUNT+++[] @@ -256,7 +258,7 @@ Environment variable: `+++QUARKUS_QUARTZ_THREAD_COUNT+++` endif::add-copy-button-to-env-var[] -- |int -|`25` +|`10` a| [[quarkus-quartz_quarkus-quartz-thread-priority]] [.property-path]##link:#quarkus-quartz_quarkus-quartz-thread-priority[`quarkus.quartz.thread-priority`]## diff --git a/_generated-doc/main/config/quarkus-quartz_quarkus.quartz.adoc b/_generated-doc/main/config/quarkus-quartz_quarkus.quartz.adoc index 7030b2a79d..bd14b32c16 100644 --- a/_generated-doc/main/config/quarkus-quartz_quarkus.quartz.adoc +++ b/_generated-doc/main/config/quarkus-quartz_quarkus.quartz.adoc @@ -247,6 +247,8 @@ a| [[quarkus-quartz_quarkus-quartz-thread-count]] [.property-path]##link:#quarku -- The size of scheduler thread pool. This will initialize the number of worker threads in the pool. +It's important to bear in mind that Quartz threads are not used to execute scheduled methods, instead the regular Quarkus thread pool is used by default. See also `quarkus.quartz.run-blocking-scheduled-method-on-quartz-thread`. + ifdef::add-copy-button-to-env-var[] Environment variable: env_var_with_copy_button:+++QUARKUS_QUARTZ_THREAD_COUNT+++[] @@ -256,7 +258,7 @@ Environment variable: `+++QUARKUS_QUARTZ_THREAD_COUNT+++` endif::add-copy-button-to-env-var[] -- |int -|`25` +|`10` a| [[quarkus-quartz_quarkus-quartz-thread-priority]] [.property-path]##link:#quarkus-quartz_quarkus-quartz-thread-priority[`quarkus.quartz.thread-priority`]## diff --git a/_generated-doc/main/config/quarkus-smallrye-openapi.adoc b/_generated-doc/main/config/quarkus-smallrye-openapi.adoc index f44ac38fe5..eb8aa2f810 100644 --- a/_generated-doc/main/config/quarkus-smallrye-openapi.adoc +++ b/_generated-doc/main/config/quarkus-smallrye-openapi.adoc @@ -211,6 +211,23 @@ endif::add-copy-button-to-env-var[] |boolean |`true` +a|icon:lock[title=Fixed at build time] [[quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-operation-summary]] [.property-path]##link:#quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-operation-summary[`quarkus.smallrye-openapi.auto-add-operation-summary`]## + +[.description] +-- +This will automatically add a summary to operations based on the Java method name. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_SMALLRYE_OPENAPI_AUTO_ADD_OPERATION_SUMMARY+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_SMALLRYE_OPENAPI_AUTO_ADD_OPERATION_SUMMARY+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`true` + a|icon:lock[title=Fixed at build time] [[quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-server]] [.property-path]##link:#quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-server[`quarkus.smallrye-openapi.auto-add-server`]## [.description] diff --git a/_generated-doc/main/config/quarkus-smallrye-openapi_quarkus.smallrye-openapi.adoc b/_generated-doc/main/config/quarkus-smallrye-openapi_quarkus.smallrye-openapi.adoc index f44ac38fe5..eb8aa2f810 100644 --- a/_generated-doc/main/config/quarkus-smallrye-openapi_quarkus.smallrye-openapi.adoc +++ b/_generated-doc/main/config/quarkus-smallrye-openapi_quarkus.smallrye-openapi.adoc @@ -211,6 +211,23 @@ endif::add-copy-button-to-env-var[] |boolean |`true` +a|icon:lock[title=Fixed at build time] [[quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-operation-summary]] [.property-path]##link:#quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-operation-summary[`quarkus.smallrye-openapi.auto-add-operation-summary`]## + +[.description] +-- +This will automatically add a summary to operations based on the Java method name. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_SMALLRYE_OPENAPI_AUTO_ADD_OPERATION_SUMMARY+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_SMALLRYE_OPENAPI_AUTO_ADD_OPERATION_SUMMARY+++` +endif::add-copy-button-to-env-var[] +-- +|boolean +|`true` + a|icon:lock[title=Fixed at build time] [[quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-server]] [.property-path]##link:#quarkus-smallrye-openapi_quarkus-smallrye-openapi-auto-add-server[`quarkus.smallrye-openapi.auto-add-server`]## [.description] diff --git a/_versions/main/guides/datasource.adoc b/_versions/main/guides/datasource.adoc index 887a9ca125..974157657f 100644 --- a/_versions/main/guides/datasource.adoc +++ b/_versions/main/guides/datasource.adoc @@ -213,7 +213,7 @@ Read <> for suggestions re * PostgreSQL - `quarkus-jdbc-postgresql` ifndef::no-quarkiverse[] * Other JDBC extensions, such as link:https://github.com/quarkiverse/quarkus-jdbc-sqlite[SQLite] and its link:https://docs.quarkiverse.io/quarkus-jdbc-sqlite/dev/index.html[documentation], can be found in the https://github.com/quarkiverse[Quarkiverse]. -ifndef::no-quarkiverse[] +endif::no-quarkiverse[] + For example, to add the PostgreSQL driver dependency: + diff --git a/_versions/main/guides/dev-ui.adoc b/_versions/main/guides/dev-ui.adoc index 75c4d41b05..dedfcef592 100644 --- a/_versions/main/guides/dev-ui.adoc +++ b/_versions/main/guides/dev-ui.adoc @@ -747,7 +747,7 @@ import 'qui-ide-link'; [${sourceClassNameFull}]; + lineNumber='${sourceLineNumber}'>[${sourceClassNameFull}]; ---- https://github.com/quarkusio/quarkus/blob/582f1f78806d2268885faea7aa8f5a4d2b3f5b98/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-server-log.js#L315[Example code] diff --git a/_versions/main/guides/security-authorize-web-endpoints-reference.adoc b/_versions/main/guides/security-authorize-web-endpoints-reference.adoc index f666e782d8..b2ce601cfc 100644 --- a/_versions/main/guides/security-authorize-web-endpoints-reference.adoc +++ b/_versions/main/guides/security-authorize-web-endpoints-reference.adoc @@ -1055,8 +1055,85 @@ Because `MediaLibrary` is the `TvLibrary` class parent, a user with the `admin` CAUTION: Annotation-based permissions do not work with custom xref:security-customization.adoc#jaxrs-security-context[Jakarta REST SecurityContexts] because there are no permissions in `jakarta.ws.rs.core.SecurityContext`. +[[permission-checker]] +==== Create permission checkers + +By default, `SecurityIdentity` must be configured with permissions which can be used to check if this identity passes `@PermissionAllowed` authorization restrictions. +Alternatively, you can use a `@PermissionChecker` annotation to mark any CDI bean method as a permission checker. +The `@PermissionChecker` annotation value should match required permission declared by the `@PermissionsAllowed` annotation value. +For example, a permission checker can be created like this: + +[source,java] +---- +package org.acme.security.rest.resource; + +import io.quarkus.security.PermissionChecker; +import io.quarkus.security.PermissionsAllowed; +import io.quarkus.security.identity.SecurityIdentity; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; + +import org.jboss.resteasy.reactive.RestForm; +import org.jboss.resteasy.reactive.RestPath; + +@Path("/project") +public class ProjectResource { + + @PermissionsAllowed("rename-project") <1> + @POST + public void renameProject(@RestPath String projectName, @RestForm String newName) { + Project project = Project.findByName(projectName); + project.name = newName; + } + + @PermissionChecker("rename-project") <2> + boolean canRenameProject(SecurityIdentity identity, String projectName) { <3> <4> + var principalName = identity.getPrincipal().getName(); + var user = User.getUserByName(principalName); + return userOwnsProject(projectName, user); + } +} +---- +<1> The permission required to access the `ProjectResource#renameProject` is the `rename-project` permission. +<2> The `ProjectResource#canRenameProject` method authorizes access to the `ProjectResource#renameProject` endpoint. +<3> The `SecurityIdentity` instance can be injected into any permission checker method. +<4> In this example, the `rename-project` permission checker is declared on the same resource. +However, there is no restriction on where this permission checker can be declared as demonstrated in the next example. + +NOTE: Permission checker methods can be declared on a normal scoped CDI bean or on a `@Singleton` bean. +The `@Dependent` CDI bean scope is currently not supported. + +The permission checker above requires the `SecurityIdentity` instance to authorize the `renameProject` endpoint. +Instead of declaring the `rename-project` permission checker directly on the resource, you can declare it on any CDI bean like in this example: + +[source,java] +---- +package org.acme.security.rest.resource; + +import io.quarkus.security.PermissionChecker; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped <1> +public class ProjectPermissionChecker { + + @PermissionChecker("rename-project") + boolean canRenameProject(String projectName, SecurityIdentity identity) { <2> + var principalName = identity.getPrincipal().getName(); + var user = User.getUserByName(principalName); + return userOwnsProject(projectName, user); + } + +} +---- +<1> A CDI bean with the permission checker must be either a normal scoped bean or a `@Singleton` bean. +<2> The permission checker method must return either `boolean` or `Uni`. Private checker methods are not supported. + +TIP: Permission checks run by default on event loops whenever possible. +Annotate a permission checker method with the `io.smallrye.common.annotation.Blocking` annotation if you want to run the check on a worker thread. + [[permission-meta-annotation]] -=== Create permission meta-annotations +==== Create permission meta-annotations `@PermissionsAllowed` can also be used in meta-annotations. For example, a new `@CanWrite` security annotation can be created like this: @@ -1080,7 +1157,7 @@ public @interface CanWrite { <1> Any method or class annotated with the `@CanWrite` annotation is secured with this `@PermissionsAllowed` annotation instance. [[permission-bean-params]] -=== Pass `@BeanParam` parameters into a custom permission +==== Pass `@BeanParam` parameters into a custom permission Quarkus can map fields of a secured method parameters to a custom permission constructor parameters. You can use this feature to pass `jakarta.ws.rs.BeanParam` parameters into your custom permission. @@ -1096,10 +1173,9 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @Path("/hello") -public class SimpleResource { +public class HelloResource { - @PermissionsAllowed(value = "say:hello", permission = BeanParamPermission.class, - params = "beanParam.securityContext.userPrincipal.name") <1> + @PermissionsAllowed(value = "say-hello", params = "beanParam.securityContext.userPrincipal.name") <1> @GET public String sayHello(@BeanParam SimpleBeanParam beanParam) { return "Hello from " + beanParam.uriInfo.getPath(); @@ -1107,9 +1183,9 @@ public class SimpleResource { } ---- -<1> The `params` annotation attribute specifies that user principal name should be passed to the `BeanParamPermission` constructor. -Other `BeanParamPermission` constructor parameters like `customAuthorizationHeader` and `query` are matched automatically. -Quarkus identifies the `BeanParamPermission` constructor parameters among `beanParam` fields and their public accessors. +<1> The `params` annotation attribute specifies that user principal name should be passed to the `BeanParamPermissionChecker#canSayHello` method. +Other `BeanParamPermissionChecker#canSayHello` method parameters like `customAuthorizationHeader` and `query` are matched automatically. +Quarkus identifies the `BeanParamPermissionChecker#canSayHello` method parameters among `beanParam` fields and their public accessors. To avoid ambiguous resolution, automatic detection only works for the `beanParam` fields. For that reason, we had to specify path to the user principal name explicitly. @@ -1155,47 +1231,31 @@ public class SimpleBeanParam { <3> The `customAuthorizationHeader` field is not public, therefore Quarkus access this field with the `customAuthorizationHeader` accessor. That is particularly useful with Java records, where generated accessors are not prefixed with `get`. -Here is an example of the `BeanParamPermission` permission that checks user principal, custom header and query parameter: +Here is an example of a `@PermissionChecker` method that checks the `say-hello` permission based on a user principal, custom header and query parameter: [source,java] ---- package org.acme.security.permission; -import java.security.Permission; - -public class BeanParamPermission extends Permission { - - private final String actions; - - public BeanParamPermission(String permissionName, String customAuthorizationHeader, String name, String query) { - super(permissionName); - this.actions = computeActions(customAuthorizationHeader, name, query); - } +import jakarta.enterprise.context.ApplicationScoped; +import io.quarkus.security.PermissionChecker; - @Override - public boolean implies(Permission p) { - boolean nameMatches = getName().equals(p.getName()); - boolean actionMatches = actions.equals(p.getActions()); - return nameMatches && actionMatches; - } +@ApplicationScoped +public class BeanParamPermissionChecker { - private static String computeActions(String customAuthorizationHeader, String name, String query) { + @PermissionChecker("say-hello") + boolean canSayHello(String customAuthorizationHeader, String name, String query) { boolean queryParamAllowedForPermissionName = checkQueryParams(query); boolean usernameWhitelisted = isUserNameWhitelisted(name); boolean customAuthorizationMatches = checkCustomAuthorization(customAuthorizationHeader); - var isAuthorized = queryParamAllowedForPermissionName && usernameWhitelisted && customAuthorizationMatches; - if (isAuthorized) { - return "hello"; - } else { - return "goodbye"; - } + return queryParamAllowedForPermissionName && usernameWhitelisted && customAuthorizationMatches; } ... } ---- -NOTE: You can pass `@BeanParam` directly into a custom permission constructor and access its fields programmatically in the constructor instead. +NOTE: You can pass `@BeanParam` directly into a `@PermissionChecker` method and access its fields programmatically. Ability to reference `@BeanParam` fields with the `@PermissionsAllowed#params` attribute is useful when you have multiple differently structured `@BeanParam` classes. == References