Skip to content

Commit

Permalink
Merge pull request #38768 from gsmet/3.7.3-backports-2
Browse files Browse the repository at this point in the history
3.7.3 backports 2
  • Loading branch information
gsmet committed Feb 14, 2024
2 parents aecce90 + 412740a commit 1dbf5d3
Show file tree
Hide file tree
Showing 46 changed files with 601 additions and 65 deletions.
2 changes: 1 addition & 1 deletion bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@
<jna.version>5.8.0</jna.version><!-- should satisfy both testcontainers and mongodb -->
<antlr.version>4.13.0</antlr.version><!-- needs to align with same property in build-parent/pom.xml -->
<quarkus-security.version>2.0.3.Final</quarkus-security.version>
<keycloak.version>23.0.4</keycloak.version>
<keycloak.version>23.0.6</keycloak.version>
<logstash-gelf.version>1.15.1</logstash-gelf.version>
<checker-qual.version>3.42.0</checker-qual.version>
<error-prone-annotations.version>2.24.0</error-prone-annotations.version>
Expand Down
2 changes: 1 addition & 1 deletion build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@

<!-- The image to use for tests that run Keycloak -->
<!-- IMPORTANT: If this is changed you must also update bom/application/pom.xml and KeycloakBuildTimeConfig/DevServicesConfig in quarkus-oidc/deployment to match the version -->
<keycloak.version>23.0.4</keycloak.version>
<keycloak.version>23.0.6</keycloak.version>
<keycloak.wildfly.version>19.0.3</keycloak.wildfly.version>
<keycloak.docker.image>quay.io/keycloak/keycloak:${keycloak.version}</keycloak.docker.image>
<keycloak.docker.legacy.image>quay.io/keycloak/keycloak:${keycloak.wildfly.version}-legacy</keycloak.docker.legacy.image>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ protected TsArtifact composeApplication() {
final TsArtifact depC2 = TsArtifact.jar("dep-c", "2");
// make sure provided dependencies don't override compile/runtime dependencies
directProvidedDep.addDependency(depC2);
directProvidedDep.addDependency(extADeploymentDep);

final TsArtifact transitiveProvidedDep = TsArtifact.jar("transitive-provided-dep");
directProvidedDep.addDependency(transitiveProvidedDep);
Expand All @@ -68,7 +69,7 @@ protected void assertAppModel(ApplicationModel model) throws Exception {
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-deployment", "1"),
DependencyFlags.DEPLOYMENT_CP));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-deployment-dep", "1"),
DependencyFlags.DEPLOYMENT_CP));
DependencyFlags.DEPLOYMENT_CP, DependencyFlags.COMPILE_ONLY));
assertEquals(expected, getDeploymentOnlyDeps(model));

final Set<Dependency> expectedRuntime = new HashSet<>();
Expand All @@ -83,7 +84,8 @@ protected void assertAppModel(ApplicationModel model) throws Exception {
DependencyFlags.DEPLOYMENT_CP));
expectedRuntime.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "dep-c", "1"),
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.COMPILE_ONLY));
assertEquals(expectedRuntime, getDependenciesWithFlag(model, DependencyFlags.RUNTIME_CP));

final Set<Dependency> expectedCompileOnly = new HashSet<>();
Expand All @@ -102,6 +104,13 @@ protected void assertAppModel(ApplicationModel model) throws Exception {
.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "transitive-provided-dep", "1"),
JavaScopes.PROVIDED,
DependencyFlags.COMPILE_ONLY));
expectedCompileOnly.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "dep-c", "1"),
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.COMPILE_ONLY));
expectedCompileOnly
.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-deployment-dep", "1"),
DependencyFlags.DEPLOYMENT_CP, DependencyFlags.COMPILE_ONLY));
assertEquals(expectedCompileOnly, getDependenciesWithFlag(model, DependencyFlags.COMPILE_ONLY));

final Set<Dependency> compileOnlyPlusRuntime = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,8 @@ private List<ConfigDocItem> recursivelyFindConfigItems(Element element, String r
configDocKey.setConfigPhase(configPhase);
configDocKey.setDefaultValue(defaultValue);
configDocKey.setDocMapKey(configDocMapKey);
configDocKey.setConfigDoc(javaDocParser.parseConfigDescription(rawJavaDoc));
javaDocParser.parseConfigDescription(rawJavaDoc, configDocKey::setConfigDoc, configDocKey::setSince);
configDocKey.setEnvironmentVariable(DocGeneratorUtil.toEnvVarName(name));
configDocKey.setAcceptedValues(acceptedValues);
configDocKey.setJavaDocSiteLink(getJavaDocSiteLink(type));
ConfigDocItem configDocItem = new ConfigDocItem();
Expand Down Expand Up @@ -628,6 +629,8 @@ private List<ConfigDocItem> decorateGroupItems(
additionalKeys.addAll(additionalNames.stream().map(k -> k + configDocKey.getKey()).collect(toList()));
configDocKey.setAdditionalKeys(additionalKeys);
configDocKey.setKey(parentName + configDocKey.getKey());
configDocKey.setEnvironmentVariable(
DocGeneratorUtil.toEnvVarName(parentName) + configDocKey.getEnvironmentVariable());
decoratedItems.add(configDocItem);
} else {
ConfigDocSection section = configDocItem.getConfigDocSection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ final public class ConfigDocKey implements ConfigDocElement, Comparable<ConfigDo
// if a key is "quarkus.kubernetes.part-of", then the value of this would be "kubernetes"
private String topLevelGrouping;
private boolean isEnum;
private String since;
private String environmentVariable;

public ConfigDocKey() {
}
Expand Down Expand Up @@ -130,7 +132,7 @@ public boolean isWithinAMap() {
return withinAMap;
}

String computeTypeSimpleName() {
public String computeTypeSimpleName() {
String unwrappedType = DocGeneratorUtil.unbox(type);

Matcher matcher = Constants.CLASS_NAME_PATTERN.matcher(unwrappedType);
Expand Down Expand Up @@ -193,6 +195,22 @@ public void setEnum(boolean anEnum) {
isEnum = anEnum;
}

public String getSince() {
return since;
}

public void setSince(String since) {
this.since = since;
}

public String getEnvironmentVariable() {
return environmentVariable;
}

public void setEnvironmentVariable(String environmentVariable) {
this.environmentVariable = environmentVariable;
}

@Override
public void accept(Writer writer, DocFormatter docFormatter) throws IOException {
docFormatter.format(writer, this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.hyphenate;

import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
Expand All @@ -13,6 +15,7 @@
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.javadoc.Javadoc;
import com.github.javaparser.javadoc.JavadocBlockTag;
import com.github.javaparser.javadoc.JavadocBlockTag.Type;
import com.github.javaparser.javadoc.description.JavadocDescription;
import com.github.javaparser.javadoc.description.JavadocDescriptionElement;
import com.github.javaparser.javadoc.description.JavadocInlineTag;
Expand Down Expand Up @@ -80,8 +83,20 @@ public JavaDocParser() {
}

public String parseConfigDescription(String javadocComment) {
final AtomicReference<String> ref = new AtomicReference<>();
parseConfigDescription(javadocComment, ref::set, s -> {
});
return ref.get();
}

public void parseConfigDescription(
String javadocComment,
Consumer<String> javadocTextConsumer,
Consumer<String> sinceConsumer) {

if (javadocComment == null || javadocComment.trim().isEmpty()) {
return Constants.EMPTY;
javadocTextConsumer.accept(Constants.EMPTY);
return;
}

// the parser expects all the lines to start with "* "
Expand All @@ -90,10 +105,16 @@ public String parseConfigDescription(String javadocComment) {
Javadoc javadoc = StaticJavaParser.parseJavadoc(javadocComment);

if (isAsciidoc(javadoc)) {
return handleEolInAsciidoc(javadoc);
javadocTextConsumer.accept(handleEolInAsciidoc(javadoc));
} else {
javadocTextConsumer.accept(htmlJavadocToAsciidoc(javadoc.getDescription()));
}

return htmlJavadocToAsciidoc(javadoc.getDescription());
javadoc.getBlockTags().stream()
.filter(t -> t.getType() == Type.SINCE)
.map(JavadocBlockTag::getContent)
.map(JavadocDescription::toText)
.findFirst()
.ifPresent(sinceConsumer::accept);
}

public SectionHolder parseConfigSection(String javadocComment, int sectionLevel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,8 @@ public void addParam(String type, String name, String defaultValue, boolean requ
configDocKey.setAdditionalKeys(List.of(name));
configDocKey.setConfigPhase(ConfigPhase.RUN_TIME);
configDocKey.setDefaultValue(defaultValue == null ? Constants.EMPTY : defaultValue);
if (description != null && !description.isBlank()) {
configDocKey.setConfigDoc(javaDocParser.parseConfigDescription(description));
} else {
configDocKey.setConfigDoc(EMPTY);
}
javaDocParser.parseConfigDescription(description, configDocKey::setConfigDoc, configDocKey::setSince);
configDocKey.setEnvironmentVariable(DocGeneratorUtil.toEnvVarName(name));
configDocKey.setOptional(!required);
final ConfigDocItem configDocItem = new ConfigDocItem();
configDocItem.setConfigDocKey(configDocKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Collections;
import java.util.concurrent.atomic.AtomicReference;

import org.asciidoctor.Asciidoctor.Factory;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -252,6 +253,15 @@ public void parseJavaDocWithCodeBlock() {
// parser.parseConfigDescription("Example:\n\n<pre>{@code\nfoo\nbar\n}</pre>"));
}

@Test
public void since() {
AtomicReference<String> javadoc = new AtomicReference<>();
AtomicReference<String> since = new AtomicReference<>();
parser.parseConfigDescription("Javadoc text\n\n@since 1.2.3", javadoc::set, since::set);
assertEquals("Javadoc text", javadoc.get());
assertEquals("1.2.3", since.get());
}

@Test
public void asciidoc() {
String asciidoc = "== My Asciidoc\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,16 @@ public static Project findIncludedProject(Project project, ExternalModuleDepende
}
}

final Gradle parentGradle = project.getRootProject().getGradle().getParent();
if (parentGradle != null) {
return findIncludedProject(parentGradle.getRootProject(), dependency);
} else {
try {
final Gradle parentGradle = project.getRootProject().getGradle().getParent();
if (parentGradle != null) {
return findIncludedProject(parentGradle.getRootProject(), dependency);
} else {
return null;
}
} catch (IllegalStateException ise) {
// This can happen if the project itself is in an included build, which means that the root-project
// is not yet known, so `DefaultGradle.getRootProject()` throws an ISE.
return null;
}
}
Expand All @@ -134,9 +140,15 @@ private static Project findIncludedBuildProject(IncludedBuild ib, ExternalModule
}

final DefaultIncludedBuild.IncludedBuildImpl dib = (DefaultIncludedBuild.IncludedBuildImpl) ib;
final Project rootProject = dib.getTarget().getMutableModel().getRootProject();
try {
final Project rootProject = dib.getTarget().getMutableModel().getRootProject();

return findLocalProject(rootProject, dependency);
return findLocalProject(rootProject, dependency);
} catch (IllegalStateException ise) {
// This can happen if the project itself is in an included build, which means that the root-project
// is not yet known, so `DefaultGradle.getRootProject()` throws an ISE.
return null;
}
}

public static Path serializeAppModel(ApplicationModel appModel, Task context, boolean test) throws IOException {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 10 additions & 4 deletions docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -492,9 +492,9 @@ For more information on how to configure Auth0 and Quarkus to have authorization

So far we have only tested the Quarkus endpoint using OIDC authorization code flow. In this flow you use the browser to access the Quarkus endpoint, Quarkus itself manages the authorization code flow, a user is redirected to Auth0, logs in, is redirected back to Quarkus, Quarkus completes the flow by exchanging the code for the ID, access, and refresh tokens, and works with the ID token representing the successful user authentication. The access token is not relevant at the moment. As mentioned earlier, in the authorization code flow, Quarkus will only use the access token to access downstream services on behalf of the currently authenticated user.

Lets imagine though that the Quarkus endpoint we have developed has to accept `Bearer` access tokens too: it may be that the other Quarkus endpoint which is propagating it to this endpoint or it can be SPA which uses the access token to access the Quarkus endpoint. And Quarkus OIDC DevUI SPA which we already used to analyze the ID token fits perfectly for using the access token available to SPA to test the Quarkus endpoint.
Let's imagine though that the Quarkus endpoint we have developed has to accept `Bearer` access tokens too: it may be that the other Quarkus endpoint which is propagating it to this endpoint or it can be SPA which uses the access token to access the Quarkus endpoint. And Quarkus OIDC DevUI SPA which we already used to analyze the ID token fits perfectly for using the access token available to SPA to test the Quarkus endpoint.

Lets go again to http://localhost:8080/q/dev, select the `OpenId Connect` card, login to Auth0, and check the Access token content:
Let's go again to http://localhost:8080/q/dev-ui, select the `OpenId Connect` card, login to Auth0, and check the Access token content:

image::auth0-devui-accesstoken.png[Auth0 DevUI Access Token]

Expand Down Expand Up @@ -632,7 +632,7 @@ For more information about token propagation, see xref:security-openid-connect-c

We have already looked in detail at how Quarkus OIDC can handle <<opaque-access-tokens>>, but we don't want to propagate Auth0 opaque tokens to micro services which do something useful on behalf on the currently authenticated user, beyond checking its UserInfo.

A microservice which the front-end Quarkus application will access by propagating authorization code flow access tokens to it is represented in the Auth0 dashboard as an `API`. Lets add it in the `Applications/APIs`:
A microservice which the front-end Quarkus application will access by propagating authorization code flow access tokens to it is represented in the Auth0 dashboard as an `API`. Let's add it in the `Applications/APIs`:

image::auth0-api.png[Auth0 API]

Expand Down Expand Up @@ -804,6 +804,12 @@ public class GreetingResource {

Open a browser, access http://localhost:8080/hello and get your name displayed in the browser.

Let's go to http://localhost:8080/q/dev-ui, select the `OpenId Connect` card, login to Auth0, and check the Access token content:

image::auth0-devui-jwt-accesstoken.png[Auth0 DevUI JWT Access Token]

As you can see, the access token is no longer encrypted as shown in the <<opaque-access-tokens>> section and indeed it is in the JWT format now.

[[permission-based-access-control]]
=== Permission Based Access Control

Expand Down Expand Up @@ -939,7 +945,7 @@ quarkus.oidc.client-id=sKQu1dXjHB6r0sra0Y1YCqBZKWXqCkly
quarkus.oidc.credentials.secret=${client-secret}
----

In production, you will distinguish between prod and test level configuration with `%prod.` and `%test.` qualifiers. Lets assume that the above configuration will indeed be prefixed with `%test.` in your real application, with this configuration also including the `%prod.` qualified Auth0 production tenant configuration.
In production, you will distinguish between prod and test level configuration with `%prod.` and `%test.` qualifiers. Let's assume that the above configuration will indeed be prefixed with `%test.` in your real application, with this configuration also including the `%prod.` qualified Auth0 production tenant configuration.

Using `OidcTestClient` to test such configuration requires acquiring a token from the Auth0 dev tenant, using either OAuth2 `password` or `client_credentials` grant, we will try a `password` grant. Make sure the application registered in the Auth0 dashboard allows the `password` grant:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ For more information, see xref:security-oidc-bearer-token-authentication.adoc#in
[[keycloak-initialization]]
=== Keycloak initialization

The `quay.io/keycloak/keycloak:23.0.4` image which contains a Keycloak distribution powered by Quarkus is used to start a container by default.
The `quay.io/keycloak/keycloak:23.0.6` image which contains a Keycloak distribution powered by Quarkus is used to start a container by default.
`quarkus.keycloak.devservices.image-name` can be used to change the Keycloak image name.
For example, set it to `quay.io/keycloak/keycloak:19.0.3-legacy` to use a Keycloak distribution powered by WildFly.
Be aware that a Quarkus-based Keycloak distribution is only available starting from Keycloak `20.0.0`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@
import org.hibernate.validator.spi.messageinterpolation.LocaleResolver;
import org.hibernate.validator.spi.messageinterpolation.LocaleResolverContext;
import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.common.util.CaseInsensitiveMap;

abstract class AbstractLocaleResolver implements LocaleResolver {

private static final Logger log = Logger.getLogger(AbstractLocaleResolver.class);
private static final String ACCEPT_HEADER = "Accept-Language";

/**
* @return case-insensitive map
* @see CaseInsensitiveMap
*/
protected abstract Map<String, List<String>> getHeaders();

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package io.quarkus.hibernate.validator.runtime.locale;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jakarta.inject.Inject;
import jakarta.inject.Singleton;

import org.jboss.resteasy.reactive.common.util.CaseInsensitiveMap;

import io.quarkus.arc.Arc;
import io.quarkus.arc.ManagedContext;
import io.quarkus.vertx.http.runtime.CurrentVertxRequest;
Expand All @@ -31,7 +32,7 @@ protected Map<String, List<String>> getHeaders() {
}
RoutingContext current = currentVertxRequest.getCurrent();
if (current != null) {
Map<String, List<String>> result = new HashMap<>();
Map<String, List<String>> result = new CaseInsensitiveMap();
MultiMap headers = current.request().headers();
for (String name : headers.names()) {
result.put(name, headers.getAll(name));
Expand Down
Loading

0 comments on commit 1dbf5d3

Please sign in to comment.