Skip to content

Commit

Permalink
Merge branch 'quarkusio:main' into #34477
Browse files Browse the repository at this point in the history
  • Loading branch information
Eng-Fouad authored Jul 6, 2023
2 parents c15f337 + 6fde192 commit fbb40fc
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 12 deletions.
6 changes: 3 additions & 3 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<microprofile-rest-client.version>3.0.1</microprofile-rest-client.version>
<microprofile-jwt.version>2.1</microprofile-jwt.version>
<microprofile-lra.version>2.0</microprofile-lra.version>
<microprofile-openapi.version>3.1</microprofile-openapi.version>
<microprofile-openapi.version>3.1.1</microprofile-openapi.version>
<smallrye-common.version>2.1.0</smallrye-common.version>
<smallrye-config.version>3.3.0</smallrye-config.version>
<smallrye-health.version>4.0.2</smallrye-health.version>
Expand All @@ -63,7 +63,7 @@
<smallrye-graphql.version>2.2.1</smallrye-graphql.version>
<smallrye-opentracing.version>3.0.3</smallrye-opentracing.version>
<smallrye-fault-tolerance.version>6.2.4</smallrye-fault-tolerance.version>
<smallrye-jwt.version>4.2.1</smallrye-jwt.version>
<smallrye-jwt.version>4.3.0</smallrye-jwt.version>
<smallrye-context-propagation.version>2.1.0</smallrye-context-propagation.version>
<smallrye-reactive-streams-operators.version>1.0.13</smallrye-reactive-streams-operators.version>
<smallrye-reactive-types-converter.version>3.0.0</smallrye-reactive-types-converter.version>
Expand Down Expand Up @@ -204,7 +204,7 @@
<log4j2-jboss-logmanager.version>1.1.1.Final</log4j2-jboss-logmanager.version>
<log4j2-api.version>2.20.0</log4j2-api.version>
<log4j-jboss-logmanager.version>1.3.0.Final</log4j-jboss-logmanager.version>
<avro.version>1.11.1</avro.version>
<avro.version>1.11.2</avro.version>
<apicurio-registry.version>2.4.3.Final</apicurio-registry.version>
<apicurio-common-rest-client.version>0.1.17.Final</apicurio-common-rest-client.version> <!-- must be the version Apicurio Registry uses -->
<testcontainers.version>1.18.3</testcontainers.version> <!-- Make sure to also update docker-java.version to match its needs -->
Expand Down
2 changes: 1 addition & 1 deletion build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
<version>4.0.12</version>
<version>4.0.13</version>
</dependency>
</dependencies>
</plugin>
Expand Down
22 changes: 19 additions & 3 deletions docs/src/main/asciidoc/security-jwt.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,19 @@ public class TestJWTCallerPrincipalFactory extends JWTCallerPrincipalFactory {
}
----

=== Blocking calls

`quarkus-smallrye-jwt` extension uses link:https://github.com/smallrye/smallrye-jwt[SmallRye JWT] library which is currently not reactive.

What it means from the perspective of `quarkus-smallrye-jwt` which operates as part of the reactive Quarkus security architecture, is that an IO thread entering the link:https://github.com/smallrye/smallrye-jwt[SmallRye JWT] verification or decryption code might block in one of the following cases:

* Default key resolver refreshes `JsonWebKey` set containing the keys which involves a remote call to the OIDC endpoint
* Custom key resolver such as `AWS Application Load Balancer` (`ALB`) key resolver, resolves the keys against the AWS ALB key endpoint using the current token's key identifier header value

In such cases, if the connections are slow, for example, it may take more than 3 seconds to get a response from the key endpoint, the current event loop thread will most likely block.

To prevent it, set `quarkus.smallrye-jwt.blocking-authentication=true`.

=== Token Propagation

Please see the xref:security-openid-connect-client.adoc#token-propagation[Token Propagation] section about the Bearer access token propagation to the downstream services.
Expand Down Expand Up @@ -1048,10 +1061,13 @@ SmallRye JWT provides more properties which can be used to customize the token p
|smallrye.jwt.verify.key.location|NONE|Location of the verification key which can point to both public and secret keys. Secret keys can only be in the JWK format. Note that 'mp.jwt.verify.publickey.location' will be ignored if this property is set.
|smallrye.jwt.verify.algorithm||Signature algorithm. This property should only be used for setting a required symmetric algorithm such as `HS256`. It is deprecated for setting asymmetric algorithms such as `ES256` - use 'mp.jwt.verify.publickey.algorithm' instead.
|smallrye.jwt.verify.key-format|`ANY`|Set this property to a specific key format such as `PEM_KEY`, `PEM_CERTIFICATE`, `JWK` or `JWK_BASE64URL` to optimize the way the verification key is loaded.
|smallrye.jwt.verify.key-provider|`DEFAULT`|By default, PEM, JWK or JWK key sets can be read from the local file system or fetched from URIs as required by MicroProfile JWT specification. Set this property to `AWS_ALB` to support an AWS Application Load Balancer verification key resolution.
|smallrye.jwt.verify.relax-key-validation|false|Relax the validation of the verification keys, setting this property to `true` will allow public RSA keys with the length less than 2048 bit.
|smallrye.jwt.verify.certificate-thumbprint|false|If this property is enabled then a signed token must contain either 'x5t' or 'x5t#S256' X509Certificate thumbprint headers. Verification keys can only be in JWK or PEM Certificate key formats in this case. JWK keys must have a 'x5c' (Base64-encoded X509Certificate) property set.
|smallrye.jwt.token.header|`Authorization`|Set this property if another header such as `Cookie` is used to pass the token. This property is deprecated - use 'mp.jwt.token.header'.
|smallrye.jwt.token.cookie|none|Name of the cookie containing a token. This property will be effective only if `smallrye.jwt.token.header` is set to `Cookie`. This property is deprecated - use 'mp.jwt.token.cookie`.
|smallrye.jwt.key-cache-size|`100`|Key cache size. Use this property, as well as `smallrye.jwt.key-cache-time-to-live`, to control the key cache when a key provider such as `AWS_ALB` is configured with `smallrye.jwt.verify.key-provider=AWS_ALB` for resolving the keys dynamically.
|smallrye.jwt.key-cache-time-to-live|`10`|Key cache entry time-to-live in minutes. Use this property, as well as `smallrye.jwt.key-cache-size`, to control the key cache when a key provider such as `AWS_ALB` is configured with `smallrye.jwt.verify.key-provider=AWS_ALB` for resolving the keys dynamically.
|smallrye.jwt.token.cookie|none|Name of the cookie containing a token. This property will be effective only if `smallrye.jwt.token.header` is set to `Cookie`. This property is deprecated - use `mp.jwt.token.cookie`.
|smallrye.jwt.always-check-authorization|false|Set this property to `true` for `Authorization` header be checked even if the `smallrye.jwt.token.header` is set to `Cookie` but no cookie with a `smallrye.jwt.token.cookie` name exists.
|smallrye.jwt.token.schemes|`Bearer`|Comma-separated list containing an alternative single or multiple schemes, for example, `DPoP`.
|smallrye.jwt.token.kid|none|Key identifier. If it is set then the verification JWK key as well every JWT token must have a matching `kid` header.
Expand All @@ -1060,14 +1076,14 @@ SmallRye JWT provides more properties which can be used to customize the token p
|smallrye.jwt.path.sub|none|Path to the claim containing the subject name. It starts from the top level JSON object and can contain multiple segments where each segment represents a JSON object name only, example: `realms/subject`. This property can be used if a token has no 'sub' claim but has the subject set in a different claim. Use double quotes with the namespace qualified claims.
|smallrye.jwt.claims.sub|none| This property can be used to set a default sub claim value when the current token has no standard or custom `sub` claim available. Effectively this property can be used to customize `java.security.Principal` name if no `upn` or `preferred_username` or `sub` claim is set.
|smallrye.jwt.path.groups|none|Path to the claim containing the groups. It starts from the top level JSON object and can contain multiple segments where each segment represents a JSON object name only, example: `realm/groups`. This property can be used if a token has no 'groups' claim but has the groups set in a different claim. Use double quotes with the namespace qualified claims.
|smallrye.jwt.groups-separator|' '|Separator for splitting a string which may contain multiple group values. It will only be used if the `smallrye.jwt.path.groups` property points to a custom claim whose value is a string. The default value is a single space because a standard OAuth2 `scope` claim may contain a space separated sequence.
|smallrye.jwt.groups-separator|space|Separator for splitting a string which may contain multiple group values. It will only be used if the `smallrye.jwt.path.groups` property points to a custom claim whose value is a string. The default value is a single space because a standard OAuth2 `scope` claim may contain a space separated sequence.
|smallrye.jwt.claims.groups|none| This property can be used to set a default groups claim value when the current token has no standard or custom groups claim available.
|smallrye.jwt.jwks.refresh-interval|60|JWK cache refresh interval in minutes. It will be ignored unless the `mp.jwt.verify.publickey.location` points to the HTTP or HTTPS URL based JWK set and no HTTP `Cache-Control` response header with a positive `max-age` parameter value is returned from a JWK HTTPS endpoint.
|smallrye.jwt.jwks.forced-refresh-interval|30|Forced JWK cache refresh interval in minutes which is used to restrict the frequency of the forced refresh attempts which may happen when the token verification fails due to the cache having no JWK key with a `kid` property matching the current token's `kid` header. It will be ignored unless the `mp.jwt.verify.publickey.location` points to the HTTP or HTTPS URL based JWK set.
|smallrye.jwt.expiration.grace|0|Expiration grace in seconds. By default an expired token will still be accepted if the current time is no more than 1 min after the token expiry time. This property is deprecated. Use `mp.jwt.verify.clock.skew` instead.
|smallrye.jwt.verify.aud|none|Comma separated list of the audiences that a token `aud` claim may contain. This property is deprecated - use `mp.jwt.verify.audiences`.
|smallrye.jwt.required.claims|none|Comma separated list of the claims that a token must contain.
|smallrye.jwt.decrypt.key.location|none|Config property allows for an external or internal location of Private Decryption Key to be specified. This property is deprecated - use 'mp.jwt.decrypt.key.location'.
|smallrye.jwt.decrypt.key.location|none|Config property allows for an external or internal location of Private Decryption Key to be specified. This property is deprecated - use `mp.jwt.decrypt.key.location`.
|smallrye.jwt.decrypt.algorithm|`RSA_OAEP`|Decryption algorithm.
|smallrye.jwt.decrypt.key|none|Decryption key supplied as a string.
|smallrye.jwt.token.decryption.kid|none|Decryption Key identifier. If it is set then the decryption JWK key as well every JWT token must have a matching `kid` header.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static java.util.stream.Collectors.toList;
import static org.jboss.resteasy.reactive.common.processor.EndpointIndexer.CDI_WRAPPER_SUFFIX;
import static org.jboss.resteasy.reactive.common.processor.JandexUtil.isImplementorOf;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.APPLICATION;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.BLOCKING;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.REQUEST_SCOPED;
import static org.jboss.resteasy.reactive.common.processor.scanning.ResteasyReactiveScanner.BUILTIN_HTTP_ANNOTATIONS_TO_METHOD;
Expand Down Expand Up @@ -527,7 +528,7 @@ void addRestClientBeans(Capabilities capabilities,
for (AnnotationInstance registerBlockingClass : registerBlockingClasses) {
AnnotationTarget target = registerBlockingClass.target();
if (target.kind() == AnnotationTarget.Kind.CLASS
&& isImplementorOf(index, target.asClass(), RESPONSE_EXCEPTION_MAPPER)) {
&& isImplementorOf(index, target.asClass(), RESPONSE_EXCEPTION_MAPPER, Set.of(APPLICATION))) {
// Watch for @Blocking annotations in classes that implements ResponseExceptionMapper:
blockingClassNames.add(target.asClass().toString());
} else if (target.kind() == AnnotationTarget.Kind.METHOD
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ public class HttpConfiguration {
@ConfigItem
public String host;

/**
* Used when {@code QuarkusIntegrationTest} is meant to execute against an application that is already running and
* listening on the host specified by this property.
*/
@ConfigItem
public Optional<String> testHost;

/**
* Enable listening to host:port
*/
Expand All @@ -62,6 +69,13 @@ public class HttpConfiguration {
@ConfigItem(defaultValue = "8444")
public int testSslPort;

/**
* Used when {@code QuarkusIntegrationTest} is meant to execute against an application that is already running
* to configure the test to use SSL.
*/
@ConfigItem
public Optional<Boolean> testSslEnabled;

/**
* If insecure (i.e. http rather than https) requests are allowed. If this is {@code enabled}
* then http works as normal. {@code redirect} will still open the http port, but
Expand Down
2 changes: 1 addition & 1 deletion independent-projects/enforcer-rules/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
<version>4.0.12</version>
<version>4.0.13</version>
</dependency>
</dependencies>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,20 @@ public static boolean isSubclassOf(IndexView index, ClassInfo info, DotName pare
* @throws RuntimeException if one of the superclasses is not indexed.
*/
public static boolean isImplementorOf(IndexView index, ClassInfo info, DotName name) {
return isImplementorOf(index, info, name, Collections.emptySet());
}

/**
* Returns true if the given Jandex ClassInfo is a subclass of or inherits the given <tt>name</tt>.
*
* @param index the index to use to look up super classes.
* @param info the ClassInfo we want to check.
* @param name the name of the superclass or interface we want to find.
* @param additionalIgnoredSuperClasses return false if the class has any of these as a superclass.
* @throws RuntimeException if one of the superclasses is not indexed.
*/
public static boolean isImplementorOf(IndexView index, ClassInfo info, DotName name,
Set<DotName> additionalIgnoredSuperClasses) {
// Check interfaces
List<DotName> interfaceNames = info.interfaceNames();
for (DotName interfaceName : interfaceNames) {
Expand All @@ -382,7 +396,9 @@ public static boolean isImplementorOf(IndexView index, ClassInfo info, DotName n
}

// Check direct hierarchy
if (info.superName().equals(DOTNAME_OBJECT) || info.superName().equals(DOTNAME_RECORD)) {
DotName superDotName = info.superName();
if (superDotName.equals(DOTNAME_OBJECT) || superDotName.equals(DOTNAME_RECORD)
|| additionalIgnoredSuperClasses.contains(superDotName)) {
return false;
}
if (info.superName().equals(name)) {
Expand All @@ -393,10 +409,10 @@ public static boolean isImplementorOf(IndexView index, ClassInfo info, DotName n
Type superType = info.superClassType();
ClassInfo superClass = index.getClassByName(superType.name());
if (superClass == null) {
// this can happens if the parent is not inside the Jandex index
// this can happen if the parent is not inside the Jandex index
throw new RuntimeException("The class " + superType.name() + " is not inside the Jandex index");
}
return isImplementorOf(index, superClass, name);
return isImplementorOf(index, superClass, name, additionalIgnoredSuperClasses);
}

}

0 comments on commit fbb40fc

Please sign in to comment.