From 5b0dfd5b63d5d51a105e085593119091b85e4a16 Mon Sep 17 00:00:00 2001 From: Nuno Neto Date: Fri, 8 Sep 2023 18:16:06 +0100 Subject: [PATCH 001/207] Add capability to add topic configuration during topic creation --- .../resources/dev-ui/qwc-kafka-add-topic.js | 25 ++++++++++++++++--- .../client/runtime/KafkaAdminClient.java | 10 ++++---- .../runtime/devui/KafkaJsonRPCService.java | 12 +++++---- .../request/KafkaCreateTopicRequest.java | 12 ++++++++- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/extensions/kafka-client/deployment/src/main/resources/dev-ui/qwc-kafka-add-topic.js b/extensions/kafka-client/deployment/src/main/resources/dev-ui/qwc-kafka-add-topic.js index ad8ca2104ee67..c26c0d9cb26ea 100644 --- a/extensions/kafka-client/deployment/src/main/resources/dev-ui/qwc-kafka-add-topic.js +++ b/extensions/kafka-client/deployment/src/main/resources/dev-ui/qwc-kafka-add-topic.js @@ -59,6 +59,13 @@ export class QwcKafkaAddTopic extends LitElement { min="0" max="99"> + + ${this._renderButtons()}`; } @@ -70,10 +77,11 @@ export class QwcKafkaAddTopic extends LitElement { } _reset(){ - this._newTopic = new Object(); + this._newTopic = {}; this._newTopic.name = ''; this._newTopic.partitions = 1; this._newTopic.replications = 1; + this._newTopic.configs = undefined; } _cancel(){ @@ -89,11 +97,11 @@ export class QwcKafkaAddTopic extends LitElement { _submit(){ if(this._newTopic.name.trim() !== ''){ - this.jsonRpc.createTopic({ topicName: this._newTopic.name, partitions: parseInt(this._newTopic.partitions), - replications: parseInt(this._newTopic.replications) + replications: parseInt(this._newTopic.replications), + configs: this._newTopic.configs }).then(jsonRpcResponse => { this._reset(); const success = new CustomEvent("kafka-topic-added-success", { @@ -119,6 +127,17 @@ export class QwcKafkaAddTopic extends LitElement { _replicationsChanged(e){ this._newTopic.replications = e.detail.value; } + + _configsChanged(e){ + this._newTopic.configs = Object.fromEntries(e.detail.value.split(',') + .reduce((configs, item) => { + const split = item.trim().split('='); + if (split.length > 1) { + configs.set(split[0], split[1]); + } + return configs; + }, new Map())); + } } customElements.define('qwc-kafka-add-topic', QwcKafkaAddTopic); \ No newline at end of file diff --git a/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/KafkaAdminClient.java b/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/KafkaAdminClient.java index 0ced0504abcda..8f8486630e18c 100644 --- a/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/KafkaAdminClient.java +++ b/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/KafkaAdminClient.java @@ -70,23 +70,23 @@ public Collection getConsumerGroups() throws Interrupt .values(); } - public boolean deleteTopic(String name) { + public boolean deleteTopic(final String name) { Collection topics = new ArrayList<>(); topics.add(name); DeleteTopicsResult dtr = client.deleteTopics(topics); return dtr.topicNameValues() != null; } - public boolean createTopic(KafkaCreateTopicRequest kafkaCreateTopicRq) { + public boolean createTopic(final KafkaCreateTopicRequest kafkaCreateTopicRq) { var partitions = Optional.ofNullable(kafkaCreateTopicRq.getPartitions()).orElse(1); var replications = Optional.ofNullable(kafkaCreateTopicRq.getReplications()).orElse((short) 1); var newTopic = new NewTopic(kafkaCreateTopicRq.getTopicName(), partitions, replications); - + newTopic.configs(Optional.ofNullable(kafkaCreateTopicRq.getConfigs()).orElse(Map.of())); CreateTopicsResult ctr = client.createTopics(List.of(newTopic)); return ctr.values() != null; } - public ListConsumerGroupOffsetsResult listConsumerGroupOffsets(String groupId) { + public ListConsumerGroupOffsetsResult listConsumerGroupOffsets(final String groupId) { return client.listConsumerGroupOffsets(groupId); } @@ -96,7 +96,7 @@ public Collection getAclInfo() throws InterruptedException, Executio return client.describeAcls(filter, options).values().get(); } - public Map describeTopics(Collection topicNames) + public Map describeTopics(final Collection topicNames) throws InterruptedException, ExecutionException { return client.describeTopics(topicNames) .allTopicNames() diff --git a/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/devui/KafkaJsonRPCService.java b/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/devui/KafkaJsonRPCService.java index c9d37cbb001e4..b5fe4ebdd3fcf 100644 --- a/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/devui/KafkaJsonRPCService.java +++ b/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/devui/KafkaJsonRPCService.java @@ -30,10 +30,12 @@ public List getTopics() throws InterruptedException, ExecutionExcept return kafkaUiUtils.getTopics(); } - public List createTopic(String topicName, int partitions, int replications) + public List createTopic(final String topicName, final int partitions, final int replications, + Map configs) throws InterruptedException, ExecutionException { - KafkaCreateTopicRequest createTopicRequest = new KafkaCreateTopicRequest(topicName, partitions, (short) replications); + KafkaCreateTopicRequest createTopicRequest = new KafkaCreateTopicRequest(topicName, partitions, (short) replications, + configs); boolean created = kafkaAdminClient.createTopic(createTopicRequest); if (created) { return kafkaUiUtils.getTopics(); @@ -41,7 +43,7 @@ public List createTopic(String topicName, int partitions, int replic throw new RuntimeException("Topic [" + topicName + "] not created"); } - public List deleteTopic(String topicName) throws InterruptedException, ExecutionException { + public List deleteTopic(final String topicName) throws InterruptedException, ExecutionException { boolean deleted = kafkaAdminClient.deleteTopic(topicName); if (deleted) { return kafkaUiUtils.getTopics(); @@ -49,7 +51,7 @@ public List deleteTopic(String topicName) throws InterruptedExceptio throw new RuntimeException("Topic [" + topicName + "] not deleted"); } - public KafkaMessagePage topicMessages(String topicName) throws ExecutionException, InterruptedException { + public KafkaMessagePage topicMessages(final String topicName) throws ExecutionException, InterruptedException { List partitions = getPartitions(topicName); KafkaOffsetRequest offsetRequest = new KafkaOffsetRequest(topicName, partitions, Order.NEW_FIRST); Map offset = kafkaUiUtils.getOffset(offsetRequest); @@ -71,7 +73,7 @@ public KafkaMessagePage createMessage(String topicName, Integer partition, Strin return topicMessages(topicName); } - public List getPartitions(String topicName) throws ExecutionException, InterruptedException { + public List getPartitions(final String topicName) throws ExecutionException, InterruptedException { return new ArrayList<>(kafkaUiUtils.partitions(topicName)); } diff --git a/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/devui/model/request/KafkaCreateTopicRequest.java b/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/devui/model/request/KafkaCreateTopicRequest.java index b099bb06ca3e9..883a6ba1ecaa4 100644 --- a/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/devui/model/request/KafkaCreateTopicRequest.java +++ b/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/devui/model/request/KafkaCreateTopicRequest.java @@ -1,17 +1,22 @@ package io.quarkus.kafka.client.runtime.devui.model.request; +import java.util.Map; + public class KafkaCreateTopicRequest { private String topicName; private Integer partitions; private Short replications; + private Map configs; public KafkaCreateTopicRequest() { } - public KafkaCreateTopicRequest(String topicName, Integer partitions, Short replications) { + public KafkaCreateTopicRequest(final String topicName, final Integer partitions, final Short replications, + final Map configs) { this.topicName = topicName; this.partitions = partitions; this.replications = replications; + this.configs = configs; } public String getTopicName() { @@ -25,4 +30,9 @@ public Integer getPartitions() { public Short getReplications() { return replications; } + + public Map getConfigs() { + return configs; + } + } From bdf48fb1b0a75bba154ea6f3269d54f5c54763f6 Mon Sep 17 00:00:00 2001 From: Michael Edgar Date: Tue, 3 Dec 2024 06:30:06 -0500 Subject: [PATCH 002/207] Bump smallrye-open-api.version from 4.0.3 to 4.0.4 Signed-off-by: Michael Edgar --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index fb54502ae14b7..841de191e14c6 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -50,7 +50,7 @@ 3.10.2 4.1.0 4.0.0 - 4.0.3 + 4.0.4 2.11.0 6.7.0 4.6.1 From 74b8e3dc4128774dfc31c73c9c3325f5448d2e13 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 3 Dec 2024 15:55:30 +0100 Subject: [PATCH 003/207] Convert Jacoco config to @ConfigMapping --- test-framework/jacoco/deployment/pom.xml | 3 - .../jacoco/deployment/JacocoProcessor.java | 17 +++--- test-framework/jacoco/runtime/pom.xml | 3 - .../quarkus/jacoco/runtime/JacocoConfig.java | 60 +++++++++---------- .../quarkus/jacoco/runtime/ReportCreator.java | 13 ++-- 5 files changed, 44 insertions(+), 52 deletions(-) diff --git a/test-framework/jacoco/deployment/pom.xml b/test-framework/jacoco/deployment/pom.xml index 7aa0f877e779a..21ac798e16142 100644 --- a/test-framework/jacoco/deployment/pom.xml +++ b/test-framework/jacoco/deployment/pom.xml @@ -52,9 +52,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/test-framework/jacoco/deployment/src/main/java/io/quarkus/jacoco/deployment/JacocoProcessor.java b/test-framework/jacoco/deployment/src/main/java/io/quarkus/jacoco/deployment/JacocoProcessor.java index e8f403b855ea7..7bc26c15ef928 100644 --- a/test-framework/jacoco/deployment/src/main/java/io/quarkus/jacoco/deployment/JacocoProcessor.java +++ b/test-framework/jacoco/deployment/src/main/java/io/quarkus/jacoco/deployment/JacocoProcessor.java @@ -56,15 +56,15 @@ void transformerBuildItem(BuildProducer transforme //no code coverage for continuous testing, it does not really make sense return; } - if (!config.enabled) { + if (!config.enabled()) { log.debug("quarkus-jacoco is disabled via config"); return; } - String dataFile = getFilePath(config.dataFile, outputTargetBuildItem.getOutputDirectory(), + String dataFile = getFilePath(config.dataFile(), outputTargetBuildItem.getOutputDirectory(), JacocoConfig.JACOCO_QUARKUS_EXEC); System.setProperty("jacoco-agent.destfile", dataFile); - if (!config.reuseDataFile) { + if (!config.reuseDataFile()) { Files.deleteIfExists(Paths.get(dataFile)); } @@ -97,15 +97,16 @@ public byte[] apply(String className, byte[] bytes) { }).build()); } } - if (config.report) { + if (config.report()) { ReportInfo info = new ReportInfo(); info.dataFile = dataFile; File targetdir = new File( - getFilePath(config.reportLocation, outputTargetBuildItem.getOutputDirectory(), JacocoConfig.JACOCO_REPORT)); + getFilePath(config.reportLocation(), outputTargetBuildItem.getOutputDirectory(), + JacocoConfig.JACOCO_REPORT)); info.reportDir = targetdir.getAbsolutePath(); - String includes = String.join(",", config.includes); - String excludes = String.join(",", config.excludes.orElse(Collections.emptyList())); + String includes = String.join(",", config.includes()); + String excludes = String.join(",", config.excludes().orElse(Collections.emptyList())); Set classes = new HashSet<>(); info.classFiles = classes; @@ -128,7 +129,7 @@ public byte[] apply(String className, byte[] bytes) { private void addProjectModule(ResolvedDependency module, JacocoConfig config, ReportInfo info, String includes, String excludes, Set classes, Set sources) throws Exception { - String dataFile = getFilePath(config.dataFile, module.getWorkspaceModule().getBuildDir().toPath(), + String dataFile = getFilePath(config.dataFile(), module.getWorkspaceModule().getBuildDir().toPath(), JacocoConfig.JACOCO_QUARKUS_EXEC); info.savedData.add(new File(dataFile).getAbsolutePath()); if (module.getSources() == null) { diff --git a/test-framework/jacoco/runtime/pom.xml b/test-framework/jacoco/runtime/pom.xml index 449c9951353b7..8a73f6019b40f 100644 --- a/test-framework/jacoco/runtime/pom.xml +++ b/test-framework/jacoco/runtime/pom.xml @@ -82,9 +82,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/JacocoConfig.java b/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/JacocoConfig.java index 5891ac704f6fa..f463cbd0dc003 100644 --- a/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/JacocoConfig.java +++ b/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/JacocoConfig.java @@ -4,68 +4,68 @@ import java.util.Optional; import io.quarkus.runtime.annotations.ConfigDocDefault; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; @ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) -public class JacocoConfig { +@ConfigMapping(prefix = "quarkus.jacoco") +public interface JacocoConfig { - public static final String JACOCO_QUARKUS_EXEC = "jacoco-quarkus.exec"; - public static final String JACOCO_REPORT = "jacoco-report"; - public static final String TARGET_JACOCO_QUARKUS_EXEC = "target/" + JACOCO_QUARKUS_EXEC; - public static final String TARGET_JACOCO_REPORT = "target/" + JACOCO_REPORT; + static final String JACOCO_QUARKUS_EXEC = "jacoco-quarkus.exec"; + static final String JACOCO_REPORT = "jacoco-report"; + static final String TARGET_JACOCO_QUARKUS_EXEC = "target/" + JACOCO_QUARKUS_EXEC; + static final String TARGET_JACOCO_REPORT = "target/" + JACOCO_REPORT; /** - * Whether or not the jacoco extension is enabled. + * Whether or not the Jacoco extension is enabled. */ - @ConfigItem(defaultValue = "true") - public boolean enabled; + @WithDefault("true") + boolean enabled(); /** - * The jacoco data file. + * The Jacoco data file. * The path can be relative (to the module) or absolute. */ - @ConfigItem @ConfigDocDefault(TARGET_JACOCO_QUARKUS_EXEC) - public Optional dataFile; + Optional dataFile(); /** - * Whether to reuse ({@code true}) or delete ({@code false}) the jacoco + * Whether to reuse ({@code true}) or delete ({@code false}) the Jacoco * data file on each run. */ - @ConfigItem(defaultValue = "false") - public boolean reuseDataFile; + @WithDefault("false") + boolean reuseDataFile(); /** * If Quarkus should generate the Jacoco report */ - @ConfigItem(defaultValue = "true") - public boolean report; + @WithDefault("true") + boolean report(); /** * Encoding of the generated reports. */ - @ConfigItem(defaultValue = "UTF-8") - public String outputEncoding; + @WithDefault("UTF-8") + String outputEncoding(); /** * Name of the root node HTML report pages. */ - @ConfigItem(defaultValue = "${quarkus.application.name}") - public Optional title; + @WithDefault("${quarkus.application.name}") + Optional title(); /** * Footer text used in HTML report pages. */ - @ConfigItem - public Optional footer; + public Optional footer(); /** * Encoding of the source files. */ - @ConfigItem(defaultValue = "UTF-8") - public String sourceEncoding; + @WithDefault("UTF-8") + public String sourceEncoding(); /** * A list of class files to include in the report. May use wildcard @@ -78,8 +78,8 @@ public class JacocoConfig { *
  • **/*BAR*.class targets classes that contain BAR in their name regardless of path
  • * */ - @ConfigItem(defaultValue = "**") - public List includes; + @WithDefault("**") + public List includes(); /** * A list of class files to exclude from the report. May use wildcard @@ -92,14 +92,12 @@ public class JacocoConfig { *
  • **/*BAR*.class targets classes that contain BAR in their name regardless of path
  • * */ - @ConfigItem - public Optional> excludes; + public Optional> excludes(); /** * The location of the report files. * The path can be relative (to the module) or absolute. */ - @ConfigItem @ConfigDocDefault(TARGET_JACOCO_REPORT) - public Optional reportLocation; + public Optional reportLocation(); } diff --git a/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/ReportCreator.java b/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/ReportCreator.java index 0a8351b0aab74..0e09043eae504 100644 --- a/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/ReportCreator.java +++ b/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/ReportCreator.java @@ -23,10 +23,9 @@ import org.jacoco.report.csv.CSVFormatter; import org.jacoco.report.html.HTMLFormatter; import org.jacoco.report.xml.XMLFormatter; -import org.jboss.logging.Logger; public class ReportCreator implements Runnable { - private static final Logger log = Logger.getLogger(ReportCreator.class); + private final ReportInfo reportInfo; private final JacocoConfig config; @@ -94,9 +93,9 @@ private void doRun() { } List formatters = new ArrayList<>(); - addXmlFormatter(new File(targetdir, "jacoco.xml"), config.outputEncoding, formatters); - addCsvFormatter(new File(targetdir, "jacoco.csv"), config.outputEncoding, formatters); - addHtmlFormatter(targetdir, config.outputEncoding, config.footer.orElse(""), Locale.getDefault(), + addXmlFormatter(new File(targetdir, "jacoco.xml"), config.outputEncoding(), formatters); + addCsvFormatter(new File(targetdir, "jacoco.csv"), config.outputEncoding(), formatters); + addHtmlFormatter(targetdir, config.outputEncoding(), config.footer().orElse(""), Locale.getDefault(), formatters); //now for the hacky bit @@ -106,9 +105,9 @@ private void doRun() { loader.getExecutionDataStore().getContents()); MultiSourceFileLocator sourceFileLocator = new MultiSourceFileLocator(4); for (String i : reportInfo.sourceDirectories) { - sourceFileLocator.add(new DirectorySourceFileLocator(new File(i), config.sourceEncoding, 4)); + sourceFileLocator.add(new DirectorySourceFileLocator(new File(i), config.sourceEncoding(), 4)); } - final IBundleCoverage bundle = builder.getBundle(config.title.orElse(reportInfo.artifactId)); + final IBundleCoverage bundle = builder.getBundle(config.title().orElse(reportInfo.artifactId)); visitor.visitBundle(bundle, sourceFileLocator); visitor.visitEnd(); System.out.println("Generated Jacoco reports in " + targetdir); From 794f7acd1213e685b707b40041594fe6a217d22c Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Tue, 3 Dec 2024 15:34:25 +0100 Subject: [PATCH 004/207] Tests: rename the "kotlin" integration tests module to "kotlin-maven-invoker" This is because these tests use the Maven invoker. --- .../{kotlin => kotlin-maven-invoker}/disable-native-profile | 0 integration-tests/{kotlin => kotlin-maven-invoker}/pom.xml | 5 +++-- .../quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java | 0 .../java/io/quarkus/kotlin/maven/it/KotlinDevModeIT.java | 0 .../io/quarkus/kotlin/maven/it/KotlinRemoteDevModeIT.java | 0 .../src/test/resources/projects/classic-kotlin/pom.xml | 0 .../src/main/kotlin/org/acme/GreetingService.kt | 0 .../classic-kotlin/src/main/kotlin/org/acme/HelloResource.kt | 0 .../classic-kotlin/src/main/kotlin/org/acme/MyApplication.kt | 0 .../src/main/resources/META-INF/resources/index.html | 0 .../classic-kotlin/src/main/resources/application.properties | 0 .../src/test/kotlin/org/acme/HelloResourceTest.kt | 0 .../projects/external-reloadable-artifacts/app/pom.xml | 0 .../app/src/main/kotlin/org/acme/GreetingResource.kt | 0 .../app/src/main/resources/application.properties | 0 .../external-reloadable-artifacts/external-lib/pom.xml | 0 .../external-lib/src/main/kotlin/org/acme/lib/Greeting.kt | 0 .../src/test/resources/projects/kotlin-compiler-args/pom.xml | 0 .../src/main/kotlin/org/acme/GraphQLResource.kt | 0 .../src/main/kotlin/org/acme/HelloResource.kt | 0 .../src/main/resources/META-INF/resources/index.html | 0 .../src/main/resources/application.properties | 0 integration-tests/pom.xml | 2 +- 23 files changed, 4 insertions(+), 3 deletions(-) rename integration-tests/{kotlin => kotlin-maven-invoker}/disable-native-profile (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/pom.xml (95%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/java/io/quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/java/io/quarkus/kotlin/maven/it/KotlinDevModeIT.java (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/java/io/quarkus/kotlin/maven/it/KotlinRemoteDevModeIT.java (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/classic-kotlin/pom.xml (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/GreetingService.kt (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/HelloResource.kt (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/MyApplication.kt (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/classic-kotlin/src/main/resources/META-INF/resources/index.html (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/classic-kotlin/src/main/resources/application.properties (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/classic-kotlin/src/test/kotlin/org/acme/HelloResourceTest.kt (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/external-reloadable-artifacts/app/pom.xml (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/external-reloadable-artifacts/app/src/main/kotlin/org/acme/GreetingResource.kt (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/external-reloadable-artifacts/app/src/main/resources/application.properties (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/external-reloadable-artifacts/external-lib/pom.xml (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/external-reloadable-artifacts/external-lib/src/main/kotlin/org/acme/lib/Greeting.kt (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/kotlin-compiler-args/pom.xml (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/GraphQLResource.kt (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/HelloResource.kt (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/kotlin-compiler-args/src/main/resources/META-INF/resources/index.html (100%) rename integration-tests/{kotlin => kotlin-maven-invoker}/src/test/resources/projects/kotlin-compiler-args/src/main/resources/application.properties (100%) diff --git a/integration-tests/kotlin/disable-native-profile b/integration-tests/kotlin-maven-invoker/disable-native-profile similarity index 100% rename from integration-tests/kotlin/disable-native-profile rename to integration-tests/kotlin-maven-invoker/disable-native-profile diff --git a/integration-tests/kotlin/pom.xml b/integration-tests/kotlin-maven-invoker/pom.xml similarity index 95% rename from integration-tests/kotlin/pom.xml rename to integration-tests/kotlin-maven-invoker/pom.xml index c4af49aad8f44..6f79c2f1b039b 100644 --- a/integration-tests/kotlin/pom.xml +++ b/integration-tests/kotlin-maven-invoker/pom.xml @@ -10,8 +10,9 @@ 999-SNAPSHOT - quarkus-integration-test-kotlin - Quarkus - Integration Tests - Kotlin + quarkus-integration-test-kotlin-invoker + Quarkus - Integration Tests - Kotlin - Invoker + Kotlin integration tests that need to use the Maven invoker diff --git a/integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java b/integration-tests/kotlin-maven-invoker/src/test/java/io/quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java similarity index 100% rename from integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java rename to integration-tests/kotlin-maven-invoker/src/test/java/io/quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java diff --git a/integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinDevModeIT.java b/integration-tests/kotlin-maven-invoker/src/test/java/io/quarkus/kotlin/maven/it/KotlinDevModeIT.java similarity index 100% rename from integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinDevModeIT.java rename to integration-tests/kotlin-maven-invoker/src/test/java/io/quarkus/kotlin/maven/it/KotlinDevModeIT.java diff --git a/integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinRemoteDevModeIT.java b/integration-tests/kotlin-maven-invoker/src/test/java/io/quarkus/kotlin/maven/it/KotlinRemoteDevModeIT.java similarity index 100% rename from integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinRemoteDevModeIT.java rename to integration-tests/kotlin-maven-invoker/src/test/java/io/quarkus/kotlin/maven/it/KotlinRemoteDevModeIT.java diff --git a/integration-tests/kotlin/src/test/resources/projects/classic-kotlin/pom.xml b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/pom.xml similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/classic-kotlin/pom.xml rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/pom.xml diff --git a/integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/GreetingService.kt b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/GreetingService.kt similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/GreetingService.kt rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/GreetingService.kt diff --git a/integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/HelloResource.kt b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/HelloResource.kt similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/HelloResource.kt rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/HelloResource.kt diff --git a/integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/MyApplication.kt b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/MyApplication.kt similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/MyApplication.kt rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/kotlin/org/acme/MyApplication.kt diff --git a/integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/resources/META-INF/resources/index.html b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/resources/META-INF/resources/index.html similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/resources/META-INF/resources/index.html rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/resources/META-INF/resources/index.html diff --git a/integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/resources/application.properties b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/resources/application.properties similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/main/resources/application.properties rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/main/resources/application.properties diff --git a/integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/test/kotlin/org/acme/HelloResourceTest.kt b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/test/kotlin/org/acme/HelloResourceTest.kt similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/classic-kotlin/src/test/kotlin/org/acme/HelloResourceTest.kt rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/classic-kotlin/src/test/kotlin/org/acme/HelloResourceTest.kt diff --git a/integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/app/pom.xml b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/app/pom.xml similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/app/pom.xml rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/app/pom.xml diff --git a/integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/app/src/main/kotlin/org/acme/GreetingResource.kt b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/app/src/main/kotlin/org/acme/GreetingResource.kt similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/app/src/main/kotlin/org/acme/GreetingResource.kt rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/app/src/main/kotlin/org/acme/GreetingResource.kt diff --git a/integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/app/src/main/resources/application.properties b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/app/src/main/resources/application.properties similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/app/src/main/resources/application.properties rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/app/src/main/resources/application.properties diff --git a/integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/external-lib/pom.xml b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/external-lib/pom.xml similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/external-lib/pom.xml rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/external-lib/pom.xml diff --git a/integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/external-lib/src/main/kotlin/org/acme/lib/Greeting.kt b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/external-lib/src/main/kotlin/org/acme/lib/Greeting.kt similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/external-reloadable-artifacts/external-lib/src/main/kotlin/org/acme/lib/Greeting.kt rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/external-reloadable-artifacts/external-lib/src/main/kotlin/org/acme/lib/Greeting.kt diff --git a/integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/pom.xml b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/pom.xml similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/pom.xml rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/pom.xml diff --git a/integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/GraphQLResource.kt b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/GraphQLResource.kt similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/GraphQLResource.kt rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/GraphQLResource.kt diff --git a/integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/HelloResource.kt b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/HelloResource.kt similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/HelloResource.kt rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/src/main/kotlin/org/acme/HelloResource.kt diff --git a/integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/src/main/resources/META-INF/resources/index.html b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/src/main/resources/META-INF/resources/index.html similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/src/main/resources/META-INF/resources/index.html rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/src/main/resources/META-INF/resources/index.html diff --git a/integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/src/main/resources/application.properties b/integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/src/main/resources/application.properties similarity index 100% rename from integration-tests/kotlin/src/test/resources/projects/kotlin-compiler-args/src/main/resources/application.properties rename to integration-tests/kotlin-maven-invoker/src/test/resources/projects/kotlin-compiler-args/src/main/resources/application.properties diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 356cb2336c5c3..f5b6eb084a5b1 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -303,7 +303,7 @@ virtual-http-resteasy maven scala - kotlin + kotlin-maven-invoker kotlin-serialization mongodb-panache mongodb-panache-kotlin From bd8d514fce523346ed6f68c4c0052c26c69a7160 Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Tue, 3 Dec 2024 15:38:30 +0100 Subject: [PATCH 005/207] Tests: rename the "kotlin-serialization" integration tests module to "kotlin" This is because these tests use the standard `@QuarkusTest` facility. --- .github/native-tests.json | 2 +- integration-tests/{kotlin-serialization => kotlin}/pom.xml | 5 ++--- .../main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt | 0 .../src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt | 0 .../src/main/kotlin/io/quarkus/it/kotser/TitleCase.kt | 0 .../src/main/kotlin/io/quarkus/it/kotser/model/Person.kt | 0 .../src/main/kotlin/io/quarkus/it/kotser/model/Person2.kt | 0 .../src/main/resources/application.properties | 0 .../src/test/kotlin/io/quarkus/it/kotser/ResourceIT.kt | 0 .../src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt | 0 integration-tests/pom.xml | 2 +- 11 files changed, 4 insertions(+), 5 deletions(-) rename integration-tests/{kotlin-serialization => kotlin}/pom.xml (95%) rename integration-tests/{kotlin-serialization => kotlin}/src/main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt (100%) rename integration-tests/{kotlin-serialization => kotlin}/src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt (100%) rename integration-tests/{kotlin-serialization => kotlin}/src/main/kotlin/io/quarkus/it/kotser/TitleCase.kt (100%) rename integration-tests/{kotlin-serialization => kotlin}/src/main/kotlin/io/quarkus/it/kotser/model/Person.kt (100%) rename integration-tests/{kotlin-serialization => kotlin}/src/main/kotlin/io/quarkus/it/kotser/model/Person2.kt (100%) rename integration-tests/{kotlin-serialization => kotlin}/src/main/resources/application.properties (100%) rename integration-tests/{kotlin-serialization => kotlin}/src/test/kotlin/io/quarkus/it/kotser/ResourceIT.kt (100%) rename integration-tests/{kotlin-serialization => kotlin}/src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt (100%) diff --git a/.github/native-tests.json b/.github/native-tests.json index 87547f9ca469d..cd9b3beb494a9 100644 --- a/.github/native-tests.json +++ b/.github/native-tests.json @@ -99,7 +99,7 @@ { "category": "Misc1", "timeout": 70, - "test-modules": "maven, jackson, jsonb, kotlin-serialization, rest-client-reactive-kotlin-serialization, quartz, qute, logging-min-level-unset, logging-min-level-set, simple with space", + "test-modules": "maven, jackson, jsonb, kotlin, rest-client-reactive-kotlin-serialization, quartz, qute, logging-min-level-unset, logging-min-level-set, simple with space", "os-name": "ubuntu-latest" }, { diff --git a/integration-tests/kotlin-serialization/pom.xml b/integration-tests/kotlin/pom.xml similarity index 95% rename from integration-tests/kotlin-serialization/pom.xml rename to integration-tests/kotlin/pom.xml index 99919f36e3dbb..bf5587575cf76 100644 --- a/integration-tests/kotlin-serialization/pom.xml +++ b/integration-tests/kotlin/pom.xml @@ -10,9 +10,8 @@ 999-SNAPSHOT - quarkus-integration-test-kotlin-serialization - Quarkus - Integration Tests - Kotlin Serialization - Kotlin Serialization integration tests module + quarkus-integration-test-kotlin + Quarkus - Integration Tests - Kotlin 1.3.1 diff --git a/integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt b/integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt similarity index 100% rename from integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt rename to integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt diff --git a/integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt b/integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt similarity index 100% rename from integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt rename to integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt diff --git a/integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/TitleCase.kt b/integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/TitleCase.kt similarity index 100% rename from integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/TitleCase.kt rename to integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/TitleCase.kt diff --git a/integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/model/Person.kt b/integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/model/Person.kt similarity index 100% rename from integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/model/Person.kt rename to integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/model/Person.kt diff --git a/integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/model/Person2.kt b/integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/model/Person2.kt similarity index 100% rename from integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/model/Person2.kt rename to integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/model/Person2.kt diff --git a/integration-tests/kotlin-serialization/src/main/resources/application.properties b/integration-tests/kotlin/src/main/resources/application.properties similarity index 100% rename from integration-tests/kotlin-serialization/src/main/resources/application.properties rename to integration-tests/kotlin/src/main/resources/application.properties diff --git a/integration-tests/kotlin-serialization/src/test/kotlin/io/quarkus/it/kotser/ResourceIT.kt b/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/kotser/ResourceIT.kt similarity index 100% rename from integration-tests/kotlin-serialization/src/test/kotlin/io/quarkus/it/kotser/ResourceIT.kt rename to integration-tests/kotlin/src/test/kotlin/io/quarkus/it/kotser/ResourceIT.kt diff --git a/integration-tests/kotlin-serialization/src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt b/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt similarity index 100% rename from integration-tests/kotlin-serialization/src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt rename to integration-tests/kotlin/src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index f5b6eb084a5b1..6376d450f75fa 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -303,8 +303,8 @@ virtual-http-resteasy maven scala + kotlin kotlin-maven-invoker - kotlin-serialization mongodb-panache mongodb-panache-kotlin mongodb-rest-data-panache From 5d11efeeee233bddb96f7d8c7f0d52116ba45283 Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Tue, 3 Dec 2024 15:56:38 +0100 Subject: [PATCH 006/207] Testing: add reproducers for testing bugs --- .../it/testing/repro34099/Repro34099Test.kt | 23 ++++++++ .../it/testing/repro42000/Repro42000Test.kt | 42 +++++++++++++++ .../it/testing/repro44320/MyService.java | 17 ++++++ .../testing/repro13261/Repro13261Test.java | 24 +++++++++ .../testing/repro42006/Repro42006Test.java | 43 +++++++++++++++ .../testing/repro44320/Repro44320Test.java | 43 +++++++++++++++ .../it/main/testing/repro8446/Greeter.java | 5 ++ .../testing/repro8446/GreeterExtension.java | 52 +++++++++++++++++++ .../main/testing/repro8446/Repro8446Test.java | 20 +++++++ 9 files changed, 269 insertions(+) create mode 100644 integration-tests/kotlin/src/test/kotlin/io/quarkus/it/testing/repro34099/Repro34099Test.kt create mode 100644 integration-tests/kotlin/src/test/kotlin/io/quarkus/it/testing/repro42000/Repro42000Test.kt create mode 100644 integration-tests/main/src/main/java/io/quarkus/it/testing/repro44320/MyService.java create mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro13261/Repro13261Test.java create mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro42006/Repro42006Test.java create mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro44320/Repro44320Test.java create mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/Greeter.java create mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/GreeterExtension.java create mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/Repro8446Test.java diff --git a/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/testing/repro34099/Repro34099Test.kt b/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/testing/repro34099/Repro34099Test.kt new file mode 100644 index 0000000000000..5e63473cbc4b9 --- /dev/null +++ b/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/testing/repro34099/Repro34099Test.kt @@ -0,0 +1,23 @@ +package io.quarkus.it.testing.repro34099 + +import io.quarkus.test.junit.QuarkusTest +import java.time.Duration +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertTimeout + +@QuarkusTest +class Repro34099Test { + @Test + fun javaAssertion() { + Assertions.assertTimeout(Duration.ofSeconds(1)) {} + } + + @Test + @Disabled("https://github.com/quarkusio/quarkus/issues/34099") + // fails with `Linkage loader constraint violation` + fun kotlinAssertion() { + assertTimeout(Duration.ofSeconds(1)) {} + } +} diff --git a/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/testing/repro42000/Repro42000Test.kt b/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/testing/repro42000/Repro42000Test.kt new file mode 100644 index 0000000000000..cbcb4a259fbb1 --- /dev/null +++ b/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/testing/repro42000/Repro42000Test.kt @@ -0,0 +1,42 @@ +package io.quarkus.it.testing.repro42000 + +import io.quarkus.test.junit.QuarkusTest +import java.util.stream.Stream +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource + +@QuarkusTest +class Repro42000Test { + companion object { + val lambda: (String) -> String = { s -> s } + + fun function(s: String) = s + + @JvmStatic + fun lambdaProvider(): Stream { + return Stream.of(Arguments.of(lambda)) + } + + @JvmStatic + fun functionProvider(): Stream { + return Stream.of(Arguments.of(::function)) + } + } + + @ParameterizedTest + @MethodSource("lambdaProvider") + @Disabled("https://github.com/quarkusio/quarkus/issues/42000") + // fails with `IllegalArgumentException: argument type mismatch` + fun testLambdaProvider(function: (String) -> String) { + assertNotNull(function) + } + + @ParameterizedTest + @MethodSource("functionProvider") + fun testFunctionProvider(function: (String) -> String) { + assertNotNull(function) + } +} diff --git a/integration-tests/main/src/main/java/io/quarkus/it/testing/repro44320/MyService.java b/integration-tests/main/src/main/java/io/quarkus/it/testing/repro44320/MyService.java new file mode 100644 index 0000000000000..1f2b031c1d5fd --- /dev/null +++ b/integration-tests/main/src/main/java/io/quarkus/it/testing/repro44320/MyService.java @@ -0,0 +1,17 @@ +package io.quarkus.it.testing.repro44320; + +import java.util.Set; + +import jakarta.enterprise.context.ApplicationScoped; + +import io.quarkus.arc.Unremovable; +import io.quarkus.runtime.Startup; + +@ApplicationScoped +@Startup +@Unremovable +public class MyService { + public Set get() { + return Set.of("a", "b", "c"); + } +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro13261/Repro13261Test.java b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro13261/Repro13261Test.java new file mode 100644 index 0000000000000..e6abb234611f7 --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro13261/Repro13261Test.java @@ -0,0 +1,24 @@ +package io.quarkus.it.main.testing.repro13261; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.nio.file.Path; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import io.quarkus.test.junit.QuarkusTest; + +@Disabled("https://github.com/quarkusio/quarkus/issues/13261") +// fails with `expected: not ` +@QuarkusTest +public class Repro13261Test { + @TempDir + Path tempDir; + + @Test + public void test() { + assertNotNull(tempDir); + } +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro42006/Repro42006Test.java b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro42006/Repro42006Test.java new file mode 100644 index 0000000000000..b0929b32df3a6 --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro42006/Repro42006Test.java @@ -0,0 +1,43 @@ +package io.quarkus.it.main.testing.repro42006; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.Serializable; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.quarkus.test.junit.QuarkusTest; + +@Disabled("https://github.com/quarkusio/quarkus/issues/42006") +// fails with `java.lang.ClassNotFoundException: io.quarkus.it.main.testing.repro42006.Repro42006Test$LambdaProvider$$Lambda$4007/0x000075d5017e8450` +@QuarkusTest +public class Repro42006Test { + @ParameterizedTest + @ArgumentsSource(LambdaProvider.class) + void test(String type, Object lambda) { + assertTrue(lambda.toString().contains("$$Lambda"), "Failed on " + type); + } + + private static class LambdaProvider implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + Arguments.of("SerializableSupplier", (SerializableSupplier) () -> "foo"), + Arguments.of("SerializableCustom", (SerializableCustom) () -> "bar")); + } + } + + public interface SerializableSupplier extends Supplier, Serializable { + } + + public interface SerializableCustom extends Serializable { + String get(); + } +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro44320/Repro44320Test.java b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro44320/Repro44320Test.java new file mode 100644 index 0000000000000..cb4588dbca060 --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro44320/Repro44320Test.java @@ -0,0 +1,43 @@ +package io.quarkus.it.main.testing.repro44320; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.HashSet; +import java.util.Set; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import io.quarkus.it.testing.repro44320.MyService; +import io.quarkus.test.junit.QuarkusTest; + +@Disabled("https://github.com/quarkusio/quarkus/issues/44320") +// fails with `You must configure at least one set of arguments for this @ParameterizedTest`, because the `set` is empty +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@QuarkusTest +public class Repro44320Test { + private static Set set = new HashSet<>(); + + @Inject + MyService service; + + @BeforeAll + public void beforeAllTests() { + set = service.get(); + } + + @ParameterizedTest + @MethodSource("getData") + public void test(String key) { + assertNotNull(key); + } + + public Set getData() { + return set; + } +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/Greeter.java b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/Greeter.java new file mode 100644 index 0000000000000..8a410d2f0afc8 --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/Greeter.java @@ -0,0 +1,5 @@ +package io.quarkus.it.main.testing.repro8446; + +public interface Greeter { + String hello(); +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/GreeterExtension.java b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/GreeterExtension.java new file mode 100644 index 0000000000000..05155a0bd61cb --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/GreeterExtension.java @@ -0,0 +1,52 @@ +package io.quarkus.it.main.testing.repro8446; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.api.extension.TestTemplateInvocationContext; +import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; + +public class GreeterExtension implements TestTemplateInvocationContextProvider { + @Override + public boolean supportsTestTemplate(ExtensionContext context) { + return context.getTestMethod().map(method -> { + return Arrays.asList(method.getParameterTypes()).contains(Greeter.class); + }).orElse(false); + } + + @Override + public Stream provideTestTemplateInvocationContexts(ExtensionContext context) { + return Stream.of(new HelloTestTemplateInvocationContext(() -> "hello")); + } + + private static class HelloTestTemplateInvocationContext implements TestTemplateInvocationContext, ParameterResolver { + private final Greeter greeter; + + public HelloTestTemplateInvocationContext(Greeter greeter) { + this.greeter = greeter; + } + + @Override + public List getAdditionalExtensions() { + return Collections.singletonList(this); + } + + @Override + public boolean supportsParameter(ParameterContext pc, ExtensionContext extensionContext) + throws ParameterResolutionException { + return pc.getParameter().getType() == Greeter.class; + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return greeter; + } + } +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/Repro8446Test.java b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/Repro8446Test.java new file mode 100644 index 0000000000000..2edab696af117 --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/testing/repro8446/Repro8446Test.java @@ -0,0 +1,20 @@ +package io.quarkus.it.main.testing.repro8446; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.extension.ExtendWith; + +import io.quarkus.test.junit.QuarkusTest; + +@Disabled("https://github.com/quarkusio/quarkus/issues/8446") +// fails with `IllegalArgumentException: argument type mismatch` +@QuarkusTest +public class Repro8446Test { + @TestTemplate + @ExtendWith(GreeterExtension.class) + public void test(Greeter greeter) { + assertEquals("hello", greeter.hello()); + } +} From 21a2b33d12805027e41cf9fccef8359206a46a6e Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 3 Dec 2024 11:38:56 +0000 Subject: [PATCH 007/207] Added compatible method for GlobalDevServicesConfig --- .../DevServicesSharedNetworkBuildItem.java | 14 ++++++++++++++ .../dev/devservices/GlobalDevServicesConfig.java | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesSharedNetworkBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesSharedNetworkBuildItem.java index df98eb89db333..e6a60b50116c6 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesSharedNetworkBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesSharedNetworkBuildItem.java @@ -10,6 +10,7 @@ import io.quarkus.builder.BuildStepBuilder; import io.quarkus.builder.item.MultiBuildItem; import io.quarkus.deployment.dev.devservices.DevServicesConfig; +import io.quarkus.deployment.dev.devservices.GlobalDevServicesConfig; /** * A marker build item that indicates, if any instances are provided during the build, the containers started by DevServices @@ -81,4 +82,17 @@ public static boolean isSharedNetworkRequired( (!devServicesSharedNetworkBuildItem.isEmpty() && devServicesSharedNetworkBuildItem.get(0).getSource().equals("io.quarkus.test.junit")); } + + /** + * @deprecated Please, use {@link DevServicesSharedNetworkBuildItem#isSharedNetworkRequired(DevServicesConfig, List)} + * instead. + */ + @Deprecated(forRemoval = true, since = "3.18") + public static boolean isSharedNetworkRequired( + GlobalDevServicesConfig globalDevServicesConfig, + List devServicesSharedNetworkBuildItem) { + return globalDevServicesConfig.launchOnSharedNetwork || + (!devServicesSharedNetworkBuildItem.isEmpty() + && devServicesSharedNetworkBuildItem.get(0).getSource().equals("io.quarkus.test.junit")); + } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/GlobalDevServicesConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/GlobalDevServicesConfig.java index 5f8d619e0b74c..593b8f3514f14 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/GlobalDevServicesConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/GlobalDevServicesConfig.java @@ -12,7 +12,7 @@ * * @deprecated Please, use {@link DevServicesConfig} instead. */ -@Deprecated(forRemoval = true) +@Deprecated(forRemoval = true, since = "3.18") @ConfigRoot(name = "devservices") public class GlobalDevServicesConfig { From 1cf51d1302345951044960fd3a236b6085732238 Mon Sep 17 00:00:00 2001 From: Rolfe Dlugy-Hegwer Date: Tue, 3 Dec 2024 14:11:10 -0500 Subject: [PATCH 008/207] Fix minor typo --- docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc b/docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc index a7efa83699346..68ae114f911d4 100644 --- a/docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc @@ -332,6 +332,7 @@ A similar technique can be used with `TenantConfigResolver`, where a `tenant-id` ==== If you also use Hibernate ORM multitenancy or MongoDB with Panache multitenancy and both tenant ids are the same, you can get the tenant id from the `RoutingContext` attribute with `tenant-id`. You can find more information here: + * xref:hibernate-orm.adoc#multitenancy[Hibernate ORM multitenancy] * xref:mongodb-panache.adoc#multitenancy[MongoDB with Panache multitenancy] ==== From 76a947e6f1de063eaf12177ca5c0b2b29577bc21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 22:18:24 +0000 Subject: [PATCH 009/207] Bump flyway.version from 11.0.0 to 11.0.1 Bumps `flyway.version` from 11.0.0 to 11.0.1. Updates `org.flywaydb:flyway-core` from 11.0.0 to 11.0.1 - [Release notes](https://github.com/flyway/flyway/releases) - [Commits](https://github.com/flyway/flyway/compare/flyway-11.0.0...flyway-11.0.1) Updates `org.flywaydb:flyway-sqlserver` from 11.0.0 to 11.0.1 Updates `org.flywaydb:flyway-mysql` from 11.0.0 to 11.0.1 Updates `org.flywaydb:flyway-database-oracle` from 11.0.0 to 11.0.1 Updates `org.flywaydb:flyway-database-postgresql` from 11.0.0 to 11.0.1 Updates `org.flywaydb:flyway-database-db2` from 11.0.0 to 11.0.1 Updates `org.flywaydb:flyway-database-derby` from 11.0.0 to 11.0.1 Updates `org.flywaydb:flyway-database-mongodb` from 11.0.0 to 11.0.1 --- updated-dependencies: - dependency-name: org.flywaydb:flyway-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.flywaydb:flyway-sqlserver dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.flywaydb:flyway-mysql dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.flywaydb:flyway-database-oracle dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.flywaydb:flyway-database-postgresql dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.flywaydb:flyway-database-db2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.flywaydb:flyway-database-derby dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.flywaydb:flyway-database-mongodb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 841de191e14c6..7b40168b0a875 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -158,7 +158,7 @@ 3.2.0 4.2.2 3.1.0.Final - 11.0.0 + 11.0.1 3.0.4 4.29.1 From 9b2367c3f63ab65b224f3bf21ee2decdbaf4e12a Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Tue, 3 Dec 2024 20:04:02 -0300 Subject: [PATCH 010/207] Convert Lambda REST and HTTP to @ConfigMapping --- .../amazon-lambda-http/deployment/pom.xml | 3 --- .../deployment/AmazonLambdaHttpProcessor.java | 2 +- .../deployment/LambdaHttpBuildTimeConfig.java | 10 +++++---- extensions/amazon-lambda-http/pom.xml | 1 - extensions/amazon-lambda-http/runtime/pom.xml | 3 --- .../amazon/lambda/http/CognitoPrincipal.java | 4 ++-- .../http/DefaultLambdaIdentityProvider.java | 2 +- .../amazon/lambda/http/LambdaHttpConfig.java | 22 ++++++++++--------- .../lambda/http/LambdaHttpRecorder.java | 2 +- .../amazon-lambda-rest/deployment/pom.xml | 3 --- .../deployment/AmazonLambdaHttpProcessor.java | 2 +- .../deployment/LambdaHttpBuildTimeConfig.java | 10 +++++---- extensions/amazon-lambda-rest/runtime/pom.xml | 3 --- .../amazon/lambda/http/CognitoPrincipal.java | 2 +- .../http/DefaultLambdaIdentityProvider.java | 2 +- .../amazon/lambda/http/LambdaHttpConfig.java | 20 +++++++++-------- .../lambda/http/LambdaHttpRecorder.java | 2 +- extensions/amazon-lambda/deployment/pom.xml | 3 --- 18 files changed, 44 insertions(+), 52 deletions(-) diff --git a/extensions/amazon-lambda-http/deployment/pom.xml b/extensions/amazon-lambda-http/deployment/pom.xml index d7088a8788cc3..9dfa37b46b7a1 100644 --- a/extensions/amazon-lambda-http/deployment/pom.xml +++ b/extensions/amazon-lambda-http/deployment/pom.xml @@ -68,9 +68,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/amazon-lambda-http/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java b/extensions/amazon-lambda-http/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java index dbe75f0b8d76f..e64a2b3e3b5a8 100644 --- a/extensions/amazon-lambda-http/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java +++ b/extensions/amazon-lambda-http/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java @@ -49,7 +49,7 @@ public void setupCDI(BuildProducer additionalBeans) { @BuildStep public void setupSecurity(BuildProducer additionalBeans, LambdaHttpBuildTimeConfig config) { - if (!config.enableSecurity) + if (!config.enableSecurity()) return; AdditionalBeanBuildItem.Builder builder = AdditionalBeanBuildItem.builder().setUnremovable(); diff --git a/extensions/amazon-lambda-http/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java b/extensions/amazon-lambda-http/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java index ba81e36664ba0..6d4d9c546bc78 100644 --- a/extensions/amazon-lambda-http/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java +++ b/extensions/amazon-lambda-http/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java @@ -1,14 +1,16 @@ package io.quarkus.amazon.lambda.http.deployment; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; @ConfigRoot -public class LambdaHttpBuildTimeConfig { +@ConfigMapping(prefix = "quarkus.lambda-http") +public interface LambdaHttpBuildTimeConfig { /** * Enable security mechanisms to process lambda and AWS based security (i.e. Cognito, IAM) from * the http event sent from API Gateway */ - @ConfigItem(defaultValue = "false") - public boolean enableSecurity; + @WithDefault("false") + boolean enableSecurity(); } diff --git a/extensions/amazon-lambda-http/pom.xml b/extensions/amazon-lambda-http/pom.xml index 78c20a2fb26b2..4d8f0ce264b8f 100644 --- a/extensions/amazon-lambda-http/pom.xml +++ b/extensions/amazon-lambda-http/pom.xml @@ -19,7 +19,6 @@ runtime http-event-server deployment - maven-archetype diff --git a/extensions/amazon-lambda-http/runtime/pom.xml b/extensions/amazon-lambda-http/runtime/pom.xml index f71b749e0497d..6a54eb16c6040 100644 --- a/extensions/amazon-lambda-http/runtime/pom.xml +++ b/extensions/amazon-lambda-http/runtime/pom.xml @@ -76,9 +76,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/CognitoPrincipal.java b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/CognitoPrincipal.java index a6a8714b7bf06..419388e56733c 100644 --- a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/CognitoPrincipal.java +++ b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/CognitoPrincipal.java @@ -76,8 +76,8 @@ public long getIssuedAtTime() { @Override public Set getGroups() { if (groups == null) { - if (jwt.getClaims().containsKey(LambdaHttpRecorder.config.cognitoRoleClaim)) { - String claim = jwt.getClaims().get(LambdaHttpRecorder.config.cognitoRoleClaim); + if (jwt.getClaims().containsKey(LambdaHttpRecorder.config.cognitoRoleClaim())) { + String claim = jwt.getClaims().get(LambdaHttpRecorder.config.cognitoRoleClaim()); Matcher matcher = LambdaHttpRecorder.groupPattern.matcher(claim); groups = new HashSet<>(); while (matcher.find()) { diff --git a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java index 4984b060fc758..41dce4966df13 100644 --- a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java +++ b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java @@ -27,7 +27,7 @@ public Class getRequestType() { public Uni authenticate(DefaultLambdaAuthenticationRequest request, AuthenticationRequestContext context) { APIGatewayV2HTTPEvent event = request.getEvent(); - SecurityIdentity identity = authenticate(event, LambdaHttpRecorder.config.mapCognitoToRoles); + SecurityIdentity identity = authenticate(event, LambdaHttpRecorder.config.mapCognitoToRoles()); if (identity == null) { return Uni.createFrom().optional(Optional.empty()); } diff --git a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpConfig.java b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpConfig.java index a89d1ec1159fa..acb5db14f201c 100644 --- a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpConfig.java +++ b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpConfig.java @@ -1,34 +1,36 @@ package io.quarkus.amazon.lambda.http; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; @ConfigRoot(phase = ConfigPhase.RUN_TIME) -public class LambdaHttpConfig { +@ConfigMapping(prefix = "quarkus.lambda-http") +public interface LambdaHttpConfig { /** * If true, Quarkus will map claims from Cognito to Quarkus security roles. * The "cognito:groups" claim will be used by default. Change cognitoRoleClaim * config value to change the claim source. - * + *

    * True by default */ - @ConfigItem(defaultValue = "true") - public boolean mapCognitoToRoles; + @WithDefault("true") + boolean mapCognitoToRoles(); /** * Cognito claim that contains roles you want to map. Defaults to "cognito:groups" */ - @ConfigItem(defaultValue = "cognito:groups") - public String cognitoRoleClaim; + @WithDefault("cognito:groups") + String cognitoRoleClaim(); /** * Regular expression to locate role values within a Cognito claim string. - * By default it looks for space delimited strings enclosed in brackets + * By default, it looks for space delimited strings enclosed in brackets * "[^\[\] \t]+" */ - @ConfigItem(defaultValue = "[^\\[\\] \\t]+") - public String cognitoClaimMatcher; + @WithDefault(value = "[^\\[\\] \\t]+") + String cognitoClaimMatcher(); } diff --git a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpRecorder.java b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpRecorder.java index c5c6a40677b35..616ca65c9c421 100644 --- a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpRecorder.java +++ b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpRecorder.java @@ -11,7 +11,7 @@ public class LambdaHttpRecorder { public void setConfig(LambdaHttpConfig c) { config = c; - String pattern = c.cognitoClaimMatcher; + String pattern = c.cognitoClaimMatcher(); groupPattern = Pattern.compile(pattern); } } diff --git a/extensions/amazon-lambda-rest/deployment/pom.xml b/extensions/amazon-lambda-rest/deployment/pom.xml index a4680f09844c4..8a9646c238b2d 100644 --- a/extensions/amazon-lambda-rest/deployment/pom.xml +++ b/extensions/amazon-lambda-rest/deployment/pom.xml @@ -68,9 +68,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/amazon-lambda-rest/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java b/extensions/amazon-lambda-rest/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java index d9c77a471769b..8925222267404 100644 --- a/extensions/amazon-lambda-rest/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java +++ b/extensions/amazon-lambda-rest/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/AmazonLambdaHttpProcessor.java @@ -49,7 +49,7 @@ public void setupCDI(BuildProducer additionalBeans) { @BuildStep public void setupSecurity(BuildProducer additionalBeans, LambdaHttpBuildTimeConfig config) { - if (!config.enableSecurity) + if (!config.enableSecurity()) return; AdditionalBeanBuildItem.Builder builder = AdditionalBeanBuildItem.builder().setUnremovable(); diff --git a/extensions/amazon-lambda-rest/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java b/extensions/amazon-lambda-rest/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java index ba81e36664ba0..6d4d9c546bc78 100644 --- a/extensions/amazon-lambda-rest/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java +++ b/extensions/amazon-lambda-rest/deployment/src/main/java/io/quarkus/amazon/lambda/http/deployment/LambdaHttpBuildTimeConfig.java @@ -1,14 +1,16 @@ package io.quarkus.amazon.lambda.http.deployment; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; @ConfigRoot -public class LambdaHttpBuildTimeConfig { +@ConfigMapping(prefix = "quarkus.lambda-http") +public interface LambdaHttpBuildTimeConfig { /** * Enable security mechanisms to process lambda and AWS based security (i.e. Cognito, IAM) from * the http event sent from API Gateway */ - @ConfigItem(defaultValue = "false") - public boolean enableSecurity; + @WithDefault("false") + boolean enableSecurity(); } diff --git a/extensions/amazon-lambda-rest/runtime/pom.xml b/extensions/amazon-lambda-rest/runtime/pom.xml index 9dd7859810e4c..b5c1e2111b4f0 100644 --- a/extensions/amazon-lambda-rest/runtime/pom.xml +++ b/extensions/amazon-lambda-rest/runtime/pom.xml @@ -57,9 +57,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/CognitoPrincipal.java b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/CognitoPrincipal.java index 3f49b91c199de..54c9c13530df3 100644 --- a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/CognitoPrincipal.java +++ b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/CognitoPrincipal.java @@ -81,7 +81,7 @@ public long getIssuedAtTime() { @Override public Set getGroups() { if (groups == null) { - String grpClaim = claims.getClaim(LambdaHttpRecorder.config.cognitoRoleClaim); + String grpClaim = claims.getClaim(LambdaHttpRecorder.config.cognitoRoleClaim()); if (grpClaim != null) { Matcher matcher = LambdaHttpRecorder.groupPattern.matcher(grpClaim); groups = new HashSet<>(); diff --git a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java index f9724fa8b4837..002d2af6dd60a 100644 --- a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java +++ b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/DefaultLambdaIdentityProvider.java @@ -27,7 +27,7 @@ public Class getRequestType() { public Uni authenticate(DefaultLambdaAuthenticationRequest request, AuthenticationRequestContext context) { AwsProxyRequest event = request.getEvent(); - SecurityIdentity identity = authenticate(event, LambdaHttpRecorder.config.mapCognitoToRoles); + SecurityIdentity identity = authenticate(event, LambdaHttpRecorder.config.mapCognitoToRoles()); if (identity == null) { return Uni.createFrom().optional(Optional.empty()); } diff --git a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpConfig.java b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpConfig.java index 08155dc49f59c..55ebc8c911fac 100644 --- a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpConfig.java +++ b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpConfig.java @@ -1,11 +1,13 @@ package io.quarkus.amazon.lambda.http; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; @ConfigRoot(phase = ConfigPhase.RUN_TIME) -public class LambdaHttpConfig { +@ConfigMapping(prefix = "quarkus.lambda-http") +public interface LambdaHttpConfig { /** * If true, runtime will search Cognito JWT claims for "cognito:groups" @@ -13,20 +15,20 @@ public class LambdaHttpConfig { * * True by default */ - @ConfigItem(defaultValue = "true") - public boolean mapCognitoToRoles; + @WithDefault("true") + boolean mapCognitoToRoles(); /** * Cognito claim that contains roles you want to map. Defaults to "cognito:groups" */ - @ConfigItem(defaultValue = "cognito:groups") - public String cognitoRoleClaim; + @WithDefault("cognito:groups") + String cognitoRoleClaim(); /** * Regular expression to locate role values within a Cognito claim string. - * By default it looks for space delimited strings enclosed in brackets + * By default, it looks for space delimited strings enclosed in brackets * "[^\[\] \t]+" */ - @ConfigItem(defaultValue = "[^\\[\\] \\t]+") - public String cognitoClaimMatcher; + @WithDefault("[^\\[\\] \\t]+") + String cognitoClaimMatcher(); } diff --git a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpRecorder.java b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpRecorder.java index c5c6a40677b35..616ca65c9c421 100644 --- a/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpRecorder.java +++ b/extensions/amazon-lambda-rest/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpRecorder.java @@ -11,7 +11,7 @@ public class LambdaHttpRecorder { public void setConfig(LambdaHttpConfig c) { config = c; - String pattern = c.cognitoClaimMatcher; + String pattern = c.cognitoClaimMatcher(); groupPattern = Pattern.compile(pattern); } } diff --git a/extensions/amazon-lambda/deployment/pom.xml b/extensions/amazon-lambda/deployment/pom.xml index 083bdd130e531..2eb03cfce23ff 100644 --- a/extensions/amazon-lambda/deployment/pom.xml +++ b/extensions/amazon-lambda/deployment/pom.xml @@ -62,9 +62,6 @@ ${project.version} - - -AlegacyConfigRoot=true - From 58f6144fd64b61d4b33be9b6f0f0e8c1144d150c Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Tue, 3 Dec 2024 20:54:52 -0300 Subject: [PATCH 011/207] Remove `cleanOnValidationError` config in Flyway Starting in Flyway 11.0.0 (see https://documentation.red-gate.com/flyway/release-notes-and-older-versions/release-notes-for-flyway-engine), the `cleanOnValidationError` function and configuration has been removed. An error will be thrown if this feature is configured. Therefore it is better to remove this configuration from Quarkus so applications using it would fail as well (instead of deprecating it) --- .../io/quarkus/flyway/runtime/FlywayCreator.java | 1 - .../runtime/FlywayDataSourceRuntimeConfig.java | 6 ------ .../flyway/runtime/FlywayCreatorTest.java | 16 ---------------- 3 files changed, 23 deletions(-) diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayCreator.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayCreator.java index bcdbb76e0361d..9401b42d184fe 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayCreator.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayCreator.java @@ -117,7 +117,6 @@ public Flyway createFlyway(DataSource dataSource) { } configure.ignoreMigrationPatterns(ignoreMigrationPatterns); - configure.cleanOnValidationError(flywayRuntimeConfig.cleanOnValidationError); configure.outOfOrder(flywayRuntimeConfig.outOfOrder); if (flywayRuntimeConfig.baselineVersion.isPresent()) { configure.baselineVersion(flywayRuntimeConfig.baselineVersion.get()); diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java index 772ba52458280..ed0c82aaa2a76 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java @@ -131,12 +131,6 @@ public static FlywayDataSourceRuntimeConfig defaultConfig() { @ConfigItem public boolean cleanDisabled; - /** - * true to automatically call clean when a validation error occurs, false otherwise. - */ - @ConfigItem - public boolean cleanOnValidationError; - /** * true to execute Flyway automatically when the application starts, false otherwise. * diff --git a/extensions/flyway/runtime/src/test/java/io/quarkus/flyway/runtime/FlywayCreatorTest.java b/extensions/flyway/runtime/src/test/java/io/quarkus/flyway/runtime/FlywayCreatorTest.java index 17764887791ed..4995671779b3f 100644 --- a/extensions/flyway/runtime/src/test/java/io/quarkus/flyway/runtime/FlywayCreatorTest.java +++ b/extensions/flyway/runtime/src/test/java/io/quarkus/flyway/runtime/FlywayCreatorTest.java @@ -222,22 +222,6 @@ void testIgnoreFutureMigrations() { assertTrue(ValidatePatternUtils.isFutureIgnored(createdFlywayConfig().getIgnoreMigrationPatterns())); } - @Test - @DisplayName("cleanOnValidationError defaults to false and is correctly set") - void testCleanOnValidationError() { - creator = new FlywayCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.cleanOnValidationError, createdFlywayConfig().isCleanOnValidationError()); - assertFalse(runtimeConfig.cleanOnValidationError); - - runtimeConfig.cleanOnValidationError = false; - creator = new FlywayCreator(runtimeConfig, buildConfig); - assertFalse(createdFlywayConfig().isCleanOnValidationError()); - - runtimeConfig.cleanOnValidationError = true; - creator = new FlywayCreator(runtimeConfig, buildConfig); - assertTrue(createdFlywayConfig().isCleanOnValidationError()); - } - @ParameterizedTest @MethodSource("validateOnMigrateOverwritten") @DisplayName("validate on migrate overwritten in configuration") From 87817c6c2a8b060dc61645ace51b73bf87332e57 Mon Sep 17 00:00:00 2001 From: Holly Cummins Date: Wed, 4 Dec 2024 11:15:15 +1100 Subject: [PATCH 012/207] Add guard that network is available on test --- .../builditem/GeneratedResourceBuildItemTest.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/GeneratedResourceBuildItemTest.java b/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/GeneratedResourceBuildItemTest.java index 4a2ff352966e7..85c75b637ca23 100644 --- a/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/GeneratedResourceBuildItemTest.java +++ b/integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/deployment/pkg/builditem/GeneratedResourceBuildItemTest.java @@ -6,11 +6,14 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.InetAddress; import java.net.URL; +import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -35,7 +38,8 @@ class GeneratedResourceBuildItemTest { Dependency.of("org.apache.cxf", "cxf-rt-bindings-soap", "3.4.3"))); @Test - public void testXMLResourceWasMerged() throws IOException { + public void testXMLResourceWasMerged() { + Assumptions.assumeTrue(isOnline()); assertThat(runner.getStartupConsoleOutput()).contains("RESOURCES: 1", "org.apache.cxf.binding.xml.wsdl11.HttpAddressPlugin", "org.apache.cxf.binding.xml.wsdl11.XmlBindingPlugin", @@ -58,4 +62,13 @@ public static void main(String[] args) throws IOException { } } } + + boolean isOnline() { + try { + InetAddress resolved = InetAddress.getByName("sun.com"); + return resolved != null; + } catch (UnknownHostException e) { + return false; + } + } } From f3de58ee8028a93f76b707ced5d0c4db0856bba7 Mon Sep 17 00:00:00 2001 From: Holly Cummins Date: Wed, 4 Dec 2024 17:34:20 +1100 Subject: [PATCH 013/207] Run test on non-native scenarios --- .../java/io/quarkus/it/extension/ClasspathTestCase.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/ClasspathTestCase.java b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/ClasspathTestCase.java index 3a8efbf1b22f1..29fed1e8a63f1 100644 --- a/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/ClasspathTestCase.java +++ b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/ClasspathTestCase.java @@ -3,7 +3,6 @@ import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.is; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import io.quarkus.test.junit.DisabledOnIntegrationTest; @@ -53,9 +52,10 @@ public void testStaticInitMainResourceNoDuplicate() { .body(is("OK")); } + // For some reason, class files are not accessible as resources through the runtime init classloader;" + // that's beside the point of this PR though, so we'll ignore that." @Test - @Disabled("For some reason, class files are not accessible as resources through the runtime init classloader;" - + " that's beside the point of this PR though, so we'll ignore that.") + @DisabledOnIntegrationTest() public void testRuntimeInitMainClassNoDuplicate() { given().param("resourceName", CLASS_FILE) .param("phase", "runtime_init") @@ -65,6 +65,8 @@ public void testRuntimeInitMainClassNoDuplicate() { @Test public void testRuntimeInitMainResourceNoDuplicate() { + // Runtime classloader classes are stored in memory, as "quarkus:" resources, and we do not have a quarkus filesystem provider + // at the moment, the path helper works around that by hacking/reverse engineering a file-based location given().param("resourceName", RESOURCE_FILE) .param("phase", "runtime_init") .when().get("/core/classpath").then() From c9b80463b4a468f0ef9e943eca8da2dcc43f52dd Mon Sep 17 00:00:00 2001 From: Stephan Strate Date: Wed, 4 Dec 2024 15:37:08 +0100 Subject: [PATCH 014/207] Register Kotlin's empty set for reflection --- .../java/io/quarkus/kotlin/deployment/KotlinProcessor.java | 4 +++- .../main/kotlin/io/quarkus/it/kotser/GreetingResource.kt | 6 ++++++ .../src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/extensions/kotlin/deployment/src/main/java/io/quarkus/kotlin/deployment/KotlinProcessor.java b/extensions/kotlin/deployment/src/main/java/io/quarkus/kotlin/deployment/KotlinProcessor.java index aff88dfbd80b2..8a95b61750fe2 100644 --- a/extensions/kotlin/deployment/src/main/java/io/quarkus/kotlin/deployment/KotlinProcessor.java +++ b/extensions/kotlin/deployment/src/main/java/io/quarkus/kotlin/deployment/KotlinProcessor.java @@ -62,7 +62,9 @@ void registerKotlinReflection(final BuildProducer refl reflectiveClass.produce(ReflectiveClassBuildItem.builder("kotlin.KotlinVersion$Companion[]").constructors(false) .build()); reflectiveClass.produce( - ReflectiveClassBuildItem.builder("kotlin.collections.EmptyList", "kotlin.collections.EmptyMap").build()); + ReflectiveClassBuildItem + .builder("kotlin.collections.EmptyList", "kotlin.collections.EmptyMap", "kotlin.collections.EmptySet") + .build()); nativeResourcePatterns.produce(builder().includePatterns( "META-INF/.*.kotlin_module$", diff --git a/integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt b/integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt index a1d0804d563c0..bbf30af7b3626 100644 --- a/integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt +++ b/integration-tests/kotlin/src/main/kotlin/io/quarkus/it/kotser/GreetingResource.kt @@ -85,5 +85,11 @@ class GreetingResource { return emptyMap() } + @GET + @Path("emptySet") + fun emptySet(): Set { + return emptySet() + } + fun reflect() = "hello, world" } diff --git a/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt b/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt index 35d43c86e164f..4f50cae5545b5 100644 --- a/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt +++ b/integration-tests/kotlin/src/test/kotlin/io/quarkus/it/kotser/ResourceTest.kt @@ -134,4 +134,9 @@ open class ResourceTest { fun testEmptyMap() { When { get("/emptyList") } Then { statusCode(200) } } + + @Test + fun testEmptySet() { + When { get("/emptySet") } Then { statusCode(200) } + } } From 24b69e5c76fb623be75c5982f48df29959f5a28e Mon Sep 17 00:00:00 2001 From: Marek Skacelik Date: Wed, 4 Dec 2024 16:11:06 +0100 Subject: [PATCH 015/207] Moved 3 SmallRye GraphQL properties to runtime specific config properties --- .../deployment/SmallRyeGraphQLProcessor.java | 7 -- .../ExcludeNullFieldsInResponseTest.java | 86 +++++++++++++++++ .../HideCheckedExceptionMessageTest.java | 95 +++++++++++++++++++ .../ShowRuntimeExceptionMessageTest.java | 71 ++++++++++++++ .../runtime/SmallRyeGraphQLConfig.java | 22 ----- .../runtime/SmallRyeGraphQLConfigMapping.java | 2 + .../runtime/SmallRyeGraphQLRuntimeConfig.java | 25 +++++ 7 files changed, 279 insertions(+), 29 deletions(-) create mode 100644 extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/ExcludeNullFieldsInResponseTest.java create mode 100644 extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/HideCheckedExceptionMessageTest.java create mode 100644 extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/ShowRuntimeExceptionMessageTest.java diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java index f0ea44583d256..f63ee7467a648 100644 --- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java +++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java @@ -641,13 +641,6 @@ private Set getAllReferenceClasses(Reference reference) { return classes; } - @BuildStep - void excludeNullFieldsInResponses(SmallRyeGraphQLConfig graphQLConfig, - BuildProducer systemProperties) { - systemProperties.produce(new SystemPropertyBuildItem(ConfigKey.EXCLUDE_NULL_FIELDS_IN_RESPONSES, - String.valueOf(graphQLConfig.excludeNullFieldsInResponses.orElse(false)))); - } - @BuildStep void printDataFetcherExceptionInDevMode(SmallRyeGraphQLConfig graphQLConfig, LaunchModeBuildItem launchMode, diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/ExcludeNullFieldsInResponseTest.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/ExcludeNullFieldsInResponseTest.java new file mode 100644 index 0000000000000..bcf839cf299b2 --- /dev/null +++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/ExcludeNullFieldsInResponseTest.java @@ -0,0 +1,86 @@ +package io.quarkus.smallrye.graphql.deployment; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; +import static org.jboss.resteasy.reactive.RestResponse.StatusCode.OK; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class ExcludeNullFieldsInResponseTest extends AbstractGraphQLTest { + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(TestApi.class, Book.class, Author.class) + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") + .addAsResource( + new StringAsset( + "quarkus.smallrye-graphql.exclude-null-fields-in-responses=true"), + "application.properties")); + + @Test + void testExcludeNullFieldsInResponse() { + final String request = getPayload(""" + { + books { + name + pages + author { + firstName + lastName + } + } + }"""); + given() + .when() + .accept(MEDIATYPE_JSON) + .contentType(MEDIATYPE_JSON) + .body(request) + .post("/graphql") + .then() + .assertThat() + .statusCode(OK) + .and() + .body(containsString("{\"data\":{" + + "\"books\":[{" + + "\"name\":\"The Hobbit\"," + + // missing null field + "\"author\":{" + + "\"firstName\":\"J.R.R.\"" + + // missing null field + "}" + + "},{" + + "\"name\":\"The Lord of the Rings\"," + + "\"pages\":1178," + + "\"author\":{" + + "\"firstName\":\"J.R.R.\"," + + "\"lastName\":\"Tolkien\"" + + "}" + + "}]" + + "}}")); + } + + @GraphQLApi + public static class TestApi { + @Query + public Book[] getBooks() { + return new Book[] { + new Book("The Hobbit", null, new Author("J.R.R.", null)), + new Book("The Lord of the Rings", 1178, new Author("J.R.R.", "Tolkien")) + }; + } + } + + public record Book(String name, Integer pages, Author author) { + } + + public record Author(String firstName, String lastName) { + } +} diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/HideCheckedExceptionMessageTest.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/HideCheckedExceptionMessageTest.java new file mode 100644 index 0000000000000..7c9c13fd86af7 --- /dev/null +++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/HideCheckedExceptionMessageTest.java @@ -0,0 +1,95 @@ +package io.quarkus.smallrye.graphql.deployment; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; +import static org.jboss.resteasy.reactive.RestResponse.StatusCode.OK; + +import java.io.IOException; +import java.sql.SQLException; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class HideCheckedExceptionMessageTest extends AbstractGraphQLTest { + + private static final String IOEXCEPTION_MESSAGE = "Something went wrong"; + private static final String INTERRUPTED_EXCEPTION_MESSAGE = "Something else went wrong"; + private static final String SQL_EXCEPTION_MESSAGE = "Something went really wrong, but should expect a message"; + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(TestApi.class) + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") + .addAsResource( + new StringAsset( + "quarkus.smallrye-graphql.hide-checked-exception-message=" + + "java.io.IOException," + + "java.lang.InterruptedException"), + "application.properties")); + + @Test + void testExcludeNullFieldsInResponse() { + given() + .when() + .accept(MEDIATYPE_JSON) + .contentType(MEDIATYPE_JSON) + .body(getPayload("{ something }")) + .post("/graphql") + .then() + .assertThat() + .statusCode(OK) + .and() + .body(not(containsString(IOEXCEPTION_MESSAGE))); + + given() + .when() + .accept(MEDIATYPE_JSON) + .contentType(MEDIATYPE_JSON) + .body(getPayload("{ somethingElse }")) + .post("/graphql") + .then() + .assertThat() + .statusCode(OK) + .and() + .body(not(containsString(INTERRUPTED_EXCEPTION_MESSAGE))); + + given() + .when() + .accept(MEDIATYPE_JSON) + .contentType(MEDIATYPE_JSON) + .body(getPayload("{ somethingElseElse }")) + .post("/graphql") + .then() + .assertThat() + .statusCode(OK) + .and() + .body(containsString(SQL_EXCEPTION_MESSAGE)); + } + + @GraphQLApi + public static class TestApi { + @Query + public String getSomething() throws IOException { + throw new IOException(IOEXCEPTION_MESSAGE); + } + + @Query + public String getSomethingElse() throws InterruptedException { + throw new InterruptedException(INTERRUPTED_EXCEPTION_MESSAGE); + } + + @Query + public String getSomethingElseElse() throws SQLException { + throw new SQLException(SQL_EXCEPTION_MESSAGE); + } + } + +} diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/ShowRuntimeExceptionMessageTest.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/ShowRuntimeExceptionMessageTest.java new file mode 100644 index 0000000000000..8256ef413c017 --- /dev/null +++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/ShowRuntimeExceptionMessageTest.java @@ -0,0 +1,71 @@ +package io.quarkus.smallrye.graphql.deployment; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; +import static org.jboss.resteasy.reactive.RestResponse.StatusCode.OK; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Query; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class ShowRuntimeExceptionMessageTest extends AbstractGraphQLTest { + + private static final String ILLEGAL_ARGUMENT_EXCEPTION_MESSAGE = "Something went wrong"; + private static final String ILLEGAL_STATE_EXCEPTION_MESSAGE = "Something else went wrong"; + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(TestApi.class) + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") + .addAsResource( + new StringAsset( + "quarkus.smallrye-graphql.show-runtime-exception-message=" + + "java.lang.IllegalArgumentException," + + "java.lang.IllegalStateException"), + "application.properties")); + + @Test + void testExcludeNullFieldsInResponse() { + given() + .when() + .accept(MEDIATYPE_JSON) + .contentType(MEDIATYPE_JSON) + .body(getPayload("{ something }")) + .post("/graphql") + .then() + .assertThat() + .statusCode(OK) + .and() + .body(containsString(ILLEGAL_ARGUMENT_EXCEPTION_MESSAGE)); + + given() + .when() + .accept(MEDIATYPE_JSON) + .contentType(MEDIATYPE_JSON) + .body(getPayload("{ somethingElse }")) + .post("/graphql") + .then() + .assertThat() + .statusCode(OK) + .and() + .body(containsString(ILLEGAL_STATE_EXCEPTION_MESSAGE)); + } + + @GraphQLApi + public static class TestApi { + @Query + public String getSomething() { + throw new IllegalArgumentException(ILLEGAL_ARGUMENT_EXCEPTION_MESSAGE); + } + + @Query + public String getSomethingElse() { + throw new IllegalStateException(ILLEGAL_STATE_EXCEPTION_MESSAGE); + } + } +} diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLConfig.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLConfig.java index 0dcc17601d7fa..74d4b382698a9 100644 --- a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLConfig.java +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLConfig.java @@ -83,20 +83,6 @@ public class SmallRyeGraphQLConfig { @ConfigItem public Optional> errorExtensionFields; - /** - * List of Runtime Exceptions class names that should show the error message. - * By default, Runtime Exception messages will be hidden and a generic `Server Error` message will be returned. - */ - @ConfigItem - public Optional> showRuntimeExceptionMessage; - - /** - * List of Checked Exceptions class names that should hide the error message. - * By default, Checked Exception messages will show the exception message. - */ - @ConfigItem - public Optional> hideCheckedExceptionMessage; - /** * The default error message that will be used for hidden exception messages. * Defaults to "Server Error" @@ -215,12 +201,4 @@ public class SmallRyeGraphQLConfig { */ @ConfigItem public Optional> extraScalars; - - /** - * Excludes all the 'null' fields in the GraphQL response's data field, - * except for the non-successfully resolved fields (errors). - * Disabled by default. - */ - @ConfigItem - public Optional excludeNullFieldsInResponses; } diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLConfigMapping.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLConfigMapping.java index f5a41dc4f494c..f78f20bd66f25 100644 --- a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLConfigMapping.java +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLConfigMapping.java @@ -41,6 +41,7 @@ private static Map relocations() { mapKey(relocations, ConfigKey.ALLOW_GET, QUARKUS_HTTP_GET_ENABLED); mapKey(relocations, ConfigKey.ALLOW_POST_WITH_QUERY_PARAMETERS, QUARKUS_HTTP_POST_QUERYPARAMETERS_ENABLED); mapKey(relocations, ConfigKey.ERROR_EXTENSION_FIELDS, QUARKUS_ERROR_EXTENSION_FIELDS); + mapKey(relocations, ConfigKey.EXCLUDE_NULL_FIELDS_IN_RESPONSES, QUARKUS_EXCLUDE_NULL_FIELDS_IN_RESPONSES); mapKey(relocations, ConfigKey.DEFAULT_ERROR_MESSAGE, QUARKUS_DEFAULT_ERROR_MESSAGE); mapKey(relocations, ConfigKey.SCHEMA_INCLUDE_SCALARS, QUARKUS_SCHEMA_INCLUDE_SCALARS); mapKey(relocations, ConfigKey.SCHEMA_INCLUDE_DEFINITION, QUARKUS_SCHEMA_INCLUDE_DEFINITION); @@ -69,6 +70,7 @@ private static void mapKey(Map map, String quarkusKey, String ot private static final String SHOW_ERROR_MESSAGE = "mp.graphql.showErrorMessage"; private static final String HIDE_ERROR_MESSAGE = "mp.graphql.hideErrorMessage"; private static final String QUARKUS_ERROR_EXTENSION_FIELDS = "quarkus.smallrye-graphql.error-extension-fields"; + private static final String QUARKUS_EXCLUDE_NULL_FIELDS_IN_RESPONSES = "quarkus.smallrye-graphql.exclude-null-fields-in-responses"; private static final String QUARKUS_DEFAULT_ERROR_MESSAGE = "quarkus.smallrye-graphql.default-error-message"; private static final String QUARKUS_SHOW_ERROR_MESSAGE = "quarkus.smallrye-graphql.show-runtime-exception-message"; private static final String QUARKUS_HIDE_ERROR_MESSAGE = "quarkus.smallrye-graphql.hide-checked-exception-message"; diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRuntimeConfig.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRuntimeConfig.java index 9cd45806c253f..e74025abcb765 100644 --- a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRuntimeConfig.java +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRuntimeConfig.java @@ -1,5 +1,8 @@ package io.quarkus.smallrye.graphql.runtime; +import java.util.List; +import java.util.Optional; + import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; @@ -23,4 +26,26 @@ public class SmallRyeGraphQLRuntimeConfig { */ @ConfigItem(defaultValue = "default") public String fieldVisibility; + + /** + * Excludes all the 'null' fields in the GraphQL response's data field, + * except for the non-successfully resolved fields (errors). + * Disabled by default. + */ + @ConfigItem + public Optional excludeNullFieldsInResponses; + + /** + * List of Runtime Exceptions class names that should show the error message. + * By default, Runtime Exception messages will be hidden and a generic `Server Error` message will be returned. + */ + @ConfigItem + public Optional> showRuntimeExceptionMessage; + + /** + * List of Checked Exceptions class names that should hide the error message. + * By default, Checked Exception messages will show the exception message. + */ + @ConfigItem + public Optional> hideCheckedExceptionMessage; } From dbcc61b27bf13ce1a4efc91e506ed2e87faf6cdf Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 29 Nov 2024 17:13:32 +0100 Subject: [PATCH 016/207] Avoid providing Java 11 as a viable alternative in CLI --- .../src/main/java/io/quarkus/devtools/project/JavaVersion.java | 2 +- .../test/java/io/quarkus/devtools/project/JavaVersionTest.java | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/JavaVersion.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/JavaVersion.java index d443bc65b04ec..9fa717adc08c2 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/JavaVersion.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/JavaVersion.java @@ -66,7 +66,7 @@ public String toString() { } // ordering is important here, so let's keep them ordered - public static final SortedSet JAVA_VERSIONS_LTS = new TreeSet<>(List.of(11, 17, 21)); + public static final SortedSet JAVA_VERSIONS_LTS = new TreeSet<>(List.of(17, 21)); public static final int DEFAULT_JAVA_VERSION = 17; // we want to maximize the compatibility of extensions with the Quarkus ecosystem so let's stick to 17 by default public static final String DEFAULT_JAVA_VERSION_FOR_EXTENSION = "17"; diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/devtools/project/JavaVersionTest.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/devtools/project/JavaVersionTest.java index 329801653dac8..7f4b390e2061a 100644 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/devtools/project/JavaVersionTest.java +++ b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/devtools/project/JavaVersionTest.java @@ -37,7 +37,6 @@ public void givenJavaVersion21ShouldReturn21() { @Test void shouldProperlyUseMinJavaVersion() { - assertThat(getCompatibleLTSVersions(new JavaVersion("11"))).isEqualTo(JAVA_VERSIONS_LTS); assertThat(getCompatibleLTSVersions(new JavaVersion("17"))).containsExactly(17, 21); assertThat(getCompatibleLTSVersions(new JavaVersion("21"))).containsExactly(21); assertThat(getCompatibleLTSVersions(new JavaVersion("100"))).isEmpty(); @@ -52,8 +51,6 @@ public void givenAutoDetectShouldReturnAppropriateVersion() { @Test public void testDetermineBestLtsVersion() { - assertEquals(17, determineBestJavaLtsVersion(8)); - assertEquals(11, determineBestJavaLtsVersion(11)); assertEquals(17, determineBestJavaLtsVersion(17)); assertEquals(17, determineBestJavaLtsVersion(18)); assertEquals(21, determineBestJavaLtsVersion(21)); From 0eb2f3c13885c5cc74889f3ca79da745f5400aa0 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 29 Nov 2024 17:13:48 +0100 Subject: [PATCH 017/207] Drop Java 11/17 methods: minimum is Java 17 anyway --- .../CompiledJavaVersionBuildItem.java | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/CompiledJavaVersionBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/CompiledJavaVersionBuildItem.java index 33d544f1fadd4..77f79cb7f3298 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/CompiledJavaVersionBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/builditem/CompiledJavaVersionBuildItem.java @@ -24,15 +24,6 @@ public JavaVersion getJavaVersion() { public interface JavaVersion { - @Deprecated(forRemoval = true) - Status isExactlyJava11(); - - @Deprecated(forRemoval = true) - Status isJava11OrHigher(); - - @Deprecated(forRemoval = true) - Status isJava17OrHigher(); - Status isJava21OrHigher(); Status isJava19OrHigher(); @@ -48,21 +39,6 @@ final class Unknown implements JavaVersion { Unknown() { } - @Override - public Status isExactlyJava11() { - return Status.UNKNOWN; - } - - @Override - public Status isJava11OrHigher() { - return Status.UNKNOWN; - } - - @Override - public Status isJava17OrHigher() { - return Status.UNKNOWN; - } - @Override public Status isJava21OrHigher() { return Status.UNKNOWN; @@ -76,8 +52,6 @@ public Status isJava19OrHigher() { final class Known implements JavaVersion { - private static final int JAVA_11_MAJOR = 55; - private static final int JAVA_17_MAJOR = 61; private static final int JAVA_19_MAJOR = 63; private static final int JAVA_21_MAJOR = 65; @@ -87,21 +61,6 @@ final class Known implements JavaVersion { this.determinedMajor = determinedMajor; } - @Override - public Status isExactlyJava11() { - return equalStatus(JAVA_11_MAJOR); - } - - @Override - public Status isJava11OrHigher() { - return higherOrEqualStatus(JAVA_11_MAJOR); - } - - @Override - public Status isJava17OrHigher() { - return higherOrEqualStatus(JAVA_17_MAJOR); - } - @Override public Status isJava19OrHigher() { return higherOrEqualStatus(JAVA_19_MAJOR); From 139a74ddf6e7b9d44c3b67ade6d50044420abb41 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 29 Nov 2024 17:17:27 +0100 Subject: [PATCH 018/207] Update version examples in CLI documentation These were way outdated and not even using our new version convention. --- .../io/quarkus/cli/common/TargetQuarkusPlatformGroup.java | 6 +++--- .../io/quarkus/cli/common/TargetQuarkusVersionGroup.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/devtools/cli/src/main/java/io/quarkus/cli/common/TargetQuarkusPlatformGroup.java b/devtools/cli/src/main/java/io/quarkus/cli/common/TargetQuarkusPlatformGroup.java index 113d3c3d2a4ae..f1ba101c2cc35 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/common/TargetQuarkusPlatformGroup.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/common/TargetQuarkusPlatformGroup.java @@ -9,7 +9,7 @@ public class TargetQuarkusPlatformGroup { static final String FULL_EXAMPLE = ToolsConstants.DEFAULT_PLATFORM_BOM_GROUP_ID + ":" - + ToolsConstants.DEFAULT_PLATFORM_BOM_ARTIFACT_ID + ":2.2.0.Final"; + + ToolsConstants.DEFAULT_PLATFORM_BOM_ARTIFACT_ID + ":3.15.2"; PlatformStreamCoords streamCoords = null; String validStream = null; @@ -20,7 +20,7 @@ public class TargetQuarkusPlatformGroup { CommandSpec spec; @CommandLine.Option(paramLabel = "platformKey:streamId", names = { "-S", - "--stream" }, description = "A target stream, for example:%n io.quarkus.platform:2.0") + "--stream" }, description = "A target stream, for example:%n 3.15 or io.quarkus.platform:3.15") void setStream(String stream) { stream = stream.trim(); if (!stream.isEmpty()) { @@ -39,7 +39,7 @@ void setStream(String stream) { "--platform-bom" }, description = "A specific Quarkus platform BOM, for example:%n" + " " + FULL_EXAMPLE + "%n" + " io.quarkus::999-SNAPSHOT" - + " 2.2.0.Final%n" + + " 3.15.2%n" + "Default groupId: " + ToolsConstants.DEFAULT_PLATFORM_BOM_GROUP_ID + "%n" + "Default artifactId: " + ToolsConstants.DEFAULT_PLATFORM_BOM_ARTIFACT_ID + "%n") void setPlatformBom(String bom) { diff --git a/devtools/cli/src/main/java/io/quarkus/cli/common/TargetQuarkusVersionGroup.java b/devtools/cli/src/main/java/io/quarkus/cli/common/TargetQuarkusVersionGroup.java index 53b2ff28a120b..1ed701fc35355 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/common/TargetQuarkusVersionGroup.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/common/TargetQuarkusVersionGroup.java @@ -5,12 +5,12 @@ public class TargetQuarkusVersionGroup { @CommandLine.Option(paramLabel = "targetStream", names = { "-S", - "--stream" }, description = "A target stream, for example:%n 2.0") + "--stream" }, description = "A target stream, for example:%n 3.15") public String streamId; @CommandLine.Option(paramLabel = "targetPlatformVersion", names = { "-P", "--platform-version" }, description = "A specific target Quarkus platform version, for example:%n" - + " 2.2.0.Final%n") + + " 3.15.2%n") public String platformVersion; //@CommandLine.Option(names = { "-L", From 8b82767d5c7e06aef3021b99bb56b223f5f5c34f Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Wed, 4 Dec 2024 17:56:29 +0000 Subject: [PATCH 019/207] Avoid Converters annotations introspection at runtime --- .../steps/ConfigGenerationBuildStep.java | 51 ++++++++++++++++--- .../configuration/AbstractConfigBuilder.java | 12 +++-- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java index 2a9ce52ff6a43..6d87ce82fa6f1 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java @@ -27,12 +27,19 @@ import java.util.Optional; import java.util.Set; +import jakarta.annotation.Priority; + import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; import org.eclipse.microprofile.config.ConfigValue; import org.eclipse.microprofile.config.spi.ConfigSource; import org.eclipse.microprofile.config.spi.ConfigSourceProvider; import org.eclipse.microprofile.config.spi.Converter; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.DotName; +import org.jboss.jandex.ParameterizedType; +import org.jboss.jandex.Type; import org.objectweb.asm.Opcodes; import io.quarkus.bootstrap.classloading.QuarkusClassLoader; @@ -200,6 +207,7 @@ void generateMappings( @BuildStep void generateBuilders( ConfigurationBuildItem configItem, + CombinedIndexBuildItem combinedIndex, List configMappings, List runTimeDefaults, List staticInitConfigBuilders, @@ -246,6 +254,7 @@ void generateBuilders( staticCustomizers.add(StaticInitConfigBuilder.class.getName()); generateConfigBuilder(generatedClass, reflectiveClass, CONFIG_STATIC_NAME, + combinedIndex, defaultValues, converters, interceptors, @@ -269,6 +278,7 @@ void generateBuilders( runtimeCustomizers.add(RuntimeConfigBuilder.class.getName()); generateConfigBuilder(generatedClass, reflectiveClass, CONFIG_RUNTIME_NAME, + combinedIndex, defaultValues, converters, interceptors, @@ -520,7 +530,7 @@ private static String getPathWithoutExtension(Path path) { "withDefaultValue", void.class, SmallRyeConfigBuilder.class, String.class, String.class); private static final MethodDescriptor WITH_CONVERTER = MethodDescriptor.ofMethod(AbstractConfigBuilder.class, - "withConverter", void.class, SmallRyeConfigBuilder.class, Converter.class); + "withConverter", void.class, SmallRyeConfigBuilder.class, String.class, int.class, Converter.class); private static final MethodDescriptor WITH_INTERCEPTOR = MethodDescriptor.ofMethod(AbstractConfigBuilder.class, "withInterceptor", void.class, SmallRyeConfigBuilder.class, ConfigSourceInterceptor.class); @@ -549,17 +559,15 @@ private static String getPathWithoutExtension(Path path) { private static final MethodDescriptor WITH_BUILDER = MethodDescriptor.ofMethod(AbstractConfigBuilder.class, "withBuilder", void.class, SmallRyeConfigBuilder.class, ConfigBuilder.class); - private static final MethodDescriptor WITH_NAMES = MethodDescriptor.ofMethod(SmallRyeConfigBuilder.class, - "withMappingNames", - SmallRyeConfigBuilder.class, Map.class); - private static final MethodDescriptor WITH_KEYS = MethodDescriptor.ofMethod(SmallRyeConfigBuilder.class, - "withMappingKeys", - SmallRyeConfigBuilder.class, Set.class); + + private static final DotName CONVERTER_NAME = DotName.createSimple(Converter.class.getName()); + private static final DotName PRIORITY_NAME = DotName.createSimple(Priority.class.getName()); private static void generateConfigBuilder( BuildProducer generatedClass, BuildProducer reflectiveClass, String className, + CombinedIndexBuildItem combinedIndex, Map defaultValues, Set converters, Set interceptors, @@ -591,7 +599,13 @@ private static void generateConfigBuilder( } for (String converter : converters) { + ClassInfo converterClass = combinedIndex.getComputingIndex().getClassByName(converter); + Type type = getConverterType(converterClass, combinedIndex); + AnnotationInstance priorityAnnotation = converterClass.annotation(PRIORITY_NAME); + int priority = priorityAnnotation != null ? priorityAnnotation.value().asInt() : 100; method.invokeStaticMethod(WITH_CONVERTER, configBuilder, + method.load(type.name().toString()), + method.load(priority), method.newInstance(MethodDescriptor.ofConstructor(converter))); } @@ -716,4 +730,27 @@ private static Set runtimeConfigMappings(List arguments = parameterizedType.arguments(); + if (arguments.size() != 1) { + throw new IllegalArgumentException( + "Converter " + converter.name() + " must be parameterized with a single type"); + } + return arguments.get(0); + } + } + } + + return getConverterType(combinedIndex.getComputingIndex().getClassByName(converter.superName()), combinedIndex); + } } diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/AbstractConfigBuilder.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/AbstractConfigBuilder.java index 84f9336c4ad61..15dc4e2604aa2 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/AbstractConfigBuilder.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/AbstractConfigBuilder.java @@ -21,10 +21,14 @@ protected static void withDefaultValue(SmallRyeConfigBuilder builder, String nam builder.withDefaultValue(name, value); } - // TODO - radcortez - Can be improved by avoiding introspection work in the Converter class. - // Not a big issue, because registering Converters via ServiceLoader is not a common case - protected static void withConverter(SmallRyeConfigBuilder builder, Converter converter) { - builder.withConverters(new Converter[] { converter }); + @SuppressWarnings("unchecked") + protected static void withConverter(SmallRyeConfigBuilder builder, String type, int priority, Converter converter) { + try { + // To support converters that are not public + builder.withConverter((Class) builder.getClassLoader().loadClass(type), priority, converter); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } } protected static void withInterceptor(SmallRyeConfigBuilder builder, ConfigSourceInterceptor interceptor) { From 12c00c57f6febecf0228ffd9827058e97bcee7b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:50:50 +0000 Subject: [PATCH 020/207] Bump io.quarkus:quarkus-platform-bom-maven-plugin Bumps [io.quarkus:quarkus-platform-bom-maven-plugin](https://github.com/quarkusio/quarkus-platform-bom-generator) from 0.0.117 to 0.0.118. - [Release notes](https://github.com/quarkusio/quarkus-platform-bom-generator/releases) - [Commits](https://github.com/quarkusio/quarkus-platform-bom-generator/compare/0.0.117...0.0.118) --- updated-dependencies: - dependency-name: io.quarkus:quarkus-platform-bom-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1c4bd24f8598e..5e27a8f5998dc 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ jdbc:postgresql:hibernate_orm_test 4.5.4 - 0.0.117 + 0.0.118 false false From f8fee84425144d59f9cdbfddce7ad768e61acf16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:51:43 +0000 Subject: [PATCH 021/207] Bump org.eclipse.jgit:org.eclipse.jgit Bumps [org.eclipse.jgit:org.eclipse.jgit](https://github.com/eclipse-jgit/jgit) from 7.0.0.202409031743-r to 7.1.0.202411261347-r. - [Commits](https://github.com/eclipse-jgit/jgit/compare/v7.0.0.202409031743-r...v7.1.0.202411261347-r) --- updated-dependencies: - dependency-name: org.eclipse.jgit:org.eclipse.jgit dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- docs/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 7b40168b0a875..f20011fbaa72c 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -203,7 +203,7 @@ 2.8.2 2.6 2.4.0 - 7.0.0.202409031743-r + 7.1.0.202411261347-r 0.15.0 9.47 diff --git a/docs/pom.xml b/docs/pom.xml index 25280e567b7c7..8dd5d654a0a7c 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -29,7 +29,7 @@ 2.26.0.Final 37 11.1.0 - 7.0.0.202409031743-r + 7.1.0.202411261347-r https://quarkus.io https://github.com/quarkusio/quarkus From e5a67e5a188a681212d3ad29b2603ddd5df4936f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:54:40 +0000 Subject: [PATCH 022/207] Bump com.unboundid:unboundid-ldapsdk from 7.0.1 to 7.0.2 Bumps [com.unboundid:unboundid-ldapsdk](https://github.com/pingidentity/ldapsdk) from 7.0.1 to 7.0.2. - [Release notes](https://github.com/pingidentity/ldapsdk/releases) - [Changelog](https://github.com/pingidentity/ldapsdk/blob/master/docs/release-notes.html) - [Commits](https://github.com/pingidentity/ldapsdk/compare/7.0.1...7.0.2) --- updated-dependencies: - dependency-name: com.unboundid:unboundid-ldapsdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 332c47bfc7e08..90f8d96630628 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -101,7 +101,7 @@ quay.io/keycloak/keycloak:${keycloak.version} quay.io/keycloak/keycloak:${keycloak.wildfly.version}-legacy - 7.0.1 + 7.0.2 3.26.3 From 6e9ee38fd8fd0b03738387d6b958edd071e0118e Mon Sep 17 00:00:00 2001 From: Thomas Canava Date: Wed, 4 Dec 2024 22:57:07 +0100 Subject: [PATCH 023/207] feat: Add support of @RunOnVirtualThread on class for websockets next server --- .../next/deployment/WebSocketProcessor.java | 5 ++- .../RunOnVirtualThreadTest.java | 42 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java b/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java index 6b33ff21fd719..1c5ecbb6df7ce 100644 --- a/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java +++ b/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java @@ -1613,12 +1613,15 @@ private static Callback findCallback(Target target, IndexView index, BeanInfo be private static ExecutionModel executionModel(MethodInfo method, TransformedAnnotationsBuildItem transformedAnnotations) { if (KotlinUtils.isKotlinSuspendMethod(method) && (transformedAnnotations.hasAnnotation(method, WebSocketDotNames.RUN_ON_VIRTUAL_THREAD) + || transformedAnnotations.hasAnnotation(method.declaringClass(), + WebSocketDotNames.RUN_ON_VIRTUAL_THREAD) || transformedAnnotations.hasAnnotation(method, WebSocketDotNames.BLOCKING) || transformedAnnotations.hasAnnotation(method, WebSocketDotNames.NON_BLOCKING))) { throw new WebSocketException("Kotlin `suspend` functions in WebSockets Next endpoints may not be " + "annotated @Blocking, @NonBlocking or @RunOnVirtualThread: " + method); } - if (transformedAnnotations.hasAnnotation(method, WebSocketDotNames.RUN_ON_VIRTUAL_THREAD)) { + if (transformedAnnotations.hasAnnotation(method, WebSocketDotNames.RUN_ON_VIRTUAL_THREAD) + || transformedAnnotations.hasAnnotation(method.declaringClass(), WebSocketDotNames.RUN_ON_VIRTUAL_THREAD)) { return ExecutionModel.VIRTUAL_THREAD; } else if (transformedAnnotations.hasAnnotation(method, WebSocketDotNames.BLOCKING)) { return ExecutionModel.WORKER_THREAD; diff --git a/extensions/websockets-next/deployment/src/test/java21/io/quarkus/websockets/next/test/virtualthreads/RunOnVirtualThreadTest.java b/extensions/websockets-next/deployment/src/test/java21/io/quarkus/websockets/next/test/virtualthreads/RunOnVirtualThreadTest.java index 0c767e18834cd..80676788b7dbf 100644 --- a/extensions/websockets-next/deployment/src/test/java21/io/quarkus/websockets/next/test/virtualthreads/RunOnVirtualThreadTest.java +++ b/extensions/websockets-next/deployment/src/test/java21/io/quarkus/websockets/next/test/virtualthreads/RunOnVirtualThreadTest.java @@ -13,6 +13,7 @@ import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.quarkus.websockets.next.OnError; +import io.quarkus.websockets.next.OnOpen; import io.quarkus.websockets.next.OnTextMessage; import io.quarkus.websockets.next.WebSocket; import io.quarkus.websockets.next.test.utils.WSClient; @@ -38,6 +39,9 @@ public class RunOnVirtualThreadTest { @TestHTTPResource("end") URI endUri; + @TestHTTPResource("virt-on-class") + URI onClassUri; + @Test void testVirtualThreads() { try (WSClient client = new WSClient(vertx).connect(endUri)) { @@ -52,6 +56,22 @@ void testVirtualThreads() { } } + @Test + void testVirtualThreadsOnClass() { + try (WSClient client = new WSClient(vertx).connect(onClassUri)) { + client.sendAndAwait("foo"); + client.sendAndAwait("bar"); + client.waitForMessages(3); + String open = client.getMessages().get(0).toString(); + String message1 = client.getMessages().get(1).toString(); + String message2 = client.getMessages().get(2).toString(); + assertNotEquals(open, message1, message2); + assertTrue(open.startsWith("wsnext-virtual-thread-")); + assertTrue(message1.startsWith("wsnext-virtual-thread-")); + assertTrue(message2.startsWith("wsnext-virtual-thread-")); + } + } + @WebSocket(path = "/end") public static class Endpoint { @@ -71,7 +91,27 @@ String error(Throwable t) { } } - + + @RunOnVirtualThread + @WebSocket(path = "/virt-on-class") + public static class EndpointVirtOnClass { + + @Inject + RequestScopedBean bean; + + @OnOpen + String open() { + VirtualThreadsAssertions.assertEverything(); + return Thread.currentThread().getName(); + } + + @OnTextMessage + String text(String ignored) { + VirtualThreadsAssertions.assertEverything(); + return Thread.currentThread().getName(); + } + } + @RequestScoped public static class RequestScopedBean { From e0d0b1ae57c1e5c4438d553bc12c9293b256e440 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Wed, 4 Dec 2024 11:49:36 +0100 Subject: [PATCH 024/207] Arc - Introduce SyntheticBeanBuildItem#create. Arc - Allow adding whole type closures to BeanConfiguratorBase. Arc - Allow restricting bean types in BeanConfiguratorBase. --- .../deployment/SyntheticBeanBuildItem.java | 32 +++++ .../SyntheticBeanBuildItemCreateTest.java | 77 +++++++++++ ...SyntheticBeanBuildItemRemoveTypesTest.java | 103 ++++++++++++++ ...anBuildItemAddTypeClosureGenericsTest.java | 129 ++++++++++++++++++ ...theticBeanBuildItemAddTypeClosureTest.java | 100 ++++++++++++++ .../arc/processor/BeanConfigurator.java | 8 ++ .../arc/processor/BeanConfiguratorBase.java | 76 +++++++++++ .../quarkus/arc/processor/BeanRegistrar.java | 2 +- .../java/io/quarkus/arc/processor/Types.java | 32 +++++ 9 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/create/SyntheticBeanBuildItemCreateTest.java create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/removeTypes/SyntheticBeanBuildItemRemoveTypesTest.java create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureGenericsTest.java create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureTest.java diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeanBuildItem.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeanBuildItem.java index 0bee6f858918c..91b10940263cf 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeanBuildItem.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeanBuildItem.java @@ -32,6 +32,9 @@ public final class SyntheticBeanBuildItem extends MultiBuildItem { /** + * Returns a configurator object allowing for further customization of the synthetic bean. + *

    + * The implementation class is automatically registered as a resulting bean type. * * @param implClazz * @return a new configurator instance @@ -42,6 +45,9 @@ public static ExtendedBeanConfigurator configure(Class implClazz) { } /** + * Returns a configurator object allowing for further customization of the synthetic bean. + *

    + * The implementation class is automatically registered as a resulting bean type. * * @param implClazz * @return a new configurator instance @@ -51,6 +57,32 @@ public static ExtendedBeanConfigurator configure(DotName implClazz) { return new ExtendedBeanConfigurator(implClazz).addType(implClazz); } + /** + * Returns a configurator object allowing for further customization of the synthetic bean. + *

    + * Unlike {@link #configure(Class)}, the implementation class is not registered as a resulting bean type. + * + * @param implClazz + * @return a new configurator instance + * @see ExtendedBeanConfigurator#done() + */ + public static ExtendedBeanConfigurator create(Class implClazz) { + return create(DotName.createSimple(implClazz.getName())); + } + + /** + * Returns a configurator object allowing for further customization of the synthetic bean. + *

    + * Unlike {@link #configure(DotName)}, the implementation class is not registered as a resulting bean type. + * + * @param implClazz + * @return a new configurator instance + * @see ExtendedBeanConfigurator#done() + */ + public static ExtendedBeanConfigurator create(DotName implClazz) { + return new ExtendedBeanConfigurator(implClazz); + } + private final ExtendedBeanConfigurator configurator; SyntheticBeanBuildItem(ExtendedBeanConfigurator configurator) { diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/create/SyntheticBeanBuildItemCreateTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/create/SyntheticBeanBuildItemCreateTest.java new file mode 100644 index 0000000000000..9dbcf9e929612 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/create/SyntheticBeanBuildItemCreateTest.java @@ -0,0 +1,77 @@ +package io.quarkus.arc.test.synthetic.create; + +import java.util.function.Consumer; + +import jakarta.enterprise.inject.Vetoed; + +import org.jboss.jandex.DotName; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.BeanCreator; +import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.BuiltinScope; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.test.QuarkusUnitTest; + +/** + * Tests that {@link SyntheticBeanBuildItem#create(DotName)} does not add automatically register the param type as bean type + */ +public class SyntheticBeanBuildItemCreateTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(SyntheticBeanBuildItemCreateTest.class, FooCreator.class, FooInterface.class, Foo.class)) + .addBuildChainCustomizer(buildCustomizer()); + + static Consumer buildCustomizer() { + return new Consumer() { + + @Override + public void accept(BuildChainBuilder builder) { + builder.addBuildStep(new BuildStep() { + + @Override + public void execute(BuildContext context) { + context.produce(SyntheticBeanBuildItem.create(Foo.class) + .addType(FooInterface.class) + .scope(BuiltinScope.SINGLETON.getInfo()) + .unremovable() + .creator(FooCreator.class) + .done()); + } + }).produces(SyntheticBeanBuildItem.class).build(); + } + }; + } + + @Test + public void testBeanTypes() { + ArcContainer container = Arc.container(); + Assertions.assertFalse(container.select(Foo.class).isResolvable()); + Assertions.assertTrue(container.select(FooInterface.class).isResolvable()); + } + + @Vetoed + public static class Foo implements FooInterface { + } + + interface FooInterface { + } + + public static class FooCreator implements BeanCreator { + + @Override + public Foo create(SyntheticCreationalContext context) { + return new Foo(); + } + + } +} diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/removeTypes/SyntheticBeanBuildItemRemoveTypesTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/removeTypes/SyntheticBeanBuildItemRemoveTypesTest.java new file mode 100644 index 0000000000000..cbe724fbfc236 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/removeTypes/SyntheticBeanBuildItemRemoveTypesTest.java @@ -0,0 +1,103 @@ +package io.quarkus.arc.test.synthetic.removeTypes; + +import java.util.function.Consumer; + +import org.jboss.jandex.DotName; +import org.jboss.jandex.Type; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.BeanCreator; +import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.BuiltinScope; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.test.QuarkusUnitTest; + +public class SyntheticBeanBuildItemRemoveTypesTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(SyntheticBeanBuildItemRemoveTypesTest.class, FooCreator.class, FooInterface.class, Foo.class, + FooSubclass.class, Charlie.class, CharlieSubclass.class, CharlieInterface.class, BarInterface.class, + BazInterface.class)) + .addBuildChainCustomizer(buildCustomizer()); + + static Consumer buildCustomizer() { + return new Consumer() { + + @Override + public void accept(BuildChainBuilder builder) { + builder.addBuildStep(new BuildStep() { + + @Override + public void execute(BuildContext context) { + context.produce(SyntheticBeanBuildItem.create(FooSubclass.class) + .addTypeClosure(FooSubclass.class) + .removeTypes(DotName.createSimple(CharlieSubclass.class)) + .removeTypes(DotName.createSimple(FooSubclass.class)) + .removeTypes(Type.create(BazInterface.class)) + .scope(BuiltinScope.SINGLETON.getInfo()) + .unremovable() + .creator(FooCreator.class) + .done()); + } + }).produces(SyntheticBeanBuildItem.class).build(); + } + }; + } + + @Test + public void testRemovingBeanTypes() { + ArcContainer container = Arc.container(); + Assertions.assertTrue(container.select(Foo.class).isResolvable()); + Assertions.assertTrue(container.select(FooInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BarInterface.class).isResolvable()); + Assertions.assertTrue(container.select(Charlie.class).isResolvable()); + Assertions.assertTrue(container.select(CharlieInterface.class).isResolvable()); + + // CharlieSubclass, FooSubclass and BazInterface should not be registered as bean types + Assertions.assertFalse(container.select(CharlieSubclass.class).isResolvable()); + Assertions.assertFalse(container.select(FooSubclass.class).isResolvable()); + Assertions.assertFalse(container.select(BazInterface.class).isResolvable()); + } + + public static class FooSubclass extends Foo implements FooInterface { + } + + public static class Foo extends Charlie implements BazInterface { + } + + public static class CharlieSubclass extends Charlie { + } + + public static class Charlie implements CharlieInterface { + } + + interface CharlieInterface { + } + + interface FooInterface extends BarInterface { + } + + interface BarInterface { + } + + interface BazInterface { + } + + public static class FooCreator implements BeanCreator { + + @Override + public FooSubclass create(SyntheticCreationalContext context) { + return new FooSubclass(); + } + + } +} diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureGenericsTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureGenericsTest.java new file mode 100644 index 0000000000000..779aeff0de853 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureGenericsTest.java @@ -0,0 +1,129 @@ +package io.quarkus.arc.test.synthetic.typeClosure; + +import java.util.function.Consumer; + +import jakarta.enterprise.util.TypeLiteral; + +import org.jboss.jandex.ParameterizedType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.BeanCreator; +import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.BuiltinScope; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.test.QuarkusUnitTest; + +public class SyntheticBeanBuildItemAddTypeClosureGenericsTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(SyntheticBeanBuildItemAddTypeClosureGenericsTest.class, FooCreator.class, FooInterface.class, + Foo.class, + FooSubclass.class, Charlie.class, CharlieSubclass.class, CharlieInterface.class, BarInterface.class, + BazInterface.class, Alpha.class, Beta.class)) + .addBuildChainCustomizer(buildCustomizer()); + + static Consumer buildCustomizer() { + return new Consumer() { + + @Override + public void accept(BuildChainBuilder builder) { + builder.addBuildStep(new BuildStep() { + + @Override + public void execute(BuildContext context) { + context.produce(SyntheticBeanBuildItem.create(FooSubclass.class) + .addTypeClosure(ParameterizedType.builder(FooSubclass.class).addArgument(Beta.class).build()) + .scope(BuiltinScope.SINGLETON.getInfo()) + .unremovable() + .creator(FooCreator.class) + .done()); + } + }).produces(SyntheticBeanBuildItem.class).build(); + } + }; + } + + @Test + public void testBeanTypesDiscovered() { + ArcContainer container = Arc.container(); + + // Foo/Bar/Baz interfaces should work normally, no generics there + Assertions.assertTrue(container.select(FooInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BarInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BazInterface.class).isResolvable()); + + // FooSubclass is resolvable only as correct parameterized type + Assertions.assertTrue(container.select(new TypeLiteral>() { + }).isResolvable()); + Assertions.assertFalse(container.select(new TypeLiteral>() { + }).isResolvable()); + Assertions.assertFalse(container.select(FooSubclass.class).isResolvable()); + + // Foo type should work only parameterized + Assertions.assertTrue(container.select(new TypeLiteral>() { + }).isResolvable()); + Assertions.assertFalse(container.select(Foo.class).isResolvable()); + + // Foo extends Charlie raw type + // we should be able to perform resolution for raw type but not for a parameterized type + Assertions.assertTrue(container.select(Charlie.class).isResolvable()); + Assertions.assertTrue(container.select(CharlieInterface.class).isResolvable()); + Assertions.assertFalse(container.select(new TypeLiteral>() { + }).isResolvable()); + Assertions.assertFalse(container.select(new TypeLiteral>() { + }).isResolvable()); + + // CharlieSubclass should not be discovered as bean type + Assertions.assertFalse(container.select(CharlieSubclass.class).isResolvable()); + } + + public static class Alpha { + + } + + public static class Beta { + + } + + public static class FooSubclass extends Foo implements FooInterface { + } + + public static class Foo extends Charlie implements BazInterface { + } + + public static class CharlieSubclass extends Charlie { + } + + public static class Charlie implements CharlieInterface { + } + + interface CharlieInterface { + } + + interface FooInterface extends BarInterface { + } + + interface BarInterface { + } + + interface BazInterface { + } + + public static class FooCreator implements BeanCreator> { + + @Override + public FooSubclass create(SyntheticCreationalContext> context) { + return new FooSubclass(); + } + + } +} diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureTest.java new file mode 100644 index 0000000000000..3801726f44eb7 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureTest.java @@ -0,0 +1,100 @@ +package io.quarkus.arc.test.synthetic.typeClosure; + +import java.util.function.Consumer; + +import org.jboss.jandex.DotName; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.BeanCreator; +import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.BuiltinScope; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.test.QuarkusUnitTest; + +public class SyntheticBeanBuildItemAddTypeClosureTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(SyntheticBeanBuildItemAddTypeClosureTest.class, FooCreator.class, FooInterface.class, Foo.class, + FooSubclass.class, Charlie.class, CharlieSubclass.class, CharlieInterface.class, BarInterface.class, + BazInterface.class)) + .addBuildChainCustomizer(buildCustomizer()); + + static Consumer buildCustomizer() { + return new Consumer() { + + @Override + public void accept(BuildChainBuilder builder) { + builder.addBuildStep(new BuildStep() { + + @Override + public void execute(BuildContext context) { + context.produce(SyntheticBeanBuildItem.create(FooSubclass.class) + .addTypeClosure(FooInterface.class) + .addTypeClosure(DotName.createSimple(Foo.class)) + .scope(BuiltinScope.SINGLETON.getInfo()) + .unremovable() + .creator(FooCreator.class) + .done()); + } + }).produces(SyntheticBeanBuildItem.class).build(); + } + }; + } + + @Test + public void testBeanTypesDiscovered() { + ArcContainer container = Arc.container(); + Assertions.assertTrue(container.select(Foo.class).isResolvable()); + Assertions.assertTrue(container.select(FooInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BarInterface.class).isResolvable()); + Assertions.assertTrue(container.select(Charlie.class).isResolvable()); + Assertions.assertTrue(container.select(CharlieInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BazInterface.class).isResolvable()); + + // Charlie and Foo subclasses should not be registered as bean types + Assertions.assertFalse(container.select(CharlieSubclass.class).isResolvable()); + Assertions.assertFalse(container.select(FooSubclass.class).isResolvable()); + } + + public static class FooSubclass extends Foo implements FooInterface { + } + + public static class Foo extends Charlie implements BazInterface { + } + + public static class CharlieSubclass extends Charlie { + } + + public static class Charlie implements CharlieInterface { + } + + interface CharlieInterface { + } + + interface FooInterface extends BarInterface { + } + + interface BarInterface { + } + + interface BazInterface { + } + + public static class FooCreator implements BeanCreator { + + @Override + public FooSubclass create(SyntheticCreationalContext context) { + return new FooSubclass(); + } + + } +} diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfigurator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfigurator.java index 156df45341604..80f7b6add09fd 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfigurator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfigurator.java @@ -85,6 +85,14 @@ public void done() { .build()); } + // perform type discovery for registered types + for (Type jandexType : registeredTypeClosures) { + this.types.addAll(Types.getTypeClosureFromJandexType(jandexType, beanDeployment).unrestrictedTypes()); + } + + // restrict resulting bean types if needed + this.types.removeAll(typesToRemove); + BeanInfo.Builder builder = new BeanInfo.Builder() .implClazz(implClass) .identifier(identifier) diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfiguratorBase.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfiguratorBase.java index 84644292fd52a..f2992031c8ba4 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfiguratorBase.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfiguratorBase.java @@ -45,6 +45,8 @@ public abstract class BeanConfiguratorBase types; + protected final Set registeredTypeClosures; + protected final Set typesToRemove; protected final Set qualifiers; protected ScopeInfo scope; protected Boolean alternative; @@ -66,6 +68,8 @@ public abstract class BeanConfiguratorBase(); + this.registeredTypeClosures = new HashSet<>(); + this.typesToRemove = new HashSet<>(); this.qualifiers = new HashSet<>(); this.stereotypes = new ArrayList<>(); this.removable = true; @@ -83,6 +87,10 @@ public THIS read(BeanConfiguratorBase base) { identifier = base.identifier; types.clear(); types.addAll(base.types); + registeredTypeClosures.clear(); + registeredTypeClosures.addAll(base.registeredTypeClosures); + typesToRemove.clear(); + typesToRemove.addAll(base.typesToRemove); qualifiers.clear(); qualifiers.addAll(base.qualifiers); scope = base.scope; @@ -134,6 +142,74 @@ public THIS addType(Class type) { return addType(DotName.createSimple(type.getName())); } + /** + * Adds an unrestricted set of bean types for the given type as if it represented a bean class of a managed bean. + * + * @param typeName {@link DotName} representation of a class that should be scanned for types + * @return self + */ + public THIS addTypeClosure(DotName typeName) { + return addTypeClosure(Type.create(typeName, Kind.CLASS)); + } + + /** + * Adds an unrestricted set of bean types for the given type as if it represented a bean class of a managed bean. + * + * @param type a class that should be scanned for types + * @return self + */ + public THIS addTypeClosure(Class type) { + return addTypeClosure(Type.create(type)); + } + + /** + * Adds an unrestricted set of bean types for the given type as if it represented a bean class of a managed bean. + * + * @param type {@link Type} representation of a class that should be scanned for types + * @return self + */ + public THIS addTypeClosure(Type type) { + this.registeredTypeClosures.add(type); + return self(); + } + + /** + * Removes listed types from the resulting types of the synthetic bean. + * + * @param types types that should be removed from the resulting set of bean types + * @return self + */ + public THIS removeTypes(Class... types) { + for (Class classType : types) { + removeTypes(Type.create(classType)); + } + return self(); + } + + /** + * Removes listed types from the resulting types of the synthetic bean. + * + * @param types types that should be removed from the resulting set of bean types + * @return self + */ + public THIS removeTypes(DotName... types) { + for (DotName name : types) { + removeTypes(Type.create(name, Kind.CLASS)); + } + return self(); + } + + /** + * Removes listed types from the resulting types of the synthetic bean. + * + * @param types types that should be removed from the resulting set of bean types + * @return self + */ + public THIS removeTypes(Type... types) { + Collections.addAll(this.typesToRemove, types); + return self(); + } + public THIS addQualifier(Class annotationClass) { return addQualifier(DotName.createSimple(annotationClass.getName())); } diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanRegistrar.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanRegistrar.java index fb21183066102..c1307f808b520 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanRegistrar.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanRegistrar.java @@ -25,7 +25,7 @@ interface RegistrationContext extends BuildContext { * Configure a new synthetic bean. The bean is not added to the deployment unless the {@link BeanConfigurator#done()} * method is called. * - * @param beanClass + * @param beanClassName * @return a new synthetic bean configurator */ BeanConfigurator configure(DotName beanClassName); diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java index a2018013dc4c4..e085ef67e1516 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java @@ -522,6 +522,38 @@ record TypeClosure(Set types, Set unrestrictedTypes) { } } + static TypeClosure getTypeClosureFromJandexType(Type jandexType, BeanDeployment beanDeployment) { + Set types; + Set unrestrictedBeanTypes = new HashSet<>(); + if (jandexType.kind() == Kind.TYPE_VARIABLE) { + throw new IllegalStateException("A type variable is not a legal bean type"); + } + if (jandexType.kind() == Kind.PRIMITIVE || jandexType.kind() == Kind.ARRAY) { + types = new HashSet<>(); + types.add(jandexType); + types.add(OBJECT_TYPE); + return new TypeClosure(types); + } else { + ClassInfo jandexTypeClassInfo = getClassByName(beanDeployment.getBeanArchiveIndex(), jandexType); + if (jandexTypeClassInfo == null) { + throw new IllegalArgumentException( + "Provided Jandex type not found in index: " + jandexType.name()); + } + if (Kind.CLASS.equals(jandexType.kind())) { + types = getTypeClosure(jandexTypeClassInfo, null, Collections.emptyMap(), beanDeployment, null, + unrestrictedBeanTypes); + } else if (Kind.PARAMETERIZED_TYPE.equals(jandexType.kind())) { + types = getTypeClosure(jandexTypeClassInfo, null, + buildResolvedMap(jandexType.asParameterizedType().arguments(), jandexTypeClassInfo.typeParameters(), + Collections.emptyMap(), beanDeployment.getBeanArchiveIndex()), + beanDeployment, null, unrestrictedBeanTypes); + } else { + throw new IllegalArgumentException("Unsupported return type"); + } + } + return new TypeClosure(types, unrestrictedBeanTypes); + } + static Set getClassUnrestrictedTypeClosure(ClassInfo classInfo, BeanDeployment beanDeployment) { Set types; Set unrestrictedBeanTypes = new HashSet<>(); From 0bf88b67c7eeea1d1346752e823c315bdcf39fa9 Mon Sep 17 00:00:00 2001 From: brunobat Date: Thu, 5 Dec 2024 09:21:49 +0000 Subject: [PATCH 025/207] Reduce log level of otel side exporter classes --- .../deployment/exporter/otlp/OtlpExporterProcessor.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterProcessor.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterProcessor.java index 6fc49278641f0..09a6989f74d61 100644 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterProcessor.java +++ b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterProcessor.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.function.BooleanSupplier; +import java.util.logging.Level; import jakarta.enterprise.inject.Instance; import jakarta.inject.Singleton; @@ -21,6 +22,7 @@ import io.quarkus.arc.deployment.SyntheticBeanBuildItem; import io.quarkus.deployment.annotations.*; import io.quarkus.deployment.annotations.Record; +import io.quarkus.deployment.builditem.LogCategoryBuildItem; import io.quarkus.deployment.builditem.RunTimeConfigBuilderBuildItem; import io.quarkus.opentelemetry.runtime.config.build.OTelBuildConfig; import io.quarkus.opentelemetry.runtime.config.build.exporter.OtlpExporterBuildConfig; @@ -75,6 +77,13 @@ public boolean getAsBoolean() { } } + @BuildStep + void logging(BuildProducer log) { + // Reduce the log level of the exporters because it's too much, and we do log important things ourselves. + log.produce(new LogCategoryBuildItem("io.opentelemetry.exporter.internal.grpc.GrpcExporter", Level.OFF)); + log.produce(new LogCategoryBuildItem("io.opentelemetry.exporter.internal.http.HttpExporter", Level.OFF)); + } + @BuildStep void config(BuildProducer runTimeConfigBuilderProducer) { runTimeConfigBuilderProducer.produce(new RunTimeConfigBuilderBuildItem(OtlpExporterConfigBuilder.class)); From adedb08a6394ed8f53a9207921e25eb5a60f0e81 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 19 Nov 2024 17:56:07 +0000 Subject: [PATCH 026/207] Register a Config instance to bootstrap tests --- bom/application/pom.xml | 2 +- .../deployment/dev/testing/TestConfig.java | 16 +- .../configuration/QuarkusConfigFactory.java | 14 +- .../asciidoc/getting-started-testing.adoc | 22 +-- .../common/runtime/util/SchedulerUtils.java | 6 +- .../VertxEventBusConsumerRecorder.java | 6 +- .../src/main/resources/application.properties | 4 +- .../src/main/resources/application.properties | 4 +- .../src/main/resources/application.properties | 4 +- .../src/main/resources/application.properties | 4 +- .../io/quarkus/test/common/LauncherUtil.java | 9 +- .../test/common/TestResourceManager.java | 14 -- test-framework/junit5-config/pom.xml | 35 +++++ .../test/config/ConfigLauncherSession.java | 28 ++++ .../test/config/LoggingSetupExtension.java | 17 ++ .../test/config/QuarkusClassOrderer.java | 41 +++++ .../config/TestConfigProviderResolver.java | 99 ++++++++++++ .../org.junit.jupiter.api.extension.Extension | 1 + ....platform.launcher.LauncherSessionListener | 1 + .../main/resources/junit-platform.properties | 2 + test-framework/junit5-internal/pom.xml | 4 + .../io/quarkus/test/QuarkusDevModeTest.java | 10 +- test-framework/junit5-properties/pom.xml | 23 --- .../main/resources/junit-platform.properties | 2 - test-framework/junit5/pom.xml | 2 +- .../AbstractJvmQuarkusTestExtension.java | 13 +- .../test/junit/BasicLoggingEnabler.java | 146 ------------------ .../test/junit/QuarkusTestExtension.java | 12 +- .../test/junit/RunningAppConfigResolver.java | 2 +- .../QuarkusTestProfileAwareClassOrderer.java | 82 +++++----- .../org.junit.jupiter.api.extension.Extension | 1 - ...arkusTestProfileAwareClassOrdererTest.java | 27 +--- test-framework/pom.xml | 2 +- 33 files changed, 337 insertions(+), 318 deletions(-) create mode 100644 test-framework/junit5-config/pom.xml create mode 100644 test-framework/junit5-config/src/main/java/io/quarkus/test/config/ConfigLauncherSession.java create mode 100644 test-framework/junit5-config/src/main/java/io/quarkus/test/config/LoggingSetupExtension.java create mode 100644 test-framework/junit5-config/src/main/java/io/quarkus/test/config/QuarkusClassOrderer.java create mode 100644 test-framework/junit5-config/src/main/java/io/quarkus/test/config/TestConfigProviderResolver.java create mode 100644 test-framework/junit5-config/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension create mode 100644 test-framework/junit5-config/src/main/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener create mode 100644 test-framework/junit5-config/src/main/resources/junit-platform.properties delete mode 100644 test-framework/junit5-properties/pom.xml delete mode 100644 test-framework/junit5-properties/src/main/resources/junit-platform.properties delete mode 100644 test-framework/junit5/src/main/java/io/quarkus/test/junit/BasicLoggingEnabler.java delete mode 100644 test-framework/junit5/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 7b40168b0a875..478050c3426c3 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -3284,7 +3284,7 @@ io.quarkus - quarkus-junit5-properties + quarkus-junit5-config ${project.version} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java index da1a31e3f43d9..f4c3b9eb0f4ae 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java @@ -8,7 +8,9 @@ import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.quarkus.runtime.configuration.TrimmedStringConverter; import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithConverter; import io.smallrye.config.WithDefault; import io.smallrye.config.WithParentName; @@ -45,6 +47,16 @@ public interface TestConfig { @WithDefault("false") boolean displayTestOutput(); + /** + * The FQCN of the JUnit ClassOrderer to use. If the class cannot be found, it fallbacks to JUnit + * default behaviour which does not set a ClassOrderer at all. + * + * @see JUnit Class + * Order + */ + @WithDefault("io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer") + Optional classOrderer(); + /** * Tags that should be included for continuous testing. This supports JUnit Tag Expressions. * @@ -77,7 +89,6 @@ public interface TestConfig { * is matched against the test class name (not the file name). *

    * This is ignored if include-pattern has been set. - * */ @WithDefault(".*\\.IT[^.]+|.*IT|.*ITCase") Optional excludePattern(); @@ -241,7 +252,6 @@ public interface TestConfig { * is matched against the module groupId:artifactId. *

    * This is ignored if include-module-pattern has been set. - * */ Optional excludeModulePattern(); @@ -265,7 +275,7 @@ interface Profile { * then Quarkus will only execute tests that are annotated with a {@code @TestProfile} that has at least one of the * supplied (via the aforementioned system property) tags. */ - Optional> tags(); + Optional> tags(); } interface Container { diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/QuarkusConfigFactory.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/QuarkusConfigFactory.java index 2adc409fab816..85f778217b946 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/QuarkusConfigFactory.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/QuarkusConfigFactory.java @@ -1,5 +1,7 @@ package io.quarkus.runtime.configuration; +import org.eclipse.microprofile.config.spi.ConfigProviderResolver; + import io.quarkus.runtime.LaunchMode; import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfigFactory; @@ -12,13 +14,6 @@ public final class QuarkusConfigFactory extends SmallRyeConfigFactory { private static volatile SmallRyeConfig config; - /** - * Construct a new instance. Called by service loader. - */ - public QuarkusConfigFactory() { - // todo: replace with {@code provider()} post-Java 11 - } - @Override public SmallRyeConfig getConfigFor(final SmallRyeConfigProviderResolver configProviderResolver, final ClassLoader classLoader) { @@ -30,15 +25,12 @@ public SmallRyeConfig getConfigFor(final SmallRyeConfigProviderResolver configPr } public static void setConfig(SmallRyeConfig config) { - SmallRyeConfigProviderResolver configProviderResolver = (SmallRyeConfigProviderResolver) SmallRyeConfigProviderResolver - .instance(); + ConfigProviderResolver configProviderResolver = ConfigProviderResolver.instance(); // Uninstall previous config if (QuarkusConfigFactory.config != null) { configProviderResolver.releaseConfig(QuarkusConfigFactory.config); QuarkusConfigFactory.config = null; } - // Also release the TCCL config, in case that config was not QuarkusConfigFactory.config - configProviderResolver.releaseConfig(Thread.currentThread().getContextClassLoader()); // Install new config if (config != null) { QuarkusConfigFactory.config = config; diff --git a/docs/src/main/asciidoc/getting-started-testing.adoc b/docs/src/main/asciidoc/getting-started-testing.adoc index 916b16f57fd08..e2c0fac89ccbe 100644 --- a/docs/src/main/asciidoc/getting-started-testing.adoc +++ b/docs/src/main/asciidoc/getting-started-testing.adoc @@ -472,24 +472,10 @@ a bit slower, as it adds a shutdown/startup cycle to the test time, but gives a To reduce the amount of times Quarkus needs to restart, `io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer` is registered as a global `ClassOrderer` as described in the link:https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-execution-order-classes[JUnit 5 User Guide]. -The behavior of this `ClassOrderer` is configurable via `junit-platform.properties` (see the source code or javadoc for more details). -It can also be disabled entirely by setting another `ClassOrderer` that is provided by JUnit 5 or even your own custom one. + -Please note that as of JUnit 5.8.2 link:https://github.com/junit-team/junit5/issues/2794[only a single `junit-platform.properties` is picked up and a warning is logged if more than one is found]. -If you encounter such warnings, you can get rid of them by removing the Quarkus-supplied `junit-platform.properties` from the classpath via an exclusion: -[source,xml] ----- - - io.quarkus - quarkus-junit5 - test - - - io.quarkus - quarkus-junit5-properties - - - ----- +The behavior of this `ClassOrderer` is configurable via `application.properties` using the property +`quarkus.test.class-orderer`. The property accepts the FQCN of the `ClassOrderer` to use. If the class cannot be found, +it fallbacks to JUnit default behaviour which does not set a `ClassOrderer` at all. It can also be disabled entirely by +setting another `ClassOrderer` that is provided by JUnit 5 or even your own custom one. === Writing a Profile diff --git a/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/util/SchedulerUtils.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/util/SchedulerUtils.java index 96b87a5e33ce3..289b9beef6876 100644 --- a/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/util/SchedulerUtils.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/util/SchedulerUtils.java @@ -14,7 +14,7 @@ import jakarta.enterprise.inject.Instance; import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; +import org.eclipse.microprofile.config.ConfigProvider; import io.quarkus.arc.Arc; import io.quarkus.runtime.configuration.DurationConverter; @@ -147,9 +147,7 @@ private static String adjustExpressionSyntax(String val) { * Adapted from {@link io.smallrye.config.ExpressionConfigSourceInterceptor} */ private static String resolvePropertyExpression(String expr) { - // Force the runtime CL in order to make the DEV UI page work - final ClassLoader cl = SchedulerUtils.class.getClassLoader(); - final Config config = ConfigProviderResolver.instance().getConfig(cl); + final Config config = ConfigProvider.getConfig(); final Expression expression = Expression.compile(expr, LENIENT_SYNTAX, NO_TRIM); final String expanded = expression.evaluate(new BiConsumer, StringBuilder>() { @Override diff --git a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxEventBusConsumerRecorder.java b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxEventBusConsumerRecorder.java index 145e34e844bd8..469458e5117f2 100644 --- a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxEventBusConsumerRecorder.java +++ b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxEventBusConsumerRecorder.java @@ -19,7 +19,7 @@ import java.util.function.Supplier; import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; +import org.eclipse.microprofile.config.ConfigProvider; import org.jboss.logging.Logger; import io.quarkus.arc.CurrentContextFactory; @@ -310,9 +310,7 @@ private static String lookUpPropertyValue(String propertyValue) { * Adapted from {@link io.smallrye.config.ExpressionConfigSourceInterceptor} */ private static String resolvePropertyExpression(String expr) { - // Force the runtime CL in order to make the DEV UI page work - final ClassLoader cl = VertxEventBusConsumerRecorder.class.getClassLoader(); - final Config config = ConfigProviderResolver.instance().getConfig(cl); + final Config config = ConfigProvider.getConfig(); final Expression expression = Expression.compile(expr, LENIENT_SYNTAX, NO_TRIM); final String expanded = expression.evaluate(new BiConsumer, StringBuilder>() { @Override diff --git a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-callback-from-extension/src/main/resources/application.properties b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-callback-from-extension/src/main/resources/application.properties index 8d698e657885b..442095ca8410c 100644 --- a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-callback-from-extension/src/main/resources/application.properties +++ b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-callback-from-extension/src/main/resources/application.properties @@ -1,3 +1 @@ -quarkus.test.continuous-testing=enabled -# this should not be needed, but something in the tests is setting this to 1234 and confusing the test framework, so set it here to match -quarkus.http.non-application-root-path=1234 \ No newline at end of file +quarkus.test.continuous-testing=enabled \ No newline at end of file diff --git a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-parameter-injection/src/main/resources/application.properties b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-parameter-injection/src/main/resources/application.properties index 8d698e657885b..442095ca8410c 100644 --- a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-parameter-injection/src/main/resources/application.properties +++ b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-parameter-injection/src/main/resources/application.properties @@ -1,3 +1 @@ -quarkus.test.continuous-testing=enabled -# this should not be needed, but something in the tests is setting this to 1234 and confusing the test framework, so set it here to match -quarkus.http.non-application-root-path=1234 \ No newline at end of file +quarkus.test.continuous-testing=enabled \ No newline at end of file diff --git a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension-with-bytecode-changes/src/main/resources/application.properties b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension-with-bytecode-changes/src/main/resources/application.properties index 8d698e657885b..442095ca8410c 100644 --- a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension-with-bytecode-changes/src/main/resources/application.properties +++ b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension-with-bytecode-changes/src/main/resources/application.properties @@ -1,3 +1 @@ -quarkus.test.continuous-testing=enabled -# this should not be needed, but something in the tests is setting this to 1234 and confusing the test framework, so set it here to match -quarkus.http.non-application-root-path=1234 \ No newline at end of file +quarkus.test.continuous-testing=enabled \ No newline at end of file diff --git a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension/src/main/resources/application.properties b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension/src/main/resources/application.properties index 8d698e657885b..442095ca8410c 100644 --- a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension/src/main/resources/application.properties +++ b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension/src/main/resources/application.properties @@ -1,3 +1 @@ -quarkus.test.continuous-testing=enabled -# this should not be needed, but something in the tests is setting this to 1234 and confusing the test framework, so set it here to match -quarkus.http.non-application-root-path=1234 \ No newline at end of file +quarkus.test.continuous-testing=enabled \ No newline at end of file diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java index 22a4ed3fcca75..63c687909ef0b 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java @@ -22,13 +22,10 @@ import java.util.regex.Pattern; import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; -import io.quarkus.runtime.LaunchMode; -import io.quarkus.runtime.configuration.ConfigUtils; -import io.quarkus.runtime.configuration.QuarkusConfigFactory; import io.quarkus.test.common.http.TestHTTPResourceManager; import io.quarkus.utilities.OS; -import io.smallrye.config.SmallRyeConfig; public final class LauncherUtil { @@ -38,9 +35,7 @@ private LauncherUtil() { } public static Config installAndGetSomeConfig() { - SmallRyeConfig config = ConfigUtils.configBuilder(false, LaunchMode.NORMAL).build(); - QuarkusConfigFactory.setConfig(config); - return config; + return ConfigProvider.getConfig(); } /** diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java b/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java index d5f606290bebe..176751c654bf4 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java @@ -38,8 +38,6 @@ import org.jboss.jandex.DotName; import org.jboss.jandex.IndexView; -import io.smallrye.config.SmallRyeConfigProviderResolver; - /** * Manages {@link QuarkusTestResourceLifecycleManager} */ @@ -214,18 +212,6 @@ public void close() { throw new RuntimeException("Unable to stop Quarkus test resource " + entry.getTestResource(), e); } } - // TODO using QuarkusConfigFactory.setConfig(null) here makes continuous testing fail, - // e.g. in io.quarkus.hibernate.orm.HibernateHotReloadTestCase - // or io.quarkus.opentelemetry.deployment.OpenTelemetryContinuousTestingTest; - // maybe this cleanup is not really necessary and just "doesn't hurt" because - // the released config is still cached in QuarkusConfigFactory#config - // and will be restored soon after when QuarkusConfigFactory#getConfigFor is called? - // In that case we should remove this cleanup. - try { - ((SmallRyeConfigProviderResolver) SmallRyeConfigProviderResolver.instance()) - .releaseConfig(Thread.currentThread().getContextClassLoader()); - } catch (Throwable ignored) { - } configProperties.clear(); } diff --git a/test-framework/junit5-config/pom.xml b/test-framework/junit5-config/pom.xml new file mode 100644 index 0000000000000..9e5a21c6e54bb --- /dev/null +++ b/test-framework/junit5-config/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + + io.quarkus + quarkus-test-framework + 999-SNAPSHOT + + + quarkus-junit5-config + Quarkus - Test Framework - JUnit 5 Config + + + + org.junit.jupiter + junit-jupiter-api + + + io.smallrye.config + smallrye-config + + + io.quarkus + quarkus-core + + + io.quarkus + quarkus-core-deployment + + + + diff --git a/test-framework/junit5-config/src/main/java/io/quarkus/test/config/ConfigLauncherSession.java b/test-framework/junit5-config/src/main/java/io/quarkus/test/config/ConfigLauncherSession.java new file mode 100644 index 0000000000000..32a59806500a6 --- /dev/null +++ b/test-framework/junit5-config/src/main/java/io/quarkus/test/config/ConfigLauncherSession.java @@ -0,0 +1,28 @@ +package io.quarkus.test.config; + +import org.eclipse.microprofile.config.spi.ConfigProviderResolver; +import org.junit.platform.launcher.LauncherSession; +import org.junit.platform.launcher.LauncherSessionListener; + +import io.quarkus.runtime.LaunchMode; + +/** + * A JUnit {@link LauncherSessionListener}, used to register the initial test config. Test set up code can safely call + * ConfigProvider.getConfig() to retrieve an instance of the Quarkus configuration. + *

    + * The test config only contains sources known at bootstrap test time. For instance, config sources generated by + * Quarkus are not available in the test config. + */ +public class ConfigLauncherSession implements LauncherSessionListener { + @Override + public void launcherSessionOpened(final LauncherSession session) { + TestConfigProviderResolver resolver = new TestConfigProviderResolver(); + ConfigProviderResolver.setInstance(resolver); + resolver.getConfig(LaunchMode.TEST); + } + + @Override + public void launcherSessionClosed(final LauncherSession session) { + ((TestConfigProviderResolver) ConfigProviderResolver.instance()).restore(); + } +} diff --git a/test-framework/junit5-config/src/main/java/io/quarkus/test/config/LoggingSetupExtension.java b/test-framework/junit5-config/src/main/java/io/quarkus/test/config/LoggingSetupExtension.java new file mode 100644 index 0000000000000..b15c6f8f4e43f --- /dev/null +++ b/test-framework/junit5-config/src/main/java/io/quarkus/test/config/LoggingSetupExtension.java @@ -0,0 +1,17 @@ +package io.quarkus.test.config; + +import org.junit.jupiter.api.extension.Extension; + +import io.quarkus.runtime.logging.LoggingSetupRecorder; + +/** + * A global JUnit extension that enables/sets up basic logging if logging has not already been set up. + *

    + * This is useful for getting log output from non-Quarkus tests (if executed separately or before the first Quarkus + * test), but also for getting instant log output from {@code QuarkusTestResourceLifecycleManagers} etc. + */ +public class LoggingSetupExtension implements Extension { + public LoggingSetupExtension() { + LoggingSetupRecorder.handleFailedStart(); + } +} diff --git a/test-framework/junit5-config/src/main/java/io/quarkus/test/config/QuarkusClassOrderer.java b/test-framework/junit5-config/src/main/java/io/quarkus/test/config/QuarkusClassOrderer.java new file mode 100644 index 0000000000000..857c13a842548 --- /dev/null +++ b/test-framework/junit5-config/src/main/java/io/quarkus/test/config/QuarkusClassOrderer.java @@ -0,0 +1,41 @@ +package io.quarkus.test.config; + +import org.eclipse.microprofile.config.ConfigProvider; +import org.junit.jupiter.api.ClassOrderer; +import org.junit.jupiter.api.ClassOrdererContext; +import org.junit.platform.commons.util.ReflectionUtils; + +import io.quarkus.deployment.dev.testing.TestConfig; +import io.smallrye.config.SmallRyeConfig; + +/** + * A JUnit {@link ClassOrderer}, used to delegate to a custom implementations of {@link ClassOrderer} set by Quarkus + * config. + */ +public class QuarkusClassOrderer implements ClassOrderer { + private final ClassOrderer delegate; + + public QuarkusClassOrderer() { + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + TestConfig testConfig = config.getConfigMapping(TestConfig.class); + + delegate = testConfig.classOrderer() + .map(klass -> ReflectionUtils.tryToLoadClass(klass) + .andThenTry(ReflectionUtils::newInstance) + .andThenTry(instance -> (ClassOrderer) instance) + .toOptional().orElse(EMPTY)) + .orElse(EMPTY); + } + + @Override + public void orderClasses(final ClassOrdererContext context) { + delegate.orderClasses(context); + } + + private static final ClassOrderer EMPTY = new ClassOrderer() { + @Override + public void orderClasses(final ClassOrdererContext context) { + + } + }; +} diff --git a/test-framework/junit5-config/src/main/java/io/quarkus/test/config/TestConfigProviderResolver.java b/test-framework/junit5-config/src/main/java/io/quarkus/test/config/TestConfigProviderResolver.java new file mode 100644 index 0000000000000..9bda00bace7f1 --- /dev/null +++ b/test-framework/junit5-config/src/main/java/io/quarkus/test/config/TestConfigProviderResolver.java @@ -0,0 +1,99 @@ +package io.quarkus.test.config; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.spi.ConfigProviderResolver; + +import io.quarkus.deployment.dev.testing.TestConfig; +import io.quarkus.runtime.LaunchMode; +import io.quarkus.runtime.configuration.ConfigUtils; +import io.smallrye.config.SmallRyeConfig; +import io.smallrye.config.SmallRyeConfigBuilder; +import io.smallrye.config.SmallRyeConfigProviderResolver; + +/** + * A {@link org.eclipse.microprofile.config.spi.ConfigProviderResolver} to register {@link Config} in the Test + * classloader. + */ +public class TestConfigProviderResolver extends SmallRyeConfigProviderResolver { + private final SmallRyeConfigProviderResolver resolver; + private final ClassLoader classLoader; + private final Map configs; + + TestConfigProviderResolver() { + this.resolver = (SmallRyeConfigProviderResolver) SmallRyeConfigProviderResolver.instance(); + this.classLoader = Thread.currentThread().getContextClassLoader(); + this.configs = new ConcurrentHashMap<>(); + } + + @Override + public Config getConfig() { + return resolver.getConfig(); + } + + /** + * Registers a config in the Test classloader, by {@link LaunchMode}. Required for tests that launch Quarkus in + * Dev mode (which uses the dev config profile, instead of test. + *

    + * Retrieving the {@link Config} in a {@link LaunchMode} other than {@link LaunchMode#TEST}, must call + * {@link TestConfigProviderResolver#restoreConfig()} after using the config, to avoid mismatches in the config + * profile through the stack. + * + * @param mode the {@link LaunchMode} + * @return the registed {@link Config} instance + */ + public Config getConfig(final LaunchMode mode) { + if (classLoader.equals(Thread.currentThread().getContextClassLoader())) { + resolver.releaseConfig(classLoader); + SmallRyeConfig config = configs.computeIfAbsent(mode, new Function() { + @Override + public SmallRyeConfig apply(final LaunchMode launchMode) { + return ConfigUtils.configBuilder(false, true, mode) + .withProfile(mode.getDefaultProfile()) + .withMapping(TestConfig.class, "quarkus.test") + .build(); + } + }); + resolver.registerConfig(config, classLoader); + return config; + } + throw new IllegalStateException(); + } + + public void restoreConfig() { + if (classLoader.equals(Thread.currentThread().getContextClassLoader())) { + resolver.releaseConfig(classLoader); + resolver.registerConfig(configs.get(LaunchMode.TEST), classLoader); + } else { + throw new IllegalStateException(); + } + } + + public void restore() { + this.configs.clear(); + ConfigProviderResolver.setInstance(resolver); + } + + @Override + public Config getConfig(final ClassLoader loader) { + return resolver.getConfig(loader); + } + + @Override + public SmallRyeConfigBuilder getBuilder() { + return resolver.getBuilder(); + } + + @Override + public void registerConfig(final Config config, final ClassLoader classLoader) { + resolver.registerConfig(config, classLoader); + } + + @Override + public void releaseConfig(final Config config) { + resolver.releaseConfig(config); + } +} diff --git a/test-framework/junit5-config/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/test-framework/junit5-config/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 0000000000000..a91b69862a876 --- /dev/null +++ b/test-framework/junit5-config/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +io.quarkus.test.config.LoggingSetupExtension diff --git a/test-framework/junit5-config/src/main/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener b/test-framework/junit5-config/src/main/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener new file mode 100644 index 0000000000000..ca3c61a72cde2 --- /dev/null +++ b/test-framework/junit5-config/src/main/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener @@ -0,0 +1 @@ +io.quarkus.test.config.ConfigLauncherSession diff --git a/test-framework/junit5-config/src/main/resources/junit-platform.properties b/test-framework/junit5-config/src/main/resources/junit-platform.properties new file mode 100644 index 0000000000000..d24c3ed5820f5 --- /dev/null +++ b/test-framework/junit5-config/src/main/resources/junit-platform.properties @@ -0,0 +1,2 @@ +junit.jupiter.extensions.autodetection.enabled=true +junit.jupiter.testclass.order.default=io.quarkus.test.config.QuarkusClassOrderer diff --git a/test-framework/junit5-internal/pom.xml b/test-framework/junit5-internal/pom.xml index 526869cab070b..9bd5cf5b47f47 100644 --- a/test-framework/junit5-internal/pom.xml +++ b/test-framework/junit5-internal/pom.xml @@ -39,6 +39,10 @@ junit-jupiter-engine compile + + io.quarkus + quarkus-junit5-config + io.quarkus quarkus-core diff --git a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java index d99d553734bfb..d2718b04f55cf 100644 --- a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java +++ b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java @@ -28,6 +28,7 @@ import java.util.logging.LogRecord; import java.util.stream.Stream; +import org.eclipse.microprofile.config.spi.ConfigProviderResolver; import org.jboss.logmanager.Logger; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.exporter.ExplodedExporter; @@ -63,6 +64,7 @@ import io.quarkus.test.common.TestConfigUtil; import io.quarkus.test.common.TestResourceManager; import io.quarkus.test.common.http.TestHTTPResourceManager; +import io.quarkus.test.config.TestConfigProviderResolver; /** * A test extension for black-box testing of Quarkus development mode in extensions. @@ -234,11 +236,10 @@ public Object createTestInstance(TestInstanceFactoryContext factoryContext, Exte } @Override - public void beforeAll(ExtensionContext context) throws Exception { + public void beforeAll(ExtensionContext context) { + ((TestConfigProviderResolver) ConfigProviderResolver.instance()).getConfig(LaunchMode.DEVELOPMENT); TestConfigUtil.cleanUp(); GroovyClassValue.disable(); - //set the right launch mode in the outer CL, used by the HTTP host config source - LaunchMode.set(LaunchMode.DEVELOPMENT); originalRootLoggerHandlers = rootLogger.getHandlers(); rootLogger.addHandler(inMemoryLogHandler); } @@ -305,7 +306,7 @@ public void beforeEach(ExtensionContext extensionContext) throws Exception { } @Override - public void afterAll(ExtensionContext context) throws Exception { + public void afterAll(ExtensionContext context) { for (Map.Entry e : oldSystemProps.entrySet()) { if (e.getValue() == null) { System.clearProperty(e.getKey()); @@ -318,6 +319,7 @@ public void afterAll(ExtensionContext context) throws Exception { inMemoryLogHandler.setFilter(null); ClearCache.clearCaches(); TestConfigUtil.cleanUp(); + ((TestConfigProviderResolver) ConfigProviderResolver.instance()).restoreConfig(); } @Override diff --git a/test-framework/junit5-properties/pom.xml b/test-framework/junit5-properties/pom.xml deleted file mode 100644 index 63fb5bf6fe370..0000000000000 --- a/test-framework/junit5-properties/pom.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - 4.0.0 - - - io.quarkus - quarkus-test-framework - 999-SNAPSHOT - - - quarkus-junit5-properties - Quarkus - Test Framework - JUnit 5 - Properties - - Contains junit-platform.properties in a "user-excludable" way - until https://github.com/junit-team/junit5/issues/2794 is available. - - - - - diff --git a/test-framework/junit5-properties/src/main/resources/junit-platform.properties b/test-framework/junit5-properties/src/main/resources/junit-platform.properties deleted file mode 100644 index cdac134076ffb..0000000000000 --- a/test-framework/junit5-properties/src/main/resources/junit-platform.properties +++ /dev/null @@ -1,2 +0,0 @@ -junit.jupiter.extensions.autodetection.enabled=true -junit.jupiter.testclass.order.default=io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer diff --git a/test-framework/junit5/pom.xml b/test-framework/junit5/pom.xml index 449f8fda37df5..c4cb92b72454d 100644 --- a/test-framework/junit5/pom.xml +++ b/test-framework/junit5/pom.xml @@ -37,7 +37,7 @@ io.quarkus - quarkus-junit5-properties + quarkus-junit5-config org.junit.jupiter diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/AbstractJvmQuarkusTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/AbstractJvmQuarkusTestExtension.java index f8db488299016..5b73fbfaaaf2c 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/AbstractJvmQuarkusTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/AbstractJvmQuarkusTestExtension.java @@ -12,6 +12,7 @@ import java.util.Collection; import java.util.Deque; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -20,6 +21,7 @@ import jakarta.enterprise.inject.Alternative; +import org.eclipse.microprofile.config.ConfigProvider; import org.jboss.jandex.Index; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.extension.ConditionEvaluationResult; @@ -38,11 +40,13 @@ import io.quarkus.bootstrap.workspace.SourceDir; import io.quarkus.bootstrap.workspace.WorkspaceModule; import io.quarkus.deployment.dev.testing.CurrentTestApplication; +import io.quarkus.deployment.dev.testing.TestConfig; import io.quarkus.paths.PathList; import io.quarkus.runtime.LaunchMode; import io.quarkus.test.common.PathTestHelper; import io.quarkus.test.common.RestorableSystemProperties; import io.quarkus.test.common.TestClassIndexer; +import io.smallrye.config.SmallRyeConfig; public class AbstractJvmQuarkusTestExtension extends AbstractQuarkusTestWithContextExtension implements ExecutionCondition { @@ -279,8 +283,10 @@ public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext con if (context.getTestInstance().isPresent()) { return ConditionEvaluationResult.enabled("Quarkus Test Profile tags only affect classes"); } - String tagsStr = System.getProperty("quarkus.test.profile.tags"); - if ((tagsStr == null) || tagsStr.isEmpty()) { + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + TestConfig testConfig = config.getConfigMapping(TestConfig.class); + Optional> tags = testConfig.profile().tags(); + if (tags.isEmpty() || tags.get().isEmpty()) { return ConditionEvaluationResult.enabled("No Quarkus Test Profile tags"); } Class testProfile = getQuarkusTestProfile(context); @@ -295,8 +301,7 @@ public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext con throw new RuntimeException(e); } Set testProfileTags = profileInstance.tags(); - String[] tags = tagsStr.split(","); - for (String tag : tags) { + for (String tag : tags.get()) { String trimmedTag = tag.trim(); if (testProfileTags.contains(trimmedTag)) { return ConditionEvaluationResult.enabled("Tag '" + trimmedTag + "' is present on '" + testProfile diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/BasicLoggingEnabler.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/BasicLoggingEnabler.java deleted file mode 100644 index 1edc18fe9c662..0000000000000 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/BasicLoggingEnabler.java +++ /dev/null @@ -1,146 +0,0 @@ -package io.quarkus.test.junit; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; -import org.junit.jupiter.api.extension.BeforeAllCallback; -import org.junit.jupiter.api.extension.ExtensionContext; - -import io.quarkus.bootstrap.logging.InitialConfigurator; -import io.quarkus.runtime.LaunchMode; -import io.quarkus.runtime.configuration.ConfigUtils; - -/** - * A (global) JUnit callback that enables/sets up basic logging if logging has not already been set up. - *

    - * This is useful for getting log output from non-Quarkus tests (if executed separately or before the first Quarkus test), - * but also for getting instant log output from {@code QuarkusTestResourceLifecycleManagers} etc. - *

    - * This callback can be disabled via {@link #CFGKEY_ENABLED} in {@code junit-platform.properties} or via system property. - */ -public class BasicLoggingEnabler implements BeforeAllCallback { - - private static final String CFGKEY_ENABLED = "junit.quarkus.enable-basic-logging"; - private static Boolean enabled; - - private static final CompletableFuture configFuture; - - // internal flag, not meant to be used like CFGKEY_ENABLED - private static final boolean VERBOSE = Boolean.getBoolean(BasicLoggingEnabler.class.getName() + ".verbose"); - private static final long staticInitStart; - - // to speed things up a little, eager async loading of the config that will be looked up in LoggingSetupRecorder - // downside: doesn't obey CFGKEY_ENABLED, but that should be bearable - static { - staticInitStart = VERBOSE ? System.currentTimeMillis() : 0; - // e.g. continuous testing has everything set up already (DELAYED_HANDLER is active) - if (!InitialConfigurator.DELAYED_HANDLER.isActivated() - // at least respect CFGKEY_ENABLED if set as system property - && Boolean.parseBoolean(System.getProperty(CFGKEY_ENABLED, "true"))) { - - configFuture = CompletableFuture.supplyAsync(BasicLoggingEnabler::buildConfig); - } else { - configFuture = CompletableFuture.completedFuture(null); - } - } - - @Override - public synchronized void beforeAll(ExtensionContext context) { - if (enabled == null) { - enabled = context.getConfigurationParameter(CFGKEY_ENABLED).map(Boolean::valueOf).orElse(Boolean.TRUE); - } - if (!enabled || InitialConfigurator.DELAYED_HANDLER.isActivated()) { - return; - } - - var beforeAllStart = VERBOSE ? System.currentTimeMillis() : 0; - if (VERBOSE) { - System.out.printf("BasicLoggingEnabler took %s ms from static init to start of beforeAll()%n", - beforeAllStart - staticInitStart); - } - - ////////////////////// - // get the test config - - Config testConfig; - try { - testConfig = configFuture.get(); - // highly unlikely, but things might have changed since the static block decided to _not_ load the config - if (testConfig == null) { - testConfig = buildConfig(); - } - } catch (Exception e) { - // don't be too noisy (don't log the stacktrace) - System.err.printf("BasicLoggingEnabler failed to retrieve config: %s%n", - e instanceof ExecutionException ? ((ExecutionException) e).getCause() : e); - if (VERBOSE) { - e.printStackTrace(); - } - return; - } - - /////////////////////////// - // register the test config - - var configProviderResolver = ConfigProviderResolver.instance(); - var tccl = Thread.currentThread().getContextClassLoader(); - Config configToRestore; - try { - configProviderResolver.registerConfig(testConfig, tccl); - configToRestore = null; - } catch (IllegalStateException e) { - if (VERBOSE) { - System.out.println("BasicLoggingEnabler is swapping config after " + e); - } - // a config is already registered, which can happen in rare cases, - // so remember it for later restore, release it and register the test config instead - configToRestore = configProviderResolver.getConfig(); - configProviderResolver.releaseConfig(configToRestore); - configProviderResolver.registerConfig(testConfig, tccl); - } - - /////////////////// - // activate logging - - try { - IntegrationTestUtil.activateLogging(); - } catch (RuntimeException e) { - // don't be too noisy (don't log the stacktrace by default) - System.err.println("BasicLoggingEnabler failed to enable basic logging: " + e); - if (VERBOSE) { - e.printStackTrace(); - } - } finally { - // release the config that was registered previously so that tests that try to register their own config - // don't fail with: - // "IllegalStateException: SRCFG00017: Configuration already registered for the given class loader" - // also, a possible recreation of basically the same config for a later test class will consume far less time - configProviderResolver.releaseConfig(testConfig); - // if another config was already registered, restore/re-register it now - if (configToRestore != null) { - configProviderResolver.registerConfig(configToRestore, tccl); - } - } - if (VERBOSE) { - System.out.printf("BasicLoggingEnabler took %s ms from start of beforeAll() to end%n", - System.currentTimeMillis() - beforeAllStart); - } - } - - private static Config buildConfig() { - // make sure to load ConfigSources with the proper LaunchMode in place - LaunchMode.set(LaunchMode.TEST); - // notes: - // - addDiscovered might seem a bit much, but this ensures that yaml files are loaded (if extension is around) - // - LaunchMode.NORMAL instead of TEST avoids failing on missing RuntimeOverrideConfigSource$$GeneratedMapHolder - var start = VERBOSE ? System.currentTimeMillis() : 0; - var testConfig = ConfigUtils.configBuilder(true, true, LaunchMode.NORMAL).build(); - if (VERBOSE) { - System.out.printf("BasicLoggingEnabler took %s ms to load config%n", System.currentTimeMillis() - start); - testConfig.getConfigSources().forEach(s -> System.out.println("BasicLoggingEnabler ConfigSource: " + s)); - } - return testConfig; - } -} diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java index 97ee658d4e4c0..b3e366e56d849 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java @@ -80,6 +80,7 @@ import io.quarkus.test.junit.callback.QuarkusTestMethodContext; import io.quarkus.test.junit.internal.DeepClone; import io.quarkus.test.junit.internal.NewSerializingDeepClone; +import io.smallrye.config.SmallRyeConfigProviderResolver; public class QuarkusTestExtension extends AbstractJvmQuarkusTestExtension implements BeforeEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, AfterEachCallback, @@ -244,7 +245,9 @@ public Thread newThread(Runnable r) { .orElse(Duration.of(10, ChronoUnit.MINUTES)); hangTaskKey = hangDetectionExecutor.schedule(hangDetectionTask, hangTimeout.toMillis(), TimeUnit.MILLISECONDS); } - ConfigProviderResolver.setInstance(new RunningAppConfigResolver(runningQuarkusApplication)); + ConfigProviderResolver.instance().registerConfig( + new RunningAppConfigResolver(runningQuarkusApplication).getConfig(), + runningQuarkusApplication.getClassLoader()); RestorableSystemProperties restorableSystemProperties = RestorableSystemProperties.setProperties( Collections.singletonMap("test.url", TestHTTPResourceManager.getUri(runningQuarkusApplication))); @@ -352,7 +355,6 @@ public void beforeTestExecution(ExtensionContext context) throws Exception { } } else { throwBootFailureException(); - return; } } @@ -386,7 +388,6 @@ public void beforeEach(ExtensionContext context) throws Exception { } } else { throwBootFailureException(); - return; } } @@ -1134,21 +1135,20 @@ protected void doClose() { } catch (Throwable e) { log.error("Failed to shutdown Quarkus", e); } finally { + ((SmallRyeConfigProviderResolver) ConfigProviderResolver.instance()) + .releaseConfig(runningQuarkusApplication.getClassLoader()); runningQuarkusApplication = null; Thread.currentThread().setContextClassLoader(old); - ConfigProviderResolver.setInstance(null); } } } class FailedCleanup implements ExtensionContext.Store.CloseableResource { - @Override public void close() { shutdownHangDetection(); firstException = null; failedBoot = false; - ConfigProviderResolver.setInstance(null); } } diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/RunningAppConfigResolver.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/RunningAppConfigResolver.java index e3ec91cd40b6a..54580344058a4 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/RunningAppConfigResolver.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/RunningAppConfigResolver.java @@ -44,7 +44,7 @@ public Iterable getConfigSources() { @Override public ConfigValue getConfigValue(final String propertyName) { - throw illegalStateException(); + return runningQuarkusApplication.getConfigValue(propertyName, ConfigValue.class).get(); } @Override diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrderer.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrderer.java index 9607d14b5f7d7..a3d13b02f0436 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrderer.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrderer.java @@ -6,6 +6,8 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; import org.junit.jupiter.api.ClassDescriptor; import org.junit.jupiter.api.ClassOrderer; import org.junit.jupiter.api.ClassOrdererContext; @@ -27,7 +29,7 @@ *

    * By default, Quarkus*Tests not using any profile come first, then classes using a profile (in groups) and then all other * non-Quarkus tests (e.g. plain unit tests).
    - * Quarkus*Tests with {@linkplain WithTestResource#restrictToAnnotatedClass()} or + * Quarkus*Tests with {@linkplain WithTestResource#scope() matching resources} or * {@linkplain QuarkusTestResource#restrictToAnnotatedClass() restricted} {@code QuarkusTestResource} come * after tests with profiles and Quarkus*Tests with only unrestricted resources are handled like tests without a profile (come * first). @@ -35,7 +37,7 @@ * Internally, ordering is based on prefixes that are prepended to a secondary order suffix (by default the fully qualified * name of the respective test class), with the fully qualified class name of the * {@link io.quarkus.test.junit.QuarkusTestProfile QuarkusTestProfile} as an infix (if present). - * The default prefixes are defined by {@code DEFAULT_ORDER_PREFIX_*} and can be overridden in {@code junit-platform.properties} + * The default prefixes are defined by {@code DEFAULT_ORDER_PREFIX_*} and can be overridden in {@code application.properties} * via {@code CFGKEY_ORDER_PREFIX_*}, e.g. non-Quarkus tests can be run first (not last) by setting * {@link #CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST} to {@code 10_}. *

    @@ -69,31 +71,57 @@ public class QuarkusTestProfileAwareClassOrderer implements ClassOrderer { static final String CFGKEY_SECONDARY_ORDERER = "junit.quarkus.orderer.secondary-orderer"; + private final String prefixQuarkusTest; + private final String prefixQuarkusTestWithProfile; + private final String prefixQuarkusTestWithRestrictedResource; + private final String prefixNonQuarkusTest; + private final Optional secondaryOrderer; + + public QuarkusTestProfileAwareClassOrderer() { + Config config = ConfigProvider.getConfig(); + this.prefixQuarkusTest = config.getOptionalValue(CFGKEY_ORDER_PREFIX_QUARKUS_TEST, String.class) + .orElse(DEFAULT_ORDER_PREFIX_QUARKUS_TEST); + this.prefixQuarkusTestWithProfile = config.getOptionalValue(CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE, String.class) + .orElse(DEFAULT_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE); + this.prefixQuarkusTestWithRestrictedResource = config + .getOptionalValue(CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES, String.class) + .orElse(DEFAULT_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES); + this.prefixNonQuarkusTest = config.getOptionalValue(CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST, String.class) + .orElse(DEFAULT_ORDER_PREFIX_NON_QUARKUS_TEST); + this.secondaryOrderer = config.getOptionalValue(CFGKEY_SECONDARY_ORDERER, String.class); + } + + QuarkusTestProfileAwareClassOrderer( + final String prefixQuarkusTest, + final String prefixQuarkusTestWithProfile, + final String prefixQuarkusTestWithRestrictedResource, + final String prefixNonQuarkusTest, + final Optional secondaryOrderer) { + this.prefixQuarkusTest = prefixQuarkusTest; + this.prefixQuarkusTestWithProfile = prefixQuarkusTestWithProfile; + this.prefixQuarkusTestWithRestrictedResource = prefixQuarkusTestWithRestrictedResource; + this.prefixNonQuarkusTest = prefixNonQuarkusTest; + this.secondaryOrderer = secondaryOrderer; + } + @Override public void orderClasses(ClassOrdererContext context) { // don't do anything if there is just one test class or the current order request is for @Nested tests if (context.getClassDescriptors().size() <= 1 || context.getClassDescriptors().get(0).isAnnotated(Nested.class)) { return; } - var prefixQuarkusTest = getConfigParam( - CFGKEY_ORDER_PREFIX_QUARKUS_TEST, - DEFAULT_ORDER_PREFIX_QUARKUS_TEST, - context); - var prefixQuarkusTestWithProfile = getConfigParam( - CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE, - DEFAULT_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE, - context); - var prefixQuarkusTestWithRestrictedResource = getConfigParam( - CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES, - DEFAULT_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES, - context); - var prefixNonQuarkusTest = getConfigParam( - CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST, - DEFAULT_ORDER_PREFIX_NON_QUARKUS_TEST, - context); // first pass: run secondary orderer first (!), which is easier than running it per "grouping" - buildSecondaryOrderer(context).orderClasses(context); + secondaryOrderer + .map(fqcn -> { + try { + return (ClassOrderer) Class.forName(fqcn).getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new IllegalArgumentException("Failed to instantiate " + fqcn, e); + } + }) + .orElseGet(ClassName::new).orderClasses(context); + var classDecriptors = context.getClassDescriptors(); var firstPassIndexMap = IntStream.range(0, classDecriptors.size()).boxed() .collect(Collectors.toMap(classDecriptors::get, i -> String.format("%06d", i))); @@ -123,22 +151,6 @@ public void orderClasses(ClassOrdererContext context) { })); } - private String getConfigParam(String key, String fallbackValue, ClassOrdererContext context) { - return context.getConfigurationParameter(key).orElse(fallbackValue); - } - - private ClassOrderer buildSecondaryOrderer(ClassOrdererContext context) { - return Optional.ofNullable(getConfigParam(CFGKEY_SECONDARY_ORDERER, null, context)) - .map(fqcn -> { - try { - return (ClassOrderer) Class.forName(fqcn).getDeclaredConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new IllegalArgumentException("Failed to instantiate " + fqcn, e); - } - }) - .orElseGet(ClassOrderer.ClassName::new); - } - private boolean hasRestrictedResource(ClassDescriptor classDescriptor) { return classDescriptor.findRepeatableAnnotations(WithTestResource.class).stream() .anyMatch( diff --git a/test-framework/junit5/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/test-framework/junit5/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension deleted file mode 100644 index 3d466fc6d2db5..0000000000000 --- a/test-framework/junit5/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension +++ /dev/null @@ -1 +0,0 @@ -io.quarkus.test.junit.BasicLoggingEnabler diff --git a/test-framework/junit5/src/test/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrdererTest.java b/test-framework/junit5/src/test/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrdererTest.java index acb5f2cf5b834..d91035f34f311 100644 --- a/test-framework/junit5/src/test/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrdererTest.java +++ b/test-framework/junit5/src/test/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrdererTest.java @@ -1,7 +1,5 @@ package io.quarkus.test.junit.util; -import static io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer.CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST; -import static io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer.CFGKEY_SECONDARY_ORDERER; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; @@ -40,14 +38,12 @@ class QuarkusTestProfileAwareClassOrdererTest { @Mock ClassOrdererContext contextMock; - QuarkusTestProfileAwareClassOrderer underTest = new QuarkusTestProfileAwareClassOrderer(); - @Test void singleClass() { doReturn(Arrays.asList(descriptorMock(Test01.class))) .when(contextMock).getClassDescriptors(); - underTest.orderClasses(contextMock); + new QuarkusTestProfileAwareClassOrderer().orderClasses(contextMock); verify(contextMock, never()).getConfigurationParameter(anyString()); } @@ -89,7 +85,7 @@ void allVariants() { quarkusTestWithUnrestrictedQuarkusTestResourceDesc); doReturn(input).when(contextMock).getClassDescriptors(); - underTest.orderClasses(contextMock); + new QuarkusTestProfileAwareClassOrderer().orderClasses(contextMock); assertThat(input).containsExactly( quarkusTest1Desc, @@ -114,11 +110,7 @@ void configuredPrefix() { List input = Arrays.asList(quarkusTestDesc, nonQuarkusTestDesc); doReturn(input).when(contextMock).getClassDescriptors(); - when(contextMock.getConfigurationParameter(anyString())).thenReturn(Optional.empty()); // for strict stubbing - // prioritize unit tests - when(contextMock.getConfigurationParameter(CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST)).thenReturn(Optional.of("01_")); - - underTest.orderClasses(contextMock); + new QuarkusTestProfileAwareClassOrderer("20_", "40_", "45_", "01_", Optional.empty()).orderClasses(contextMock); assertThat(input).containsExactly(nonQuarkusTestDesc, quarkusTestDesc); } @@ -137,12 +129,8 @@ void secondaryOrderer() { quarkusTest1Desc); doReturn(input).when(contextMock).getClassDescriptors(); - when(contextMock.getConfigurationParameter(anyString())).thenReturn(Optional.empty()); // for strict stubbing - // change secondary orderer from ClassName to OrderAnnotation - when(contextMock.getConfigurationParameter(CFGKEY_SECONDARY_ORDERER)) - .thenReturn(Optional.of(ClassOrderer.OrderAnnotation.class.getName())); - - underTest.orderClasses(contextMock); + new QuarkusTestProfileAwareClassOrderer("20_", "40_", "45_", "60_", + Optional.of(ClassOrderer.OrderAnnotation.class.getName())).orderClasses(contextMock); assertThat(input).containsExactly( quarkusTest1Desc, @@ -157,14 +145,13 @@ void customOrderKey() { List input = Arrays.asList(quarkusTest1Desc, quarkusTest2Desc); doReturn(input).when(contextMock).getClassDescriptors(); - underTest = new QuarkusTestProfileAwareClassOrderer() { + new QuarkusTestProfileAwareClassOrderer() { @Override protected Optional getCustomOrderKey(ClassDescriptor classDescriptor, ClassOrdererContext context, String secondaryOrderSuffix) { return classDescriptor == quarkusTest2Desc ? Optional.of("00_first") : Optional.empty(); } - }; - underTest.orderClasses(contextMock); + }.orderClasses(contextMock); assertThat(input).containsExactly(quarkusTest2Desc, quarkusTest1Desc); } diff --git a/test-framework/pom.xml b/test-framework/pom.xml index 888a8dd222928..fef1a28244cb7 100644 --- a/test-framework/pom.xml +++ b/test-framework/pom.xml @@ -21,8 +21,8 @@ derby kubernetes-client openshift-client + junit5-config junit5-internal - junit5-properties junit5 junit5-component junit5-mockito From 1061fb76f4123afff5752ed5b1618876bfd2f3f4 Mon Sep 17 00:00:00 2001 From: Jochen Schalanda Date: Thu, 5 Dec 2024 14:27:26 +0100 Subject: [PATCH 027/207] Fix missing groupId in rest-virtual-threads.adoc The dependency coordinates in the `build.gradle` example was missing the groupId. --- docs/src/main/asciidoc/rest-virtual-threads.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/rest-virtual-threads.adoc b/docs/src/main/asciidoc/rest-virtual-threads.adoc index a220aec16ce0f..9de9a9bf4c728 100644 --- a/docs/src/main/asciidoc/rest-virtual-threads.adoc +++ b/docs/src/main/asciidoc/rest-virtual-threads.adoc @@ -53,7 +53,7 @@ and in particular, adds the following dependencies: .build.gradle ---- implementation("io.quarkus:quarkus-rest-jackson") -implementation("quarkus-rest-client-jackson") +implementation("io.quarkus:quarkus-rest-client-jackson") ---- [NOTE] @@ -300,4 +300,4 @@ Learn more about virtual threads support on: - xref:./messaging-virtual-threads.adoc[@RunOnVirtualThread in messaging applications] (this guide covers Apache Kafka) - xref:./grpc-virtual-threads.adoc[@RunOnVirtualThread in gRPC services] -- xref:./virtual-threads.adoc[the virtual thread reference guide] (include native compilation and containerization) \ No newline at end of file +- xref:./virtual-threads.adoc[the virtual thread reference guide] (include native compilation and containerization) From aaca7b92520bece6ca94b7dc4007aed67023acce Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Thu, 5 Dec 2024 11:03:12 -0300 Subject: [PATCH 028/207] Remove extensions migrated to Quarkiverse These extensions are in Quarkiverse and doesn't make sense to list them here --- MAINTAINERS.adoc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/MAINTAINERS.adoc b/MAINTAINERS.adoc index fa8a42f66b7e7..49d99406a5265 100644 --- a/MAINTAINERS.adoc +++ b/MAINTAINERS.adoc @@ -100,9 +100,6 @@ If you think some information is outdated, either provide a pull request or emai |Jackson |https://github.com/geoand[Georgios Andrianakis], https://github.com/gsmet[Guillaume Smet] -|Jaeger -|https://github.com/objectiser[Gary Brown] - |JAXB |https://github.com/gsmet[Guillaume Smet] @@ -121,12 +118,6 @@ If you think some information is outdated, either provide a pull request or emai |JDBC - SQL Server |https://github.com/Sanne[Sanne Grinovero] -|JGit -|https://github.com/gastaldi[George Gastaldi] - -|JSch -|https://github.com/gastaldi[George Gastaldi] - |JSON-B |https://github.com/geoand[Georgios Andrianakis], https://github.com/gsmet[Guillaume Smet] From be3ac865773afa44e8f3d07bce731a44c7012484 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Thu, 5 Dec 2024 11:24:34 -0300 Subject: [PATCH 029/207] Reuse JGit instance and avoid deprecated methods JGit 7.1.0 deprecated some methods. This uses the recommended methods. --- .../info/deployment/InfoProcessor.java | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java index c31f9dae6c19d..1509ac3314abf 100644 --- a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java +++ b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java @@ -4,13 +4,13 @@ import java.io.File; import java.net.InetAddress; +import java.time.Instant; import java.time.OffsetDateTime; +import java.time.ZoneId; import java.util.Collection; -import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.TimeZone; import java.util.stream.Collectors; import jakarta.enterprise.context.ApplicationScoped; @@ -70,11 +70,10 @@ void gitInfo(InfoBuildTimeConfig config, log.debug("Project is not checked in to git"); return; } - try (Repository repository = repositoryBuilder.build()) { + try (Repository repository = repositoryBuilder.build(); + Git git = Git.wrap(repository)) { - RevCommit latestCommit = new Git(repository).log().setMaxCount(1).call().iterator().next(); - Date commitDate = new Date(latestCommit.getCommitTime() * 1000L); - TimeZone commitTimeZone = TimeZone.getDefault(); + RevCommit latestCommit = git.log().setMaxCount(1).call().iterator().next(); boolean addFullInfo = config.git().mode() == InfoBuildTimeConfig.Git.Mode.FULL; @@ -85,16 +84,17 @@ void gitInfo(InfoBuildTimeConfig config, Map commit = new LinkedHashMap<>(); String latestCommitId = latestCommit.getName(); commit.put("id", latestCommitId); - String latestCommitTime = formatDate(commitDate, commitTimeZone); + String latestCommitTime = formatDate(Instant.ofEpochMilli(latestCommit.getCommitTime()), ZoneId.systemDefault()); commit.put("time", latestCommitTime); if (addFullInfo) { PersonIdent authorIdent = latestCommit.getAuthorIdent(); - commit.put("author", Map.of("time", formatDate(authorIdent.getWhen(), authorIdent.getTimeZone()))); + commit.put("author", Map.of("time", formatDate(authorIdent.getWhenAsInstant(), authorIdent.getZoneId()))); PersonIdent committerIdent = latestCommit.getCommitterIdent(); - commit.put("committer", Map.of("time", formatDate(committerIdent.getWhen(), committerIdent.getTimeZone()))); + commit.put("committer", + Map.of("time", formatDate(committerIdent.getWhenAsInstant(), committerIdent.getZoneId()))); Map user = new LinkedHashMap<>(); user.put("email", authorIdent.getEmailAddress()); @@ -111,7 +111,7 @@ void gitInfo(InfoBuildTimeConfig config, commit.put("id", id); - data.put("tags", getTags(repository, latestCommit)); + data.put("tags", getTags(git, latestCommit)); } data.put("commit", commit); @@ -130,9 +130,8 @@ void gitInfo(InfoBuildTimeConfig config, } } - private String formatDate(Date date, TimeZone timeZone) { - return ISO_OFFSET_DATE_TIME.format( - OffsetDateTime.ofInstant(date.toInstant(), timeZone.toZoneId())); + private String formatDate(Instant instant, ZoneId zoneId) { + return ISO_OFFSET_DATE_TIME.format(OffsetDateTime.ofInstant(instant, zoneId)); } private Map obtainBuildInfo(CurateOutcomeBuildItem curateOutcomeBuildItem, @@ -160,13 +159,11 @@ private Map obtainBuildInfo(CurateOutcomeBuildItem curateOutcome return build; } - public Collection getTags(Repository repo, final ObjectId objectId) throws GitAPIException { - try (Git git = Git.wrap(repo)) { - try (RevWalk walk = new RevWalk(repo)) { - Collection tags = getTags(git, objectId, walk); - walk.dispose(); - return tags; - } + public Collection getTags(final Git git, final ObjectId objectId) throws GitAPIException { + try (RevWalk walk = new RevWalk(git.getRepository())) { + Collection tags = getTags(git, objectId, walk); + walk.dispose(); + return tags; } } From 0cc985ec08761c3c639666a9e19c8d133f82344d Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 5 Dec 2024 16:24:35 +0200 Subject: [PATCH 030/207] Use the Quarkus configured ObjectMapper in Redis client Fixes: #44934 --- .../datasource/QuarkusObjectMapperTest.java | 134 ++++++++++++++++++ .../redis/datasource/codecs/Codecs.java | 4 +- .../jackson/QuarkusJacksonJsonCodec.java | 4 +- 3 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 extensions/redis-client/deployment/src/test/java/io/quarkus/redis/deployment/client/datasource/QuarkusObjectMapperTest.java diff --git a/extensions/redis-client/deployment/src/test/java/io/quarkus/redis/deployment/client/datasource/QuarkusObjectMapperTest.java b/extensions/redis-client/deployment/src/test/java/io/quarkus/redis/deployment/client/datasource/QuarkusObjectMapperTest.java new file mode 100644 index 0000000000000..a13ded00f6789 --- /dev/null +++ b/extensions/redis-client/deployment/src/test/java/io/quarkus/redis/deployment/client/datasource/QuarkusObjectMapperTest.java @@ -0,0 +1,134 @@ +package io.quarkus.redis.deployment.client.datasource; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +import io.quarkus.jackson.ObjectMapperCustomizer; +import io.quarkus.redis.datasource.RedisDataSource; +import io.quarkus.redis.datasource.hash.HashCommands; +import io.quarkus.redis.deployment.client.RedisTestResource; +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.QuarkusTestResource; + +@QuarkusTestResource(RedisTestResource.class) +public class QuarkusObjectMapperTest { + + @RegisterExtension + static final QuarkusUnitTest unitTest = new QuarkusUnitTest() + .setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class).addClass(CustomCodecTest.Jedi.class).addClass( + CustomCodecTest.Sith.class) + .addClass(CustomCodecTest.CustomJediCodec.class).addClass(CustomCodecTest.CustomSithCodec.class)) + .overrideConfigKey("quarkus.redis.hosts", "${quarkus.redis.tr}"); + + @Inject + RedisDataSource ds; + + @Test + public void test() { + String key = UUID.randomUUID().toString(); + HashCommands> h = ds.hash(new TypeReference<>() { + + }); + h.hset(key, "test", List.of(new Person("foo", 100))); + String stringRetrieved = ds.hash(String.class).hget(key, "test"); + assertThat(stringRetrieved).isEqualTo("[{\"nAmE\":\"foo\",\"aGe\":100}]"); + List peopleRetrieved = h.hget(key, "test"); + assertThat(peopleRetrieved).singleElement().satisfies(p -> { + assertThat(p.getName()).isEqualTo("foo"); + assertThat(p.getAge()).isEqualTo(100); + }); + } + + // without a custom module, this could not be deserialized as there are 2 constructors + public static class Person { + private final String name; + private final int age; + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + @SuppressWarnings("unused") + public Person(String name) { + this.name = name; + this.age = 0; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + } + + @Singleton + public static class PersonCustomizer implements ObjectMapperCustomizer { + + @Override + public void customize(ObjectMapper objectMapper) { + SimpleModule module = new SimpleModule(); + module.addDeserializer(Person.class, new PersonDeserializer()); + module.addSerializer(Person.class, new PersonSerializer()); + objectMapper.registerModule(module); + } + } + + public static class PersonSerializer extends StdSerializer { + + protected PersonSerializer() { + super(Person.class); + } + + @Override + public void serialize(Person person, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField("nAmE", person.getName()); + jsonGenerator.writeNumberField("aGe", person.getAge()); + jsonGenerator.writeEndObject(); + } + } + + public static class PersonDeserializer extends StdDeserializer { + + protected PersonDeserializer() { + super(Person.class); + } + + @Override + public Person deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException { + JsonNode node = jsonParser.getCodec().readTree(jsonParser); + String name = node.get("nAmE").asText(); + int age = (Integer) node.get("aGe").numberValue(); + + return new Person(name, age); + } + } +} diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/codecs/Codecs.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/codecs/Codecs.java index 765caeb025e88..5022b7dbd67fc 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/codecs/Codecs.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/codecs/Codecs.java @@ -11,9 +11,9 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import io.quarkus.vertx.runtime.jackson.QuarkusJacksonJsonCodec; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.Json; -import io.vertx.core.json.jackson.DatabindCodec; public class Codecs { @@ -61,7 +61,7 @@ public Type getType() { }; this.clazz = null; } - this.mapper = DatabindCodec.mapper(); + this.mapper = QuarkusJacksonJsonCodec.mapper(); } @Override diff --git a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/jackson/QuarkusJacksonJsonCodec.java b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/jackson/QuarkusJacksonJsonCodec.java index 1e02b5e8fef81..fa3b646350729 100644 --- a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/jackson/QuarkusJacksonJsonCodec.java +++ b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/jackson/QuarkusJacksonJsonCodec.java @@ -28,7 +28,7 @@ * The difference is that this class obtains the ObjectMapper from Arc in order to inherit the * user-customized ObjectMapper. */ -class QuarkusJacksonJsonCodec implements JsonCodec { +public class QuarkusJacksonJsonCodec implements JsonCodec { private static volatile ObjectMapper mapper; // we don't want to create this unless it's absolutely necessary (and it rarely is) @@ -43,7 +43,7 @@ public static void reset() { prettyMapper = null; } - private static ObjectMapper mapper() { + public static ObjectMapper mapper() { if (mapper == null) { synchronized (QuarkusJacksonJsonCodec.class) { if (mapper == null) { From 3575e50a4f4b1ad976ad87b0d4b72ce0d69cfa5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20=C3=89pardaud?= Date: Tue, 1 Oct 2024 17:26:12 +0200 Subject: [PATCH 031/207] Reimplement security-webauthn on top of webauthn4j --- bom/application/pom.xml | 14 + docs/src/main/asciidoc/images/webauthn-1.png | Bin 23018 -> 22503 bytes docs/src/main/asciidoc/images/webauthn-2.png | Bin 22562 -> 21815 bytes docs/src/main/asciidoc/images/webauthn-4.png | Bin 22314 -> 21876 bytes docs/src/main/asciidoc/images/webauthn-5.png | Bin 23498 -> 23029 bytes .../asciidoc/images/webauthn-custom-login.svg | 1 + .../images/webauthn-custom-register.svg | 1 + .../main/asciidoc/images/webauthn-login.svg | 1 + .../asciidoc/images/webauthn-register.svg | 1 + docs/src/main/asciidoc/security-webauthn.adoc | 633 +++++++++------- .../security-webauthn/deployment/pom.xml | 4 +- .../QuarkusSecurityWebAuthnProcessor.java | 59 +- .../webauthn/test/ManualResource.java | 6 +- .../test/WebAuthnAndBasicAuthnTest.java | 15 +- .../test/WebAuthnAutomaticBlockingTest.java | 5 + .../WebAuthnAutomaticNonBlockingTest.java | 5 + .../webauthn/test/WebAuthnAutomaticTest.java | 41 +- .../WebAuthnBlockingTestUserProvider.java | 20 +- .../test/WebAuthnManualCustomCookiesTest.java | 19 +- .../webauthn/test/WebAuthnManualTest.java | 68 +- .../test/WebAuthnManualTestUserProvider.java | 16 +- .../WebAuthnNonBlockingTestUserProvider.java | 20 +- .../webauthn/test/WebAuthnOriginsTest.java | 48 ++ .../security/webauthn/test/WebAuthnTest.java | 32 + extensions/security-webauthn/runtime/pom.xml | 8 +- .../WebAuthnAuthenticationMechanism.java | 2 +- .../WebAuthnAuthenticationRequest.java | 18 - .../WebAuthnAuthenticatorStorage.java | 32 +- .../security/webauthn/WebAuthnController.java | 274 ++----- .../webauthn/WebAuthnCredentialRecord.java | 192 +++++ .../webauthn/WebAuthnIdentityProvider.java | 56 -- .../security/webauthn/WebAuthnRecorder.java | 17 +- .../webauthn/WebAuthnRunTimeConfig.java | 230 +++++- .../security/webauthn/WebAuthnSecurity.java | 707 +++++++++++++++--- .../webauthn/WebAuthnUserProvider.java | 46 +- .../webauthn/impl/VertxHttpAsyncClient.java | 41 + .../runtime/src/main/resources/webauthn.js | 57 +- .../it/security/webauthn/LoginResource.java | 14 +- .../it/security/webauthn/MyWebAuthnSetup.java | 93 +-- .../security/webauthn/WebAuthnCredential.java | 97 +-- .../src/main/resources/application.properties | 2 + .../webauthn/test/WebAuthnResourceTest.java | 17 +- ...WebAuthnVirtualThreadTestUserProvider.java | 20 +- .../src/main/resources/application.properties | 2 + .../webauthn/RunOnVirtualThreadIT.java | 16 +- .../webauthn/RunOnVirtualThreadTest.java | 25 +- test-framework/security-webauthn/pom.xml | 6 +- .../webauthn/WebAuthnEndpointHelper.java | 36 +- .../security/webauthn/WebAuthnHardware.java | 88 +-- .../security/webauthn/WebAuthnHelper.java | 265 +++++++ .../webauthn/WebAuthnTestUserProvider.java | 89 +-- 51 files changed, 2407 insertions(+), 1052 deletions(-) create mode 100644 docs/src/main/asciidoc/images/webauthn-custom-login.svg create mode 100644 docs/src/main/asciidoc/images/webauthn-custom-register.svg create mode 100644 docs/src/main/asciidoc/images/webauthn-login.svg create mode 100644 docs/src/main/asciidoc/images/webauthn-register.svg create mode 100644 extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java delete mode 100644 extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticationRequest.java create mode 100644 extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnCredentialRecord.java delete mode 100644 extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnIdentityProvider.java create mode 100644 extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/impl/VertxHttpAsyncClient.java create mode 100644 test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnHelper.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index f20011fbaa72c..b4cdc64ed4321 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -219,6 +219,7 @@ 0.16.0 1.0.11 + 0.28.0.RELEASE @@ -6509,6 +6510,18 @@ ${project.version} + + + com.webauthn4j + webauthn4j-core-async + ${webauthn4j.version} + + + com.webauthn4j + webauthn4j-metadata-async + ${webauthn4j.version} + + io.quarkus @@ -6532,6 +6545,7 @@ ${project.version} + diff --git a/docs/src/main/asciidoc/images/webauthn-1.png b/docs/src/main/asciidoc/images/webauthn-1.png index 70b1764e343edb380622ae4f62d1141d6e3d701b..515e71df96b04b50a5d0be6ddbd26506e51017e1 100644 GIT binary patch delta 18692 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 Vn`0--Qw*WO;GocBbpdB{{tfT^u5bVV delta 19154 zcmZU4WmMQqv@P!LPVwUI?oh17o#O7U!QCnD4#nNw9g4fVyTjwVcfDUXS#$o(WHNIy z$?Uz)$zc`fNgZe`IcR4b#W%o#fV(#Ea~H!Aq8zo`zB;V~zkPQKdzdu6KumglmQKl- z2KyUIL@c9$^xkJQ}nV4Tm*U7 zNJ>_{-$fhriLQDi=2X_g(`)hJcn$fa-OvhhSB&Hh+Ixy#nw5=An!cqfTG&x zD;ji_x0M+n5xh$${%5DQg6%dZHju(S z@#ysA6$?Irhdb|a5<%cKn>SluNvYQ1~Iew3^J?YBbP=%0VG zk!ikd z4&};_LLk$RMjRcQ1g5Y*D3Q6C9HLkvJ>8XU&D1b#%9v?vlnQoVxgsSr5fuM9za?I@ zqaa>}TCsla-wyygRv|pJ1n0?FF0G-Y#A3dvqbSX?RIx!-P3xS#5rQj;Qclad;(oFq zGmh8RmFUR3KTd+kczF7kB))gN0P7Ts@kzN&QuMa+pZF-AqiBY1t#}eTB@5w4k&sKr@c&PfgUuc=Q zZ(uYQtDflOjK&e2NvHVVJh5^*tPD Lvclrh-Lnpawf?41LLkL(?+P0~X;r%#E! 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 b4w1LT4+&5)O-@h+%3*rN@^ZD2+n@gebD+5H diff --git a/docs/src/main/asciidoc/images/webauthn-2.png b/docs/src/main/asciidoc/images/webauthn-2.png index 760faf4a615067ccdfcb8e157695c7a107b5f513..e9522798b0152b6aaded14e845f538fa0a8c8ed2 100644 GIT binary patch delta 18171 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 z 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 z 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 A_W%F@ diff --git a/docs/src/main/asciidoc/images/webauthn-4.png b/docs/src/main/asciidoc/images/webauthn-4.png index 2da3b1d5a176e3e23025f5f7e3a8df5b80314ce3..934a175c7bdcd21aa38049d000a6dc4b51df7964 100644 GIT binary patch delta 17912 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 delta 19878 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 diff --git a/docs/src/main/asciidoc/images/webauthn-custom-login.svg b/docs/src/main/asciidoc/images/webauthn-custom-login.svg new file mode 100644 index 0000000000000..e08ba0cd89ee0 --- /dev/null +++ b/docs/src/main/asciidoc/images/webauthn-custom-login.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/src/main/asciidoc/images/webauthn-custom-register.svg b/docs/src/main/asciidoc/images/webauthn-custom-register.svg new file mode 100644 index 0000000000000..75b98727ac93b --- /dev/null +++ b/docs/src/main/asciidoc/images/webauthn-custom-register.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/src/main/asciidoc/images/webauthn-login.svg b/docs/src/main/asciidoc/images/webauthn-login.svg new file mode 100644 index 0000000000000..0055a442c28e9 --- /dev/null +++ b/docs/src/main/asciidoc/images/webauthn-login.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/src/main/asciidoc/images/webauthn-register.svg b/docs/src/main/asciidoc/images/webauthn-register.svg new file mode 100644 index 0000000000000..5c60cdb486b8e --- /dev/null +++ b/docs/src/main/asciidoc/images/webauthn-register.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/src/main/asciidoc/security-webauthn.adoc b/docs/src/main/asciidoc/security-webauthn.adoc index 996691c7a8183..51d49168c47ab 100644 --- a/docs/src/main/asciidoc/security-webauthn.adoc +++ b/docs/src/main/asciidoc/security-webauthn.adoc @@ -10,6 +10,8 @@ include::_attributes.adoc[] :categories: security :topics: security,webauthn,authorization :extensions: io.quarkus:quarkus-security-webauthn +:webauthn-api: https://javadoc.io/doc/io.quarkus/quarkus-security-webauthn/{quarkus-version} +:webauthn-test-api: https://javadoc.io/doc/io.quarkus/quarkus-test-security-webauthn/{quarkus-version} This guide demonstrates how your Quarkus application can use WebAuthn authentication instead of passwords. @@ -221,7 +223,7 @@ public class UserResource { === Storing our WebAuthn credentials -We can now describe how our WebAuthn credentials are stored in our database with three entities. Note that we've +We can now describe how our WebAuthn credentials are stored in our database with two entities. Note that we've simplified the model in order to only store one credential per user (who could actually have more than one WebAuthn credential and other data such as roles): @@ -229,139 +231,65 @@ and other data such as roles): ---- package org.acme.security.webauthn; -import java.util.ArrayList; import java.util.List; +import java.util.UUID; +import io.quarkus.hibernate.orm.panache.PanacheEntityBase; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord.RequiredPersistedData; import jakarta.persistence.Entity; -import jakarta.persistence.OneToMany; +import jakarta.persistence.Id; import jakarta.persistence.OneToOne; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; - -import io.quarkus.hibernate.orm.panache.PanacheEntity; -import io.vertx.ext.auth.webauthn.Authenticator; -import io.vertx.ext.auth.webauthn.PublicKeyCredential; -@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"userName", "credID"})) @Entity -public class WebAuthnCredential extends PanacheEntity { - - /** - * The username linked to this authenticator - */ - public String userName; - - /** - * The type of key (must be "public-key") - */ - public String type = "public-key"; +public class WebAuthnCredential extends PanacheEntityBase { + + @Id + public String credentialId; - /** - * The non user identifiable id for the authenticator - */ - public String credID; - - /** - * The public key associated with this authenticator - */ - public String publicKey; - - /** - * The signature counter of the authenticator to prevent replay attacks - */ + public byte[] publicKey; + public long publicKeyAlgorithm; public long counter; - - public String aaguid; - - /** - * The Authenticator attestation certificates object, a JSON like: - *

    {@code
    -     *   {
    -     *     "alg": "string",
    -     *     "x5c": [
    -     *       "base64"
    -     *     ]
    -     *   }
    -     * }
    - */ - /** - * The algorithm used for the public credential - */ - public PublicKeyCredential alg; - - /** - * The list of X509 certificates encoded as base64url. - */ - @OneToMany(mappedBy = "webAuthnCredential") - public List x5c = new ArrayList<>(); - - public String fmt; - - // owning side + public UUID aaguid; + + // this is the owning side @OneToOne public User user; public WebAuthnCredential() { } - - public WebAuthnCredential(Authenticator authenticator, User user) { - aaguid = authenticator.getAaguid(); - if(authenticator.getAttestationCertificates() != null) - alg = authenticator.getAttestationCertificates().getAlg(); - counter = authenticator.getCounter(); - credID = authenticator.getCredID(); - fmt = authenticator.getFmt(); - publicKey = authenticator.getPublicKey(); - type = authenticator.getType(); - userName = authenticator.getUserName(); - if(authenticator.getAttestationCertificates() != null - && authenticator.getAttestationCertificates().getX5c() != null) { - for (String x5c : authenticator.getAttestationCertificates().getX5c()) { - WebAuthnCertificate cert = new WebAuthnCertificate(); - cert.x5c = x5c; - cert.webAuthnCredential = this; - this.x5c.add(cert); - } - } + + public WebAuthnCredential(WebAuthnCredentialRecord credentialRecord, User user) { + RequiredPersistedData requiredPersistedData = + credentialRecord.getRequiredPersistedData(); + aaguid = requiredPersistedData.aaguid(); + counter = requiredPersistedData.counter(); + credentialId = requiredPersistedData.credentialId(); + publicKey = requiredPersistedData.publicKey(); + publicKeyAlgorithm = requiredPersistedData.publicKeyAlgorithm(); this.user = user; user.webAuthnCredential = this; } - public static List findByUserName(String userName) { - return list("userName", userName); + public WebAuthnCredentialRecord toWebAuthnCredentialRecord() { + return WebAuthnCredentialRecord + .fromRequiredPersistedData( + new RequiredPersistedData(user.userName, credentialId, + aaguid, publicKey, + publicKeyAlgorithm, counter)); } - public static List findByCredID(String credID) { - return list("credID", credID); + public static List findByUserName(String userName) { + return list("user.userName", userName); + } + + public static WebAuthnCredential findByCredentialId(String credentialId) { + return findById(credentialId); } } ---- -We also need a second entity for the credentials: - -[source,java] ----- -package org.acme.security.webauthn; - -import io.quarkus.hibernate.orm.panache.PanacheEntity; -import jakarta.persistence.Entity; -import jakarta.persistence.ManyToOne; - - -@Entity -public class WebAuthnCertificate extends PanacheEntity { - - @ManyToOne - public WebAuthnCredential webAuthnCredential; - - /** - * The list of X509 certificates encoded as base64url. - */ - public String x5c; -} ----- - -And last but not least, our user entity: +And our user entity: [source,java] ---- @@ -392,98 +320,72 @@ public class User extends PanacheEntity { ==== A note about usernames and credential IDs -WebAuthn relies on a combination of usernames (unique per user) and credential IDs (unique per authenticator device). - -The reasons why there are two such identifiers, and why they are not unique keys for the credentials themselves are: - -- A single user can have more than one authenticator device, which means a single username can map to multiple credential IDs, - all of which identify the same user. -- An authenticator device may be shared by multiple users, because a single person may want multiple user accounts with different - usernames, all of which having the same authenticator device. So a single credential ID may be used by multiple different users. +Usernames are unique and to your users. Every created WebAuthn credential record has a unique ID. -The combination of username and credential ID should be a unicity constraint for your credentials table, though. +You can allow (if you want, but you don't have to) your users to have more than one authenticator device, +which means a single username can map to multiple credential IDs, all of which identify the same user. === Exposing your entities to Quarkus WebAuthn -You need to define a bean implementing the `WebAuthnUserProvider` in order to allow the Quarkus WebAuthn +You need to define a bean implementing the link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`] in order to allow the Quarkus WebAuthn extension to load and store credentials. This is where you tell Quarkus how to turn your data model into the WebAuthn security model: [source,java] ---- -package org.acme.security.webauthn; - import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; - -import io.smallrye.common.annotation.Blocking; -import jakarta.enterprise.context.ApplicationScoped; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnUserProvider; +import io.smallrye.common.annotation.Blocking; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.AttestationCertificates; -import io.vertx.ext.auth.webauthn.Authenticator; +import jakarta.enterprise.context.ApplicationScoped; import jakarta.transaction.Transactional; -import static org.acme.security.webauthn.WebAuthnCredential.findByCredID; -import static org.acme.security.webauthn.WebAuthnCredential.findByUserName; - @Blocking @ApplicationScoped public class MyWebAuthnSetup implements WebAuthnUserProvider { @Transactional @Override - public Uni> findWebAuthnCredentialsByUserName(String userName) { - return Uni.createFrom().item(toAuthenticators(findByUserName(userName))); + public Uni> findByUserName(String userId) { + return Uni.createFrom().item( + WebAuthnCredential.findByUserName(userId) + .stream() + .map(WebAuthnCredential::toWebAuthnCredentialRecord) + .toList()); } @Transactional @Override - public Uni> findWebAuthnCredentialsByCredID(String credID) { - return Uni.createFrom().item(toAuthenticators(findByCredID(credID))); + public Uni findByCredentialId(String credId) { + WebAuthnCredential creds = WebAuthnCredential.findByCredentialId(credId); + if(creds == null) + return Uni.createFrom() + .failure(new RuntimeException("No such credential ID")); + return Uni.createFrom().item(creds.toWebAuthnCredentialRecord()); } @Transactional @Override - public Uni updateOrStoreWebAuthnCredentials(Authenticator authenticator) { - // leave the scooby user to the manual endpoint, because if we do it here it will be created/updated twice - if(!authenticator.getUserName().equals("scooby")) { - User user = User.findByUserName(authenticator.getUserName()); - if(user == null) { - // new user - User newUser = new User(); - newUser.userName = authenticator.getUserName(); - WebAuthnCredential credential = new WebAuthnCredential(authenticator, newUser); - credential.persist(); - newUser.persist(); - } else { - // existing user - user.webAuthnCredential.counter = authenticator.getCounter(); - } - } - return Uni.createFrom().nullItem(); - } - - private static List toAuthenticators(List dbs) { - return dbs.stream().map(MyWebAuthnSetup::toAuthenticator).collect(Collectors.toList()); + public Uni store(WebAuthnCredentialRecord credentialRecord) { + User newUser = new User(); + newUser.userName = credentialRecord.getUserName(); + WebAuthnCredential credential = new WebAuthnCredential(credentialRecord, newUser); + credential.persist(); + newUser.persist(); + return Uni.createFrom().voidItem(); } - private static Authenticator toAuthenticator(WebAuthnCredential credential) { - Authenticator ret = new Authenticator(); - ret.setAaguid(credential.aaguid); - AttestationCertificates attestationCertificates = new AttestationCertificates(); - attestationCertificates.setAlg(credential.alg); - ret.setAttestationCertificates(attestationCertificates); - ret.setCounter(credential.counter); - ret.setCredID(credential.credID); - ret.setFmt(credential.fmt); - ret.setPublicKey(credential.publicKey); - ret.setType(credential.type); - ret.setUserName(credential.userName); - return ret; + @Transactional + @Override + public Uni update(String credentialId, long counter) { + WebAuthnCredential credential = + WebAuthnCredential.findByCredentialId(credentialId); + credential.counter = counter; + return Uni.createFrom().voidItem(); } @Override @@ -496,6 +398,17 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider { } ---- +== Configuration + +Because we want to delegate login and registration to the default Quarkus WebAuthn endpoints, we need to enable them +in configuration (`src/main/resources/application.properties`): + +[source,properties] +---- +quarkus.webauthn.enable-login-endpoint=true +quarkus.webauthn.enable-registration-endpoint=true +---- + == Writing the HTML application We now need to write a web page with links to all our APIs, as well as a way to register a new user, login, and logout, @@ -563,7 +476,6 @@ in `src/main/resources/META-INF/resources/index.html`:

    Login

    -

    @@ -578,11 +490,7 @@ in `src/main/resources/META-INF/resources/index.html`: + +---- + +Or, if you need to customise the endpoints: + [source,javascript] ---- ---- +=== CSRF considerations + +If you use the endpoints provided by Quarkus, they will not be protected by xdoc:security-csrf-prevention.adoc[CSRF], but +if you define your own endpoints and use this JavaScript library to access them you will need to configure CSRF via headers: + +[source,javascript] +---- + + +---- + === Invoke registration -The `webAuthn.register` method invokes the registration challenge endpoint, then calls the authenticator and invokes the callback endpoint +The `webAuthn.register` method invokes the registration challenge endpoint, then calls the authenticator and invokes the registration endpoint for that registration, and returns a https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise object]: [source,javascript] @@ -847,12 +858,12 @@ webAuthn.register({ name: userName, displayName: firstName + " " + lastName }) === Invoke login -The `webAuthn.login` method invokes the login challenge endpoint, then calls the authenticator and invokes the callback endpoint +The `webAuthn.login` method invokes the login challenge endpoint, then calls the authenticator and invokes the login endpoint for that login, and returns a https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise object]: [source,javascript] ---- -webAuthn.login({ name: userName }) +webAuthn.login({ name: userName }) <1> .then(body => { // do something now that the user is logged in }) @@ -861,16 +872,18 @@ webAuthn.login({ name: userName }) }); ---- +<1> The name is optional, in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys) + === Only invoke the registration challenge and authenticator -The `webAuthn.registerOnly` method invokes the registration challenge endpoint, then calls the authenticator and returns +The `webAuthn.registerClientSteps` method invokes the registration challenge endpoint, then calls the authenticator and returns a https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise object] containing a -JSON object suitable for being sent to the callback endpoint. You can use that JSON object in order to store the credentials +JSON object suitable for being sent to the registration endpoint. You can use that JSON object in order to store the credentials in hidden form `input` elements, for example, and send it as part of a regular HTML form: [source,javascript] ---- -webAuthn.registerOnly({ name: userName, displayName: firstName + " " + lastName }) +webAuthn.registerClientSteps({ name: userName, displayName: firstName + " " + lastName }) .then(body => { // store the registration JSON in form elements document.getElementById('webAuthnId').value = body.id; @@ -886,14 +899,14 @@ webAuthn.registerOnly({ name: userName, displayName: firstName + " " + lastName === Only invoke the login challenge and authenticator -The `webAuthn.loginOnly` method invokes the login challenge endpoint, then calls the authenticator and returns +The `webAuthn.loginClientSteps` method invokes the login challenge endpoint, then calls the authenticator and returns a https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise object] containing a -JSON object suitable for being sent to the callback endpoint. You can use that JSON object in order to store the credentials +JSON object suitable for being sent to the login endpoint. You can use that JSON object in order to store the credentials in hidden form `input` elements, for example, and send it as part of a regular HTML form: [source,javascript] ---- -webAuthn.loginOnly({ name: userName }) +webAuthn.loginClientSteps({ name: userName }) <1> .then(body => { // store the login JSON in form elements document.getElementById('webAuthnId').value = body.id; @@ -909,25 +922,95 @@ webAuthn.loginOnly({ name: userName }) }); ---- +<1> The name is optional, in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys) + == Handling login and registration endpoints yourself Sometimes, you will want to ask for more data than just a username in order to register a user, -or you want to deal with login and registration with custom validation, and so the WebAuthn callback -endpoint is not enough. +or you want to deal with login and registration with custom validation, and so the default WebAuthn login +and registration endpoints are not enough. -In this case, you can use the `WebAuthn.loginOnly` and `WebAuthn.registerOnly` methods from the JavaScript +In this case, you can use the `WebAuthn.loginClientSteps` and `WebAuthn.registerClientSteps` methods from the JavaScript library, store the authenticator data in hidden form elements, and send them as part of your form payload to the server to your custom login or registration endpoints. -If you are storing them in form input elements, you can then use the `WebAuthnLoginResponse` and -`WebAuthnRegistrationResponse` classes, mark them as `@BeanParam` and then use the `WebAuthnSecurity.login` -and `WebAuthnSecurity.register` methods to replace the `/q/webauthn/callback` endpoint. This even -allows you to create two separate endpoints for handling login and registration at different endpoints. +If you are storing them in form input elements, you can then use the link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnLoginResponse.html[`WebAuthnLoginResponse`] and +link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnRegistrationResponse.html[`WebAuthnRegistrationResponse`] classes, +mark them as `@BeanParam` and then use the +link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnSecurity.html#login(io.quarkus.security.webauthn.WebAuthnLoginResponse,io.vertx.ext.web.RoutingContext)[`WebAuthnSecurity.login`] +and link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnSecurity.html#register(io.quarkus.security.webauthn.WebAuthnRegisterResponse,io.vertx.ext.web.RoutingContext)[`WebAuthnSecurity.register`] +methods to replace the `/q/webauthn/login` and `/q/webauthn/register` endpoints. -In most cases you can keep using the `/q/webauthn/login` and `/q/webauthn/register` challenge-initiating +In most cases you can keep using the `/q/webauthn/login-options-challenge` and `/q/webauthn/register-options-challenge` challenge-initiating endpoints, because this is not where custom logic is required. -For example, here's how you can handle a custom login and register action: +In this case, the registration flow is a little different because you will write your own registration endpoint +which will handle storing of the credentials and setting up the session cookie: + +image::webauthn-custom-register.svg[role="thumb"] + +Similarly, the login flow is a little different because you will write your own login endpoint +which will handle updating the credentials and setting up the session cookie: + +image::webauthn-custom-login.svg[role="thumb"] + +If you handle user and credential creation and logins yourself in your endpoints, you only need +to provide a read-only view of your entities in your link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`], so you can skip +the `store` and `update` methods: + +[source,java] +---- +package org.acme.security.webauthn; + +import java.util.List; + +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; +import io.quarkus.security.webauthn.WebAuthnUserProvider; +import io.smallrye.common.annotation.Blocking; +import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.transaction.Transactional; +import model.WebAuthnCredential; + +@Blocking +@ApplicationScoped +public class MyWebAuthnSetup implements WebAuthnUserProvider { + + @Transactional + @Override + public Uni> findByUserName(String userName) { + return Uni.createFrom().item( + WebAuthnCredential.findByUserName(userName) + .stream() + .map(WebAuthnCredential::toWebAuthnCredentialRecord) + .toList()); + } + + @Transactional + @Override + public Uni findByCredentialId(String credentialId) { + WebAuthnCredential creds = WebAuthnCredential.findByCredentialId(credentialId); + if(creds == null) + return Uni.createFrom() + .failure(new RuntimeException("No such credential ID")); + return Uni.createFrom().item(creds.toWebAuthnCredentialRecord()); + } + + @Override + public Set getRoles(String userId) { + if(userId.equals("admin")) { + return Set.of("user", "admin"); + } + return Collections.singleton("user"); + } +} +---- + +NOTE: When setting up your own login and registration endpoints, you don't need to enable the default endpoints, so you can +remove the `quarkus.webauthn.enable-login-endpoint` and `quarkus.webauthn.enable-registration-endpoint` configuration. + +Thankfully, you can use the link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnSecurity.html[`WebAuthnSecurity`] bean to handle the WebAuthn-specific part of +your registration and login endpoints, and focus on your own logic: [source,java] ---- @@ -943,10 +1026,10 @@ import jakarta.ws.rs.core.Response.Status; import org.jboss.resteasy.reactive.RestForm; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnLoginResponse; import io.quarkus.security.webauthn.WebAuthnRegisterResponse; import io.quarkus.security.webauthn.WebAuthnSecurity; -import io.vertx.ext.auth.webauthn.Authenticator; import io.vertx.ext.web.RoutingContext; @Path("") @@ -955,29 +1038,28 @@ public class LoginResource { @Inject WebAuthnSecurity webAuthnSecurity; - // Provide an alternative implementation of the /q/webauthn/callback endpoint, only for login + // Provide an alternative implementation of the /q/webauthn/login endpoint @Path("/login") @POST @Transactional - public Response login(@RestForm String userName, - @BeanParam WebAuthnLoginResponse webAuthnResponse, + public Response login(@BeanParam WebAuthnLoginResponse webAuthnResponse, RoutingContext ctx) { // Input validation - if(userName == null || userName.isEmpty() || !webAuthnResponse.isSet() || !webAuthnResponse.isValid()) { + if(!webAuthnResponse.isSet() || !webAuthnResponse.isValid()) { return Response.status(Status.BAD_REQUEST).build(); } - User user = User.findByUserName(userName); - if(user == null) { - // Invalid user - return Response.status(Status.BAD_REQUEST).build(); - } try { - Authenticator authenticator = this.webAuthnSecurity.login(webAuthnResponse, ctx).await().indefinitely(); + WebAuthnCredentialRecord credentialRecord = this.webAuthnSecurity.login(webAuthnResponse, ctx).await().indefinitely(); + User user = User.findByUserName(credentialRecord.getUserName()); + if(user == null) { + // Invalid user + return Response.status(Status.BAD_REQUEST).build(); + } // bump the auth counter - user.webAuthnCredential.counter = authenticator.getCounter(); + user.webAuthnCredential.counter = credentialRecord.getCounter(); // make a login cookie - this.webAuthnSecurity.rememberUser(authenticator.getUserName(), ctx); + this.webAuthnSecurity.rememberUser(credentialRecord.getUserName(), ctx); return Response.ok().build(); } catch (Exception exception) { // handle login failure - make a proper error response @@ -985,7 +1067,7 @@ public class LoginResource { } } - // Provide an alternative implementation of the /q/webauthn/callback endpoint, only for registration + // Provide an alternative implementation of the /q/webauthn/register endpoint @Path("/register") @POST @Transactional @@ -993,7 +1075,8 @@ public class LoginResource { @BeanParam WebAuthnRegisterResponse webAuthnResponse, RoutingContext ctx) { // Input validation - if(userName == null || userName.isEmpty() || !webAuthnResponse.isSet() || !webAuthnResponse.isValid()) { + if(userName == null || userName.isEmpty() + || !webAuthnResponse.isSet() || !webAuthnResponse.isValid()) { return Response.status(Status.BAD_REQUEST).build(); } @@ -1004,10 +1087,12 @@ public class LoginResource { } try { // store the user - Authenticator authenticator = this.webAuthnSecurity.register(webAuthnResponse, ctx).await().indefinitely(); + WebAuthnCredentialRecord credentialRecord = + webAuthnSecurity.register(webAuthnResponse, ctx).await().indefinitely(); User newUser = new User(); - newUser.userName = authenticator.getUserName(); - WebAuthnCredential credential = new WebAuthnCredential(authenticator, newUser); + newUser.userName = credentialRecord.getUserName(); + WebAuthnCredential credential = + new WebAuthnCredential(credentialRecord, newUser); credential.persist(); newUser.persist(); // make a login cookie @@ -1022,28 +1107,32 @@ public class LoginResource { } ---- -NOTE: The `WebAuthnSecurity` methods do not set or read the user cookie, so you will have to take care +NOTE: The link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnSecurity.html[`WebAuthnSecurity`] +methods do not set or read the <>, so you will have to take care of it yourself, but it allows you to use other means of storing the user, such as JWT. You can use the -`rememberUser(String userName, RoutingContext ctx)` and `logout(RoutingContext ctx)` methods on the same -`WebAuthnSecurity` class if you want to manually set up login cookies. +link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnSecurity.html#rememberUser(java.lang.String,io.vertx.ext.web.RoutingContext)[`WebAuthnSecurity.rememberUser`] + and link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnSecurity.html#logout(io.vertx.ext.web.RoutingContext)[`WebAuthnSecurity.logout`] + methods on the same link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnSecurity.html[`WebAuthnSecurity`] class if you want to manually set up login cookies. == Blocking version -If you're using a blocking data access to the database, you can safely block on the `WebAuthnSecurity` methods, +If you're using a blocking data access to the database, you can safely block on the +link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnSecurity.html[`WebAuthnSecurity`] methods, with `.await().indefinitely()`, because nothing is async in the `register` and `login` methods, besides the -data access with your `WebAuthnUserProvider`. +data access with your link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`]. -You will have to add the `@Blocking` annotation on your `WebAuthnUserProvider` class in order to tell the +You will have to add the `@Blocking` annotation on your link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`] class in order for the Quarkus WebAuthn endpoints to defer those calls to the worker pool. == Virtual-Threads version -If you're using a blocking data access to the database, you can safely block on the `WebAuthnSecurity` methods, +If you're using a blocking data access to the database, you can safely block on the +link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnSecurity.html[`WebAuthnSecurity`] methods, with `.await().indefinitely()`, because nothing is async in the `register` and `login` methods, besides the -data access with your `WebAuthnUserProvider`. +data access with your link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`]. -You will have to add the `@RunOnVirtualThread` annotation on your `WebAuthnUserProvider` class in order to tell the -Quarkus WebAuthn endpoints to defer those calls to virtual threads. +You will have to add the `@RunOnVirtualThread` annotation on your link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`] class in order to tell the +Quarkus WebAuthn endpoints to defer those calls to the worker pool. == Testing WebAuthn @@ -1066,8 +1155,10 @@ Testing WebAuthn can be complicated because normally you need a hardware token, testImplementation("io.quarkus:quarkus-test-security-webauthn") ---- -With this, you can use `WebAuthnHardware` to emulate an authenticator token, as well as the -`WebAuthnEndpointHelper` helper methods in order to invoke the WebAuthn endpoints, or even fill your form +With this, you can use link:{webauthn-test-api}/io/quarkus/test/security/webauthn/WebAuthnHardware.html[`WebAuthnHardware`] +to emulate an authenticator token, as well as the +link:{webauthn-test-api}/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.html[`WebAuthnEndpointHelper`] +helper methods in order to invoke the WebAuthn endpoints, or even fill your form data for custom endpoints: [source,java] @@ -1076,25 +1167,24 @@ package org.acme.security.webauthn.test; import static io.restassured.RestAssured.given; +import java.net.URL; import java.util.function.Consumer; -import java.util.function.Supplier; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; -import io.quarkus.security.webauthn.WebAuthnController; +import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.security.webauthn.WebAuthnEndpointHelper; import io.quarkus.test.security.webauthn.WebAuthnHardware; import io.restassured.RestAssured; import io.restassured.filter.Filter; -import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.vertx.core.json.JsonObject; @QuarkusTest public class WebAuthnResourceTest { - + enum User { USER, ADMIN; } @@ -1102,6 +1192,9 @@ public class WebAuthnResourceTest { DEFAULT, MANUAL; } + @TestHTTPResource + URL url; + @Test public void testWebAuthnUser() { testWebAuthn("FroMage", User.USER, Endpoint.DEFAULT); @@ -1112,42 +1205,41 @@ public class WebAuthnResourceTest { public void testWebAuthnAdmin() { testWebAuthn("admin", User.ADMIN, Endpoint.DEFAULT); } - + private void testWebAuthn(String userName, User user, Endpoint endpoint) { Filter cookieFilter = new RenardeCookieFilter(); - WebAuthnHardware token = new WebAuthnHardware(); + WebAuthnHardware token = new WebAuthnHardware(url); verifyLoggedOut(cookieFilter); // two-step registration - String challenge = WebAuthnEndpointHelper.invokeRegistration(userName, cookieFilter); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge(userName, cookieFilter); JsonObject registrationJson = token.makeRegistrationJson(challenge); if(endpoint == Endpoint.DEFAULT) - WebAuthnEndpointHelper.invokeCallback(registrationJson, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration(registrationJson, cookieFilter); else { invokeCustomEndpoint("/register", cookieFilter, request -> { WebAuthnEndpointHelper.addWebAuthnRegistrationFormParameters(request, registrationJson); request.formParam("userName", userName); }); } - + // verify that we can access logged-in endpoints verifyLoggedIn(cookieFilter, userName, user); - + // logout WebAuthnEndpointHelper.invokeLogout(cookieFilter); - + verifyLoggedOut(cookieFilter); - + // two-step login - challenge = WebAuthnEndpointHelper.invokeLogin(userName, cookieFilter); + challenge = WebAuthnEndpointHelper.obtainLoginChallenge(null, cookieFilter); JsonObject loginJson = token.makeLoginJson(challenge); if(endpoint == Endpoint.DEFAULT) - WebAuthnEndpointHelper.invokeCallback(loginJson, cookieFilter); + WebAuthnEndpointHelper.invokeLogin(loginJson, cookieFilter); else { invokeCustomEndpoint("/login", cookieFilter, request -> { WebAuthnEndpointHelper.addWebAuthnLoginFormParameters(request, loginJson); - request.formParam("userName", userName); }); } @@ -1156,7 +1248,7 @@ public class WebAuthnResourceTest { // logout WebAuthnEndpointHelper.invokeLogout(cookieFilter); - + verifyLoggedOut(cookieFilter); } @@ -1200,7 +1292,7 @@ public class WebAuthnResourceTest { .then() .statusCode(200) .body(Matchers.is(userName)); - + // admin API? if(user == User.ADMIN) { RestAssured.given().filter(cookieFilter) @@ -1243,7 +1335,7 @@ public class WebAuthnResourceTest { .then() .statusCode(302) .header("Location", Matchers.is("http://localhost:8081/")); - + // admin API not accessible RestAssured.given() .filter(cookieFilter) @@ -1258,32 +1350,45 @@ public class WebAuthnResourceTest { ---- For this test, since we're testing both the provided callback endpoint, which updates users -in its `WebAuthnUserProvider` and the manual `LoginResource` endpoint, which deals with users -manually, we need to override the `WebAuthnUserProvider` with one that doesn't update the +in its link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`] and the manual `LoginResource` endpoint, which deals with users +manually, we need to override the link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`] with one that doesn't update the `scooby` user: [source,java] ---- package org.acme.security.webauthn.test; -import jakarta.enterprise.context.ApplicationScoped; - import org.acme.security.webauthn.MyWebAuthnSetup; +import org.acme.security.webauthn.WebAuthnCredential; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.test.Mock; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.Authenticator; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.transaction.Transactional; @Mock @ApplicationScoped public class TestUserProvider extends MyWebAuthnSetup { + @Transactional + @Override + public Uni store(WebAuthnCredentialRecord credentialRecord) { + // this user is handled in the LoginResource endpoint manually + if (credentialRecord.getUserName().equals("scooby")) { + return Uni.createFrom().voidItem(); + } + return super.store(credentialRecord); + } + + @Transactional @Override - public Uni updateOrStoreWebAuthnCredentials(Authenticator authenticator) { - // delegate the scooby user to the manual endpoint, because if we do it here it will be - // created/updated twice - if(authenticator.getUserName().equals("scooby")) - return Uni.createFrom().nullItem(); - return super.updateOrStoreWebAuthnCredentials(authenticator); + public Uni update(String credentialId, long counter) { + WebAuthnCredential credential = WebAuthnCredential.findByCredentialId(credentialId); + // this user is handled in the LoginResource endpoint manually + if (credential.user.userName.equals("scooby")) { + return Uni.createFrom().voidItem(); + } + return super.update(credentialId, counter); } } ---- diff --git a/extensions/security-webauthn/deployment/pom.xml b/extensions/security-webauthn/deployment/pom.xml index bf0f0d74fe732..dd286d827b5ce 100644 --- a/extensions/security-webauthn/deployment/pom.xml +++ b/extensions/security-webauthn/deployment/pom.xml @@ -1,6 +1,6 @@ - + 4.0.0 io.quarkus diff --git a/extensions/security-webauthn/deployment/src/main/java/io/quarkus/security/webauthn/deployment/QuarkusSecurityWebAuthnProcessor.java b/extensions/security-webauthn/deployment/src/main/java/io/quarkus/security/webauthn/deployment/QuarkusSecurityWebAuthnProcessor.java index 9a12d8e4e9f55..a624fdf872752 100644 --- a/extensions/security-webauthn/deployment/src/main/java/io/quarkus/security/webauthn/deployment/QuarkusSecurityWebAuthnProcessor.java +++ b/extensions/security-webauthn/deployment/src/main/java/io/quarkus/security/webauthn/deployment/QuarkusSecurityWebAuthnProcessor.java @@ -7,6 +7,20 @@ import org.jboss.jandex.DotName; +import com.webauthn4j.data.AuthenticationRequest; +import com.webauthn4j.data.AuthenticatorAssertionResponse; +import com.webauthn4j.data.AuthenticatorAttestationResponse; +import com.webauthn4j.data.PublicKeyCredential; +import com.webauthn4j.data.PublicKeyCredentialCreationOptions; +import com.webauthn4j.data.PublicKeyCredentialParameters; +import com.webauthn4j.data.PublicKeyCredentialRequestOptions; +import com.webauthn4j.data.PublicKeyCredentialRpEntity; +import com.webauthn4j.data.PublicKeyCredentialType; +import com.webauthn4j.data.PublicKeyCredentialUserEntity; +import com.webauthn4j.data.RegistrationRequest; +import com.webauthn4j.data.attestation.AttestationObject; +import com.webauthn4j.data.client.CollectedClientData; + import io.quarkus.arc.deployment.AdditionalBeanBuildItem; import io.quarkus.arc.deployment.BeanContainerBuildItem; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; @@ -15,12 +29,12 @@ import io.quarkus.deployment.annotations.BuildSteps; import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Record; -import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; +import io.quarkus.deployment.builditem.IndexDependencyBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem; import io.quarkus.security.webauthn.WebAuthn; import io.quarkus.security.webauthn.WebAuthnAuthenticationMechanism; import io.quarkus.security.webauthn.WebAuthnAuthenticatorStorage; import io.quarkus.security.webauthn.WebAuthnBuildTimeConfig; -import io.quarkus.security.webauthn.WebAuthnIdentityProvider; import io.quarkus.security.webauthn.WebAuthnRecorder; import io.quarkus.security.webauthn.WebAuthnSecurity; import io.quarkus.security.webauthn.WebAuthnTrustedIdentityProvider; @@ -28,18 +42,50 @@ import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem; import io.quarkus.vertx.http.deployment.VertxWebRouterBuildItem; import io.quarkus.vertx.http.runtime.security.HttpAuthenticationMechanism; -import io.vertx.ext.auth.webauthn.impl.attestation.Attestation; @BuildSteps(onlyIf = QuarkusSecurityWebAuthnProcessor.IsEnabled.class) class QuarkusSecurityWebAuthnProcessor { + @BuildStep + public IndexDependencyBuildItem addTypesToJandex() { + // needed by registerJacksonTypes() + return new IndexDependencyBuildItem("com.webauthn4j", "webauthn4j-core"); + } + + @BuildStep + public void registerJacksonTypes(BuildProducer reflection) { + reflection.produce( + ReflectiveHierarchyBuildItem.builder(AuthenticatorAssertionResponse.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(AuthenticatorAttestationResponse.class).build()); + reflection.produce(ReflectiveHierarchyBuildItem.builder(AuthenticationRequest.class).build()); + reflection.produce(ReflectiveHierarchyBuildItem.builder(RegistrationRequest.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(PublicKeyCredentialCreationOptions.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(PublicKeyCredentialRequestOptions.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(PublicKeyCredentialRpEntity.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(PublicKeyCredentialUserEntity.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(PublicKeyCredentialParameters.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(PublicKeyCredentialType.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(PublicKeyCredential.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(AttestationObject.class).build()); + reflection.produce( + ReflectiveHierarchyBuildItem.builder(CollectedClientData.class).build()); + } + @BuildStep public void myBeans(BuildProducer additionalBeans) { AdditionalBeanBuildItem.Builder builder = AdditionalBeanBuildItem.builder().setUnremovable(); builder.addBeanClass(WebAuthnSecurity.class) .addBeanClass(WebAuthnAuthenticatorStorage.class) - .addBeanClass(WebAuthnIdentityProvider.class) .addBeanClass(WebAuthnTrustedIdentityProvider.class); additionalBeans.produce(builder.build()); } @@ -55,11 +101,6 @@ public void setup( nonApplicationRootPathBuildItem.getNonApplicationRootPath()); } - @BuildStep - public ServiceProviderBuildItem serviceLoader() { - return ServiceProviderBuildItem.allProvidersFromClassPath(Attestation.class.getName()); - } - @BuildStep @Record(ExecutionTime.RUNTIME_INIT) SyntheticBeanBuildItem initWebAuthnAuth( diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java index 8d2f628d426b4..12559d36c4d5c 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java @@ -26,7 +26,7 @@ public class ManualResource { public Uni register(@BeanParam WebAuthnRegisterResponse register, RoutingContext ctx) { return security.register(register, ctx).map(authenticator -> { // need to attach the authenticator to the user - userProvider.store(authenticator); + userProvider.reallyStore(authenticator); security.rememberUser(authenticator.getUserName(), ctx); return "OK"; }); @@ -34,10 +34,10 @@ public Uni register(@BeanParam WebAuthnRegisterResponse register, Routin @Path("login") @POST - public Uni register(@BeanParam WebAuthnLoginResponse login, RoutingContext ctx) { + public Uni login(@BeanParam WebAuthnLoginResponse login, RoutingContext ctx) { return security.login(login, ctx).map(authenticator -> { // need to update the user's authenticator - userProvider.update(authenticator.getUserName(), authenticator.getCredID(), authenticator.getCounter()); + userProvider.reallyUpdate(authenticator.getCredentialID(), authenticator.getCounter()); security.rememberUser(authenticator.getUserName(), ctx); return "OK"; }); diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java index ced7d44860ff1..f6bb3b188511e 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java @@ -1,5 +1,6 @@ package io.quarkus.security.webauthn.test; +import java.net.URL; import java.util.List; import jakarta.inject.Inject; @@ -13,9 +14,11 @@ import io.quarkus.security.test.utils.TestIdentityController; import io.quarkus.security.test.utils.TestIdentityProvider; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnRunTimeConfig; import io.quarkus.security.webauthn.WebAuthnUserProvider; import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.security.webauthn.WebAuthnEndpointHelper; import io.quarkus.test.security.webauthn.WebAuthnHardware; import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; @@ -24,7 +27,6 @@ import io.restassured.specification.RequestSpecification; import io.smallrye.config.SmallRyeConfigBuilder; import io.vertx.core.json.JsonObject; -import io.vertx.ext.auth.webauthn.Authenticator; public class WebAuthnAndBasicAuthnTest { @@ -40,6 +42,9 @@ public class WebAuthnAndBasicAuthnTest { @Inject WebAuthnUserProvider userProvider; + @TestHTTPResource + URL url; + @BeforeAll public static void setupUsers() { TestIdentityController.resetRoles() @@ -50,10 +55,10 @@ public static void setupUsers() { @Test public void test() throws Exception { - Assertions.assertTrue(userProvider.findWebAuthnCredentialsByUserName("stev").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUserName("stev").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); - String challenge = WebAuthnEndpointHelper.invokeRegistration("stev", cookieFilter); - WebAuthnHardware hardwareKey = new WebAuthnHardware(); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stev", cookieFilter); + WebAuthnHardware hardwareKey = new WebAuthnHardware(url); JsonObject registration = hardwareKey.makeRegistrationJson(challenge); // now finalise @@ -74,7 +79,7 @@ public void test() throws Exception { .cookie("quarkus-credential", Matchers.notNullValue()); // make sure we stored the user - List users = userProvider.findWebAuthnCredentialsByUserName("stev").await().indefinitely(); + List users = userProvider.findByUserName("stev").await().indefinitely(); Assertions.assertEquals(1, users.size()); Assertions.assertTrue(users.get(0).getUserName().equals("stev")); Assertions.assertEquals(1, users.get(0).getCounter()); diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticBlockingTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticBlockingTest.java index 1a48817c00263..2381effb59ecf 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticBlockingTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticBlockingTest.java @@ -1,5 +1,6 @@ package io.quarkus.security.webauthn.test; +import org.jboss.shrinkwrap.api.asset.StringAsset; import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.test.QuarkusUnitTest; @@ -11,6 +12,10 @@ public class WebAuthnAutomaticBlockingTest extends WebAuthnAutomaticTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar + .addAsResource(new StringAsset(""" + quarkus.webauthn.enable-login-endpoint=true + quarkus.webauthn.enable-registration-endpoint=true + """), "application.properties") .addClasses(WebAuthnBlockingTestUserProvider.class, WebAuthnTestUserProvider.class, WebAuthnHardware.class, TestResource.class, TestUtil.class)); } diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticNonBlockingTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticNonBlockingTest.java index 8c56262608a26..485144730881c 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticNonBlockingTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticNonBlockingTest.java @@ -1,5 +1,6 @@ package io.quarkus.security.webauthn.test; +import org.jboss.shrinkwrap.api.asset.StringAsset; import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.test.QuarkusUnitTest; @@ -11,6 +12,10 @@ public class WebAuthnAutomaticNonBlockingTest extends WebAuthnAutomaticTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar + .addAsResource(new StringAsset(""" + quarkus.webauthn.enable-login-endpoint=true + quarkus.webauthn.enable-registration-endpoint=true + """), "application.properties") .addClasses(WebAuthnNonBlockingTestUserProvider.class, WebAuthnTestUserProvider.class, WebAuthnHardware.class, TestResource.class, TestUtil.class)); diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java index 696b1bb5481a7..9c601b6c5a5df 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java @@ -1,5 +1,6 @@ package io.quarkus.security.webauthn.test; +import java.net.URL; import java.util.List; import jakarta.inject.Inject; @@ -8,19 +9,23 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnUserProvider; +import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.security.webauthn.WebAuthnEndpointHelper; import io.quarkus.test.security.webauthn.WebAuthnHardware; import io.restassured.RestAssured; import io.restassured.filter.cookie.CookieFilter; import io.vertx.core.json.JsonObject; -import io.vertx.ext.auth.webauthn.Authenticator; public abstract class WebAuthnAutomaticTest { @Inject WebAuthnUserProvider userProvider; + @TestHTTPResource + URL url; + @Test public void test() throws Exception { @@ -35,17 +40,17 @@ public void test() throws Exception { .given().redirects().follow(false) .get("/cheese").then().statusCode(302); - Assertions.assertTrue(userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); - WebAuthnHardware hardwareKey = new WebAuthnHardware(); - String challenge = WebAuthnEndpointHelper.invokeRegistration("stef", cookieFilter); + WebAuthnHardware hardwareKey = new WebAuthnHardware(url); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); JsonObject registration = hardwareKey.makeRegistrationJson(challenge); // now finalise - WebAuthnEndpointHelper.invokeCallback(registration, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration(registration, cookieFilter); // make sure we stored the user - List users = userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely(); + List users = userProvider.findByUserName("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); Assertions.assertTrue(users.get(0).getUserName().equals("stef")); Assertions.assertEquals(1, users.get(0).getCounter()); @@ -56,20 +61,38 @@ public void test() throws Exception { // reset cookies for the login phase cookieFilter = new CookieFilter(); // now try to log in - challenge = WebAuthnEndpointHelper.invokeLogin("stef", cookieFilter); + challenge = WebAuthnEndpointHelper.obtainLoginChallenge("stef", cookieFilter); JsonObject login = hardwareKey.makeLoginJson(challenge); // now finalise - WebAuthnEndpointHelper.invokeCallback(login, cookieFilter); + WebAuthnEndpointHelper.invokeLogin(login, cookieFilter); // make sure we bumped the user - users = userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely(); + users = userProvider.findByUserName("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); Assertions.assertTrue(users.get(0).getUserName().equals("stef")); Assertions.assertEquals(2, users.get(0).getCounter()); // make sure our login cookie still works checkLoggedIn(cookieFilter); + + // reset cookies for a new login + cookieFilter = new CookieFilter(); + // now try to log in without a username + challenge = WebAuthnEndpointHelper.obtainLoginChallenge(null, cookieFilter); + login = hardwareKey.makeLoginJson(challenge); + + // now finalise + WebAuthnEndpointHelper.invokeLogin(login, cookieFilter); + + // make sure we bumped the user + users = userProvider.findByUserName("stef").await().indefinitely(); + Assertions.assertEquals(1, users.size()); + Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertEquals(3, users.get(0).getCounter()); + + // make sure our login cookie still works + checkLoggedIn(cookieFilter); } private void checkLoggedIn(CookieFilter cookieFilter) { diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnBlockingTestUserProvider.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnBlockingTestUserProvider.java index de755e7cd41be..9fd20f321a561 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnBlockingTestUserProvider.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnBlockingTestUserProvider.java @@ -6,10 +6,10 @@ import org.jboss.resteasy.reactive.server.core.BlockingOperationSupport; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; import io.smallrye.common.annotation.Blocking; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.Authenticator; /** * This UserProvider stores and updates the credentials in the callback endpoint, but is blocking @@ -18,21 +18,27 @@ @Blocking public class WebAuthnBlockingTestUserProvider extends WebAuthnTestUserProvider { @Override - public Uni> findWebAuthnCredentialsByCredID(String credId) { + public Uni findByCredentialId(String credId) { assertBlockingAllowed(); - return super.findWebAuthnCredentialsByCredID(credId); + return super.findByCredentialId(credId); } @Override - public Uni> findWebAuthnCredentialsByUserName(String userId) { + public Uni> findByUserName(String userId) { assertBlockingAllowed(); - return super.findWebAuthnCredentialsByUserName(userId); + return super.findByUserName(userId); } @Override - public Uni updateOrStoreWebAuthnCredentials(Authenticator authenticator) { + public Uni update(String credentialId, long counter) { assertBlockingAllowed(); - return super.updateOrStoreWebAuthnCredentials(authenticator); + return super.update(credentialId, counter); + } + + @Override + public Uni store(WebAuthnCredentialRecord credentialRecord) { + assertBlockingAllowed(); + return super.store(credentialRecord); } private void assertBlockingAllowed() { diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java index 47489fae56e8d..4bb16011ac76e 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java @@ -1,5 +1,6 @@ package io.quarkus.security.webauthn.test; +import java.net.URL; import java.util.List; import jakarta.inject.Inject; @@ -10,8 +11,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnUserProvider; import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.security.webauthn.WebAuthnEndpointHelper; import io.quarkus.test.security.webauthn.WebAuthnHardware; import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; @@ -19,7 +22,6 @@ import io.restassured.filter.cookie.CookieFilter; import io.restassured.specification.RequestSpecification; import io.vertx.core.json.JsonObject; -import io.vertx.ext.auth.webauthn.Authenticator; /** * Same test as WebAuthnManualTest but with custom cookies configured @@ -38,6 +40,9 @@ public class WebAuthnManualCustomCookiesTest { @Inject WebAuthnUserProvider userProvider; + @TestHTTPResource + URL url; + @Test public void test() throws Exception { @@ -52,10 +57,10 @@ public void test() throws Exception { .given().redirects().follow(false) .get("/cheese").then().statusCode(302); - Assertions.assertTrue(userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); - String challenge = WebAuthnEndpointHelper.invokeRegistration("stef", cookieFilter); - WebAuthnHardware hardwareKey = new WebAuthnHardware(); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); + WebAuthnHardware hardwareKey = new WebAuthnHardware(url); JsonObject registration = hardwareKey.makeRegistrationJson(challenge); // now finalise @@ -72,7 +77,7 @@ public void test() throws Exception { .cookie("main-cookie", Matchers.notNullValue()); // make sure we stored the user - List users = userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely(); + List users = userProvider.findByUserName("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); Assertions.assertTrue(users.get(0).getUserName().equals("stef")); Assertions.assertEquals(1, users.get(0).getCounter()); @@ -83,7 +88,7 @@ public void test() throws Exception { // reset cookies for the login phase cookieFilter = new CookieFilter(); // now try to log in - challenge = WebAuthnEndpointHelper.invokeLogin("stef", cookieFilter); + challenge = WebAuthnEndpointHelper.obtainLoginChallenge("stef", cookieFilter); JsonObject login = hardwareKey.makeLoginJson(challenge); // now finalise @@ -100,7 +105,7 @@ public void test() throws Exception { .cookie("main-cookie", Matchers.notNullValue()); // make sure we bumped the user - users = userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely(); + users = userProvider.findByUserName("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); Assertions.assertTrue(users.get(0).getUserName().equals("stef")); Assertions.assertEquals(2, users.get(0).getCounter()); diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java index be602ec2aa4c6..70ac351225693 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java @@ -1,16 +1,19 @@ package io.quarkus.security.webauthn.test; +import java.net.URL; import java.util.List; import jakarta.inject.Inject; import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import io.quarkus.security.webauthn.WebAuthnUserProvider; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.security.webauthn.WebAuthnEndpointHelper; import io.quarkus.test.security.webauthn.WebAuthnHardware; import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; @@ -18,18 +21,26 @@ import io.restassured.filter.cookie.CookieFilter; import io.restassured.specification.RequestSpecification; import io.vertx.core.json.JsonObject; -import io.vertx.ext.auth.webauthn.Authenticator; public class WebAuthnManualTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar - .addClasses(WebAuthnManualTestUserProvider.class, WebAuthnTestUserProvider.class, WebAuthnHardware.class, + .addClasses(WebAuthnManualTestUserProvider.class, WebAuthnTestUserProvider.class, + WebAuthnTestUserProvider.class, WebAuthnHardware.class, TestResource.class, ManualResource.class, TestUtil.class)); @Inject - WebAuthnUserProvider userProvider; + WebAuthnManualTestUserProvider userProvider; + + @TestHTTPResource + URL url; + + @BeforeEach + public void before() { + userProvider.clear(); + } @Test public void test() throws Exception { @@ -45,10 +56,10 @@ public void test() throws Exception { .given().redirects().follow(false) .get("/cheese").then().statusCode(302); - Assertions.assertTrue(userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); - String challenge = WebAuthnEndpointHelper.invokeRegistration("stef", cookieFilter); - WebAuthnHardware hardwareKey = new WebAuthnHardware(); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); + WebAuthnHardware hardwareKey = new WebAuthnHardware(url); JsonObject registration = hardwareKey.makeRegistrationJson(challenge); // now finalise @@ -57,15 +68,17 @@ public void test() throws Exception { .filter(cookieFilter); WebAuthnEndpointHelper.addWebAuthnRegistrationFormParameters(request, registration); request + .log().ifValidationFails() .post("/register") .then().statusCode(200) + .log().ifValidationFails() .body(Matchers.is("OK")) .cookie("_quarkus_webauthn_challenge", Matchers.is("")) .cookie("_quarkus_webauthn_username", Matchers.is("")) .cookie("quarkus-credential", Matchers.notNullValue()); // make sure we stored the user - List users = userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely(); + List users = userProvider.findByUserName("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); Assertions.assertTrue(users.get(0).getUserName().equals("stef")); Assertions.assertEquals(1, users.get(0).getCounter()); @@ -76,7 +89,7 @@ public void test() throws Exception { // reset cookies for the login phase cookieFilter = new CookieFilter(); // now try to log in - challenge = WebAuthnEndpointHelper.invokeLogin("stef", cookieFilter); + challenge = WebAuthnEndpointHelper.obtainLoginChallenge("stef", cookieFilter); JsonObject login = hardwareKey.makeLoginJson(challenge); // now finalise @@ -85,21 +98,56 @@ public void test() throws Exception { .filter(cookieFilter); WebAuthnEndpointHelper.addWebAuthnLoginFormParameters(request, login); request + .log().ifValidationFails() .post("/login") .then().statusCode(200) + .log().ifValidationFails() .body(Matchers.is("OK")) .cookie("_quarkus_webauthn_challenge", Matchers.is("")) .cookie("_quarkus_webauthn_username", Matchers.is("")) .cookie("quarkus-credential", Matchers.notNullValue()); // make sure we bumped the user - users = userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely(); + users = userProvider.findByUserName("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); Assertions.assertTrue(users.get(0).getUserName().equals("stef")); Assertions.assertEquals(2, users.get(0).getCounter()); // make sure our login cookie still works checkLoggedIn(cookieFilter); + + // make sure we can't log in via the default endpoint + // reset cookies for the login phase + CookieFilter finalCookieFilter = new CookieFilter(); + // now try to log in + challenge = WebAuthnEndpointHelper.obtainLoginChallenge("stef", finalCookieFilter); + JsonObject defaultLogin = hardwareKey.makeLoginJson(challenge); + + // now finalise + Assertions.assertThrows(AssertionError.class, + () -> WebAuthnEndpointHelper.invokeLogin(defaultLogin, finalCookieFilter)); + + // make sure we did not bump the user + users = userProvider.findByUserName("stef").await().indefinitely(); + Assertions.assertEquals(1, users.size()); + Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertEquals(2, users.get(0).getCounter()); + } + + @Test + public void checkDefaultRegistrationDisabled() { + Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); + CookieFilter cookieFilter = new CookieFilter(); + WebAuthnHardware hardwareKey = new WebAuthnHardware(url); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); + JsonObject registration = hardwareKey.makeRegistrationJson(challenge); + + // now finalise + Assertions.assertThrows(AssertionError.class, + () -> WebAuthnEndpointHelper.invokeRegistration(registration, cookieFilter)); + + // make sure we did not create any user + Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); } private void checkLoggedIn(CookieFilter cookieFilter) { diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTestUserProvider.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTestUserProvider.java index 65ae0801fdd95..be5779656c498 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTestUserProvider.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTestUserProvider.java @@ -5,10 +5,10 @@ import jakarta.enterprise.context.ApplicationScoped; import io.quarkus.arc.Arc; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnSecurity; import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.Authenticator; /** * This UserProvider does not update or store credentials in the callback endpoint: you do it manually after calls to @@ -19,21 +19,15 @@ public class WebAuthnManualTestUserProvider extends WebAuthnTestUserProvider { @Override - public Uni> findWebAuthnCredentialsByCredID(String credId) { + public Uni findByCredentialId(String credId) { assertRequestContext(); - return super.findWebAuthnCredentialsByCredID(credId); + return super.findByCredentialId(credId); } @Override - public Uni> findWebAuthnCredentialsByUserName(String userId) { + public Uni> findByUserName(String userId) { assertRequestContext(); - return super.findWebAuthnCredentialsByUserName(userId); - } - - @Override - public Uni updateOrStoreWebAuthnCredentials(Authenticator authenticator) { - assertRequestContext(); - return Uni.createFrom().nullItem(); + return super.findByUserName(userId); } private void assertRequestContext() { diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnNonBlockingTestUserProvider.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnNonBlockingTestUserProvider.java index 1ce44c088ed52..4cab358e2a838 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnNonBlockingTestUserProvider.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnNonBlockingTestUserProvider.java @@ -6,9 +6,9 @@ import org.jboss.resteasy.reactive.server.core.BlockingOperationSupport; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.Authenticator; /** * This UserProvider stores and updates the credentials in the callback endpoint, and checks that it's non-blocking @@ -16,21 +16,27 @@ @ApplicationScoped public class WebAuthnNonBlockingTestUserProvider extends WebAuthnTestUserProvider { @Override - public Uni> findWebAuthnCredentialsByCredID(String credId) { + public Uni findByCredentialId(String credId) { assertBlockingNotAllowed(); - return super.findWebAuthnCredentialsByCredID(credId); + return super.findByCredentialId(credId); } @Override - public Uni> findWebAuthnCredentialsByUserName(String userId) { + public Uni> findByUserName(String userId) { assertBlockingNotAllowed(); - return super.findWebAuthnCredentialsByUserName(userId); + return super.findByUserName(userId); } @Override - public Uni updateOrStoreWebAuthnCredentials(Authenticator authenticator) { + public Uni update(String credentialId, long counter) { assertBlockingNotAllowed(); - return super.updateOrStoreWebAuthnCredentials(authenticator); + return super.update(credentialId, counter); + } + + @Override + public Uni store(WebAuthnCredentialRecord credentialRecord) { + assertBlockingNotAllowed(); + return super.store(credentialRecord); } private void assertBlockingNotAllowed() { diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java new file mode 100644 index 0000000000000..4acb80be4f140 --- /dev/null +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java @@ -0,0 +1,48 @@ +package io.quarkus.security.webauthn.test; + +import org.hamcrest.Matchers; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import io.vertx.core.json.JsonObject; + +public class WebAuthnOriginsTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(WebAuthnManualTestUserProvider.class, WebAuthnTestUserProvider.class, TestUtil.class) + .addAsResource(new StringAsset("quarkus.webauthn.origins=http://foo,https://bar:42"), + "application.properties")); + + @Test + public void testLoginRpFromFirstOrigin() { + RestAssured + .given() + .body(new JsonObject() + .put("name", "foo").encode()) + .contentType(ContentType.JSON) + .post("/q/webauthn/register-options-challenge") + .then() + .log().all() + .statusCode(200) + .contentType(ContentType.JSON) + .body("rp.id", Matchers.equalTo("foo")); + } + + @Test + public void testWellKnownConfigured() { + RestAssured.get("/.well-known/webauthn") + .then() + .statusCode(200) + .contentType(ContentType.JSON) + .body("origins.size()", Matchers.equalTo(2)) + .body("origins[0]", Matchers.equalTo("http://foo")) + .body("origins[1]", Matchers.equalTo("https://bar:42")); + } +} diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java index 1752a5ecac77a..fb3114039b8b8 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java @@ -5,8 +5,11 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import io.vertx.core.json.JsonObject; public class WebAuthnTest { @@ -15,8 +18,37 @@ public class WebAuthnTest { .withApplicationRoot((jar) -> jar .addClasses(WebAuthnManualTestUserProvider.class, WebAuthnTestUserProvider.class, TestUtil.class)); + @TestHTTPResource + public String url; + @Test public void testJavaScriptFile() { RestAssured.get("/q/webauthn/webauthn.js").then().statusCode(200).body(Matchers.startsWith("\"use strict\";")); } + + @Test + public void testLoginRpFromFirstOrigin() { + RestAssured + .given() + .body(new JsonObject() + .put("name", "foo").encode()) + .contentType(ContentType.JSON) + .post("/q/webauthn/register-options-challenge") + .then() + .statusCode(200) + .contentType(ContentType.JSON) + .body("rp.id", Matchers.equalTo("localhost")); + } + + @Test + public void testWellKnownDefault() { + String origin = url; + if (origin.endsWith("/")) { + origin = origin.substring(0, origin.length() - 1); + } + RestAssured.get("/.well-known/webauthn").then().statusCode(200) + .contentType(ContentType.JSON) + .body("origins.size()", Matchers.equalTo(1)) + .body("origins[0]", Matchers.equalTo(origin)); + } } diff --git a/extensions/security-webauthn/runtime/pom.xml b/extensions/security-webauthn/runtime/pom.xml index cc609bd087d12..0aebc6cd0ba03 100644 --- a/extensions/security-webauthn/runtime/pom.xml +++ b/extensions/security-webauthn/runtime/pom.xml @@ -35,8 +35,12 @@ quarkus-vertx-http
    - io.vertx - vertx-auth-webauthn + com.webauthn4j + webauthn4j-core-async + + + com.webauthn4j + webauthn4j-metadata-async
    diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticationMechanism.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticationMechanism.java index 6ed0ef49744c3..ce07656549710 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticationMechanism.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticationMechanism.java @@ -69,7 +69,7 @@ static Uni getRedirect(final RoutingContext exchange, final Strin @Override public Set> getCredentialTypes() { - return new HashSet<>(Arrays.asList(WebAuthnAuthenticationRequest.class, TrustedAuthenticationRequest.class)); + return new HashSet<>(Arrays.asList(TrustedAuthenticationRequest.class)); } @Override diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticationRequest.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticationRequest.java deleted file mode 100644 index f24ac245ad060..0000000000000 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticationRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.quarkus.security.webauthn; - -import io.quarkus.security.identity.request.BaseAuthenticationRequest; -import io.vertx.ext.auth.webauthn.WebAuthnCredentials; - -public class WebAuthnAuthenticationRequest extends BaseAuthenticationRequest { - - private WebAuthnCredentials credentials; - - public WebAuthnAuthenticationRequest(WebAuthnCredentials credentials) { - this.credentials = credentials; - } - - public WebAuthnCredentials getCredentials() { - return credentials; - } - -} diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticatorStorage.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticatorStorage.java index ef680306535cb..bc67b739be83b 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticatorStorage.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticatorStorage.java @@ -1,6 +1,5 @@ package io.quarkus.security.webauthn; -import java.util.Collections; import java.util.List; import java.util.function.Supplier; @@ -13,8 +12,6 @@ import io.smallrye.common.annotation.NonBlocking; import io.smallrye.common.annotation.RunOnVirtualThread; import io.smallrye.mutiny.Uni; -import io.vertx.core.Future; -import io.vertx.ext.auth.webauthn.Authenticator; import io.vertx.mutiny.core.Vertx; /** @@ -29,15 +26,20 @@ public class WebAuthnAuthenticatorStorage { @Inject Vertx vertx; - public Future> fetcher(Authenticator query) { - Uni> res; - if (query.getUserName() != null) - res = runPotentiallyBlocking(() -> userProvider.findWebAuthnCredentialsByUserName(query.getUserName())); - else if (query.getCredID() != null) - res = runPotentiallyBlocking(() -> userProvider.findWebAuthnCredentialsByCredID(query.getCredID())); - else - return Future.succeededFuture(Collections.emptyList()); - return Future.fromCompletionStage(res.subscribeAsCompletionStage()); + public Uni> findByUserName(String userName) { + return runPotentiallyBlocking(() -> userProvider.findByUserName(userName)); + } + + public Uni findByCredID(String credID) { + return runPotentiallyBlocking(() -> userProvider.findByCredentialId(credID)); + } + + public Uni create(WebAuthnCredentialRecord credentialRecord) { + return runPotentiallyBlocking(() -> userProvider.store(credentialRecord)); + } + + public Uni update(String credID, long counter) { + return runPotentiallyBlocking(() -> userProvider.update(credID, counter)); } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -80,10 +82,4 @@ private boolean isRunOnVirtualThread(Class klass) { // no information, assumed non-blocking return false; } - - public Future updater(Authenticator authenticator) { - return Future - .fromCompletionStage(runPotentiallyBlocking(() -> userProvider.updateOrStoreWebAuthnCredentials(authenticator)) - .subscribeAsCompletionStage()); - } } diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java index 0c7894568bcba..aeb165c5920f6 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java @@ -1,187 +1,114 @@ package io.quarkus.security.webauthn; -import java.util.function.Consumer; - -import org.jboss.logging.Logger; +import java.util.function.Supplier; import io.quarkus.arc.Arc; import io.quarkus.arc.InjectableContext.ContextState; import io.quarkus.arc.ManagedContext; -import io.quarkus.security.identity.IdentityProviderManager; -import io.quarkus.security.identity.SecurityIdentity; -import io.quarkus.vertx.http.runtime.security.HttpSecurityUtils; -import io.quarkus.vertx.http.runtime.security.PersistentLoginManager.RestoreResult; +import io.smallrye.mutiny.Uni; +import io.vertx.core.http.HttpHeaders; import io.vertx.core.json.JsonObject; -import io.vertx.ext.auth.webauthn.WebAuthnCredentials; -import io.vertx.ext.auth.webauthn.impl.attestation.AttestationException; import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.impl.Origin; /** * Endpoints for login/register/callback */ public class WebAuthnController { - private static final Logger log = Logger.getLogger(WebAuthnController.class); - - private String challengeUsernameCookie; - private String challengeCookie; - private WebAuthnSecurity security; - private String origin; - - private String domain; - - private IdentityProviderManager identityProviderManager; - - private WebAuthnAuthenticationMechanism authMech; - - public WebAuthnController(WebAuthnSecurity security, WebAuthnRunTimeConfig config, - IdentityProviderManager identityProviderManager, - WebAuthnAuthenticationMechanism authMech) { - origin = config.origin().orElse(null); - if (origin != null) { - Origin o = Origin.parse(origin); - domain = o.host(); - } + public WebAuthnController(WebAuthnSecurity security) { this.security = security; - this.identityProviderManager = identityProviderManager; - this.authMech = authMech; - this.challengeCookie = config.challengeCookieName(); - this.challengeUsernameCookie = config.challengeUsernameCookieName(); } - private static boolean containsRequiredString(JsonObject json, String key) { + /** + * Endpoint for getting a list of allowed origins + * + * @param ctx the current request + */ + public void wellKnown(RoutingContext ctx) { try { - if (json == null) { - return false; - } - if (!json.containsKey(key)) { - return false; - } - Object s = json.getValue(key); - return (s instanceof String) && !"".equals(s); - } catch (ClassCastException e) { - return false; + ctx.response() + .putHeader(HttpHeaders.CONTENT_TYPE, "application/json") + .end(new JsonObject() + .put("origins", security.getAllowedOrigins(ctx)) + .encode()); + } catch (IllegalArgumentException e) { + ctx.fail(400, e); + } catch (RuntimeException e) { + ctx.fail(e); } } - private static boolean containsOptionalString(JsonObject json, String key) { + /** + * Endpoint for getting a register challenge and options + * + * @param ctx the current request + */ + public void registerOptionsChallenge(RoutingContext ctx) { try { - if (json == null) { - return true; - } - if (!json.containsKey(key)) { - return true; - } - Object s = json.getValue(key); - return (s instanceof String); - } catch (ClassCastException e) { - return false; + // might throw runtime exception if there's no json or is bad formed + final JsonObject webauthnRegister = ctx.getBodyAsJson(); + + String name = webauthnRegister.getString("name"); + String displayName = webauthnRegister.getString("displayName"); + withContext(() -> security.getRegisterChallenge(name, displayName, ctx)) + .map(challenge -> security.toJsonString(challenge)) + .subscribe().with(challenge -> ok(ctx, challenge), ctx::fail); + + } catch (IllegalArgumentException e) { + ctx.fail(400, e); + } catch (RuntimeException e) { + ctx.fail(e); } } - private static boolean containsRequiredObject(JsonObject json, String key) { - try { - if (json == null) { - return false; - } - if (!json.containsKey(key)) { - return false; - } - JsonObject s = json.getJsonObject(key); - return s != null; - } catch (ClassCastException e) { - return false; - } + private Uni withContext(Supplier> uni) { + ManagedContext requestContext = Arc.container().requestContext(); + requestContext.activate(); + ContextState contextState = requestContext.getState(); + return uni.get().eventually(() -> requestContext.destroy(contextState)); } /** - * Endpoint for getting a register challenge + * Endpoint for getting a login challenge and options * * @param ctx the current request */ - public void register(RoutingContext ctx) { + public void loginOptionsChallenge(RoutingContext ctx) { try { // might throw runtime exception if there's no json or is bad formed - final JsonObject webauthnRegister = ctx.getBodyAsJson(); - - // the register object should match a Webauthn user. - // A user has only a required field: name - // And optional fields: displayName and icon - if (webauthnRegister == null || !containsRequiredString(webauthnRegister, "name")) { - ctx.fail(400, new IllegalArgumentException("missing 'name' field from request json")); - } else { - // input basic validation is OK - - ManagedContext requestContext = Arc.container().requestContext(); - requestContext.activate(); - ContextState contextState = requestContext.getState(); - security.getWebAuthn().createCredentialsOptions(webauthnRegister, createCredentialsOptions -> { - requestContext.destroy(contextState); - if (createCredentialsOptions.failed()) { - ctx.fail(createCredentialsOptions.cause()); - return; - } - - final JsonObject credentialsOptions = createCredentialsOptions.result(); + final JsonObject webauthnLogin = ctx.getBodyAsJson(); - // save challenge to the session - authMech.getLoginManager().save(credentialsOptions.getString("challenge"), ctx, challengeCookie, null, - ctx.request().isSSL()); - authMech.getLoginManager().save(webauthnRegister.getString("name"), ctx, challengeUsernameCookie, null, - ctx.request().isSSL()); + String name = webauthnLogin.getString("name"); + withContext(() -> security.getLoginChallenge(name, ctx)) + .map(challenge -> security.toJsonString(challenge)) + .subscribe().with(challenge -> ok(ctx, challenge), ctx::fail); - ok(ctx, credentialsOptions); - }); - } } catch (IllegalArgumentException e) { ctx.fail(400, e); } catch (RuntimeException e) { ctx.fail(e); } + } /** - * Endpoint for getting a login challenge + * Endpoint for login. This will call {@link} * * @param ctx the current request */ public void login(RoutingContext ctx) { try { // might throw runtime exception if there's no json or is bad formed - final JsonObject webauthnLogin = ctx.getBodyAsJson(); - - if (webauthnLogin == null || !containsRequiredString(webauthnLogin, "name")) { - ctx.fail(400, new IllegalArgumentException("Request missing 'name' field")); - return; - } - - // input basic validation is OK - - final String username = webauthnLogin.getString("name"); - - ManagedContext requestContext = Arc.container().requestContext(); - requestContext.activate(); - ContextState contextState = requestContext.getState(); - // STEP 18 Generate assertion - security.getWebAuthn().getCredentialsOptions(username, generateServerGetAssertion -> { - requestContext.destroy(contextState); - if (generateServerGetAssertion.failed()) { - ctx.fail(generateServerGetAssertion.cause()); - return; - } - - final JsonObject getAssertion = generateServerGetAssertion.result(); - - authMech.getLoginManager().save(getAssertion.getString("challenge"), ctx, challengeCookie, null, - ctx.request().isSSL()); - authMech.getLoginManager().save(username, ctx, challengeUsernameCookie, null, - ctx.request().isSSL()); + final JsonObject webauthnResp = ctx.getBodyAsJson(); - ok(ctx, getAssertion); - }); + withContext(() -> security.login(webauthnResp, ctx)) + .onItem().call(record -> security.storage().update(record.getCredentialID(), record.getCounter())) + .subscribe().with(record -> { + security.rememberUser(record.getUserName(), ctx); + ok(ctx); + }, x -> ctx.fail(400, x)); } catch (IllegalArgumentException e) { ctx.fail(400, e); } catch (RuntimeException e) { @@ -191,76 +118,21 @@ public void login(RoutingContext ctx) { } /** - * Endpoint for getting authenticated + * Endpoint for registration * * @param ctx the current request */ - public void callback(RoutingContext ctx) { + public void register(RoutingContext ctx) { try { // might throw runtime exception if there's no json or is bad formed final JsonObject webauthnResp = ctx.getBodyAsJson(); - // input validation - if (webauthnResp == null || - !containsRequiredString(webauthnResp, "id") || - !containsRequiredString(webauthnResp, "rawId") || - !containsRequiredObject(webauthnResp, "response") || - !containsOptionalString(webauthnResp.getJsonObject("response"), "userHandle") || - !containsRequiredString(webauthnResp, "type") || - !"public-key".equals(webauthnResp.getString("type"))) { - - ctx.fail(400, new IllegalArgumentException( - "Response missing one or more of id/rawId/response[.userHandle]/type fields, or type is not public-key")); - return; - } - RestoreResult challenge = authMech.getLoginManager().restore(ctx, challengeCookie); - RestoreResult username = authMech.getLoginManager().restore(ctx, challengeUsernameCookie); - if (challenge == null || challenge.getPrincipal() == null || challenge.getPrincipal().isEmpty() - || username == null || username.getPrincipal() == null || username.getPrincipal().isEmpty()) { - ctx.fail(400, new IllegalArgumentException("Missing challenge or username")); - return; - } - - ManagedContext requestContext = Arc.container().requestContext(); - requestContext.activate(); - ContextState contextState = requestContext.getState(); - // input basic validation is OK - // authInfo - WebAuthnCredentials credentials = new WebAuthnCredentials() - .setOrigin(origin) - .setDomain(domain) - .setChallenge(challenge.getPrincipal()) - .setUsername(username.getPrincipal()) - .setWebauthn(webauthnResp); - identityProviderManager - .authenticate(HttpSecurityUtils - .setRoutingContextAttribute(new WebAuthnAuthenticationRequest(credentials), ctx)) - .subscribe().with(new Consumer() { - @Override - public void accept(SecurityIdentity identity) { - requestContext.destroy(contextState); - // invalidate the challenge - WebAuthnSecurity.removeCookie(ctx, challengeCookie); - WebAuthnSecurity.removeCookie(ctx, challengeUsernameCookie); - try { - authMech.getLoginManager().save(identity, ctx, null, ctx.request().isSSL()); - ok(ctx); - } catch (Throwable t) { - log.error("Unable to complete post authentication", t); - ctx.fail(t); - } - } - }, new Consumer() { - @Override - public void accept(Throwable throwable) { - requestContext.terminate(); - if (throwable instanceof AttestationException) { - ctx.fail(400, throwable); - } else { - ctx.fail(throwable); - } - } - }); + withContext(() -> security.register(webauthnResp, ctx)) + .onItem().call(record -> security.storage().create(record)) + .subscribe().with(record -> { + security.rememberUser(record.getUserName(), ctx); + ok(ctx); + }, x -> ctx.fail(400, x)); } catch (IllegalArgumentException e) { ctx.fail(400, e); } catch (RuntimeException e) { @@ -275,20 +147,22 @@ public void accept(Throwable throwable) { * @param ctx the current request */ public void logout(RoutingContext ctx) { - authMech.getLoginManager().clear(ctx); + security.logout(ctx); ctx.redirect("/"); } + private static void ok(RoutingContext ctx, String json) { + ctx.response() + .putHeader(HttpHeaders.CONTENT_TYPE, "application/json") + .end(json); + } + private static void ok(RoutingContext ctx) { ctx.response() .setStatusCode(204) .end(); } - private static void ok(RoutingContext ctx, JsonObject result) { - ctx.json(result); - } - public void javascript(RoutingContext ctx) { ctx.response().sendFile("webauthn.js"); } diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnCredentialRecord.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnCredentialRecord.java new file mode 100644 index 0000000000000..9deedc2ffa5cf --- /dev/null +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnCredentialRecord.java @@ -0,0 +1,192 @@ +package io.quarkus.security.webauthn; + +import static io.vertx.ext.auth.impl.Codec.base64UrlDecode; + +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.EdECPublicKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.Set; +import java.util.UUID; + +import com.webauthn4j.credential.CredentialRecordImpl; +import com.webauthn4j.data.AuthenticatorTransport; +import com.webauthn4j.data.attestation.AttestationObject; +import com.webauthn4j.data.attestation.authenticator.AAGUID; +import com.webauthn4j.data.attestation.authenticator.AttestedCredentialData; +import com.webauthn4j.data.attestation.authenticator.COSEKey; +import com.webauthn4j.data.attestation.authenticator.EC2COSEKey; +import com.webauthn4j.data.attestation.authenticator.EdDSACOSEKey; +import com.webauthn4j.data.attestation.authenticator.RSACOSEKey; +import com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier; +import com.webauthn4j.data.client.CollectedClientData; +import com.webauthn4j.data.extension.client.AuthenticationExtensionsClientOutputs; +import com.webauthn4j.data.extension.client.RegistrationExtensionClientOutput; +import com.webauthn4j.util.Base64UrlUtil; + +/** + * This is the internal WebAuthn4J representation for a credential record, augmented with + * a user name. One user name can be shared among multiple credential records, but each + * credential record has a unique credential ID. + */ +public class WebAuthnCredentialRecord extends CredentialRecordImpl { + + private String userName; + + /* + * This is used for registering + */ + public WebAuthnCredentialRecord(String userName, + AttestationObject attestationObject, + CollectedClientData clientData, + AuthenticationExtensionsClientOutputs clientExtensions, + Set transports) { + super(attestationObject, clientData, clientExtensions, transports); + this.userName = userName; + } + + /* + * This is used for login + */ + private WebAuthnCredentialRecord(String userName, + long counter, + AttestedCredentialData attestedCredentialData) { + super(null, null, null, null, counter, attestedCredentialData, null, null, null, null); + this.userName = userName; + } + + /** + * The increasing signature counter for usage of this credential record. See + * https://w3c.github.io/webauthn/#signature-counter + * + * @return The increasing signature counter. + */ + @Override + public long getCounter() { + // this method is just to get rid of deprecation warnings for users. + return super.getCounter(); + } + + /** + * The username for this credential record + * + * @return the username for this credential record + */ + public String getUserName() { + return userName; + } + + /** + * The unique credential ID for this record. This is a convenience method returning a Base64Url-encoded + * version of getAttestedCredentialData().getCredentialId() + * + * @return The unique credential ID for this record + */ + public String getCredentialID() { + return Base64UrlUtil.encodeToString(getAttestedCredentialData().getCredentialId()); + } + + /** + * Returns the fields of this credential record that are necessary to persist for your users + * to be able to log back in using WebAuthn. + * + * @return the fields required to be persisted. + */ + public RequiredPersistedData getRequiredPersistedData() { + return new RequiredPersistedData(getUserName(), + getCredentialID(), + getAttestedCredentialData().getAaguid().getValue(), + getAttestedCredentialData().getCOSEKey().getPublicKey().getEncoded(), + getAttestedCredentialData().getCOSEKey().getAlgorithm().getValue(), + getCounter()); + } + + /** + * Reassembles a credential record from the given required persisted fields. + * + * @param persistedData the required fields to be able to log back in with WebAuthn. + * @return the internal representation of a WebAuthn credential record. + */ + public static WebAuthnCredentialRecord fromRequiredPersistedData(RequiredPersistedData persistedData) { + // important + long counter = persistedData.counter(); + X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(persistedData.publicKey); + COSEAlgorithmIdentifier coseAlgorithm = COSEAlgorithmIdentifier.create(persistedData.publicKeyAlgorithm); + COSEKey coseKey; + try { + switch (coseAlgorithm.getKeyType()) { + case EC2: + coseKey = EC2COSEKey.create((ECPublicKey) KeyFactory.getInstance("EC").generatePublic(x509EncodedKeySpec), + coseAlgorithm); + break; + case OKP: + coseKey = EdDSACOSEKey + .create((EdECPublicKey) KeyFactory.getInstance("EdDSA").generatePublic(x509EncodedKeySpec), + coseAlgorithm); + break; + case RSA: + coseKey = RSACOSEKey + .create((RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec), + coseAlgorithm); + break; + default: + throw new IllegalArgumentException("Invalid cose algorithm: " + coseAlgorithm); + } + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + throw new IllegalArgumentException("Invalid public key", e); + } + byte[] credentialId = base64UrlDecode(persistedData.credentialId()); + AAGUID aaguid = new AAGUID(persistedData.aaguid()); + AttestedCredentialData attestedCredentialData = new AttestedCredentialData(aaguid, credentialId, coseKey); + + return new WebAuthnCredentialRecord(persistedData.userName(), counter, attestedCredentialData); + } + + /** + * Record holding all the required persistent fields for logging back someone over WebAuthn. + */ + public record RequiredPersistedData( + /** + * The user name. A single user name may be associated with multiple WebAuthn credentials. + */ + String userName, + /** + * The credential ID. This must be unique. See https://w3c.github.io/webauthn/#credential-id + */ + String credentialId, + /** + * See https://w3c.github.io/webauthn/#aaguid + */ + UUID aaguid, + /** + * A X.509 encoding of the public key. See https://w3c.github.io/webauthn/#credential-public-key + */ + byte[] publicKey, + /** + * The COSE algorithm used for signing with the public key. See + * https://w3c.github.io/webauthn/#typedefdef-cosealgorithmidentifier + */ + long publicKeyAlgorithm, + /** + * The increasing signature counter for usage of this credential record. See + * https://w3c.github.io/webauthn/#signature-counter + */ + long counter) { + /** + * Returns a PEM-encoded representation of the public key. This is a utility method you can use as an alternate for + * storing the + * binary public key if you do not want to store a byte[] and prefer strings. + * + * @return a PEM-encoded representation of the public key + */ + public String getPublicKeyPEM() { + return "-----BEGIN PUBLIC KEY-----\n" + + Base64.getEncoder().encodeToString(publicKey) + + "\n-----END PUBLIC KEY-----\n"; + } + } +} diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnIdentityProvider.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnIdentityProvider.java deleted file mode 100644 index 8e1e62fffdd9a..0000000000000 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnIdentityProvider.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.quarkus.security.webauthn; - -import java.util.function.Consumer; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import io.quarkus.security.identity.AuthenticationRequestContext; -import io.quarkus.security.identity.IdentityProvider; -import io.quarkus.security.identity.SecurityIdentity; -import io.quarkus.security.runtime.QuarkusPrincipal; -import io.quarkus.security.runtime.QuarkusSecurityIdentity; -import io.smallrye.mutiny.Uni; -import io.smallrye.mutiny.subscription.UniEmitter; -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; -import io.vertx.ext.auth.User; - -/** - * WebAuthn IdentityProvider - */ -@ApplicationScoped -public class WebAuthnIdentityProvider implements IdentityProvider { - - @Inject - WebAuthnSecurity security; - - @Override - public Class getRequestType() { - return WebAuthnAuthenticationRequest.class; - } - - @Override - public Uni authenticate(WebAuthnAuthenticationRequest request, AuthenticationRequestContext context) { - return Uni.createFrom().emitter(new Consumer>() { - @Override - public void accept(UniEmitter emitter) { - security.getWebAuthn().authenticate(request.getCredentials(), new Handler>() { - @Override - public void handle(AsyncResult event) { - if (event.failed()) { - emitter.fail(event.cause()); - } else { - QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(); - // only the username matters, because when we auth we create a session cookie with it - // and we reply instantly so the roles are never used - builder.setPrincipal(new QuarkusPrincipal(request.getCredentials().getUsername())); - emitter.complete(builder.build()); - } - } - }); - } - }); - } - -} diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java index b21affad39408..eb309405ff015 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java @@ -10,7 +10,6 @@ import io.quarkus.arc.runtime.BeanContainer; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; -import io.quarkus.security.identity.IdentityProviderManager; import io.quarkus.vertx.http.runtime.HttpConfiguration; import io.quarkus.vertx.http.runtime.security.PersistentLoginManager; import io.vertx.ext.web.Router; @@ -34,18 +33,22 @@ public WebAuthnRecorder(RuntimeValue httpConfiguration, Runti public void setupRoutes(BeanContainer beanContainer, RuntimeValue routerValue, String prefix) { WebAuthnSecurity security = beanContainer.beanInstance(WebAuthnSecurity.class); - WebAuthnAuthenticationMechanism authMech = beanContainer.beanInstance(WebAuthnAuthenticationMechanism.class); - IdentityProviderManager identityProviderManager = beanContainer.beanInstance(IdentityProviderManager.class); - WebAuthnController controller = new WebAuthnController(security, config.getValue(), identityProviderManager, authMech); + WebAuthnController controller = new WebAuthnController(security); Router router = routerValue.getValue(); BodyHandler bodyHandler = BodyHandler.create(); // FIXME: paths configurable // prefix is the non-application root path, ends with a slash: defaults to /q/ - router.post(prefix + "webauthn/login").handler(bodyHandler).handler(controller::login); - router.post(prefix + "webauthn/register").handler(bodyHandler).handler(controller::register); - router.post(prefix + "webauthn/callback").handler(bodyHandler).handler(controller::callback); + router.post(prefix + "webauthn/login-options-challenge").handler(bodyHandler).handler(controller::loginOptionsChallenge); + router.post(prefix + "webauthn/register-options-challenge").handler(bodyHandler).handler(controller::registerOptionsChallenge); + if (config.getValue().enableLoginEndpoint().orElse(false)) { + router.post(prefix + "webauthn/login").handler(bodyHandler).handler(controller::login); + } + if (config.getValue().enableRegistrationEndpoint().orElse(false)) { + router.post(prefix + "webauthn/register").handler(bodyHandler).handler(controller::register); + } router.get(prefix + "webauthn/webauthn.js").handler(controller::javascript); router.get(prefix + "webauthn/logout").handler(controller::logout); + router.get("/.well-known/webauthn").handler(controller::wellKnown); } public Supplier setupWebAuthnAuthenticationMechanism() { diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java index ab7ef3ea30dcd..6d55cfc38739a 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java @@ -5,17 +5,16 @@ import java.util.Optional; import java.util.OptionalInt; +import com.webauthn4j.data.AttestationConveyancePreference; +import com.webauthn4j.data.ResidentKeyRequirement; +import com.webauthn4j.data.UserVerificationRequirement; + import io.quarkus.runtime.annotations.ConfigDocDefault; import io.quarkus.runtime.annotations.ConfigGroup; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; import io.smallrye.config.ConfigMapping; import io.smallrye.config.WithDefault; -import io.vertx.ext.auth.webauthn.Attestation; -import io.vertx.ext.auth.webauthn.AuthenticatorAttachment; -import io.vertx.ext.auth.webauthn.AuthenticatorTransport; -import io.vertx.ext.auth.webauthn.PublicKeyCredential; -import io.vertx.ext.auth.webauthn.UserVerification; /** * Webauthn runtime configuration object. @@ -24,6 +23,172 @@ @ConfigRoot(phase = ConfigPhase.RUN_TIME) public interface WebAuthnRunTimeConfig { + /** + * COSEAlgorithm + * https://www.iana.org/assignments/cose/cose.xhtml#algorithms + */ + public enum COSEAlgorithm { + ES256(-7), + ES384(-35), + ES512(-36), + PS256(-37), + PS384(-38), + PS512(-39), + ES256K(-47), + RS256(-257), + RS384(-258), + RS512(-259), + RS1(-65535), + EdDSA(-8); + + private final int coseId; + + COSEAlgorithm(int coseId) { + this.coseId = coseId; + } + + public static COSEAlgorithm valueOf(int coseId) { + switch (coseId) { + case -7: + return ES256; + case -35: + return ES384; + case -36: + return ES512; + case -37: + return PS256; + case -38: + return PS384; + case -39: + return PS512; + case -47: + return ES256K; + case -257: + return RS256; + case -258: + return RS384; + case -259: + return RS512; + case -65535: + return RS1; + case -8: + return EdDSA; + default: + throw new IllegalArgumentException("Unknown cose-id: " + coseId); + } + } + + public int coseId() { + return coseId; + } + } + + /** + * AttestationConveyancePreference + * https://www.w3.org/TR/webauthn/#attestation-convey + */ + public enum Attestation { + NONE, + INDIRECT, + DIRECT, + ENTERPRISE; + + AttestationConveyancePreference toWebAuthn4J() { + switch (this) { + case DIRECT: + return AttestationConveyancePreference.DIRECT; + case ENTERPRISE: + return AttestationConveyancePreference.ENTERPRISE; + case INDIRECT: + return AttestationConveyancePreference.INDIRECT; + case NONE: + return AttestationConveyancePreference.NONE; + default: + throw new IllegalStateException("Illegal enum value: " + this); + } + } + } + + /** + * UserVerificationRequirement + * https://www.w3.org/TR/webauthn/#enumdef-userverificationrequirement + */ + public enum UserVerification { + REQUIRED, + PREFERRED, + DISCOURAGED; + + UserVerificationRequirement toWebAuthn4J() { + switch (this) { + case DISCOURAGED: + return UserVerificationRequirement.DISCOURAGED; + case PREFERRED: + return UserVerificationRequirement.PREFERRED; + case REQUIRED: + return UserVerificationRequirement.REQUIRED; + default: + throw new IllegalStateException("Illegal enum value: " + this); + } + } + } + + /** + * AuthenticatorAttachment + * https://www.w3.org/TR/webauthn/#enumdef-authenticatorattachment + */ + public enum AuthenticatorAttachment { + PLATFORM, + CROSS_PLATFORM; + + com.webauthn4j.data.AuthenticatorAttachment toWebAuthn4J() { + switch (this) { + case CROSS_PLATFORM: + return com.webauthn4j.data.AuthenticatorAttachment.CROSS_PLATFORM; + case PLATFORM: + return com.webauthn4j.data.AuthenticatorAttachment.PLATFORM; + default: + throw new IllegalStateException("Illegal enum value: " + this); + } + } + } + + /** + * AuthenticatorTransport + * https://www.w3.org/TR/webauthn/#enumdef-authenticatortransport + */ + public enum AuthenticatorTransport { + USB, + NFC, + BLE, + HYBRID, + INTERNAL; + } + + /** + * ResidentKey + * https://www.w3.org/TR/webauthn-2/#dictdef-authenticatorselectioncriteria + * + * This enum is used to specify the desired behaviour for resident keys with the authenticator. + */ + public enum ResidentKey { + DISCOURAGED, + PREFERRED, + REQUIRED; + + ResidentKeyRequirement toWebAuthn4J() { + switch (this) { + case DISCOURAGED: + return ResidentKeyRequirement.DISCOURAGED; + case PREFERRED: + return ResidentKeyRequirement.PREFERRED; + case REQUIRED: + return ResidentKeyRequirement.REQUIRED; + default: + throw new IllegalStateException("Illegal enum value: " + this); + } + } + } + /** * SameSite attribute values for the session cookie. */ @@ -34,7 +199,7 @@ enum CookieSameSite { } /** - * The origin of the application. The origin is basically protocol, host and port. + * The origins of the application. The origin is basically protocol, host and port. * * If you are calling WebAuthn API while your application is located at {@code https://example.com/login}, * then origin will be {@code https://example.com}. @@ -44,8 +209,14 @@ enum CookieSameSite { * * Please note that WebAuthn API will not work on pages loaded over HTTP, unless it is localhost, * which is considered secure context. + * + * If unspecified, this defaults to whatever URI this application is deployed on. + * + * This allows more than one value if you want to allow multiple origins. See + * https://w3c.github.io/webauthn/#sctn-related-origins */ - Optional origin(); + @ConfigDocDefault("The URI this application is deployed on") + Optional> origins(); /** * Authenticator Transports allowed by the application. Authenticators can interact with the user web browser @@ -86,12 +257,19 @@ enum CookieSameSite { */ Optional authenticatorAttachment(); + /** + * Load the FIDO metadata for verification. See https://fidoalliance.org/metadata/. Only useful for attestations + * different from {@code Attestation.NONE}. + */ + @ConfigDocDefault("false") + Optional loadMetadata(); + /** * Resident key required. A resident (private) key, is a key that cannot leave your authenticator device, this * means that you cannot reuse the authenticator to log into a second computer. */ - @ConfigDocDefault("false") - Optional requireResidentKey(); + @ConfigDocDefault("REQUIRED") + Optional residentKey(); /** * User Verification requirements. Webauthn applications may choose {@code REQUIRED} verification to assert that @@ -104,15 +282,21 @@ enum CookieSameSite { *
  • {@code DISCOURAGED} - User should avoid interact with the browser
  • * */ - @ConfigDocDefault("DISCOURAGED") + @ConfigDocDefault("REQUIRED") Optional userVerification(); + /** + * User presence requirements. + */ + @ConfigDocDefault("true") + Optional userPresenceRequired(); + /** * Non-negative User Verification timeout. Authentication must occur within the timeout, this will prevent the user * browser from being blocked with a pop-up required user verification, and the whole ceremony must be completed * within the timeout period. After the timeout, any previously issued challenge is automatically invalidated. */ - @ConfigDocDefault("60s") + @ConfigDocDefault("5m") Optional timeout(); /** @@ -144,9 +328,11 @@ enum CookieSameSite { * * Note that the use of stronger algorithms, e.g.: {@code EdDSA} may require Java 15 or a cryptographic {@code JCE} * provider that implements the algorithms. + * + * See https://www.w3.org/TR/webauthn-1/#dictdef-publickeycredentialparameters */ @ConfigDocDefault("ES256,RS256") - Optional> pubKeyCredParams(); + Optional> publicKeyCredentialParameters(); /** * Length of the challenges exchanged between the application and the browser. @@ -180,8 +366,10 @@ enum CookieSameSite { @ConfigGroup interface RelyingPartyConfig { /** - * The id (or domain name of your server) + * The id (or domain name of your server, as obtained from the first entry of origins or looking + * at where this request is being served from) */ + @ConfigDocDefault("The host name of the first allowed origin, or the host where this application is deployed") Optional id(); /** @@ -261,4 +449,20 @@ interface RelyingPartyConfig { * The default value is empty, which means the cookie will be kept until the browser is closed. */ Optional cookieMaxAge(); + + /** + * Set to true if you want to enable the default registration endpoint at /q/webauthn/register, in + * which case + * you should also implement the WebAuthnUserProvider.store method. + */ + @WithDefault("false") + Optional enableRegistrationEndpoint(); + + /** + * Set to true if you want to enable the default login endpoint at /q/webauthn/login, in which + * case + * you should also implement the WebAuthnUserProvider.update method. + */ + @WithDefault("false") + Optional enableLoginEndpoint(); } diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java index d803512ea5a34..368a76327a409 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java @@ -1,23 +1,80 @@ package io.quarkus.security.webauthn; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.security.Principal; +import java.security.cert.CertificateException; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; +import com.webauthn4j.async.WebAuthnAsyncManager; +import com.webauthn4j.async.anchor.KeyStoreTrustAnchorAsyncRepository; +import com.webauthn4j.async.anchor.TrustAnchorAsyncRepository; +import com.webauthn4j.async.metadata.FidoMDS3MetadataBLOBAsyncProvider; +import com.webauthn4j.async.metadata.HttpAsyncClient; +import com.webauthn4j.async.metadata.anchor.MetadataBLOBBasedTrustAnchorAsyncRepository; +import com.webauthn4j.async.verifier.attestation.statement.androidkey.AndroidKeyAttestationStatementAsyncVerifier; +import com.webauthn4j.async.verifier.attestation.statement.androidsafetynet.AndroidSafetyNetAttestationStatementAsyncVerifier; +import com.webauthn4j.async.verifier.attestation.statement.apple.AppleAnonymousAttestationStatementAsyncVerifier; +import com.webauthn4j.async.verifier.attestation.statement.packed.PackedAttestationStatementAsyncVerifier; +import com.webauthn4j.async.verifier.attestation.statement.tpm.TPMAttestationStatementAsyncVerifier; +import com.webauthn4j.async.verifier.attestation.statement.u2f.FIDOU2FAttestationStatementAsyncVerifier; +import com.webauthn4j.async.verifier.attestation.trustworthiness.certpath.DefaultCertPathTrustworthinessAsyncVerifier; +import com.webauthn4j.async.verifier.attestation.trustworthiness.self.DefaultSelfAttestationTrustworthinessAsyncVerifier; +import com.webauthn4j.converter.util.ObjectConverter; +import com.webauthn4j.data.AuthenticationParameters; +import com.webauthn4j.data.AuthenticatorSelectionCriteria; +import com.webauthn4j.data.PublicKeyCredentialCreationOptions; +import com.webauthn4j.data.PublicKeyCredentialDescriptor; +import com.webauthn4j.data.PublicKeyCredentialParameters; +import com.webauthn4j.data.PublicKeyCredentialRequestOptions; +import com.webauthn4j.data.PublicKeyCredentialRpEntity; +import com.webauthn4j.data.PublicKeyCredentialType; +import com.webauthn4j.data.PublicKeyCredentialUserEntity; +import com.webauthn4j.data.RegistrationParameters; +import com.webauthn4j.data.attestation.statement.COSEAlgorithmIdentifier; +import com.webauthn4j.data.client.Origin; +import com.webauthn4j.data.client.challenge.DefaultChallenge; +import com.webauthn4j.data.extension.client.AuthenticationExtensionsClientInputs; +import com.webauthn4j.server.ServerProperty; +import com.webauthn4j.util.Base64UrlUtil; + import io.quarkus.security.runtime.QuarkusPrincipal; import io.quarkus.security.runtime.QuarkusSecurityIdentity; +import io.quarkus.security.webauthn.WebAuthnRunTimeConfig.Attestation; +import io.quarkus.security.webauthn.WebAuthnRunTimeConfig.AuthenticatorAttachment; +import io.quarkus.security.webauthn.WebAuthnRunTimeConfig.COSEAlgorithm; +import io.quarkus.security.webauthn.WebAuthnRunTimeConfig.ResidentKey; +import io.quarkus.security.webauthn.WebAuthnRunTimeConfig.UserVerification; +import io.quarkus.security.webauthn.impl.VertxHttpAsyncClient; +import io.quarkus.tls.TlsConfiguration; +import io.quarkus.tls.TlsConfigurationRegistry; import io.quarkus.vertx.http.runtime.security.PersistentLoginManager.RestoreResult; import io.smallrye.mutiny.Uni; import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; import io.vertx.core.http.Cookie; -import io.vertx.ext.auth.webauthn.Authenticator; -import io.vertx.ext.auth.webauthn.RelyingParty; -import io.vertx.ext.auth.webauthn.WebAuthn; -import io.vertx.ext.auth.webauthn.WebAuthnCredentials; -import io.vertx.ext.auth.webauthn.WebAuthnOptions; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.impl.CertificateHelper; +import io.vertx.ext.auth.impl.CertificateHelper.CertInfo; +import io.vertx.ext.auth.impl.jose.JWS; +import io.vertx.ext.auth.prng.VertxContextPRNG; import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.impl.Origin; /** * Utility class that allows users to manually login or register users using WebAuthn @@ -25,71 +82,395 @@ @ApplicationScoped public class WebAuthnSecurity { - private WebAuthn webAuthn; - private String origin; - private String domain; + /* + * Android Keystore Root is not published anywhere. + * This certificate was extracted from one of the attestations + * The last certificate in x5c must match this certificate + * This needs to be checked to ensure that malicious party won't generate fake attestations + */ + private static final String ANDROID_KEYSTORE_ROOT = "MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG" + + "EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll" + + "dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD" + + "VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw" + + "HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx" + + "EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT" + + "BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq" + + "QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH" + + "KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59" + + "dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O" + + "BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W" + + "EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG" + + "SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN" + + "C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw=="; + + // https://aboutssl.org/globalsign-root-certificates-licensing-and-use/ + // Name gsr1 + // Thumbprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c + // Valid Until 28 January 2028 + private static final String GSR1 = "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n" + + "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n" + + "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n" + + "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n" + + "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n" + + "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n" + + "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n" + + "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n" + + "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n" + + "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n" + + "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n" + + "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n" + + "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n" + + "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n" + + "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n" + + "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n" + + "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n" + + "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A=="; + + /** + * Apple WebAuthn Root CA PEM + *

    + * Downloaded from https://www.apple.com/certificateauthority/Apple_WebAuthn_Root_CA.pem + *

    + * Valid until 03/14/2045 @ 5:00 PM PST + */ + private static final String APPLE_WEBAUTHN_ROOT_CA = "MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w" + + "HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ" + + "bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx" + + "NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG" + + "A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49" + + "AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k" + + "xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/" + + "pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk" + + "2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA" + + "MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3" + + "jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B" + + "1bWeT0vT"; + + /** + * Default FIDO2 MDS3 ROOT Certificate + *

    + * Downloaded from https://valid.r3.roots.globalsign.com/ + *

    + * Valid until 18 March 2029 + */ + private static final String FIDO_MDS3_ROOT_CERTIFICATE = "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G" + + + "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp" + + "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4" + + "MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG" + + "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI" + + "hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8" + + "RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT" + + "gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm" + + "KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd" + + "QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ" + + "XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw" + + "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o" + + "LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU" + + "RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp" + + "jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK" + + "6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX" + + "mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs" + + "Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH" + + "WD9f"; + + @Inject + TlsConfigurationRegistry certificates; @Inject WebAuthnAuthenticationMechanism authMech; + + @Inject + WebAuthnAuthenticatorStorage storage; + + private ObjectConverter objectConverter = new ObjectConverter(); + private WebAuthnAsyncManager webAuthn; + private VertxContextPRNG random; + private String challengeCookie; private String challengeUsernameCookie; + private List origins; + private String rpId; + private String rpName; + + private UserVerification userVerification; + private Boolean userPresenceRequired; + private List pubKeyCredParams; + private ResidentKey residentKey; + + private Duration timeout; + private int challengeLength; + private AuthenticatorAttachment authenticatorAttachment; + + private Attestation attestation; + public WebAuthnSecurity(WebAuthnRunTimeConfig config, Vertx vertx, WebAuthnAuthenticatorStorage database) { - // create the webauthn security object - WebAuthnOptions options = new WebAuthnOptions(); - RelyingParty relyingParty = new RelyingParty(); - if (config.relyingParty().id().isPresent()) { - relyingParty.setId(config.relyingParty().id().get()); - } - // this is required - relyingParty.setName(config.relyingParty().name()); - options.setRelyingParty(relyingParty); - if (config.attestation().isPresent()) { - options.setAttestation(config.attestation().get()); - } - if (config.authenticatorAttachment().isPresent()) { - options.setAuthenticatorAttachment(config.authenticatorAttachment().get()); - } - if (config.challengeLength().isPresent()) { - options.setChallengeLength(config.challengeLength().getAsInt()); - } - if (config.pubKeyCredParams().isPresent()) { - options.setPubKeyCredParams(config.pubKeyCredParams().get()); + // apply config defaults + this.rpId = config.relyingParty().id().orElse(null); + this.rpName = config.relyingParty().name(); + this.origins = config.origins().orElse(Collections.emptyList()); + this.challengeCookie = config.challengeCookieName(); + this.challengeUsernameCookie = config.challengeUsernameCookieName(); + this.challengeLength = config.challengeLength().orElse(64); + this.userPresenceRequired = config.userPresenceRequired().orElse(true); + this.timeout = config.timeout().orElse(Duration.ofMinutes(5)); + if (config.publicKeyCredentialParameters().isPresent()) { + this.pubKeyCredParams = new ArrayList<>(config.publicKeyCredentialParameters().get().size()); + for (COSEAlgorithm publicKeyCredential : config.publicKeyCredentialParameters().get()) { + this.pubKeyCredParams.add(new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, + COSEAlgorithmIdentifier.create(publicKeyCredential.coseId()))); + } + } else { + this.pubKeyCredParams = new ArrayList<>(2); + this.pubKeyCredParams + .add(new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.ES256)); + this.pubKeyCredParams + .add(new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.RS256)); } - if (config.requireResidentKey().isPresent()) { - options.setRequireResidentKey(config.requireResidentKey().get()); + this.authenticatorAttachment = config.authenticatorAttachment().orElse(null); + this.userVerification = config.userVerification().orElse(UserVerification.REQUIRED); + this.residentKey = config.residentKey().orElse(ResidentKey.REQUIRED); + this.attestation = config.attestation().orElse(Attestation.NONE); + // create the webauthn4j manager + this.webAuthn = makeWebAuthn(vertx, config); + this.random = VertxContextPRNG.current(vertx); + } + + private String randomBase64URLBuffer() { + final byte[] buff = new byte[challengeLength]; + random.nextBytes(buff); + return Base64UrlUtil.encodeToString(buff); + } + + private WebAuthnAsyncManager makeWebAuthn(Vertx vertx, WebAuthnRunTimeConfig config) { + if (config.attestation().isPresent() + && config.attestation().get() != WebAuthnRunTimeConfig.Attestation.NONE) { + TrustAnchorAsyncRepository something; + // FIXME: make config name configurable? + Optional webauthnTlsConfiguration = certificates.get("webauthn"); + KeyStore trustStore; + if (webauthnTlsConfiguration.isPresent()) { + trustStore = webauthnTlsConfiguration.get().getTrustStore(); + } else { + try { + trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null, null); + addCert(trustStore, ANDROID_KEYSTORE_ROOT); + addCert(trustStore, APPLE_WEBAUTHN_ROOT_CA); + addCert(trustStore, FIDO_MDS3_ROOT_CERTIFICATE); + addCert(trustStore, GSR1); + } catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | IOException e) { + throw new RuntimeException("Failed to configure default WebAuthn certificates", e); + } + } + Set trustAnchors = new HashSet<>(); + try { + Enumeration aliases = trustStore.aliases(); + while (aliases.hasMoreElements()) { + trustAnchors.add(new TrustAnchor((X509Certificate) trustStore.getCertificate(aliases.nextElement()), null)); + } + } catch (KeyStoreException e) { + throw new RuntimeException("Failed to configure WebAuthn trust store", e); + } + // FIXME CLRs are not supported yet + something = new KeyStoreTrustAnchorAsyncRepository(trustStore); + if (config.loadMetadata().orElse(false)) { + HttpAsyncClient httpClient = new VertxHttpAsyncClient(vertx); + FidoMDS3MetadataBLOBAsyncProvider blobAsyncProvider = new FidoMDS3MetadataBLOBAsyncProvider(objectConverter, + FidoMDS3MetadataBLOBAsyncProvider.DEFAULT_BLOB_ENDPOINT, httpClient, trustAnchors); + something = new MetadataBLOBBasedTrustAnchorAsyncRepository(blobAsyncProvider); + } + + return new WebAuthnAsyncManager( + Arrays.asList( + new FIDOU2FAttestationStatementAsyncVerifier(), + new PackedAttestationStatementAsyncVerifier(), + new TPMAttestationStatementAsyncVerifier(), + new AndroidKeyAttestationStatementAsyncVerifier(), + new AndroidSafetyNetAttestationStatementAsyncVerifier(), + new AppleAnonymousAttestationStatementAsyncVerifier()), + new DefaultCertPathTrustworthinessAsyncVerifier(something), + new DefaultSelfAttestationTrustworthinessAsyncVerifier(), + objectConverter); + + } else { + return WebAuthnAsyncManager.createNonStrictWebAuthnAsyncManager(objectConverter); } - if (config.timeout().isPresent()) { - options.setTimeoutInMilliseconds(config.timeout().get().toMillis()); + } + + private void addCert(KeyStore keyStore, String pemCertificate) throws CertificateException, KeyStoreException { + X509Certificate cert = JWS.parseX5c(pemCertificate); + CertInfo info = CertificateHelper.getCertInfo(cert); + keyStore.setCertificateEntry(info.subject("CN"), cert); + } + + private static byte[] uUIDBytes(UUID uuid) { + Buffer buffer = Buffer.buffer(16); + buffer.setLong(0, uuid.getMostSignificantBits()); + buffer.setLong(8, uuid.getLeastSignificantBits()); + return buffer.getBytes(); + } + + /** + * Obtains a registration challenge for the given required userName and displayName. This will also + * create and save a challenge in a session cookie. + * + * @param userName the userName for the registration + * @param displayName the displayName for the registration + * @param ctx the Vert.x context + * @return the registration challenge. + */ + @SuppressWarnings("unused") + public Uni getRegisterChallenge(String userName, String displayName, + RoutingContext ctx) { + if (userName == null || userName.isEmpty()) { + return Uni.createFrom().failure(new IllegalArgumentException("Username is required")); } - if (config.transports().isPresent()) { - options.setTransports(config.transports().get()); + // default displayName to userName, but it's required really + if (displayName == null || displayName.isEmpty()) { + displayName = userName; } - if (config.userVerification().isPresent()) { - options.setUserVerification(config.userVerification().get()); + String finalDisplayName = displayName; + String challenge = randomBase64URLBuffer(); + Origin origin = Origin.create(!this.origins.isEmpty() ? this.origins.get(0) : ctx.request().absoluteURI()); + String rpId = this.rpId != null ? this.rpId : origin.getHost(); + + return storage.findByUserName(userName) + .map(credentials -> { + List excluded; + // See https://github.com/quarkusio/quarkus/issues/44292 for why this is currently disabled + if (false) { + excluded = new ArrayList<>(credentials.size()); + for (WebAuthnCredentialRecord credential : credentials) { + excluded.add(new PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, + credential.getAttestedCredentialData().getCredentialId(), + credential.getTransports())); + } + } else { + excluded = Collections.emptyList(); + } + PublicKeyCredentialCreationOptions publicKeyCredentialCreationOptions = new PublicKeyCredentialCreationOptions( + new PublicKeyCredentialRpEntity( + rpId, + rpName), + new PublicKeyCredentialUserEntity( + uUIDBytes(UUID.randomUUID()), + userName, + finalDisplayName), + new DefaultChallenge(challenge), + pubKeyCredParams, + timeout.getSeconds() * 1000, + excluded, + new AuthenticatorSelectionCriteria( + authenticatorAttachment != null ? authenticatorAttachment.toWebAuthn4J() : null, + residentKey == ResidentKey.REQUIRED, + residentKey.toWebAuthn4J(), + userVerification.toWebAuthn4J()), + attestation.toWebAuthn4J(), + new AuthenticationExtensionsClientInputs<>()); + + // save challenge to the session + authMech.getLoginManager().save(challenge, ctx, challengeCookie, null, + ctx.request().isSSL()); + authMech.getLoginManager().save(userName, ctx, challengeUsernameCookie, null, + ctx.request().isSSL()); + + return publicKeyCredentialCreationOptions; + }); + + } + + /** + * Obtains a login challenge for the given optional userName. This will also + * create and save a challenge in a session cookie. + * + * @param userName the optional userName for the login + * @param ctx the Vert.x context + * @return the login challenge. + */ + @SuppressWarnings("unused") + public Uni getLoginChallenge(String userName, RoutingContext ctx) { + // Username is not required with passkeys + if (userName == null) { + userName = ""; } - webAuthn = WebAuthn.create(vertx, options) - // where to load/update authenticators data - .authenticatorFetcher(database::fetcher) - .authenticatorUpdater(database::updater); - origin = config.origin().orElse(null); - if (origin != null) { - Origin o = Origin.parse(origin); - domain = o.host(); + String finalUserName = userName; + String challenge = randomBase64URLBuffer(); + Origin origin = Origin.create(!this.origins.isEmpty() ? this.origins.get(0) : ctx.request().absoluteURI()); + String rpId = this.rpId != null ? this.rpId : origin.getHost(); + + // do not attempt to look users up if there's no user name + Uni> credentialsUni; + if (userName.isEmpty()) { + credentialsUni = Uni.createFrom().item(Collections.emptyList()); + } else { + credentialsUni = storage.findByUserName(userName); } - this.challengeCookie = config.challengeCookieName(); - this.challengeUsernameCookie = config.challengeUsernameCookieName(); + return credentialsUni + .map(credentials -> { + List allowedCredentials; + // See https://github.com/quarkusio/quarkus/issues/44292 for why this is currently disabled + if (false) { + + if (credentials.isEmpty()) { + throw new RuntimeException("No credentials found for " + finalUserName); + } + allowedCredentials = new ArrayList<>(credentials.size()); + for (WebAuthnCredentialRecord credential : credentials) { + allowedCredentials.add(new PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, + credential.getAttestedCredentialData().getCredentialId(), + credential.getTransports())); + } + } else { + allowedCredentials = Collections.emptyList(); + } + PublicKeyCredentialRequestOptions publicKeyCredentialRequestOptions = new PublicKeyCredentialRequestOptions( + new DefaultChallenge(challenge), + timeout.getSeconds() * 1000, + rpId, + allowedCredentials, + userVerification.toWebAuthn4J(), + null); + + // save challenge to the session + authMech.getLoginManager().save(challenge, ctx, challengeCookie, null, + ctx.request().isSSL()); + authMech.getLoginManager().save(finalUserName, ctx, challengeUsernameCookie, null, + ctx.request().isSSL()); + + return publicKeyCredentialRequestOptions; + }); + } + + /** + * Registers a new WebAuthn credentials. This will check it, clear the cookies and return it in case of + * success, but not invoke {@link WebAuthnUserProvider#store(WebAuthnCredentialRecord)}, you have to do + * it manually in case of success. This will also not set a login cookie, you have to do it manually using + * {@link #rememberUser(String, RoutingContext)} + * or using any other way. + * + * @param response the Webauthn registration info + * @param ctx the current request + * @return the newly created credentials + */ + public Uni register(WebAuthnRegisterResponse response, RoutingContext ctx) { + return register(response.toJsonObject(), ctx); } /** - * Registers a new WebAuthn credentials + * Registers a new WebAuthn credentials. This will check it, clear the cookies and return it in case of + * success, but not invoke {@link WebAuthnUserProvider#store(WebAuthnCredentialRecord)}, you have to do + * it manually in case of success. This will also not set a login cookie, you have to do it manually using + * {@link #rememberUser(String, RoutingContext)} + * or using any other way. * * @param response the Webauthn registration info * @param ctx the current request * @return the newly created credentials */ - public Uni register(WebAuthnRegisterResponse response, RoutingContext ctx) { - // validation of the response is done before + public Uni register(JsonObject response, RoutingContext ctx) { RestoreResult challenge = authMech.getLoginManager().restore(ctx, challengeCookie); RestoreResult username = authMech.getLoginManager().restore(ctx, challengeUsernameCookie); if (challenge == null || challenge.getPrincipal() == null || challenge.getPrincipal().isEmpty() @@ -97,66 +478,126 @@ public Uni register(WebAuthnRegisterResponse response, RoutingCon return Uni.createFrom().failure(new RuntimeException("Missing challenge or username")); } - return Uni.createFrom().emitter(emitter -> { - webAuthn.authenticate( - // authInfo - new WebAuthnCredentials() - .setOrigin(origin) - .setDomain(domain) - .setChallenge(challenge.getPrincipal()) - .setUsername(username.getPrincipal()) - .setWebauthn(response.toJsonObject()), - authenticate -> { - removeCookie(ctx, challengeCookie); - removeCookie(ctx, challengeUsernameCookie); - if (authenticate.succeeded()) { - // this is registration, so the caller will want to store the created Authenticator, - // let's recreate it - emitter.complete(new Authenticator(authenticate.result().principal())); - } else { - emitter.fail(authenticate.cause()); - } - }); - }); + // input validation + if (response == null || + !containsRequiredString(response, "id") || + !containsRequiredString(response, "rawId") || + !containsRequiredObject(response, "response") || + !containsOptionalString(response.getJsonObject("response"), "userHandle") || + !containsRequiredString(response, "type") || + !"public-key".equals(response.getString("type"))) { + + return Uni.createFrom().failure(new IllegalArgumentException( + "Response missing one or more of id/rawId/response[.userHandle]/type fields, or type is not public-key")); + } + String registrationResponseJSON = response.encode(); + + ServerProperty serverProperty = makeServerProperty(challenge, ctx); + RegistrationParameters registrationParameters = new RegistrationParameters(serverProperty, pubKeyCredParams, + userVerification == UserVerification.REQUIRED, userPresenceRequired); + + return Uni.createFrom() + .completionStage(webAuthn.verifyRegistrationResponseJSON(registrationResponseJSON, registrationParameters)) + .eventually(() -> { + removeCookie(ctx, challengeCookie); + removeCookie(ctx, challengeUsernameCookie); + }).map(registrationData -> new WebAuthnCredentialRecord( + username.getPrincipal(), + registrationData.getAttestationObject(), + registrationData.getCollectedClientData(), + registrationData.getClientExtensions(), + registrationData.getTransports())); + } + + private ServerProperty makeServerProperty(RestoreResult challenge, RoutingContext ctx) { + Set origins = new HashSet<>(); + Origin firstOrigin = null; + if (this.origins.isEmpty()) { + firstOrigin = Origin.create(ctx.request().absoluteURI()); + origins.add(firstOrigin); + } else { + for (String origin : this.origins) { + Origin newOrigin = Origin.create(origin); + if (firstOrigin == null) { + firstOrigin = newOrigin; + origins.add(newOrigin); + } + } + } + String rpId = this.rpId != null ? this.rpId : firstOrigin.getHost(); + DefaultChallenge challengeObject = new DefaultChallenge(challenge.getPrincipal()); + return new ServerProperty(origins, rpId, challengeObject, /* this is deprecated in Level 3, so ignore it */ null); + } + + /** + * Logs an existing WebAuthn user in. This will check it, clear the cookies and return the updated credentials in case of + * success, but not invoke {@link WebAuthnUserProvider#update(String, long)}, you have to do + * it manually in case of success. This will also not set a login cookie, you have to do it manually using + * {@link #rememberUser(String, RoutingContext)} + * or using any other way. + * + * @param response the Webauthn login info + * @param ctx the current request + * @return the updated credentials + */ + public Uni login(WebAuthnLoginResponse response, RoutingContext ctx) { + return login(response.toJsonObject(), ctx); } /** - * Logs an existing WebAuthn user in + * Logs an existing WebAuthn user in. This will check it, clear the cookies and return the updated credentials in case of + * success, but not invoke {@link WebAuthnUserProvider#update(String, long)}, you have to do + * it manually in case of success. This will also not set a login cookie, you have to do it manually using + * {@link #rememberUser(String, RoutingContext)} + * or using any other way. * * @param response the Webauthn login info * @param ctx the current request * @return the updated credentials */ - public Uni login(WebAuthnLoginResponse response, RoutingContext ctx) { - // validation of the response is done before + public Uni login(JsonObject response, RoutingContext ctx) { RestoreResult challenge = authMech.getLoginManager().restore(ctx, challengeCookie); RestoreResult username = authMech.getLoginManager().restore(ctx, challengeUsernameCookie); if (challenge == null || challenge.getPrincipal() == null || challenge.getPrincipal().isEmpty() - || username == null || username.getPrincipal() == null || username.getPrincipal().isEmpty()) { + // although login can be empty, we should still have a cookie for it + || username == null || username.getPrincipal() == null) { return Uni.createFrom().failure(new RuntimeException("Missing challenge or username")); } - return Uni.createFrom().emitter(emitter -> { - webAuthn.authenticate( - // authInfo - new WebAuthnCredentials() - .setOrigin(origin) - .setDomain(domain) - .setChallenge(challenge.getPrincipal()) - .setUsername(username.getPrincipal()) - .setWebauthn(response.toJsonObject()), - authenticate -> { - removeCookie(ctx, challengeCookie); - removeCookie(ctx, challengeUsernameCookie); - if (authenticate.succeeded()) { - // this is login, so the user will want to bump the counter - // FIXME: do we need the auth here? likely the user will know it and will just ++ on the DB-stored counter, no? - emitter.complete(new Authenticator(authenticate.result().principal())); - } else { - emitter.fail(authenticate.cause()); - } - }); - }); + // input validation + if (response == null || + !containsRequiredString(response, "id") || + !containsRequiredString(response, "rawId") || + !containsRequiredObject(response, "response") || + !containsOptionalString(response.getJsonObject("response"), "userHandle") || + !containsRequiredString(response, "type") || + !"public-key".equals(response.getString("type"))) { + + return Uni.createFrom().failure(new IllegalArgumentException( + "Response missing one or more of id/rawId/response[.userHandle]/type fields, or type is not public-key")); + } + + String authenticationResponseJSON = response.encode(); + // validated + String rawId = response.getString("rawId"); + + ServerProperty serverProperty = makeServerProperty(challenge, ctx); + + return storage.findByCredID(rawId) + .chain(credentialRecord -> { + List allowCredentials = List.of(Base64UrlUtil.decode(rawId)); + AuthenticationParameters authenticationParameters = new AuthenticationParameters(serverProperty, + credentialRecord, allowCredentials, + userVerification == UserVerification.REQUIRED, userPresenceRequired); + + return Uni.createFrom() + .completionStage(webAuthn.verifyAuthenticationResponseJSON(authenticationResponseJSON, + authenticationParameters)) + .eventually(() -> { + removeCookie(ctx, challengeCookie); + removeCookie(ctx, challengeUsernameCookie); + }).map(authenticationData -> credentialRecord); + }); } static void removeCookie(RoutingContext ctx, String name) { @@ -170,11 +611,11 @@ static void removeCookie(RoutingContext ctx, String name) { } /** - * Returns the underlying Vert.x WebAuthn authenticator + * Returns the underlying WebAuthn4J authenticator * - * @return the underlying Vert.x WebAuthn authenticator + * @return the underlying WebAuthn4J authenticator */ - public WebAuthn getWebAuthn() { + public WebAuthnAsyncManager getWebAuthn4J() { return webAuthn; } @@ -198,4 +639,72 @@ public void rememberUser(String userID, RoutingContext ctx) { public void logout(RoutingContext ctx) { authMech.getLoginManager().clear(ctx); } + + static boolean containsRequiredString(JsonObject json, String key) { + try { + if (json == null) { + return false; + } + if (!json.containsKey(key)) { + return false; + } + Object s = json.getValue(key); + return (s instanceof String) && !"".equals(s); + } catch (ClassCastException e) { + return false; + } + } + + private static boolean containsOptionalString(JsonObject json, String key) { + try { + if (json == null) { + return true; + } + if (!json.containsKey(key)) { + return true; + } + Object s = json.getValue(key); + return (s instanceof String); + } catch (ClassCastException e) { + return false; + } + } + + private static boolean containsRequiredObject(JsonObject json, String key) { + try { + if (json == null) { + return false; + } + if (!json.containsKey(key)) { + return false; + } + JsonObject s = json.getJsonObject(key); + return s != null; + } catch (ClassCastException e) { + return false; + } + } + + public String toJsonString(PublicKeyCredentialCreationOptions challenge) { + return objectConverter.getJsonConverter().writeValueAsString(challenge); + } + + public String toJsonString(PublicKeyCredentialRequestOptions challenge) { + return objectConverter.getJsonConverter().writeValueAsString(challenge); + } + + /** + * Returns the list of allowed origins, or defaults to the current request's origin if unconfigured. + */ + public List getAllowedOrigins(RoutingContext ctx) { + if (this.origins.isEmpty()) { + return List.of(Origin.create(ctx.request().absoluteURI()).toString()); + } else { + return this.origins; + } + } + + WebAuthnAuthenticatorStorage storage() { + return storage; + } } diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java index b74c45363eb50..d61583e33812b 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java @@ -5,7 +5,6 @@ import java.util.Set; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.Authenticator; /** * Implement this interface in order to tell Quarkus WebAuthn how to look up @@ -14,29 +13,54 @@ */ public interface WebAuthnUserProvider { /** - * Look up a WebAuthn credential by username + * Look up a WebAuthn credential by username. This should return an empty list Uni if the user name is not found. * * @param userName the username - * @return a list of credentials for this username + * @return a list of credentials for this username, or an empty list if there are no credentials or if the user name is + * not found. */ - public Uni> findWebAuthnCredentialsByUserName(String userName); + public Uni> findByUserName(String userName); /** - * Look up a WebAuthn credential by credential ID + * Look up a WebAuthn credential by credential ID, this should return an exception Uni rather than return a null-item Uni + * in case the credential is not found. * * @param credentialId the credential ID - * @returna list of credentials for this credential ID. + * @return a credentials for this credential ID. + * @throws an exception Uni if the credential ID is unknown */ - public Uni> findWebAuthnCredentialsByCredID(String credentialId); + public Uni findByCredentialId(String credentialId); /** - * If this credential's combination of user and credential ID does not exist, - * then store the new credential. If it already exists, then only update its counter + * Update an existing WebAuthn credential's counter. This is only used by the default login enpdoint, which + * is disabled by default and can be enabled via the quarkus.webauthn.enable-login-endpoint. + * You don't have to implement this method + * if you handle logins manually via {@link WebAuthnSecurity#login(WebAuthnLoginResponse, io.vertx.ext.web.RoutingContext)}. * - * @param authenticator the new credential if it does not exist, or the credential to update + * The default behaviour is to not do anything. + * + * @param credentialId the credential ID + * @return a uni completion object + */ + public default Uni update(String credentialId, long counter) { + return Uni.createFrom().voidItem(); + } + + /** + * Store a new WebAuthn credential. This is only used by the default registration enpdoint, which + * is disabled by default and can be enabled via the quarkus.webauthn.enable-registration-endpoint. + * You don't have to implement this method if you handle registration manually via + * {@link WebAuthnSecurity#register(WebAuthnRegisterResponse, io.vertx.ext.web.RoutingContext)} + * + * The default behaviour is to not do anything. + * + * @param userName the userName's credentials + * @param credentialRecord the new credentials to store * @return a uni completion object */ - public Uni updateOrStoreWebAuthnCredentials(Authenticator authenticator); + public default Uni store(WebAuthnCredentialRecord credentialRecord) { + return Uni.createFrom().voidItem(); + } /** * Returns the set of roles for the given username diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/impl/VertxHttpAsyncClient.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/impl/VertxHttpAsyncClient.java new file mode 100644 index 0000000000000..755b9810b216b --- /dev/null +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/impl/VertxHttpAsyncClient.java @@ -0,0 +1,41 @@ +package io.quarkus.security.webauthn.impl; + +import java.io.ByteArrayInputStream; +import java.util.concurrent.CompletionStage; + +import com.webauthn4j.async.metadata.HttpAsyncClient; +import com.webauthn4j.metadata.HttpClient.Response; +import com.webauthn4j.metadata.exception.MDSException; + +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.HttpMethod; +import io.vertx.ext.auth.impl.http.SimpleHttpClient; + +public class VertxHttpAsyncClient implements HttpAsyncClient { + + private static final byte[] NO_BYTES = new byte[0]; + private SimpleHttpClient httpClient; + + public VertxHttpAsyncClient(Vertx vertx) { + this.httpClient = new SimpleHttpClient(vertx, "vertx-auth", new HttpClientOptions()); + } + + @Override + public CompletionStage fetch(String uri) throws MDSException { + return httpClient + .fetch(HttpMethod.GET, uri, null, null) + .map(res -> { + Buffer body = res.body(); + byte[] bytes; + if (body != null) { + bytes = body.getBytes(); + } else { + bytes = NO_BYTES; + } + return new Response(res.statusCode(), new ByteArrayInputStream(bytes)); + }).toCompletionStage(); + } + +} diff --git a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js index e38b2982fc23e..ae211660423e2 100644 --- a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js +++ b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js @@ -94,24 +94,33 @@ * Licensed under the Apache 2 license. */ - function WebAuthn(options) { - this.registerPath = options.registerPath; - this.loginPath = options.loginPath; - this.callbackPath = options.callbackPath; - // validation - if (!this.callbackPath) { - throw new Error('Callback path is missing!'); - } + function WebAuthn(options = {}) { + this.registerOptionsChallengePath = options.registerOptionsChallengePath || "/q/webauthn/register-options-challenge"; + this.loginOptionsChallengePath = options.loginOptionsChallengePath || "/q/webauthn/login-options-challenge"; + this.registerPath = options.registerPath || "/q/webauthn/register"; + this.loginPath = options.loginPath || "/q/webauthn/login"; + this.csrf = options.csrf; } WebAuthn.constructor = WebAuthn; - WebAuthn.prototype.registerOnly = function (user) { + WebAuthn.prototype.fetchWithCsrf = function (path, options) { const self = this; - if (!self.registerPath) { - return Promise.reject('Register path missing form the initial configuration!'); + if(self.csrf) { + if(!options.headers) { + options.headers = {}; + } + options.headers[self.csrf.header] = self.csrf.value; + } + return fetch(path, options); + } + + WebAuthn.prototype.registerClientSteps = function (user) { + const self = this; + if (!self.registerOptionsChallengePath) { + return Promise.reject('Register challenge path missing form the initial configuration!'); } - return fetch(self.registerPath, { + return self.fetchWithCsrf(self.registerOptionsChallengePath, { method: 'POST', headers: { 'Accept': 'application/json', @@ -152,9 +161,12 @@ WebAuthn.prototype.register = function (user) { const self = this; - return self.registerOnly(user) + if (!self.registerPath) { + throw new Error('Register path is missing!'); + } + return self.registerClientSteps(user) .then(body => { - return fetch(self.callbackPath, { + return self.fetchWithCsrf(self.registerPath, { method: 'POST', headers: { 'Accept': 'application/json', @@ -173,9 +185,12 @@ WebAuthn.prototype.login = function (user) { const self = this; - return self.loginOnly(user) + if (!self.loginPath) { + throw new Error('Login path is missing!'); + } + return self.loginClientSteps(user) .then(body => { - return fetch(self.callbackPath, { + return self.fetchWithCsrf(self.loginPath, { method: 'POST', headers: { 'Accept': 'application/json', @@ -192,18 +207,18 @@ }); }; - WebAuthn.prototype.loginOnly = function (user) { + WebAuthn.prototype.loginClientSteps = function (user) { const self = this; - if (!self.loginPath) { - return Promise.reject('Login path missing from the initial configuration!'); + if (!self.loginOptionsChallengePath) { + return Promise.reject('Login challenge path missing from the initial configuration!'); } - return fetch(self.loginPath, { + return self.fetchWithCsrf(self.loginOptionsChallengePath, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, - body: JSON.stringify(user) + body: JSON.stringify(user || {}) }) .then(res => { if (res.status === 200) { diff --git a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java index e14bbfbc04f73..48ad47313c2e9 100644 --- a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java +++ b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java @@ -9,12 +9,12 @@ import org.jboss.resteasy.reactive.RestForm; -import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactional; +import io.quarkus.hibernate.reactive.panache.common.WithTransaction; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnLoginResponse; import io.quarkus.security.webauthn.WebAuthnRegisterResponse; import io.quarkus.security.webauthn.WebAuthnSecurity; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.Authenticator; import io.vertx.ext.web.RoutingContext; @Path("") @@ -25,7 +25,7 @@ public class LoginResource { @Path("/login") @POST - @ReactiveTransactional + @WithTransaction public Uni login(@RestForm String userName, @BeanParam WebAuthnLoginResponse webAuthnResponse, RoutingContext ctx) { @@ -42,7 +42,7 @@ public Uni login(@RestForm String userName, // Invalid user return Uni.createFrom().item(Response.status(Status.BAD_REQUEST).build()); } - Uni authenticator = this.webAuthnSecurity.login(webAuthnResponse, ctx); + Uni authenticator = this.webAuthnSecurity.login(webAuthnResponse, ctx); return authenticator // bump the auth counter @@ -54,6 +54,7 @@ public Uni login(@RestForm String userName, }) // handle login failure .onFailure().recoverWithItem(x -> { + x.printStackTrace(); // make a proper error response return Response.status(Status.BAD_REQUEST).build(); }); @@ -63,7 +64,7 @@ public Uni login(@RestForm String userName, @Path("/register") @POST - @ReactiveTransactional + @WithTransaction public Uni register(@RestForm String userName, @BeanParam WebAuthnRegisterResponse webAuthnResponse, RoutingContext ctx) { @@ -80,7 +81,7 @@ public Uni register(@RestForm String userName, // Duplicate user return Uni.createFrom().item(Response.status(Status.BAD_REQUEST).build()); } - Uni authenticator = this.webAuthnSecurity.register(webAuthnResponse, ctx); + Uni authenticator = this.webAuthnSecurity.register(webAuthnResponse, ctx); return authenticator // store the user @@ -100,6 +101,7 @@ public Uni register(@RestForm String userName, // handle login failure .onFailure().recoverWithItem(x -> { // make a proper error response + x.printStackTrace(); return Response.status(Status.BAD_REQUEST).build(); }); diff --git a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/MyWebAuthnSetup.java b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/MyWebAuthnSetup.java index 26a5891c715d5..15423104b0f17 100644 --- a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/MyWebAuthnSetup.java +++ b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/MyWebAuthnSetup.java @@ -1,6 +1,5 @@ package io.quarkus.it.security.webauthn; -import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -8,85 +7,55 @@ import jakarta.enterprise.context.ApplicationScoped; -import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactional; +import io.quarkus.hibernate.reactive.panache.common.WithTransaction; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnUserProvider; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.AttestationCertificates; -import io.vertx.ext.auth.webauthn.Authenticator; @ApplicationScoped public class MyWebAuthnSetup implements WebAuthnUserProvider { - @ReactiveTransactional + @WithTransaction @Override - public Uni> findWebAuthnCredentialsByUserName(String userName) { + public Uni> findByUserName(String userName) { return WebAuthnCredential.findByUserName(userName) - .flatMap(MyWebAuthnSetup::toAuthenticators); + .map(list -> list.stream().map(WebAuthnCredential::toWebAuthnCredentialRecord).toList()); } - @ReactiveTransactional + @WithTransaction @Override - public Uni> findWebAuthnCredentialsByCredID(String credID) { - return WebAuthnCredential.findByCredID(credID) - .flatMap(MyWebAuthnSetup::toAuthenticators); + public Uni findByCredentialId(String credentialId) { + return WebAuthnCredential.findByCredentialId(credentialId) + .onItem().ifNull().failWith(() -> new RuntimeException("No such credentials")) + .map(WebAuthnCredential::toWebAuthnCredentialRecord); } - @ReactiveTransactional + @WithTransaction @Override - public Uni updateOrStoreWebAuthnCredentials(Authenticator authenticator) { - // leave the scooby user to the manual endpoint, because if we do it here it will be - // created/updated twice - if (authenticator.getUserName().equals("scooby")) - return Uni.createFrom().nullItem(); - return User.findByUserName(authenticator.getUserName()) - .flatMap(user -> { - // new user - if (user == null) { - User newUser = new User(); - newUser.userName = authenticator.getUserName(); - WebAuthnCredential credential = new WebAuthnCredential(authenticator, newUser); - return credential.persist() - .flatMap(c -> newUser.persist()) - .onItem().ignore().andContinueWithNull(); - } else { - // existing user - user.webAuthnCredential.counter = authenticator.getCounter(); - return Uni.createFrom().nullItem(); - } - }); - } - - private static Uni> toAuthenticators(List dbs) { - // can't call combine/uni on empty list - if (dbs.isEmpty()) - return Uni.createFrom().item(Collections.emptyList()); - List> ret = new ArrayList<>(dbs.size()); - for (WebAuthnCredential db : dbs) { - ret.add(toAuthenticator(db)); + public Uni store(WebAuthnCredentialRecord credentialRecord) { + // this user is handled in the LoginResource endpoint manually + if (credentialRecord.getUserName().equals("scooby")) { + return Uni.createFrom().voidItem(); } - return Uni.combine().all().unis(ret).combinedWith(f -> (List) f); + User newUser = new User(); + newUser.userName = credentialRecord.getUserName(); + WebAuthnCredential credential = new WebAuthnCredential(credentialRecord, newUser); + return credential.persist() + .flatMap(c -> newUser.persist()) + .onItem().ignore().andContinueWithNull(); } - private static Uni toAuthenticator(WebAuthnCredential credential) { - return credential.fetch(credential.x5c) - .map(x5c -> { - Authenticator ret = new Authenticator(); - ret.setAaguid(credential.aaguid); - AttestationCertificates attestationCertificates = new AttestationCertificates(); - attestationCertificates.setAlg(credential.alg); - List x5cs = new ArrayList<>(x5c.size()); - for (WebAuthnCertificate webAuthnCertificate : x5c) { - x5cs.add(webAuthnCertificate.x5c); + @WithTransaction + @Override + public Uni update(String credentialId, long counter) { + return WebAuthnCredential.findByCredentialId(credentialId) + .invoke(credential -> { + // this user is handled in the LoginResource endpoint manually + if (!credential.user.userName.equals("scooby")) { + credential.counter = counter; } - ret.setAttestationCertificates(attestationCertificates); - ret.setCounter(credential.counter); - ret.setCredID(credential.credID); - ret.setFmt(credential.fmt); - ret.setPublicKey(credential.publicKey); - ret.setType(credential.type); - ret.setUserName(credential.userName); - return ret; - }); + }) + .onItem().ignore().andContinueWithNull(); } @Override diff --git a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/WebAuthnCredential.java b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/WebAuthnCredential.java index b6d6fd0f9396b..ec0e526b9d9f0 100644 --- a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/WebAuthnCredential.java +++ b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/WebAuthnCredential.java @@ -1,76 +1,39 @@ package io.quarkus.it.security.webauthn; -import java.util.ArrayList; import java.util.List; +import java.util.UUID; import jakarta.persistence.Entity; -import jakarta.persistence.OneToMany; +import jakarta.persistence.Id; import jakarta.persistence.OneToOne; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; -import io.quarkus.hibernate.reactive.panache.PanacheEntity; +import io.quarkus.hibernate.reactive.panache.PanacheEntityBase; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord.RequiredPersistedData; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.Authenticator; -import io.vertx.ext.auth.webauthn.PublicKeyCredential; -@Table(uniqueConstraints = @UniqueConstraint(columnNames = { "userName", "credID" })) @Entity -public class WebAuthnCredential extends PanacheEntity { - - /** - * The username linked to this authenticator - */ - public String userName; - - /** - * The type of key (must be "public-key") - */ - public String type = "public-key"; +public class WebAuthnCredential extends PanacheEntityBase { /** * The non user identifiable id for the authenticator */ + @Id public String credID; /** * The public key associated with this authenticator */ - public String publicKey; + public byte[] publicKey; + + public long publicKeyAlgorithm; /** * The signature counter of the authenticator to prevent replay attacks */ public long counter; - public String aaguid; - - /** - * The Authenticator attestation certificates object, a JSON like: - * - *

    -     * {@code
    -     *   {
    -     *     "alg": "string",
    -     *     "x5c": [
    -     *       "base64"
    -     *     ]
    -     *   }
    -     * }
    -     * 
    - */ - /** - * The algorithm used for the public credential - */ - public PublicKeyCredential alg; - - /** - * The list of X509 certificates encoded as base64url. - */ - @OneToMany(mappedBy = "webAuthnCredential") - public List x5c = new ArrayList<>(); - - public String fmt; + public UUID aaguid; // owning side @OneToOne @@ -79,35 +42,29 @@ public class WebAuthnCredential extends PanacheEntity { public WebAuthnCredential() { } - public WebAuthnCredential(Authenticator authenticator, User user) { - aaguid = authenticator.getAaguid(); - if (authenticator.getAttestationCertificates() != null) - alg = authenticator.getAttestationCertificates().getAlg(); - counter = authenticator.getCounter(); - credID = authenticator.getCredID(); - fmt = authenticator.getFmt(); - publicKey = authenticator.getPublicKey(); - type = authenticator.getType(); - userName = authenticator.getUserName(); - if (authenticator.getAttestationCertificates() != null - && authenticator.getAttestationCertificates().getX5c() != null) { - for (String x5c : authenticator.getAttestationCertificates().getX5c()) { - WebAuthnCertificate cert = new WebAuthnCertificate(); - cert.x5c = x5c; - cert.webAuthnCredential = this; - this.x5c.add(cert); - } - } + public WebAuthnCredential(WebAuthnCredentialRecord credentialRecord, User user) { + RequiredPersistedData requiredPersistedData = credentialRecord.getRequiredPersistedData(); + aaguid = requiredPersistedData.aaguid(); + counter = requiredPersistedData.counter(); + credID = requiredPersistedData.credentialId(); + publicKey = requiredPersistedData.publicKey(); + publicKeyAlgorithm = requiredPersistedData.publicKeyAlgorithm(); this.user = user; user.webAuthnCredential = this; } + public WebAuthnCredentialRecord toWebAuthnCredentialRecord() { + return WebAuthnCredentialRecord + .fromRequiredPersistedData( + new RequiredPersistedData(user.userName, credID, aaguid, publicKey, publicKeyAlgorithm, counter)); + } + public static Uni> findByUserName(String userName) { - return list("userName", userName); + return list("user.userName", userName); } - public static Uni> findByCredID(String credID) { - return list("credID", credID); + public static Uni findByCredentialId(String credID) { + return findById(credID); } public Uni fetch(T association) { diff --git a/integration-tests/security-webauthn/src/main/resources/application.properties b/integration-tests/security-webauthn/src/main/resources/application.properties index 06af79d80af21..8c351a0f75197 100644 --- a/integration-tests/security-webauthn/src/main/resources/application.properties +++ b/integration-tests/security-webauthn/src/main/resources/application.properties @@ -6,3 +6,5 @@ quarkus.hibernate-orm.database.generation=drop-and-create quarkus.webauthn.login-page=/ +quarkus.webauthn.enable-login-endpoint=true +quarkus.webauthn.enable-registration-endpoint=true diff --git a/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java b/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java index 44171258e4675..6db2c4cf2ffbf 100644 --- a/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java +++ b/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java @@ -2,11 +2,13 @@ import static io.restassured.RestAssured.given; +import java.net.URL; import java.util.function.Consumer; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; +import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.security.webauthn.WebAuthnEndpointHelper; import io.quarkus.test.security.webauthn.WebAuthnHardware; @@ -28,6 +30,9 @@ enum Endpoint { MANUAL; } + @TestHTTPResource + URL url; + @Test public void testWebAuthnUser() { testWebAuthn("FroMage", User.USER, Endpoint.DEFAULT); @@ -41,15 +46,15 @@ public void testWebAuthnAdmin() { private void testWebAuthn(String userName, User user, Endpoint endpoint) { Filter cookieFilter = new RenardeCookieFilter(); - WebAuthnHardware token = new WebAuthnHardware(); + WebAuthnHardware token = new WebAuthnHardware(url); verifyLoggedOut(cookieFilter); // two-step registration - String challenge = WebAuthnEndpointHelper.invokeRegistration(userName, cookieFilter); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge(userName, cookieFilter); JsonObject registrationJson = token.makeRegistrationJson(challenge); if (endpoint == Endpoint.DEFAULT) - WebAuthnEndpointHelper.invokeCallback(registrationJson, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration(registrationJson, cookieFilter); else { invokeCustomEndpoint("/register", cookieFilter, request -> { WebAuthnEndpointHelper.addWebAuthnRegistrationFormParameters(request, registrationJson); @@ -66,10 +71,10 @@ private void testWebAuthn(String userName, User user, Endpoint endpoint) { verifyLoggedOut(cookieFilter); // two-step login - challenge = WebAuthnEndpointHelper.invokeLogin(userName, cookieFilter); + challenge = WebAuthnEndpointHelper.obtainLoginChallenge(userName, cookieFilter); JsonObject loginJson = token.makeLoginJson(challenge); if (endpoint == Endpoint.DEFAULT) - WebAuthnEndpointHelper.invokeCallback(loginJson, cookieFilter); + WebAuthnEndpointHelper.invokeLogin(loginJson, cookieFilter); else { invokeCustomEndpoint("/login", cookieFilter, request -> { WebAuthnEndpointHelper.addWebAuthnLoginFormParameters(request, loginJson); @@ -96,8 +101,8 @@ private void invokeCustomEndpoint(String uri, Filter cookieFilter, Consumer> findWebAuthnCredentialsByCredID(String credId) { + public Uni findByCredentialId(String credId) { assertVirtualThread(); - return super.findWebAuthnCredentialsByCredID(credId); + return super.findByCredentialId(credId); } @Override - public Uni> findWebAuthnCredentialsByUserName(String userId) { + public Uni> findByUserName(String userId) { assertVirtualThread(); - return super.findWebAuthnCredentialsByUserName(userId); + return super.findByUserName(userId); } @Override - public Uni updateOrStoreWebAuthnCredentials(Authenticator authenticator) { + public Uni store(WebAuthnCredentialRecord credentialRecord) { assertVirtualThread(); - return super.updateOrStoreWebAuthnCredentials(authenticator); + return super.store(credentialRecord); + } + + @Override + public Uni update(String credentialId, long counter) { + assertVirtualThread(); + return super.update(credentialId, counter); } private void assertVirtualThread() { diff --git a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/main/resources/application.properties b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/main/resources/application.properties index e69de29bb2d1d..6ef5d8c9ccb2e 100644 --- a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/main/resources/application.properties +++ b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/main/resources/application.properties @@ -0,0 +1,2 @@ +quarkus.webauthn.enable-login-endpoint=true +quarkus.webauthn.enable-registration-endpoint=true diff --git a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadIT.java b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadIT.java index 6ff6f8303ec7c..eb9848e45cec4 100644 --- a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadIT.java +++ b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadIT.java @@ -2,9 +2,12 @@ import static io.quarkus.virtual.security.webauthn.RunOnVirtualThreadTest.checkLoggedIn; +import java.net.URL; + import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; +import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.junit.QuarkusIntegrationTest; import io.quarkus.test.security.webauthn.WebAuthnEndpointHelper; import io.quarkus.test.security.webauthn.WebAuthnHardware; @@ -15,6 +18,9 @@ @QuarkusIntegrationTest class RunOnVirtualThreadIT { + @TestHTTPResource + URL url; + @Test public void test() { @@ -30,12 +36,12 @@ public void test() { .get("/cheese").then().statusCode(302); CookieFilter cookieFilter = new CookieFilter(); - WebAuthnHardware hardwareKey = new WebAuthnHardware(); - String challenge = WebAuthnEndpointHelper.invokeRegistration("stef", cookieFilter); + WebAuthnHardware hardwareKey = new WebAuthnHardware(url); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); JsonObject registration = hardwareKey.makeRegistrationJson(challenge); // now finalise - WebAuthnEndpointHelper.invokeCallback(registration, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration(registration, cookieFilter); // make sure our login cookie works checkLoggedIn(cookieFilter); @@ -43,11 +49,11 @@ public void test() { // reset cookies for the login phase cookieFilter = new CookieFilter(); // now try to log in - challenge = WebAuthnEndpointHelper.invokeLogin("stef", cookieFilter); + challenge = WebAuthnEndpointHelper.obtainLoginChallenge("stef", cookieFilter); JsonObject login = hardwareKey.makeLoginJson(challenge); // now finalise - WebAuthnEndpointHelper.invokeCallback(login, cookieFilter); + WebAuthnEndpointHelper.invokeLogin(login, cookieFilter); // make sure our login cookie still works checkLoggedIn(cookieFilter); diff --git a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java index 4d73fc4210d59..046c855e2a237 100644 --- a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java +++ b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java @@ -1,7 +1,6 @@ package io.quarkus.virtual.security.webauthn; -import static org.hamcrest.Matchers.is; - +import java.net.URL; import java.util.List; import jakarta.inject.Inject; @@ -10,7 +9,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnUserProvider; +import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit5.virtual.ShouldNotPin; import io.quarkus.test.junit5.virtual.VirtualThreadUnit; @@ -19,7 +20,6 @@ import io.restassured.RestAssured; import io.restassured.filter.cookie.CookieFilter; import io.vertx.core.json.JsonObject; -import io.vertx.ext.auth.webauthn.Authenticator; @QuarkusTest @VirtualThreadUnit @@ -29,6 +29,9 @@ class RunOnVirtualThreadTest { @Inject WebAuthnUserProvider userProvider; + @TestHTTPResource + URL url; + @Test public void test() throws Exception { @@ -43,17 +46,17 @@ public void test() throws Exception { .given().redirects().follow(false) .get("/cheese").then().statusCode(302); - Assertions.assertTrue(userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); - WebAuthnHardware hardwareKey = new WebAuthnHardware(); - String challenge = WebAuthnEndpointHelper.invokeRegistration("stef", cookieFilter); + WebAuthnHardware hardwareKey = new WebAuthnHardware(url); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); JsonObject registration = hardwareKey.makeRegistrationJson(challenge); // now finalise - WebAuthnEndpointHelper.invokeCallback(registration, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration(registration, cookieFilter); // make sure we stored the user - List users = userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely(); + List users = userProvider.findByUserName("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); Assertions.assertTrue(users.get(0).getUserName().equals("stef")); Assertions.assertEquals(1, users.get(0).getCounter()); @@ -64,14 +67,14 @@ public void test() throws Exception { // reset cookies for the login phase cookieFilter = new CookieFilter(); // now try to log in - challenge = WebAuthnEndpointHelper.invokeLogin("stef", cookieFilter); + challenge = WebAuthnEndpointHelper.obtainLoginChallenge("stef", cookieFilter); JsonObject login = hardwareKey.makeLoginJson(challenge); // now finalise - WebAuthnEndpointHelper.invokeCallback(login, cookieFilter); + WebAuthnEndpointHelper.invokeLogin(login, cookieFilter); // make sure we bumped the user - users = userProvider.findWebAuthnCredentialsByUserName("stef").await().indefinitely(); + users = userProvider.findByUserName("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); Assertions.assertTrue(users.get(0).getUserName().equals("stef")); Assertions.assertEquals(2, users.get(0).getCounter()); diff --git a/test-framework/security-webauthn/pom.xml b/test-framework/security-webauthn/pom.xml index 38923a799df21..3699d95ab3cf9 100644 --- a/test-framework/security-webauthn/pom.xml +++ b/test-framework/security-webauthn/pom.xml @@ -1,7 +1,7 @@ - + io.quarkus quarkus-test-framework diff --git a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java index f99e0b00a4057..9ff0b8132e6e1 100644 --- a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java +++ b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java @@ -14,7 +14,7 @@ import io.vertx.core.json.JsonObject; public class WebAuthnEndpointHelper { - public static String invokeRegistration(String userName, Filter cookieFilter) { + public static String obtainRegistrationChallenge(String userName, Filter cookieFilter) { JsonObject registerJson = new JsonObject() .put("name", userName); ExtractableResponse response = RestAssured @@ -22,9 +22,10 @@ public static String invokeRegistration(String userName, Filter cookieFilter) { .contentType(ContentType.JSON) .filter(cookieFilter) .log().ifValidationFails() - .post("/q/webauthn/register") - .then().statusCode(200) + .post("/q/webauthn/register-options-challenge") + .then() .log().ifValidationFails() + .statusCode(200) .cookie(getChallengeCookie(), Matchers.notNullValue()) .cookie(getChallengeUsernameCookie(), Matchers.notNullValue()) .extract(); @@ -35,21 +36,37 @@ public static String invokeRegistration(String userName, Filter cookieFilter) { return challenge; } - public static void invokeCallback(JsonObject registration, Filter cookieFilter) { + public static void invokeLogin(JsonObject login, Filter cookieFilter) { + RestAssured + .given().body(login.encode()) + .filter(cookieFilter) + .contentType(ContentType.JSON) + .log().ifValidationFails() + .post("/q/webauthn/login") + .then() + .log().ifValidationFails() + .statusCode(204) + .cookie(getChallengeCookie(), Matchers.is("")) + .cookie(getChallengeUsernameCookie(), Matchers.is("")) + .cookie(getMainCookie(), Matchers.notNullValue()); + } + + public static void invokeRegistration(JsonObject registration, Filter cookieFilter) { RestAssured .given().body(registration.encode()) .filter(cookieFilter) .contentType(ContentType.JSON) .log().ifValidationFails() - .post("/q/webauthn/callback") - .then().statusCode(204) + .post("/q/webauthn/register") + .then() .log().ifValidationFails() + .statusCode(204) .cookie(getChallengeCookie(), Matchers.is("")) .cookie(getChallengeUsernameCookie(), Matchers.is("")) .cookie(getMainCookie(), Matchers.notNullValue()); } - public static String invokeLogin(String userName, Filter cookieFilter) { + public static String obtainLoginChallenge(String userName, Filter cookieFilter) { JsonObject loginJson = new JsonObject() .put("name", userName); ExtractableResponse response = RestAssured @@ -57,9 +74,10 @@ public static String invokeLogin(String userName, Filter cookieFilter) { .contentType(ContentType.JSON) .filter(cookieFilter) .log().ifValidationFails() - .post("/q/webauthn/login") - .then().statusCode(200) + .post("/q/webauthn/login-options-challenge") + .then() .log().ifValidationFails() + .statusCode(200) .cookie(getChallengeCookie(), Matchers.notNullValue()) .cookie(getChallengeUsernameCookie(), Matchers.notNullValue()) .extract(); diff --git a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnHardware.java b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnHardware.java index 3dabdb619f5f9..c8f7197d9eb3a 100644 --- a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnHardware.java +++ b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnHardware.java @@ -2,6 +2,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -19,18 +20,17 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.dataformat.cbor.CBORFactory; +import com.webauthn4j.data.attestation.authenticator.AuthenticatorData; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.impl.Codec; -import io.vertx.ext.auth.webauthn.impl.AuthData; /** * Provides an emulation of a WebAuthn hardware token, suitable for generating registration * and login JSON objects that you can send to the Quarkus WebAuthn Security extension. * - * The public/private key and id/credID are randomly generated and different for every instance, - * and the origin is always for http://localhost + * The public/private key and id/credID are randomly generated and different for every instance. */ public class WebAuthnHardware { @@ -38,8 +38,9 @@ public class WebAuthnHardware { private String id; private byte[] credID; private int counter = 1; + private URL origin; - public WebAuthnHardware() { + public WebAuthnHardware(URL origin) { KeyPairGenerator generator; try { generator = KeyPairGenerator.getInstance("EC"); @@ -53,6 +54,7 @@ public WebAuthnHardware() { credID = new byte[32]; random.nextBytes(credID); id = Base64.getUrlEncoder().withoutPadding().encodeToString(credID); + this.origin = origin; } /** @@ -65,11 +67,11 @@ public JsonObject makeRegistrationJson(String challenge) { JsonObject clientData = new JsonObject() .put("type", "webauthn.create") .put("challenge", challenge) - .put("origin", "http://localhost") + .put("origin", origin.toString()) .put("crossOrigin", false); String clientDataEncoded = Base64.getUrlEncoder().encodeToString(clientData.encode().getBytes(StandardCharsets.UTF_8)); - byte[] authBytes = makeAuthBytes(); + byte[] authBytes = makeAuthBytes(true); /* * {"fmt": "none", "attStmt": {}, "authData": h'DATAAAAA'} */ @@ -108,12 +110,12 @@ public JsonObject makeLoginJson(String challenge) { JsonObject clientData = new JsonObject() .put("type", "webauthn.get") .put("challenge", challenge) - .put("origin", "http://localhost") + .put("origin", origin.toString()) .put("crossOrigin", false); byte[] clientDataBytes = clientData.encode().getBytes(StandardCharsets.UTF_8); String clientDataEncoded = Base64.getUrlEncoder().encodeToString(clientDataBytes); - byte[] authBytes = makeAuthBytes(); + byte[] authBytes = makeAuthBytes(false); String authenticatorData = Base64.getUrlEncoder().encodeToString(authBytes); // sign the authbytes + hash(client data json) @@ -148,7 +150,7 @@ public JsonObject makeLoginJson(String challenge) { .put("type", "public-key"); } - private byte[] makeAuthBytes() { + private byte[] makeAuthBytes(boolean attest) { Buffer buffer = Buffer.buffer(); String rpDomain = "localhost"; @@ -161,45 +163,47 @@ private byte[] makeAuthBytes() { byte[] rpIdHash = md.digest(rpDomain.getBytes(StandardCharsets.UTF_8)); buffer.appendBytes(rpIdHash); - byte flags = AuthData.ATTESTATION_DATA | AuthData.USER_PRESENT; + byte flags = AuthenticatorData.BIT_AT | AuthenticatorData.BIT_UP | AuthenticatorData.BIT_UV; buffer.appendByte(flags); long signCounter = counter++; buffer.appendUnsignedInt(signCounter); - // Attested Data is present - String aaguidString = "00000000-0000-0000-0000-000000000000"; - String aaguidStringShort = aaguidString.replace("-", ""); - byte[] aaguid = Codec.base16Decode(aaguidStringShort); - buffer.appendBytes(aaguid); - - buffer.appendUnsignedShort(credID.length); - buffer.appendBytes(credID); - - ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic(); - Encoder urlEncoder = Base64.getUrlEncoder(); - String x = urlEncoder.encodeToString(publicKey.getW().getAffineX().toByteArray()); - String y = urlEncoder.encodeToString(publicKey.getW().getAffineY().toByteArray()); - - CBORFactory cborFactory = new CBORFactory(); - ByteArrayOutputStream byteWriter = new ByteArrayOutputStream(); - try { - JsonGenerator generator = cborFactory.createGenerator(byteWriter); - generator.writeStartObject(); - // see CWK and https://tools.ietf.org/html/rfc8152#section-7.1 - generator.writeNumberField("1", 2); // kty: "EC" - generator.writeNumberField("3", -7); // alg: "ES256" - generator.writeNumberField("-1", 1); // crv: "P-256" - // https://tools.ietf.org/html/rfc8152#section-13.1.1 - generator.writeStringField("-2", x); // x, base64url - generator.writeStringField("-3", y); // y, base64url - generator.writeEndObject(); - generator.close(); - } catch (IOException t) { - throw new RuntimeException(t); + if (attest) { + // Attested Data is present + String aaguidString = "00000000-0000-0000-0000-000000000000"; + String aaguidStringShort = aaguidString.replace("-", ""); + byte[] aaguid = Codec.base16Decode(aaguidStringShort); + buffer.appendBytes(aaguid); + + buffer.appendUnsignedShort(credID.length); + buffer.appendBytes(credID); + + ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic(); + // NOTE: this used to be Base64 URL, but webauthn4j refuses it and wants Base64. I can't find in the spec where it's specified. + Encoder urlEncoder = Base64.getEncoder(); + String x = urlEncoder.encodeToString(publicKey.getW().getAffineX().toByteArray()); + String y = urlEncoder.encodeToString(publicKey.getW().getAffineY().toByteArray()); + + CBORFactory cborFactory = new CBORFactory(); + ByteArrayOutputStream byteWriter = new ByteArrayOutputStream(); + try { + JsonGenerator generator = cborFactory.createGenerator(byteWriter); + generator.writeStartObject(); + // see CWK and https://tools.ietf.org/html/rfc8152#section-7.1 + generator.writeNumberField("1", 2); // kty: "EC" + generator.writeNumberField("3", -7); // alg: "ES256" + generator.writeNumberField("-1", 1); // crv: "P-256" + // https://tools.ietf.org/html/rfc8152#section-13.1.1 + generator.writeStringField("-2", x); // x, base64url + generator.writeStringField("-3", y); // y, base64url + generator.writeEndObject(); + generator.close(); + } catch (IOException t) { + throw new RuntimeException(t); + } + buffer.appendBytes(byteWriter.toByteArray()); } - buffer.appendBytes(byteWriter.toByteArray()); - return buffer.getBytes(); } diff --git a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnHelper.java b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnHelper.java new file mode 100644 index 0000000000000..19011267cb182 --- /dev/null +++ b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnHelper.java @@ -0,0 +1,265 @@ +package io.quarkus.test.security.webauthn; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.dataformat.cbor.CBORFactory; +import com.fasterxml.jackson.dataformat.cbor.CBORParser; +import com.webauthn4j.util.Base64UrlUtil; + +import io.quarkus.security.webauthn.WebAuthnLoginResponse; +import io.quarkus.security.webauthn.WebAuthnRegisterResponse; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.json.JsonObject; + +public class WebAuthnHelper { + public static class PrettyPrinter { + private int indent; + + private void indent() { + for (int i = 0; i < indent; i++) { + System.err.print(" "); + } + } + + public void handleToken(CBORParser parser, JsonToken t) throws IOException { + switch (t) { + case END_ARRAY: + endArray(); + break; + case END_OBJECT: + endObject(); + break; + case FIELD_NAME: + fieldName(parser.currentName()); + break; + case NOT_AVAILABLE: + break; + case START_ARRAY: + startArray(); + break; + case START_OBJECT: + startObject(); + break; + case VALUE_EMBEDDED_OBJECT: + Object embeddedObject = parser.getEmbeddedObject(); + if (parser.currentName().equals("authData")) { + dumpAuthData((byte[]) embeddedObject); + } else { + System.err.println(embeddedObject); + } + break; + case VALUE_FALSE: + falseConstant(); + break; + case VALUE_NULL: + nullConstant(); + break; + case VALUE_NUMBER_FLOAT: + floatValue(parser.getFloatValue()); + break; + case VALUE_NUMBER_INT: + intValue(parser.getNumberValue()); + break; + case VALUE_STRING: + stringValue(parser.getValueAsString()); + break; + case VALUE_TRUE: + trueConstant(); + break; + default: + break; + + } + + } + + private void floatValue(float floatValue) { + System.err.println(floatValue); + } + + private void intValue(Number numberValue) { + System.err.println(numberValue); + } + + private void stringValue(String value) { + System.err.println("\"" + value + "\""); + } + + private void nullConstant() { + System.err.println("null"); + } + + private void trueConstant() { + System.err.println("true"); + } + + private void falseConstant() { + System.err.println("false"); + } + + private void startObject() { + indent(); + System.err.println("{"); + indent++; + } + + private void startArray() { + indent(); + System.err.println("["); + indent++; + } + + public void fieldName(String name) { + indent(); + System.err.print("\""); + System.err.print(name); + System.err.print("\": "); + } + + public void endObject() { + indent(); + System.err.println("}"); + indent--; + } + + public void endArray() { + indent(); + System.err.println("]"); + indent--; + } + + private void dumpAuthData(byte[] embeddedObject) throws IOException { + Buffer buf = Buffer.buffer(embeddedObject); + startObject(); + int current = 0; + byte[] rpIdHash = buf.getBytes(0, 32); + current += 32; + fieldName("rpIdHash"); + stringValue(""); // TODO + byte flags = buf.getByte(current); + current += 1; + fieldName("flags"); + intValue(flags); // TODO in binary + long counter = buf.getUnsignedInt(current); + current += 4; + fieldName("counter"); + intValue(counter); + if (embeddedObject.length > current) { + fieldName("attestedCredentialData"); + startObject(); + byte[] aaguid = buf.getBytes(current, current + 16); + current += 16; + fieldName("aaguid"); + stringValue(Base64UrlUtil.encodeToString(aaguid)); + + int credentialIdLength = buf.getUnsignedShort(current); + current += 2; + fieldName("credentialIdLength"); + intValue(credentialIdLength); + + byte[] credentialId = buf.getBytes(current, current + credentialIdLength); + current += credentialIdLength; + fieldName("credentialId"); + stringValue(Base64UrlUtil.encodeToString(credentialId)); + + fieldName("credentialPublicKey"); + current += readCBOR(embeddedObject, current); + + endObject(); + } + // TODO: there's more + endObject(); + } + + private int readCBOR(byte[] bytes, int offset) throws IOException { + CBORFactory factory = CBORFactory.builder().build(); + long lastReadByte = offset; + try (CBORParser parser = factory.createParser(bytes, offset, bytes.length - offset)) { + JsonToken t; + while ((t = parser.nextToken()) != null) { + // System.err.println("Token: "+t); + handleToken(parser, t); + } + lastReadByte = parser.currentLocation().getByteOffset(); + } + return (int) (lastReadByte - offset); + } + } + + public static void dumpWebAuthnRequest(JsonObject json) throws IOException { + System.err.println(json.encodePrettily()); + JsonObject response = json.getJsonObject("response"); + if (response != null) { + String attestationObject = response.getString("attestationObject"); + if (attestationObject != null) { + System.err.println("Attestation object:"); + dumpAttestationObject(attestationObject); + } + String authenticatorData = response.getString("authenticatorData"); + if (authenticatorData != null) { + System.err.println("Authenticator Data:"); + dumpAuthenticatorData(authenticatorData); + } + String clientDataJSON = response.getString("clientDataJSON"); + if (clientDataJSON != null) { + System.err.println("Client Data JSON:"); + String encoded = new String(Base64UrlUtil.decode(clientDataJSON), StandardCharsets.UTF_8); + System.err.println(new JsonObject(encoded).encodePrettily()); + } + } + } + + private static void dumpAttestationObject(String attestationObject) throws IOException { + CBORFactory factory = CBORFactory.builder().build(); + PrettyPrinter printer = new PrettyPrinter(); + try (CBORParser parser = factory.createParser(Base64UrlUtil.decode(attestationObject))) { + JsonToken t; + while ((t = parser.nextToken()) != null) { + // System.err.println("Token: "+t); + printer.handleToken(parser, t); + } + } + } + + private static void dumpAuthenticatorData(String authenticatorData) throws IOException { + PrettyPrinter printer = new PrettyPrinter(); + byte[] bytes = Base64UrlUtil.decode(authenticatorData); + printer.dumpAuthData(bytes); + } + + public static void dumpWebAuthnRequest(WebAuthnRegisterResponse response) { + try { + dumpWebAuthnRequest(response.toJsonObject()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void dumpWebAuthnRequest(WebAuthnLoginResponse response) { + try { + dumpWebAuthnRequest(response.toJsonObject()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + // WebAuthnRegisterResponse response = new WebAuthnRegisterResponse(); + // response.webAuthnId = "N3P8WalYEtlUPMcD8q7C8hfY9tZ-DZBl7oPZNGMBxjk"; + // response.webAuthnRawId = "N3P8WalYEtlUPMcD8q7C8hfY9tZ-DZBl7oPZNGMBxjk"; + // response.webAuthnResponseAttestationObject = "v2NmbXRkbm9uZWdhdHRTdG10v_9oYXV0aERhdGFYxUmWDeWIDoxodDQXD2R2YFuP5K65ooYyx5lc87qDHZdjQQAAAAEAAAAAAAAAAAAAAAAAAAAAACA3c_xZqVgS2VQ8xwPyrsLyF9j21n4NkGXug9k0YwHGOb9hMQJhMyZiLTEBYi0yeCxGR0hxMHlCTWJ5X1RuOGpmWlU4XzZSTDlFNFg4ZnhJSkVOY05NN3UtSEFRPWItM3gsQUtNVEtFRG5DSzhnVVNxamRtdU45bnVzbTRRRXJNY0pBNjV6OWhJOW5TWlP__w=="; + // response.webAuthnResponseClientDataJSON = "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibk9uVHRac1diSE5rRWNhOEZYY29NVUdIanJOY1c4S1BybWg0REFPQXFxaUVvRDNYdHhVT09TcXFiVXFndHlEbkEzU1VCM25YS21PRUp2WGNFZTBfVnciLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0IiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ=="; + // response.webAuthnType = "public-key"; + // dumpWebAuthnRequest(response); + WebAuthnLoginResponse response = new WebAuthnLoginResponse(); + response.webAuthnId = "cmokxFnWpNiqBDgI8qL41usvkUCeZC_J8EVS_jD0Brw"; + response.webAuthnRawId = "cmokxFnWpNiqBDgI8qL41usvkUCeZC_J8EVS_jD0Brw"; + response.webAuthnResponseAuthenticatorData = "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NBAAAAAgAAAAAAAAAAAAAAAAAAAAAAIHJqJMRZ1qTYqgQ4CPKi-NbrL5FAnmQvyfBFUv4w9Aa8v2ExAmEzJmItMQFiLTJ4LFhCbHRrY25LZ2xjTU94bmZYSnAydE1xc2RESFBhNVB5YnIvaFJUY2tSU3c9Yi0zeCxjZWQvdHRvZGdaQjhmUGdHZ0NIM3lIUUU5NjUzVk5GdTNET2JqNFNtZ2dRPf8="; + response.webAuthnResponseSignature = "MEUCIQDlT0NRyeElINrF59m54fsAhjVh09ykApfKzUsFw1qCVQIgHHkrPCQedlVo_fWcb7p8ch7tAT8mt3h3-GihBUP8s4o="; + response.webAuthnResponseClientDataJSON = "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiQTdYTDFvOTlINEdRZXBESDI5MnAzSUdwU0NNRHU3cUVlRVEwY3dWMU5BYm82ZzFjbC1yc2pGRHZuaVdwbE5hdk1rX1Z4YkJVcG8wdE00c2V2bXpaQUEiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwODEvIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ=="; + response.webAuthnType = "public-key"; + dumpWebAuthnRequest(response); + } +} diff --git a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnTestUserProvider.java b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnTestUserProvider.java index b18ad798661b8..e6a5ca5509e71 100644 --- a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnTestUserProvider.java +++ b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnTestUserProvider.java @@ -1,29 +1,29 @@ package io.quarkus.test.security.webauthn; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; +import com.webauthn4j.util.Base64UrlUtil; + +import io.quarkus.security.webauthn.WebAuthnCredentialRecord; import io.quarkus.security.webauthn.WebAuthnUserProvider; import io.smallrye.mutiny.Uni; -import io.vertx.ext.auth.webauthn.Authenticator; /** - * UserProvider suitable for tests, which stores and updates credentials in a list, + * UserProvider suitable for tests, which fetches and updates credentials from a list, * so you can use it in your tests. - * - * @see WebAuthnStoringTestUserProvider - * @see WebAuthnManualTestUserProvider */ public class WebAuthnTestUserProvider implements WebAuthnUserProvider { - private List auths = new ArrayList<>(); + private List auths = new ArrayList<>(); @Override - public Uni> findWebAuthnCredentialsByUserName(String userId) { - List ret = new ArrayList<>(); - for (Authenticator authenticator : auths) { + public Uni> findByUserName(String userId) { + List ret = new ArrayList<>(); + for (WebAuthnCredentialRecord authenticator : auths) { if (authenticator.getUserName().equals(userId)) { ret.add(authenticator); } @@ -32,38 +32,26 @@ public Uni> findWebAuthnCredentialsByUserName(String userId) } @Override - public Uni> findWebAuthnCredentialsByCredID(String credId) { - List ret = new ArrayList<>(); - for (Authenticator authenticator : auths) { - if (authenticator.getCredID().equals(credId)) { - ret.add(authenticator); + public Uni findByCredentialId(String credId) { + byte[] bytes = Base64UrlUtil.decode(credId); + for (WebAuthnCredentialRecord authenticator : auths) { + if (Arrays.equals(authenticator.getAttestedCredentialData().getCredentialId(), bytes)) { + return Uni.createFrom().item(authenticator); } } - return Uni.createFrom().item(ret); + return Uni.createFrom().failure(new RuntimeException("Credentials not found for credential ID " + credId)); } @Override - public Uni updateOrStoreWebAuthnCredentials(Authenticator authenticator) { - Authenticator existing = find(authenticator.getUserName(), authenticator.getCredID()); - if (existing != null) { - // update - existing.setCounter(authenticator.getCounter()); - } else { - // add - store(authenticator); - } - return Uni.createFrom().nullItem(); + public Uni update(String credentialId, long counter) { + reallyUpdate(credentialId, counter); + return Uni.createFrom().voidItem(); } - private Authenticator find(String userName, String credID) { - for (Authenticator auth : auths) { - if (userName.equals(auth.getUserName()) - && credID.equals(auth.getCredID())) { - // update - return auth; - } - } - return null; + @Override + public Uni store(WebAuthnCredentialRecord credentialRecord) { + reallyStore(credentialRecord); + return Uni.createFrom().voidItem(); } @Override @@ -71,24 +59,23 @@ public Set getRoles(String userId) { return Collections.singleton("admin"); } - /** - * Stores a new credential - * - * @param authenticator the new credential to store - */ - public void store(Authenticator authenticator) { - auths.add(authenticator); + // For tests + + public void clear() { + auths.clear(); + } + + public void reallyUpdate(String credentialId, long counter) { + byte[] bytes = Base64UrlUtil.decode(credentialId); + for (WebAuthnCredentialRecord authenticator : auths) { + if (Arrays.equals(authenticator.getAttestedCredentialData().getCredentialId(), bytes)) { + authenticator.setCounter(counter); + break; + } + } } - /** - * Updates an existing credential - * - * @param userName the user name - * @param credID the credential ID - * @param counter the new counter value - */ - public void update(String userName, String credID, long counter) { - Authenticator authenticator = find(userName, credID); - authenticator.setCounter(counter); + public void reallyStore(WebAuthnCredentialRecord credentialRecord) { + auths.add(credentialRecord); } } \ No newline at end of file From f410e5474eccd67f0b81a4ee9bdd6c4405a2e1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20=C3=89pardaud?= Date: Fri, 22 Nov 2024 10:28:22 +0100 Subject: [PATCH 032/207] Update extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java Co-authored-by: Sergey Beryozkin --- .../java/io/quarkus/security/webauthn/WebAuthnUserProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java index d61583e33812b..8ae49203244fc 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java @@ -32,7 +32,7 @@ public interface WebAuthnUserProvider { public Uni findByCredentialId(String credentialId); /** - * Update an existing WebAuthn credential's counter. This is only used by the default login enpdoint, which + * Update an existing WebAuthn credential's counter. This is only used by the default login endpoint, which * is disabled by default and can be enabled via the quarkus.webauthn.enable-login-endpoint. * You don't have to implement this method * if you handle logins manually via {@link WebAuthnSecurity#login(WebAuthnLoginResponse, io.vertx.ext.web.RoutingContext)}. From a69385edce589a0a7a17e87dd8e1954ecf30c15d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20=C3=89pardaud?= Date: Fri, 22 Nov 2024 10:28:37 +0100 Subject: [PATCH 033/207] Update extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java Co-authored-by: Sergey Beryozkin --- .../java/io/quarkus/security/webauthn/WebAuthnUserProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java index 8ae49203244fc..8cbae8bdb9548 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java @@ -47,7 +47,7 @@ public default Uni update(String credentialId, long counter) { } /** - * Store a new WebAuthn credential. This is only used by the default registration enpdoint, which + * Store a new WebAuthn credential. This is only used by the default registration endpoint, which * is disabled by default and can be enabled via the quarkus.webauthn.enable-registration-endpoint. * You don't have to implement this method if you handle registration manually via * {@link WebAuthnSecurity#register(WebAuthnRegisterResponse, io.vertx.ext.web.RoutingContext)} From 39b5a78b5c34fe14e7938bc16db99aca0bea3086 Mon Sep 17 00:00:00 2001 From: Yoshikazu Nojima Date: Fri, 15 Nov 2024 17:09:11 +0900 Subject: [PATCH 034/207] Reuse challenge when it is restorable --- .../security/webauthn/test/WebAuthnTest.java | 52 +++++++++++++++++++ .../security/webauthn/WebAuthnSecurity.java | 16 +++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java index fb3114039b8b8..554ec52f81fa0 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java @@ -1,5 +1,6 @@ package io.quarkus.security.webauthn.test; +import io.restassured.filter.cookie.CookieFilter; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -40,6 +41,57 @@ public void testLoginRpFromFirstOrigin() { .body("rp.id", Matchers.equalTo("localhost")); } + @Test + public void testRegisterChallengeIsEqualAcrossCalls() { + CookieFilter cookieFilter = new CookieFilter(); + + String challenge = RestAssured + .given() + .filter(cookieFilter) + .body(new JsonObject() + .put("name", "foo").encode()) + .contentType(ContentType.JSON) + .post("/q/webauthn/register-options-challenge") + .jsonPath().get("challenge"); + + RestAssured + .given() + .filter(cookieFilter) + .body(new JsonObject() + .put("name", "foo").encode()) + .contentType(ContentType.JSON) + .post("/q/webauthn/register-options-challenge") + .then() + .statusCode(200) + .contentType(ContentType.JSON) + .body("challenge", Matchers.equalTo(challenge)); + } + + @Test + public void testLoginChallengeIsEqualAcrossCalls() { + CookieFilter cookieFilter = new CookieFilter(); + + String challenge = RestAssured + .given() + .filter(cookieFilter) + .body(new JsonObject().encode()) + .contentType(ContentType.JSON) + .post("/q/webauthn/login-options-challenge") + .jsonPath().get("challenge"); + + RestAssured + .given() + .filter(cookieFilter) + .body(new JsonObject().encode()) + .contentType(ContentType.JSON) + .post("/q/webauthn/login-options-challenge") + .then() + .statusCode(200) + .contentType(ContentType.JSON) + .body("challenge", Matchers.equalTo(challenge)); + } + + @Test public void testWellKnownDefault() { String origin = url; diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java index 368a76327a409..cd154bb021bf7 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java @@ -333,7 +333,7 @@ public Uni getRegisterChallenge(String userN displayName = userName; } String finalDisplayName = displayName; - String challenge = randomBase64URLBuffer(); + String challenge = getOrCreateChallenge(ctx); Origin origin = Origin.create(!this.origins.isEmpty() ? this.origins.get(0) : ctx.request().absoluteURI()); String rpId = this.rpId != null ? this.rpId : origin.getHost(); @@ -397,7 +397,7 @@ public Uni getLoginChallenge(String userName, userName = ""; } String finalUserName = userName; - String challenge = randomBase64URLBuffer(); + String challenge = getOrCreateChallenge(ctx); Origin origin = Origin.create(!this.origins.isEmpty() ? this.origins.get(0) : ctx.request().absoluteURI()); String rpId = this.rpId != null ? this.rpId : origin.getHost(); @@ -444,6 +444,18 @@ public Uni getLoginChallenge(String userName, }); } + private String getOrCreateChallenge(RoutingContext ctx) { + RestoreResult challengeRestoreResult = authMech.getLoginManager().restore(ctx, challengeCookie); + String challenge; + if (challengeRestoreResult == null || challengeRestoreResult.getPrincipal() == null + || challengeRestoreResult.getPrincipal().isEmpty()) { + challenge = randomBase64URLBuffer(); + } else { + challenge = challengeRestoreResult.getPrincipal(); + } + return challenge; + } + /** * Registers a new WebAuthn credentials. This will check it, clear the cookies and return it in case of * success, but not invoke {@link WebAuthnUserProvider#store(WebAuthnCredentialRecord)}, you have to do From f7d857fcc21306de4221f32e9e75ed86a4c205b1 Mon Sep 17 00:00:00 2001 From: Yoshikazu Nojima Date: Thu, 21 Nov 2024 14:40:19 +0900 Subject: [PATCH 035/207] Take username from query parameter on register endpoint --- .../security/webauthn/test/ManualResource.java | 6 ++++-- .../webauthn/test/WebAuthnAndBasicAuthnTest.java | 1 + .../security/webauthn/test/WebAuthnAutomaticTest.java | 2 +- .../test/WebAuthnManualCustomCookiesTest.java | 1 + .../security/webauthn/test/WebAuthnManualTest.java | 3 ++- .../quarkus/security/webauthn/test/WebAuthnTest.java | 3 +-- .../quarkus/security/webauthn/WebAuthnController.java | 3 ++- .../quarkus/security/webauthn/WebAuthnRecorder.java | 6 ++++-- .../quarkus/security/webauthn/WebAuthnSecurity.java | 11 +++++------ .../quarkus/it/security/webauthn/LoginResource.java | 2 +- .../security/webauthn/test/WebAuthnResourceTest.java | 2 +- .../security/webauthn/RunOnVirtualThreadIT.java | 2 +- .../security/webauthn/RunOnVirtualThreadTest.java | 2 +- .../security/webauthn/WebAuthnEndpointHelper.java | 3 ++- 14 files changed, 27 insertions(+), 20 deletions(-) diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java index 12559d36c4d5c..42fd2c508e285 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.BeanParam; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; import io.quarkus.security.webauthn.WebAuthnLoginResponse; import io.quarkus.security.webauthn.WebAuthnRegisterResponse; @@ -23,8 +24,9 @@ public class ManualResource { @Path("register") @POST - public Uni register(@BeanParam WebAuthnRegisterResponse register, RoutingContext ctx) { - return security.register(register, ctx).map(authenticator -> { + public Uni register(@QueryParam("username") String username, @BeanParam WebAuthnRegisterResponse register, + RoutingContext ctx) { + return security.register(username, register, ctx).map(authenticator -> { // need to attach the authenticator to the user userProvider.reallyStore(authenticator); security.rememberUser(authenticator.getUserName(), ctx); diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java index f6bb3b188511e..f3dcbd0a03c05 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java @@ -71,6 +71,7 @@ public void test() throws Exception { .build() .getConfigMapping(WebAuthnRunTimeConfig.class); request + .queryParam("username", "stev") .post("/register") .then().statusCode(200) .body(Matchers.is("OK")) diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java index 9c601b6c5a5df..ce1074c868e2b 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java @@ -47,7 +47,7 @@ public void test() throws Exception { JsonObject registration = hardwareKey.makeRegistrationJson(challenge); // now finalise - WebAuthnEndpointHelper.invokeRegistration(registration, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration("stef", registration, cookieFilter); // make sure we stored the user List users = userProvider.findByUserName("stef").await().indefinitely(); diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java index 4bb16011ac76e..e5e1b9f33c3ee 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java @@ -69,6 +69,7 @@ public void test() throws Exception { .filter(cookieFilter); WebAuthnEndpointHelper.addWebAuthnRegistrationFormParameters(request, registration); request + .queryParam("username", "stef") .post("/register") .then().statusCode(200) .body(Matchers.is("OK")) diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java index 70ac351225693..7ec12db47d843 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java @@ -69,6 +69,7 @@ public void test() throws Exception { WebAuthnEndpointHelper.addWebAuthnRegistrationFormParameters(request, registration); request .log().ifValidationFails() + .queryParam("username", "stef") .post("/register") .then().statusCode(200) .log().ifValidationFails() @@ -144,7 +145,7 @@ public void checkDefaultRegistrationDisabled() { // now finalise Assertions.assertThrows(AssertionError.class, - () -> WebAuthnEndpointHelper.invokeRegistration(registration, cookieFilter)); + () -> WebAuthnEndpointHelper.invokeRegistration("stef", registration, cookieFilter)); // make sure we did not create any user Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java index 554ec52f81fa0..f671a33f0cd1a 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java @@ -1,6 +1,5 @@ package io.quarkus.security.webauthn.test; -import io.restassured.filter.cookie.CookieFilter; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -9,6 +8,7 @@ import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; import io.restassured.RestAssured; +import io.restassured.filter.cookie.CookieFilter; import io.restassured.http.ContentType; import io.vertx.core.json.JsonObject; @@ -91,7 +91,6 @@ public void testLoginChallengeIsEqualAcrossCalls() { .body("challenge", Matchers.equalTo(challenge)); } - @Test public void testWellKnownDefault() { String origin = url; diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java index aeb165c5920f6..bbe16c5d3282c 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java @@ -124,10 +124,11 @@ public void login(RoutingContext ctx) { */ public void register(RoutingContext ctx) { try { + final String username = ctx.queryParams().get("username"); // might throw runtime exception if there's no json or is bad formed final JsonObject webauthnResp = ctx.getBodyAsJson(); - withContext(() -> security.register(webauthnResp, ctx)) + withContext(() -> security.register(username, webauthnResp, ctx)) .onItem().call(record -> security.storage().create(record)) .subscribe().with(record -> { security.rememberUser(record.getUserName(), ctx); diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java index eb309405ff015..f23f509f74dd0 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java @@ -38,8 +38,10 @@ public void setupRoutes(BeanContainer beanContainer, RuntimeValue router BodyHandler bodyHandler = BodyHandler.create(); // FIXME: paths configurable // prefix is the non-application root path, ends with a slash: defaults to /q/ - router.post(prefix + "webauthn/login-options-challenge").handler(bodyHandler).handler(controller::loginOptionsChallenge); - router.post(prefix + "webauthn/register-options-challenge").handler(bodyHandler).handler(controller::registerOptionsChallenge); + router.post(prefix + "webauthn/login-options-challenge").handler(bodyHandler) + .handler(controller::loginOptionsChallenge); + router.post(prefix + "webauthn/register-options-challenge").handler(bodyHandler) + .handler(controller::registerOptionsChallenge); if (config.getValue().enableLoginEndpoint().orElse(false)) { router.post(prefix + "webauthn/login").handler(bodyHandler).handler(controller::login); } diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java index cd154bb021bf7..92b15238bf0b4 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java @@ -467,8 +467,8 @@ private String getOrCreateChallenge(RoutingContext ctx) { * @param ctx the current request * @return the newly created credentials */ - public Uni register(WebAuthnRegisterResponse response, RoutingContext ctx) { - return register(response.toJsonObject(), ctx); + public Uni register(String username, WebAuthnRegisterResponse response, RoutingContext ctx) { + return register(username, response.toJsonObject(), ctx); } /** @@ -482,11 +482,10 @@ public Uni register(WebAuthnRegisterResponse response, * @param ctx the current request * @return the newly created credentials */ - public Uni register(JsonObject response, RoutingContext ctx) { + public Uni register(String username, JsonObject response, RoutingContext ctx) { RestoreResult challenge = authMech.getLoginManager().restore(ctx, challengeCookie); - RestoreResult username = authMech.getLoginManager().restore(ctx, challengeUsernameCookie); if (challenge == null || challenge.getPrincipal() == null || challenge.getPrincipal().isEmpty() - || username == null || username.getPrincipal() == null || username.getPrincipal().isEmpty()) { + || username == null || username.isEmpty()) { return Uni.createFrom().failure(new RuntimeException("Missing challenge or username")); } @@ -514,7 +513,7 @@ public Uni register(JsonObject response, RoutingContex removeCookie(ctx, challengeCookie); removeCookie(ctx, challengeUsernameCookie); }).map(registrationData -> new WebAuthnCredentialRecord( - username.getPrincipal(), + username, registrationData.getAttestationObject(), registrationData.getCollectedClientData(), registrationData.getClientExtensions(), diff --git a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java index 48ad47313c2e9..a34e51eb8e9b0 100644 --- a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java +++ b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java @@ -81,7 +81,7 @@ public Uni register(@RestForm String userName, // Duplicate user return Uni.createFrom().item(Response.status(Status.BAD_REQUEST).build()); } - Uni authenticator = this.webAuthnSecurity.register(webAuthnResponse, ctx); + Uni authenticator = this.webAuthnSecurity.register(userName, webAuthnResponse, ctx); return authenticator // store the user diff --git a/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java b/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java index 6db2c4cf2ffbf..edb1c8655b62c 100644 --- a/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java +++ b/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java @@ -54,7 +54,7 @@ private void testWebAuthn(String userName, User user, Endpoint endpoint) { String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge(userName, cookieFilter); JsonObject registrationJson = token.makeRegistrationJson(challenge); if (endpoint == Endpoint.DEFAULT) - WebAuthnEndpointHelper.invokeRegistration(registrationJson, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration(userName, registrationJson, cookieFilter); else { invokeCustomEndpoint("/register", cookieFilter, request -> { WebAuthnEndpointHelper.addWebAuthnRegistrationFormParameters(request, registrationJson); diff --git a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadIT.java b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadIT.java index eb9848e45cec4..711f4e5140444 100644 --- a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadIT.java +++ b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadIT.java @@ -41,7 +41,7 @@ public void test() { JsonObject registration = hardwareKey.makeRegistrationJson(challenge); // now finalise - WebAuthnEndpointHelper.invokeRegistration(registration, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration("stef", registration, cookieFilter); // make sure our login cookie works checkLoggedIn(cookieFilter); diff --git a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java index 046c855e2a237..a8f7b84031a7d 100644 --- a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java +++ b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java @@ -53,7 +53,7 @@ public void test() throws Exception { JsonObject registration = hardwareKey.makeRegistrationJson(challenge); // now finalise - WebAuthnEndpointHelper.invokeRegistration(registration, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration("stef", registration, cookieFilter); // make sure we stored the user List users = userProvider.findByUserName("stef").await().indefinitely(); diff --git a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java index 9ff0b8132e6e1..620a853e63a14 100644 --- a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java +++ b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java @@ -51,12 +51,13 @@ public static void invokeLogin(JsonObject login, Filter cookieFilter) { .cookie(getMainCookie(), Matchers.notNullValue()); } - public static void invokeRegistration(JsonObject registration, Filter cookieFilter) { + public static void invokeRegistration(String username, JsonObject registration, Filter cookieFilter) { RestAssured .given().body(registration.encode()) .filter(cookieFilter) .contentType(ContentType.JSON) .log().ifValidationFails() + .queryParam("username", username) .post("/q/webauthn/register") .then() .log().ifValidationFails() From f791c2d2c07e7ce295eced706f08523e89725418 Mon Sep 17 00:00:00 2001 From: Yoshikazu Nojima Date: Thu, 21 Nov 2024 15:00:41 +0900 Subject: [PATCH 036/207] Remove username cookie --- .../webauthn/test/WebAuthnAndBasicAuthnTest.java | 1 - .../test/WebAuthnManualCustomCookiesTest.java | 2 -- .../security/webauthn/test/WebAuthnManualTest.java | 2 -- .../security/webauthn/WebAuthnRunTimeConfig.java | 6 ------ .../quarkus/security/webauthn/WebAuthnSecurity.java | 13 ++----------- .../webauthn/test/WebAuthnResourceTest.java | 1 - .../security/webauthn/WebAuthnEndpointHelper.java | 10 ---------- 7 files changed, 2 insertions(+), 33 deletions(-) diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java index f3dcbd0a03c05..efa77f85bb7cf 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java @@ -76,7 +76,6 @@ public void test() throws Exception { .then().statusCode(200) .body(Matchers.is("OK")) .cookie(config.challengeCookieName(), Matchers.is("")) - .cookie(config.challengeUsernameCookieName(), Matchers.is("")) .cookie("quarkus-credential", Matchers.notNullValue()); // make sure we stored the user diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java index e5e1b9f33c3ee..c9c15baf3c6c8 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java @@ -74,7 +74,6 @@ public void test() throws Exception { .then().statusCode(200) .body(Matchers.is("OK")) .cookie("challenge-cookie", Matchers.is("")) - .cookie("username-cookie", Matchers.is("")) .cookie("main-cookie", Matchers.notNullValue()); // make sure we stored the user @@ -102,7 +101,6 @@ public void test() throws Exception { .then().statusCode(200) .body(Matchers.is("OK")) .cookie("challenge-cookie", Matchers.is("")) - .cookie("username-cookie", Matchers.is("")) .cookie("main-cookie", Matchers.notNullValue()); // make sure we bumped the user diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java index 7ec12db47d843..ef2a4c69886ca 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java @@ -75,7 +75,6 @@ public void test() throws Exception { .log().ifValidationFails() .body(Matchers.is("OK")) .cookie("_quarkus_webauthn_challenge", Matchers.is("")) - .cookie("_quarkus_webauthn_username", Matchers.is("")) .cookie("quarkus-credential", Matchers.notNullValue()); // make sure we stored the user @@ -105,7 +104,6 @@ public void test() throws Exception { .log().ifValidationFails() .body(Matchers.is("OK")) .cookie("_quarkus_webauthn_challenge", Matchers.is("")) - .cookie("_quarkus_webauthn_username", Matchers.is("")) .cookie("quarkus-credential", Matchers.notNullValue()); // make sure we bumped the user diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java index 6d55cfc38739a..1daac0b41b7c0 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRunTimeConfig.java @@ -425,12 +425,6 @@ interface RelyingPartyConfig { @WithDefault("_quarkus_webauthn_challenge") public String challengeCookieName(); - /** - * The cookie that is used to store the username data during login/registration - */ - @WithDefault("_quarkus_webauthn_username") - public String challengeUsernameCookieName(); - /** * SameSite attribute for the session cookie. */ diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java index 92b15238bf0b4..8dff0911b49da 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java @@ -189,7 +189,6 @@ public class WebAuthnSecurity { private VertxContextPRNG random; private String challengeCookie; - private String challengeUsernameCookie; private List origins; private String rpId; @@ -212,7 +211,6 @@ public WebAuthnSecurity(WebAuthnRunTimeConfig config, Vertx vertx, WebAuthnAuthe this.rpName = config.relyingParty().name(); this.origins = config.origins().orElse(Collections.emptyList()); this.challengeCookie = config.challengeCookieName(); - this.challengeUsernameCookie = config.challengeUsernameCookieName(); this.challengeLength = config.challengeLength().orElse(64); this.userPresenceRequired = config.userPresenceRequired().orElse(true); this.timeout = config.timeout().orElse(Duration.ofMinutes(5)); @@ -374,8 +372,6 @@ public Uni getRegisterChallenge(String userN // save challenge to the session authMech.getLoginManager().save(challenge, ctx, challengeCookie, null, ctx.request().isSSL()); - authMech.getLoginManager().save(userName, ctx, challengeUsernameCookie, null, - ctx.request().isSSL()); return publicKeyCredentialCreationOptions; }); @@ -437,8 +433,6 @@ public Uni getLoginChallenge(String userName, // save challenge to the session authMech.getLoginManager().save(challenge, ctx, challengeCookie, null, ctx.request().isSSL()); - authMech.getLoginManager().save(finalUserName, ctx, challengeUsernameCookie, null, - ctx.request().isSSL()); return publicKeyCredentialRequestOptions; }); @@ -511,7 +505,6 @@ public Uni register(String username, JsonObject respon .completionStage(webAuthn.verifyRegistrationResponseJSON(registrationResponseJSON, registrationParameters)) .eventually(() -> { removeCookie(ctx, challengeCookie); - removeCookie(ctx, challengeUsernameCookie); }).map(registrationData -> new WebAuthnCredentialRecord( username, registrationData.getAttestationObject(), @@ -568,11 +561,10 @@ public Uni login(WebAuthnLoginResponse response, Routi */ public Uni login(JsonObject response, RoutingContext ctx) { RestoreResult challenge = authMech.getLoginManager().restore(ctx, challengeCookie); - RestoreResult username = authMech.getLoginManager().restore(ctx, challengeUsernameCookie); if (challenge == null || challenge.getPrincipal() == null || challenge.getPrincipal().isEmpty() // although login can be empty, we should still have a cookie for it - || username == null || username.getPrincipal() == null) { - return Uni.createFrom().failure(new RuntimeException("Missing challenge or username")); + ) { + return Uni.createFrom().failure(new RuntimeException("Missing challenge")); } // input validation @@ -606,7 +598,6 @@ public Uni login(JsonObject response, RoutingContext c authenticationParameters)) .eventually(() -> { removeCookie(ctx, challengeCookie); - removeCookie(ctx, challengeUsernameCookie); }).map(authenticationData -> credentialRecord); }); } diff --git a/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java b/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java index edb1c8655b62c..cefcdd3f22202 100644 --- a/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java +++ b/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java @@ -104,7 +104,6 @@ private void invokeCustomEndpoint(String uri, Filter cookieFilter, Consumer Date: Mon, 25 Nov 2024 17:02:54 +0100 Subject: [PATCH 037/207] WebAuthn: username cookie removal documentation and JS --- docs/src/main/asciidoc/security-webauthn.adoc | 15 ++++++-------- .../security/webauthn/WebAuthnSecurity.java | 20 ++++++++++++------- .../runtime/src/main/resources/webauthn.js | 5 ++++- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/docs/src/main/asciidoc/security-webauthn.adoc b/docs/src/main/asciidoc/security-webauthn.adoc index 51d49168c47ab..492c4ecd36533 100644 --- a/docs/src/main/asciidoc/security-webauthn.adoc +++ b/docs/src/main/asciidoc/security-webauthn.adoc @@ -613,8 +613,7 @@ The Quarkus WebAuthn extension comes out of the box with these REST endpoints pr `POST /q/webauthn/register-options-challenge`: Set up and obtain a registration challenge -This causes two cookies to be set: one for the challenge, and one for the user name, they -will be used by the registration step later. +This causes a cookie to be set for the challenge, it will be used by the registration step later. [source,json] .Request @@ -667,7 +666,7 @@ will be used by the registration step later. `POST /q/webauthn/register`: Trigger a registration -This uses the two cookies set by the registration challenge and clears them. It +This uses the challenge cookie set by the registration challenge and clears it. It also uses your link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`] to store the new credentials, and sets up the <> to log you in. @@ -693,8 +692,7 @@ This returns a 204 with no body. `POST /q/webauthn/login-options-challenge`: Set up and obtain a login challenge -This causes two cookies to be set: one for the challenge, and one for the user name, they -will be used by the login step later. +This causes a cookie to be set for the challenge, it will be used by the login step later. [source,json] .Request @@ -733,7 +731,7 @@ will be used by the login step later. === Trigger a login -This uses the two cookies set by the login challenge and clears them. It +This uses the challenge cookie set by the login challenge and clears it. It also uses your link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`] to find and update the credentials, and sets up the <> to log you in. @@ -1088,7 +1086,7 @@ public class LoginResource { try { // store the user WebAuthnCredentialRecord credentialRecord = - webAuthnSecurity.register(webAuthnResponse, ctx).await().indefinitely(); + webAuthnSecurity.register(userName, webAuthnResponse, ctx).await().indefinitely(); User newUser = new User(); newUser.userName = credentialRecord.getUserName(); WebAuthnCredential credential = @@ -1216,7 +1214,7 @@ public class WebAuthnResourceTest { String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge(userName, cookieFilter); JsonObject registrationJson = token.makeRegistrationJson(challenge); if(endpoint == Endpoint.DEFAULT) - WebAuthnEndpointHelper.invokeRegistration(registrationJson, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration(userName, registrationJson, cookieFilter); else { invokeCustomEndpoint("/register", cookieFilter, request -> { WebAuthnEndpointHelper.addWebAuthnRegistrationFormParameters(request, registrationJson); @@ -1265,7 +1263,6 @@ public class WebAuthnResourceTest { .statusCode(200) .log().ifValidationFails() .cookie(WebAuthnEndpointHelper.getChallengeCookie(), Matchers.is("")) - .cookie(WebAuthnEndpointHelper.getChallengeUsernameCookie(), Matchers.is("")) .cookie(WebAuthnEndpointHelper.getMainCookie(), Matchers.notNullValue()); } diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java index 8dff0911b49da..a489f5b892f92 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java @@ -451,12 +451,13 @@ private String getOrCreateChallenge(RoutingContext ctx) { } /** - * Registers a new WebAuthn credentials. This will check it, clear the cookies and return it in case of + * Registers a new WebAuthn credentials. This will check it, clear the challenge cookie and return it in case of * success, but not invoke {@link WebAuthnUserProvider#store(WebAuthnCredentialRecord)}, you have to do * it manually in case of success. This will also not set a login cookie, you have to do it manually using * {@link #rememberUser(String, RoutingContext)} * or using any other way. * + * @param the username to register credentials for * @param response the Webauthn registration info * @param ctx the current request * @return the newly created credentials @@ -466,21 +467,24 @@ public Uni register(String username, WebAuthnRegisterR } /** - * Registers a new WebAuthn credentials. This will check it, clear the cookies and return it in case of + * Registers a new WebAuthn credentials. This will check it, clear the challenge cookie and return it in case of * success, but not invoke {@link WebAuthnUserProvider#store(WebAuthnCredentialRecord)}, you have to do * it manually in case of success. This will also not set a login cookie, you have to do it manually using * {@link #rememberUser(String, RoutingContext)} * or using any other way. * + * @param the username to register credentials for * @param response the Webauthn registration info * @param ctx the current request * @return the newly created credentials */ public Uni register(String username, JsonObject response, RoutingContext ctx) { RestoreResult challenge = authMech.getLoginManager().restore(ctx, challengeCookie); - if (challenge == null || challenge.getPrincipal() == null || challenge.getPrincipal().isEmpty() - || username == null || username.isEmpty()) { - return Uni.createFrom().failure(new RuntimeException("Missing challenge or username")); + if (challenge == null || challenge.getPrincipal() == null || challenge.getPrincipal().isEmpty()) { + return Uni.createFrom().failure(new RuntimeException("Missing challenge")); + } + if (username == null || username.isEmpty()) { + return Uni.createFrom().failure(new RuntimeException("Missing username")); } // input validation @@ -534,7 +538,8 @@ private ServerProperty makeServerProperty(RestoreResult challenge, RoutingContex } /** - * Logs an existing WebAuthn user in. This will check it, clear the cookies and return the updated credentials in case of + * Logs an existing WebAuthn user in. This will check it, clear the challenge cookie and return the updated credentials in + * case of * success, but not invoke {@link WebAuthnUserProvider#update(String, long)}, you have to do * it manually in case of success. This will also not set a login cookie, you have to do it manually using * {@link #rememberUser(String, RoutingContext)} @@ -549,7 +554,8 @@ public Uni login(WebAuthnLoginResponse response, Routi } /** - * Logs an existing WebAuthn user in. This will check it, clear the cookies and return the updated credentials in case of + * Logs an existing WebAuthn user in. This will check it, clear the challenge cookie and return the updated credentials in + * case of * success, but not invoke {@link WebAuthnUserProvider#update(String, long)}, you have to do * it manually in case of success. This will also not set a login cookie, you have to do it manually using * {@link #rememberUser(String, RoutingContext)} diff --git a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js index ae211660423e2..cc91864350831 100644 --- a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js +++ b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js @@ -164,9 +164,12 @@ if (!self.registerPath) { throw new Error('Register path is missing!'); } + if (!user || !user.name) { + return Promise.reject('User name (user.name) required'); + } return self.registerClientSteps(user) .then(body => { - return self.fetchWithCsrf(self.registerPath, { + return self.fetchWithCsrf(self.registerPath + "?" + new URLSearchParams({username: user.name}).toString(), { method: 'POST', headers: { 'Accept': 'application/json', From 34b96fb93ec7e87b77b6f3f956d2395c136c5709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20=C3=89pardaud?= Date: Mon, 25 Nov 2024 17:18:26 +0100 Subject: [PATCH 038/207] WebAuthn: document the security constraints of WebAuthnUserProvider.store --- docs/src/main/asciidoc/security-webauthn.adoc | 10 ++++++++++ .../security/webauthn/WebAuthnUserProvider.java | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/docs/src/main/asciidoc/security-webauthn.adoc b/docs/src/main/asciidoc/security-webauthn.adoc index 492c4ecd36533..09ee4ce6b24e2 100644 --- a/docs/src/main/asciidoc/security-webauthn.adoc +++ b/docs/src/main/asciidoc/security-webauthn.adoc @@ -372,6 +372,8 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider { @Override public Uni store(WebAuthnCredentialRecord credentialRecord) { User newUser = new User(); + // We can only store one credential per userName thanks to the unicity constraint + // which will cause this transaction to fail and throw if the userName already exists newUser.userName = credentialRecord.getUserName(); WebAuthnCredential credential = new WebAuthnCredential(credentialRecord, newUser); credential.persist(); @@ -398,6 +400,14 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider { } ---- +Warning: When implementing your own `WebAuthnUserProvider.store` method, make sure that you never allow creating +new credentials for a `userName` that already exists. Otherwise you risk allowing third-parties to impersonate existing +users by letting them add their own credentials to existing accounts. If you want to allow existing users to register +more than one WebAuthn credential, you must make sure in `WebAuthnUserProvider.store` that the user is currently logged +in under the same `userName` to which you want to add new credentials. In every other case, make sure to return a failed +`Uni` from this method. In this particular example, this is checked using a unicity constraint on the user name, which +will cause the transaction to fail if the user already exists. + == Configuration Because we want to delegate login and registration to the default Quarkus WebAuthn endpoints, we need to enable them diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java index 8cbae8bdb9548..03b58ce4924b3 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java @@ -52,11 +52,23 @@ public default Uni update(String credentialId, long counter) { * You don't have to implement this method if you handle registration manually via * {@link WebAuthnSecurity#register(WebAuthnRegisterResponse, io.vertx.ext.web.RoutingContext)} * + * Make sure that you never allow creating + * new credentials for a `userName` that already exists. Otherwise you risk allowing third-parties to impersonate existing + * users by letting them add their own credentials to existing accounts. If you want to allow existing users to register + * more than one WebAuthn credential, you must make sure that the user is currently logged + * in under the same userName to which you want to add new credentials. In every other case, make sure to + * return a failed + * {@link Uni} from this method. + * * The default behaviour is to not do anything. * * @param userName the userName's credentials * @param credentialRecord the new credentials to store * @return a uni completion object + * @throws Exception a failed {@link Uni} if the credentialId already exists, or the userName + * already + * has a credential and you disallow having more, or if trying to add credentials to other users than the current + * user. */ public default Uni store(WebAuthnCredentialRecord credentialRecord) { return Uni.createFrom().voidItem(); From db12e82f897b2de0a25298e65127358fda5c0fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20=C3=89pardaud?= Date: Thu, 5 Dec 2024 15:51:10 +0100 Subject: [PATCH 039/207] Updated webauthn extension status to experimental --- .../runtime/src/main/resources/META-INF/quarkus-extension.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/security-webauthn/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/security-webauthn/runtime/src/main/resources/META-INF/quarkus-extension.yaml index b13ed8dc74128..8e56c89d705c1 100644 --- a/extensions/security-webauthn/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/extensions/security-webauthn/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -8,6 +8,6 @@ metadata: guide: "https://quarkus.io/guides/security-webauthn" categories: - "security" - status: "preview" + status: "experimental" config: - "quarkus.webauthn." From 201460bad81177ed6aeaf20e017f2313915b0f41 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Thu, 5 Dec 2024 10:48:50 +0000 Subject: [PATCH 040/207] Make sure OidcRequestContextProperties are always modifiable --- .../common/OidcRequestContextProperties.java | 3 +- .../OidcRequestContextPropertiesTest.java | 31 +++++++++++++++++++ .../quarkus/it/keycloak/OidcClientTest.java | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 extensions/oidc-common/runtime/src/test/java/io/quarkus/oidc/common/runtime/OidcRequestContextPropertiesTest.java diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/OidcRequestContextProperties.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/OidcRequestContextProperties.java index eda5b00cd66d3..45c0918cc7bef 100644 --- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/OidcRequestContextProperties.java +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/OidcRequestContextProperties.java @@ -1,6 +1,7 @@ package io.quarkus.oidc.common; import java.util.Collections; +import java.util.HashMap; import java.util.Map; public class OidcRequestContextProperties { @@ -16,7 +17,7 @@ public OidcRequestContextProperties() { } public OidcRequestContextProperties(Map properties) { - this.properties = properties; + this.properties = new HashMap<>(properties); } /** diff --git a/extensions/oidc-common/runtime/src/test/java/io/quarkus/oidc/common/runtime/OidcRequestContextPropertiesTest.java b/extensions/oidc-common/runtime/src/test/java/io/quarkus/oidc/common/runtime/OidcRequestContextPropertiesTest.java new file mode 100644 index 0000000000000..4402fe3e6e6a9 --- /dev/null +++ b/extensions/oidc-common/runtime/src/test/java/io/quarkus/oidc/common/runtime/OidcRequestContextPropertiesTest.java @@ -0,0 +1,31 @@ +package io.quarkus.oidc.common.runtime; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import io.quarkus.oidc.common.OidcRequestContextProperties; + +public class OidcRequestContextPropertiesTest { + + @Test + public void testModifyPropertiesDefaultConstructor() throws Exception { + OidcRequestContextProperties props = new OidcRequestContextProperties(); + assertNull(props.get("a")); + props.put("a", "value"); + assertEquals("value", props.get("a")); + } + + @Test + public void testModifyExistinProperties() throws Exception { + OidcRequestContextProperties props = new OidcRequestContextProperties(Map.of("a", "value")); + assertEquals("value", props.get("a")); + props.put("a", "avalue"); + assertEquals("avalue", props.get("a")); + props.put("b", "bvalue"); + assertEquals("bvalue", props.get("b")); + } +} diff --git a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java index f02e864ce4e2b..890bce60e15a9 100644 --- a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java +++ b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java @@ -58,7 +58,7 @@ public void testGetAccessTokenWithConfiguredExpiresIn() { long expectedExpiresAt = now + 5; long accessTokenExpiresAt = Long.valueOf(data[1]); assertTrue(accessTokenExpiresAt >= expectedExpiresAt - && accessTokenExpiresAt <= expectedExpiresAt + 2); + && accessTokenExpiresAt <= expectedExpiresAt + 4); } @Test From 20c598ded9d513acb2f742ef47ec4ff4f0d6c81d Mon Sep 17 00:00:00 2001 From: Thibault Meyer Date: Thu, 5 Dec 2024 20:49:37 +0100 Subject: [PATCH 041/207] Spring Cloud Configuration ordinal customization Resolves: #44923 Signed-off-by: Thibault Meyer --- .../runtime/SpringCloudConfigClientConfig.java | 6 ++++++ ...pringCloudConfigClientConfigSourceFactory.java | 2 +- ...gCloudConfigClientConfigSourceFactoryTest.java | 15 ++++++++------- .../SpringCloudConfigClientGatewayTest.java | 1 + 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/extensions/spring-cloud-config-client/runtime/src/main/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfig.java b/extensions/spring-cloud-config-client/runtime/src/main/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfig.java index 1f6db20c48b8e..dcca34587c9c0 100644 --- a/extensions/spring-cloud-config-client/runtime/src/main/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfig.java +++ b/extensions/spring-cloud-config-client/runtime/src/main/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfig.java @@ -125,6 +125,12 @@ public interface SpringCloudConfigClientConfig { */ Optional> profiles(); + /** + * Microprofile Config ordinal. + */ + @WithDefault("450") + int ordinal(); + /** */ default boolean usernameAndPasswordSet() { return username().isPresent() && password().isPresent(); diff --git a/extensions/spring-cloud-config-client/runtime/src/main/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfigSourceFactory.java b/extensions/spring-cloud-config-client/runtime/src/main/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfigSourceFactory.java index 509dddfed30ad..2d649b250a8d7 100644 --- a/extensions/spring-cloud-config-client/runtime/src/main/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfigSourceFactory.java +++ b/extensions/spring-cloud-config-client/runtime/src/main/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfigSourceFactory.java @@ -73,7 +73,7 @@ public Iterable getConfigSources(final ConfigSourceContext context log.debug("Obtained " + responses.size() + " from the config server"); - int ordinal = 450; + int ordinal = config.ordinal(); // Profiles are looked from the highest ordinal to lowest, so we reverse the collection to build the source list Collections.reverse(responses); for (Response response : responses) { diff --git a/extensions/spring-cloud-config-client/runtime/src/test/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfigSourceFactoryTest.java b/extensions/spring-cloud-config-client/runtime/src/test/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfigSourceFactoryTest.java index 384bf24e3c777..a0bc30936c3e3 100644 --- a/extensions/spring-cloud-config-client/runtime/src/test/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfigSourceFactoryTest.java +++ b/extensions/spring-cloud-config-client/runtime/src/test/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientConfigSourceFactoryTest.java @@ -47,7 +47,7 @@ void testExtensionDisabled() { // Arrange final ConfigSourceContext context = Mockito.mock(ConfigSourceContext.class); - final SpringCloudConfigClientConfig config = configForTesting(false, "foo", MOCK_SERVER_PORT, true); + final SpringCloudConfigClientConfig config = configForTesting(false, "foo", MOCK_SERVER_PORT, true, 450); final SpringCloudConfigClientConfigSourceFactory factory = new SpringCloudConfigClientConfigSourceFactory(); // Act @@ -62,7 +62,7 @@ void testNameNotProvided() { // Arrange final ConfigSourceContext context = Mockito.mock(ConfigSourceContext.class); - final SpringCloudConfigClientConfig config = configForTesting(true, null, MOCK_SERVER_PORT, true); + final SpringCloudConfigClientConfig config = configForTesting(true, null, MOCK_SERVER_PORT, true, 450); final SpringCloudConfigClientConfigSourceFactory factory = new SpringCloudConfigClientConfigSourceFactory(); // Act @@ -77,7 +77,7 @@ void testInAppCDsGeneration() { // Arrange final ConfigSourceContext context = Mockito.mock(ConfigSourceContext.class); - final SpringCloudConfigClientConfig config = configForTesting(true, "foo", MOCK_SERVER_PORT, true); + final SpringCloudConfigClientConfig config = configForTesting(true, "foo", MOCK_SERVER_PORT, true, 450); final SpringCloudConfigClientConfigSourceFactory factory = new SpringCloudConfigClientConfigSourceFactory(); System.setProperty(ApplicationLifecycleManager.QUARKUS_APPCDS_GENERATE_PROP, "true"); @@ -97,7 +97,7 @@ void testFailFastDisable() { // Arrange final ConfigSourceContext context = Mockito.mock(ConfigSourceContext.class); - final SpringCloudConfigClientConfig config = configForTesting(true, "unknown-application", 1234, false); + final SpringCloudConfigClientConfig config = configForTesting(true, "unknown-application", 1234, false, 450); final SpringCloudConfigClientConfigSourceFactory factory = new SpringCloudConfigClientConfigSourceFactory(); Mockito.when(context.getProfiles()).thenReturn(List.of("dev")); @@ -114,7 +114,7 @@ void testFailFastEnabled() { // Arrange final ConfigSourceContext context = Mockito.mock(ConfigSourceContext.class); - final SpringCloudConfigClientConfig config = configForTesting(true, "unknown-application", 1234, true); + final SpringCloudConfigClientConfig config = configForTesting(true, "unknown-application", 1234, true, 450); final SpringCloudConfigClientConfigSourceFactory factory = new SpringCloudConfigClientConfigSourceFactory(); Mockito.when(context.getProfiles()).thenReturn(List.of("dev")); @@ -130,7 +130,7 @@ void testBasic() throws IOException { // Arrange final String profile = "dev"; final ConfigSourceContext context = Mockito.mock(ConfigSourceContext.class); - final SpringCloudConfigClientConfig config = configForTesting(true, "foo", MOCK_SERVER_PORT, true); + final SpringCloudConfigClientConfig config = configForTesting(true, "foo", MOCK_SERVER_PORT, true, 450); final SpringCloudConfigClientConfigSourceFactory factory = new SpringCloudConfigClientConfigSourceFactory(); Mockito.when(context.getProfiles()).thenReturn(List.of(profile)); @@ -176,7 +176,7 @@ void testBasic() throws IOException { } private SpringCloudConfigClientConfig configForTesting(final boolean isEnabled, final String appName, - final int serverPort, final boolean isFailFastEnabled) { + final int serverPort, final boolean isFailFastEnabled, final int ordinal) { final SpringCloudConfigClientConfig config = Mockito.mock(SpringCloudConfigClientConfig.class); when(config.enabled()).thenReturn(isEnabled); @@ -192,6 +192,7 @@ private SpringCloudConfigClientConfig configForTesting(final boolean isEnabled, when(config.keyStore()).thenReturn(Optional.empty()); when(config.trustCerts()).thenReturn(false); when(config.headers()).thenReturn(new HashMap<>()); + when(config.ordinal()).thenReturn(ordinal); return config; } diff --git a/extensions/spring-cloud-config-client/runtime/src/test/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientGatewayTest.java b/extensions/spring-cloud-config-client/runtime/src/test/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientGatewayTest.java index 1a8f492534ba1..848c1b69c3892 100644 --- a/extensions/spring-cloud-config-client/runtime/src/test/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientGatewayTest.java +++ b/extensions/spring-cloud-config-client/runtime/src/test/java/io/quarkus/spring/cloud/config/client/runtime/SpringCloudConfigClientGatewayTest.java @@ -86,6 +86,7 @@ private static SpringCloudConfigClientConfig configForTesting() { when(config.keyStore()).thenReturn(Optional.empty()); when(config.trustCerts()).thenReturn(false); when(config.headers()).thenReturn(new HashMap<>()); + when(config.ordinal()).thenReturn(450); return config; } } From 75c741cbcc98f280c6edc9512a858ff8b9a89649 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 20:04:34 +0000 Subject: [PATCH 042/207] Bump com.google.http-client:google-http-client-bom from 1.45.1 to 1.45.2 Bumps [com.google.http-client:google-http-client-bom](https://github.com/googleapis/google-http-java-client) from 1.45.1 to 1.45.2. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v1.45.1...v1.45.2) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 781b8dbdaab63..89084461c0874 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -182,7 +182,7 @@ 3.48.3 2.36.0 0.27.2 - 1.45.1 + 1.45.2 2.1 4.7.6 1.1.4 From 529267983841e6056d5cf2d6e47e68aeff4bc647 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 20:06:14 +0000 Subject: [PATCH 043/207] Bump io.smallrye.common:smallrye-common-bom from 2.8.0 to 2.9.0 Bumps [io.smallrye.common:smallrye-common-bom](https://github.com/smallrye/smallrye-common) from 2.8.0 to 2.9.0. - [Release notes](https://github.com/smallrye/smallrye-common/releases) - [Commits](https://github.com/smallrye/smallrye-common/compare/2.8.0...2.9.0) --- updated-dependencies: - dependency-name: io.smallrye.common:smallrye-common-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- independent-projects/bootstrap/pom.xml | 2 +- independent-projects/resteasy-reactive/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 781b8dbdaab63..be2c4ad303d02 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -46,7 +46,7 @@ 2.1 2.0 4.0.2 - 2.8.0 + 2.9.0 3.10.2 4.1.0 4.0.0 diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml index 392291f6152e3..f9e1c6338fc9e 100644 --- a/independent-projects/bootstrap/pom.xml +++ b/independent-projects/bootstrap/pom.xml @@ -70,7 +70,7 @@ 1.26 2.0 3.5.1 - 2.8.0 + 2.9.0 1.5.2 8.9 0.0.10 diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index e7cce83392f7d..a49a586bf60e4 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -57,7 +57,7 @@ 3.1.0 2.7.0 - 2.8.0 + 2.9.0 4.5.11 5.5.0 1.0.0.Final From bb1b70f7aec6526378cd727733134f243b2348a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:54:03 +0000 Subject: [PATCH 044/207] Bump org.jboss.logmanager:jboss-logmanager Bumps [org.jboss.logmanager:jboss-logmanager](https://github.com/jboss-logging/jboss-logmanager) from 3.1.0.Final to 3.1.1.Final. - [Release notes](https://github.com/jboss-logging/jboss-logmanager/releases) - [Commits](https://github.com/jboss-logging/jboss-logmanager/compare/v3.1.0.Final...v3.1.1.Final) --- updated-dependencies: - dependency-name: org.jboss.logmanager:jboss-logmanager dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- independent-projects/bootstrap/pom.xml | 2 +- independent-projects/resteasy-reactive/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 781b8dbdaab63..fd5037ba5b914 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -157,7 +157,7 @@ 4.1.4 3.2.0 4.2.2 - 3.1.0.Final + 3.1.1.Final 11.0.1 3.0.4 diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml index 392291f6152e3..c372f788b1c07 100644 --- a/independent-projects/bootstrap/pom.xml +++ b/independent-projects/bootstrap/pom.xml @@ -61,7 +61,7 @@ 1.0.1 2.8 1.2.6 - 3.1.0.Final + 3.1.1.Final 1.1.0.Final 2.0.6 23.1.0 diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index e7cce83392f7d..af5158703d4f1 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -51,7 +51,7 @@ 3.9.9 3.26.3 3.6.1.Final - 3.1.0.Final + 3.1.1.Final 3.0.0 1.8.0 3.1.0 From 37c76876f2ada75562d26a51d1ac66d777870657 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 22:10:49 +0000 Subject: [PATCH 045/207] Bump org.jboss.resteasy.spring:resteasy-spring-web Bumps org.jboss.resteasy.spring:resteasy-spring-web from 3.1.3.Final to 3.2.0.Final. --- updated-dependencies: - dependency-name: org.jboss.resteasy.spring:resteasy-spring-web dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 781b8dbdaab63..abd3b5b05256b 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -27,7 +27,7 @@ 1 1.1.7 3.0.0.Final - 3.1.3.Final + 3.2.0.Final 6.2.11.Final 2.8.0-alpha 1.27.0-alpha From 8ce87793abd1ffe47d718ced32c1968f7ba3411b Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Fri, 6 Dec 2024 10:51:04 +0100 Subject: [PATCH 046/207] Fix InjectionPointModifier for repeated annotations on method parameters; add grpc test --- ...nterceptorConstructorRegistrationTest.java | 61 +++++++++++++++++++ .../arc/processor/InjectionPointModifier.java | 10 +-- 2 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/interceptors/ClientInterceptorConstructorRegistrationTest.java diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/interceptors/ClientInterceptorConstructorRegistrationTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/interceptors/ClientInterceptorConstructorRegistrationTest.java new file mode 100644 index 0000000000000..d5148fa9914a9 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/client/interceptors/ClientInterceptorConstructorRegistrationTest.java @@ -0,0 +1,61 @@ +package io.quarkus.grpc.client.interceptors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.grpc.examples.helloworld.Greeter; +import io.grpc.examples.helloworld.GreeterBean; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloReplyOrBuilder; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.examples.helloworld.HelloRequestOrBuilder; +import io.grpc.examples.helloworld.MutinyGreeterGrpc; +import io.quarkus.grpc.GrpcClient; +import io.quarkus.grpc.RegisterClientInterceptor; +import io.quarkus.grpc.server.services.MutinyHelloService; +import io.quarkus.test.QuarkusUnitTest; + +public class ClientInterceptorConstructorRegistrationTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest().setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .addClasses(MutinyHelloService.class, MyThirdClientInterceptor.class, MyLastClientInterceptor.class, + Calls.class, + GreeterGrpc.class, Greeter.class, GreeterBean.class, HelloRequest.class, HelloReply.class, + MutinyGreeterGrpc.class, + HelloRequestOrBuilder.class, HelloReplyOrBuilder.class)) + .withConfigurationResource("hello-config.properties"); + private static final Logger log = LoggerFactory.getLogger(ClientInterceptorConstructorRegistrationTest.class); + + private GreeterGrpc.GreeterBlockingStub client; + + public ClientInterceptorConstructorRegistrationTest( + @RegisterClientInterceptor(MyLastClientInterceptor.class) @RegisterClientInterceptor(MyThirdClientInterceptor.class) @GrpcClient("hello-service") GreeterGrpc.GreeterBlockingStub client) { + this.client = client; + } + + @Test + public void testInterceptorRegistration() { + Calls.LIST.clear(); + + HelloReply reply = client + .sayHello(HelloRequest.newBuilder().setName("neo").build()); + assertThat(reply.getMessage()).isEqualTo("Hello neo"); + + List calls = Calls.LIST; + assertEquals(2, calls.size()); + assertEquals(MyThirdClientInterceptor.class.getName(), calls.get(0)); + assertEquals(MyLastClientInterceptor.class.getName(), calls.get(1)); + } +} diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointModifier.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointModifier.java index bcac6d1bf086d..7b54da5941b6b 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointModifier.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointModifier.java @@ -3,7 +3,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; @@ -42,14 +41,7 @@ public Set applyTransformers(Type type, AnnotationTarget tar transformer.transform(transformationContext); } } - if (methodParameterTarget != null && AnnotationTarget.Kind.METHOD_PARAMETER.equals(methodParameterTarget.kind())) { - // only return set of qualifiers related to the given method parameter - return transformationContext.getQualifiers().stream().filter( - annotationInstance -> methodParameterTarget.equals(annotationInstance.target())) - .collect(Collectors.toSet()); - } else { - return transformationContext.getQualifiers(); - } + return transformationContext.getQualifiers(); } // method variant used for field and resource field injection; a case where we don't need to deal with method. params From 7fffa4cc6f172f562000a243d3004719804d90e8 Mon Sep 17 00:00:00 2001 From: Antonio Musarra Date: Fri, 6 Dec 2024 09:50:26 +0100 Subject: [PATCH 047/207] Added the git remote url when git full info enabled (cherry picked from commit d0859fcc31b3c05f2dccf86f5ca95077f04e93fb) --- .../src/main/java/io/quarkus/info/deployment/InfoProcessor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java index 1509ac3314abf..5dec40f17527f 100644 --- a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java +++ b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java @@ -111,6 +111,7 @@ void gitInfo(InfoBuildTimeConfig config, commit.put("id", id); + data.put("remote", git.getRepository().getConfig().getString("remote", "origin", "url")); data.put("tags", getTags(git, latestCommit)); } From 85387f96ac9b879af1fc0fd3636179bd6137da93 Mon Sep 17 00:00:00 2001 From: Antonio Musarra Date: Fri, 6 Dec 2024 10:10:57 +0100 Subject: [PATCH 048/207] Added the name of the application in build section: The application name does not always match the artifactId value. (cherry picked from commit 67bda9cc39e71c4b0808ee53e34640c94b54d0a2) --- .../main/java/io/quarkus/info/deployment/InfoProcessor.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java index 5dec40f17527f..1cafa5308a418 100644 --- a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java +++ b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java @@ -34,6 +34,7 @@ import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Record; +import io.quarkus.deployment.builditem.ApplicationInfoBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem; import io.quarkus.info.BuildInfo; @@ -209,10 +210,13 @@ void buildInfo(CurateOutcomeBuildItem curateOutcomeBuildItem, InfoBuildTimeConfig config, BuildProducer valuesProducer, BuildProducer beanProducer, + ApplicationInfoBuildItem infoApplication, InfoRecorder recorder) { ApplicationModel applicationModel = curateOutcomeBuildItem.getApplicationModel(); ResolvedDependency appArtifact = applicationModel.getAppArtifact(); Map buildData = new LinkedHashMap<>(); + String name = infoApplication.getName(); + buildData.put("name", name); String group = appArtifact.getGroupId(); buildData.put("group", group); String artifact = appArtifact.getArtifactId(); From ebe80d5919905e8c2ec23d72264f9b686a60c618 Mon Sep 17 00:00:00 2001 From: Antonio Musarra Date: Fri, 6 Dec 2024 10:45:31 +0100 Subject: [PATCH 049/207] Added the vendor and the vendorVersion of the Java: Having the vendor and vendor version information of Java is useful in case of support and bug fixes of the specific vendor related Java version. (cherry picked from commit 9820480d8b88d30d66625e41a8024a87af124c77) --- .../io/quarkus/info/runtime/JavaInfoContributor.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/JavaInfoContributor.java b/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/JavaInfoContributor.java index 11a88a612afbd..e381b3ba41b6e 100644 --- a/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/JavaInfoContributor.java +++ b/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/JavaInfoContributor.java @@ -17,10 +17,20 @@ public Map data() { //TODO: should we add more information like 'java.runtime.*' and 'java.vm.*' ? Map result = new LinkedHashMap<>(); result.put("version", getVersion()); + result.put("vendor", getVendor()); + result.put("vendorVersion", getVendorVersion()); return result; } static String getVersion() { return System.getProperty("java.version"); } + + static String getVendor() { + return System.getProperty("java.vendor"); + } + + static String getVendorVersion() { + return System.getProperty("java.vendor.version"); + } } From 090e18661a4831737a5a48f27dd9cba3e37ef9c9 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Fri, 29 Nov 2024 13:10:17 +0100 Subject: [PATCH 050/207] Option to serialize ApplicationModel in quarkus:generate-code-tests for QuarkusTests to re-use it instead of initializing the resolver and re-resolving the model. --- .../io/quarkus/maven/GenerateCodeMojo.java | 34 +++- .../quarkus/maven/GenerateCodeTestsMojo.java | 19 ++ .../quarkus/maven/QuarkusBootstrapMojo.java | 14 ++ .../maven/QuarkusBootstrapProvider.java | 41 ++++- .../bootstrap/util/BootstrapUtils.java | 93 +++++++++- .../bootstrap/BootstrapAppModelFactory.java | 166 ++++++++++-------- .../maven/workspace/LocalProject.java | 8 +- .../maven/workspace/LocalWorkspace.java | 40 ++++- 8 files changed, 320 insertions(+), 95 deletions(-) diff --git a/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeMojo.java index c35a0befbbef0..d95e82c89028b 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeMojo.java @@ -1,5 +1,6 @@ package io.quarkus.maven; +import java.io.IOException; import java.lang.reflect.Method; import java.nio.file.Path; import java.util.List; @@ -16,6 +17,7 @@ import io.quarkus.bootstrap.app.CuratedApplication; import io.quarkus.bootstrap.classloading.QuarkusClassLoader; import io.quarkus.bootstrap.model.ApplicationModel; +import io.quarkus.bootstrap.util.BootstrapUtils; import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.paths.PathCollection; import io.quarkus.paths.PathList; @@ -31,8 +33,11 @@ public class GenerateCodeMojo extends QuarkusBootstrapMojo { * Skip the execution of this mojo */ @Parameter(defaultValue = "false", property = "quarkus.generate-code.skip", alias = "quarkus.prepare.skip") - private boolean skipSourceGeneration = false; + boolean skipSourceGeneration = false; + /** + * Application launch mode for which to generate the source code. + */ @Parameter(defaultValue = "NORMAL", property = "launchMode") String mode; @@ -55,9 +60,8 @@ protected void doExecute() throws MojoExecutionException, MojoFailureException { path -> mavenProject().addCompileSourceRoot(path.toString()), false); } - void generateCode(PathCollection sourceParents, - Consumer sourceRegistrar, - boolean test) throws MojoFailureException, MojoExecutionException { + void generateCode(PathCollection sourceParents, Consumer sourceRegistrar, boolean test) + throws MojoExecutionException { final LaunchMode launchMode; if (test) { @@ -97,13 +101,31 @@ void generateCode(PathCollection sourceParents, if (deploymentClassLoader != null) { deploymentClassLoader.close(); } - // in case of test mode, we can't share the bootstrapped app with the testing plugins, so we are closing it right away + // In case of the test mode, we can't share the application model with the test plugins, so we are closing it right away, + // but we are serializing the application model so the test plugins can deserialize it from disk instead of re-initializing + // the resolver and re-resolving it as part of the test bootstrap if (test && curatedApplication != null) { - curatedApplication.close(); + var appModel = curatedApplication.getApplicationModel(); + closeApplication(LaunchMode.TEST); + if (isSerializeTestModel()) { + final int workspaceId = getWorkspaceId(); + if (workspaceId != 0) { + try { + BootstrapUtils.writeAppModelWithWorkspaceId(appModel, workspaceId, BootstrapUtils + .getSerializedTestAppModelPath(Path.of(mavenProject().getBuild().getDirectory()))); + } catch (IOException e) { + getLog().warn("Failed to serialize application model", e); + } + } + } } } } + protected boolean isSerializeTestModel() { + return false; + } + protected PathCollection getParentDirs(List sourceDirs) { if (sourceDirs.size() == 1) { return PathList.of(Path.of(sourceDirs.get(0)).getParent()); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeTestsMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeTestsMojo.java index b644af7be0a18..ed5b9bd71e6a4 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeTestsMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/GenerateCodeTestsMojo.java @@ -13,15 +13,29 @@ import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import io.quarkus.bootstrap.app.CuratedApplication; +import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.builder.Json; import io.quarkus.maven.dependency.ResolvedDependency; import io.quarkus.runtime.LaunchMode; @Mojo(name = "generate-code-tests", defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, threadSafe = true) public class GenerateCodeTestsMojo extends GenerateCodeMojo { + + /** + * A switch that enables or disables serialization of an {@link ApplicationModel} to a file for tests. + * Deserializing an application model when bootstrapping Quarkus tests has a performance advantage in that + * the tests will not have to initialize a Maven resolver and re-resolve the application model, which may save, + * depending on a project, ~80-95% of time on {@link ApplicationModel} resolution. + *

    + * Serialization of the test model is enabled by default. + */ + @Parameter(property = "quarkus.generate-code.serialize-test-model", defaultValue = "true") + boolean serializeTestModel; + @Override protected void doExecute() throws MojoExecutionException, MojoFailureException { generateCode(getParentDirs(mavenProject().getTestCompileSourceRoots()), @@ -32,6 +46,11 @@ protected void doExecute() throws MojoExecutionException, MojoFailureException { } } + @Override + protected boolean isSerializeTestModel() { + return serializeTestModel; + } + private boolean isTestWithNativeAgent() { String value = System.getProperty("quarkus.test.integration-test-profile"); if ("test-with-native-agent".equals(value)) { diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapMojo.java index b8cfa1396f9b3..fe53cd99d3433 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapMojo.java @@ -296,6 +296,20 @@ protected CuratedApplication bootstrapApplication(LaunchMode mode) throws MojoEx return bootstrapProvider.bootstrapApplication(this, mode); } + protected void closeApplication(LaunchMode mode) { + bootstrapProvider.closeApplication(this, mode); + } + + /** + * Workspace ID associated with a given bootstrap mojo. + * If the returned value is {@code 0}, a workspace was not associated with the bootstrap mojo. + * + * @return workspace ID associated with a given bootstrap mojo + */ + protected int getWorkspaceId() { + return bootstrapProvider.getWorkspaceId(this); + } + protected CuratedApplication bootstrapApplication(LaunchMode mode, Consumer builderCustomizer) throws MojoExecutionException { return bootstrapProvider.bootstrapApplication(this, mode, builderCustomizer); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java index a2b09b2e7a06c..1341a7d14c9eb 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java @@ -45,6 +45,7 @@ import io.quarkus.bootstrap.resolver.maven.EffectiveModelResolver; import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; import io.quarkus.maven.components.ManifestSection; import io.quarkus.maven.components.QuarkusWorkspaceProvider; import io.quarkus.maven.dependency.ArtifactCoords; @@ -138,6 +139,21 @@ public CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo, Launch return bootstrapper(mojo).bootstrapApplication(mojo, mode, builderCustomizer); } + public void closeApplication(QuarkusBootstrapMojo mojo, LaunchMode mode) { + bootstrapper(mojo).closeApplication(mode); + } + + /** + * Workspace ID associated with a given bootstrap mojo. + * If the returned value is {@code 0}, a workspace was not associated with the bootstrap mojo. + * + * @param mojo bootstrap mojo + * @return workspace ID associated with a given bootstrap mojo + */ + public int getWorkspaceId(QuarkusBootstrapMojo mojo) { + return bootstrapper(mojo).workspaceId; + } + public ApplicationModel getResolvedApplicationModel(ArtifactKey projectId, LaunchMode mode, String bootstrapId) { if (appBootstrapProviders.size() == 0) { return null; @@ -180,6 +196,7 @@ private static boolean isWorkspaceDiscovery(QuarkusBootstrapMojo mojo) { public class QuarkusMavenAppBootstrap implements Closeable { + private int workspaceId; private CuratedApplication prodApp; private CuratedApplication devApp; private CuratedApplication testApp; @@ -187,7 +204,7 @@ public class QuarkusMavenAppBootstrap implements Closeable { private MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo, LaunchMode mode) { try { if (mode == LaunchMode.DEVELOPMENT || mode == LaunchMode.TEST || isWorkspaceDiscovery(mojo)) { - return workspaceProvider.createArtifactResolver( + var resolver = workspaceProvider.createArtifactResolver( BootstrapMavenContext.config() // it's important to pass user settings in case the process was not launched using the original mvn script // for example using org.codehaus.plexus.classworlds.launcher.Launcher @@ -199,6 +216,11 @@ private MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo, Launch .setRemoteRepositories(mojo.remoteRepositories()) .setEffectiveModelBuilder(BootstrapMavenContextConfig .getEffectiveModelBuilderProperty(mojo.mavenProject().getProperties()))); + final LocalProject currentProject = resolver.getMavenContext().getCurrentProject(); + if (currentProject != null && workspaceId == 0) { + workspaceId = currentProject.getWorkspace().getId(); + } + return resolver; } // PROD packaging mode with workspace discovery disabled return MavenArtifactResolver.builder() @@ -376,6 +398,23 @@ protected CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo, Lau return prodApp == null ? prodApp = doBootstrap(mojo, mode, builderCustomizer) : prodApp; } + protected void closeApplication(LaunchMode mode) { + if (mode == LaunchMode.DEVELOPMENT) { + if (devApp != null) { + devApp.close(); + devApp = null; + } + } else if (mode == LaunchMode.TEST) { + if (testApp != null) { + testApp.close(); + testApp = null; + } + } else if (prodApp != null) { + prodApp.close(); + prodApp = null; + } + } + protected ArtifactCoords managingProject(QuarkusBootstrapMojo mojo) { if (mojo.appArtifactCoords() == null) { return null; diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/util/BootstrapUtils.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/util/BootstrapUtils.java index 43602918e8e46..21659ce8d9569 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/util/BootstrapUtils.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/util/BootstrapUtils.java @@ -9,14 +9,22 @@ import java.nio.file.Path; import java.util.regex.Pattern; +import org.jboss.logging.Logger; + import io.quarkus.bootstrap.BootstrapConstants; import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.resolver.AppModelResolverException; import io.quarkus.maven.dependency.ArtifactKey; +import io.quarkus.maven.dependency.DependencyFlags; import io.quarkus.maven.dependency.GACT; +import io.quarkus.maven.dependency.ResolvedDependency; public class BootstrapUtils { + private static final Logger log = Logger.getLogger(BootstrapUtils.class); + + private static final int CP_CACHE_FORMAT_ID = 2; + private static Pattern splitByWs; public static String[] splitByWhitespace(String s) { @@ -81,7 +89,90 @@ public static ApplicationModel deserializeQuarkusModel(Path modelPath) throws Ap throw new AppModelResolverException("Unable to locate quarkus model"); } + /** + * Returns a location where a serialized {@link ApplicationModel} would be found for dev mode. + * + * @param projectBuildDir project build directory + * @return file of a serialized application model for dev mode + */ public static Path resolveSerializedAppModelPath(Path projectBuildDir) { - return projectBuildDir.resolve("quarkus").resolve("bootstrap").resolve("dev-app-model.dat"); + return getBootstrapBuildDir(projectBuildDir).resolve("dev-app-model.dat"); + } + + /** + * Returns a location where a serialized {@link ApplicationModel} would be found for test mode. + * + * @param projectBuildDir project build directory + * @return file of a serialized application model for test mode + */ + public static Path getSerializedTestAppModelPath(Path projectBuildDir) { + return getBootstrapBuildDir(projectBuildDir).resolve("test-app-model.dat"); + } + + private static Path getBootstrapBuildDir(Path projectBuildDir) { + return projectBuildDir.resolve("quarkus").resolve("bootstrap"); + } + + /** + * Serializes an {@link ApplicationModel} along with the workspace ID for which it was resolved. + * The serialization format will be different from the one used by {@link #resolveSerializedAppModelPath(Path)} + * and {@link #getSerializedTestAppModelPath(Path)}. + * + * @param appModel application model to serialize + * @param workspaceId workspace ID + * @param file target file + * @throws IOException in case of an IO failure + */ + public static void writeAppModelWithWorkspaceId(ApplicationModel appModel, int workspaceId, Path file) throws IOException { + Files.createDirectories(file.getParent()); + try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(file))) { + out.writeInt(CP_CACHE_FORMAT_ID); + out.writeInt(workspaceId); + out.writeObject(appModel); + } + log.debugf("Serialized application model to %s", file); + } + + /** + * Deserializes an {@link ApplicationModel} from a file. + *

    + * The implementation will check whether the serialization format of the file matches the expected one. + * If it does not, the method will return null even if the file exists. + *

    + * The implementation will compare the deserialized workspace ID to the argument {@code workspaceId} + * and if they don't match the method will return null. + *

    + * Once the {@link ApplicationModel} was deserialized, the dependency paths will be checked for existence. + * If a dependency path does not exist, the method will throw an exception. + * + * @param file serialized application model file + * @param workspaceId expected workspace ID + * @return deserialized application model + * @throws ClassNotFoundException in case a required class could not be loaded + * @throws IOException in case of an IO failure + */ + public static ApplicationModel readAppModelWithWorkspaceId(Path file, int workspaceId) + throws ClassNotFoundException, IOException { + try (ObjectInputStream reader = new ObjectInputStream(Files.newInputStream(file))) { + if (reader.readInt() == CP_CACHE_FORMAT_ID) { + if (reader.readInt() == workspaceId) { + final ApplicationModel appModel = (ApplicationModel) reader.readObject(); + log.debugf("Loaded application model %s from %s", appModel, file); + for (ResolvedDependency d : appModel.getDependencies(DependencyFlags.DEPLOYMENT_CP)) { + for (Path p : d.getResolvedPaths()) { + if (!Files.exists(p)) { + throw new IOException("Cached artifact does not exist: " + p); + } + } + } + return appModel; + } else { + log.debugf("Application model saved in %s has a different workspace ID", file); + } + } else { + log.debugf("Unsupported application model serialization format in %s", file); + } + } + return null; } } diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java index a748ea5a4b732..a60623be2e5d7 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java @@ -1,11 +1,11 @@ package io.quarkus.bootstrap; -import java.io.DataInputStream; -import java.io.DataOutputStream; +import static io.quarkus.bootstrap.util.BootstrapUtils.readAppModelWithWorkspaceId; +import static io.quarkus.bootstrap.util.BootstrapUtils.writeAppModelWithWorkspaceId; + import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -30,6 +30,7 @@ import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; import io.quarkus.bootstrap.resolver.maven.workspace.LocalWorkspace; import io.quarkus.bootstrap.resolver.maven.workspace.ModelUtils; +import io.quarkus.bootstrap.util.BootstrapUtils; import io.quarkus.bootstrap.util.IoUtils; import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.ArtifactKey; @@ -52,8 +53,6 @@ public class BootstrapAppModelFactory { public static final String CREATOR_APP_TYPE = "creator.app.type"; public static final String CREATOR_APP_VERSION = "creator.app.version"; - private static final int CP_CACHE_FORMAT_ID = 2; - private static final Logger log = Logger.getLogger(BootstrapAppModelFactory.class); public static BootstrapAppModelFactory newInstance() { @@ -207,35 +206,26 @@ private BootstrapMavenContext createBootstrapMavenContext() throws AppModelResol } public CurationResult resolveAppModel() throws BootstrapException { - // gradle tests and dev encode the result on the class path - final String serializedModel; - if (test) { - serializedModel = System.getProperty(BootstrapConstants.SERIALIZED_TEST_APP_MODEL); - } else { - serializedModel = System.getProperty(BootstrapConstants.SERIALIZED_APP_MODEL); + CurationResult result = loadFromSystemProperty(); + if (result != null) { + return result; } - if (serializedModel != null) { - final Path p = Paths.get(serializedModel); - if (Files.exists(p)) { - try (InputStream existing = Files.newInputStream(p)) { - final ApplicationModel appModel = (ApplicationModel) new ObjectInputStream(existing).readObject(); - return new CurationResult(appModel); - } catch (IOException | ClassNotFoundException e) { - log.error("Failed to load serialized app mode", e); - } - IoUtils.recursiveDelete(p); - } else { - log.error("Failed to locate serialized application model at " + serializedModel); - } + result = createAppModelForJarOrNull(projectRoot); + if (result != null) { + return result; } - // Massive hack to dected zipped/jar - if (projectRoot != null - && (!Files.isDirectory(projectRoot) || projectRoot.getFileSystem().getClass().getName().contains("Zip"))) { - return createAppModelForJar(projectRoot); - } + return resolveAppModelForWorkspace(); + } + /** + * Resolves an application for a project in a workspace. + * + * @return application model + * @throws BootstrapException in case of a failure + */ + private CurationResult resolveAppModelForWorkspace() throws BootstrapException { ResolvedDependency appArtifact = this.appArtifact; try { LocalProject localProject = null; @@ -264,27 +254,10 @@ public CurationResult resolveAppModel() throws BootstrapException { cachedCpPath = resolveCachedCpPath(localProject); if (Files.exists(cachedCpPath) && workspace.getLastModified() < Files.getLastModifiedTime(cachedCpPath).toMillis()) { - try (DataInputStream reader = new DataInputStream(Files.newInputStream(cachedCpPath))) { - if (reader.readInt() == CP_CACHE_FORMAT_ID) { - if (reader.readInt() == workspace.getId()) { - ObjectInputStream in = new ObjectInputStream(reader); - ApplicationModel appModel = (ApplicationModel) in.readObject(); - - log.debugf("Loaded cached AppModel %s from %s", appModel, cachedCpPath); - for (ResolvedDependency d : appModel.getDependencies()) { - for (Path p : d.getResolvedPaths()) { - if (!Files.exists(p)) { - throw new IOException("Cached artifact does not exist: " + p); - } - } - } - return new CurationResult(appModel); - } else { - debug("Cached deployment classpath has expired for %s", appArtifact); - } - } else { - debug("Unsupported classpath cache format in %s for %s", cachedCpPath, - appArtifact); + try { + final ApplicationModel appModel = readAppModelWithWorkspaceId(cachedCpPath, workspace.getId()); + if (appModel != null) { + return new CurationResult(appModel); } } catch (IOException e) { log.warn("Failed to read deployment classpath cache from " + cachedCpPath + " for " @@ -296,12 +269,9 @@ public CurationResult resolveAppModel() throws BootstrapException { .resolveManagedModel(appArtifact, forcedDependencies, managingProject, reloadableModules)); if (cachedCpPath != null) { Files.createDirectories(cachedCpPath.getParent()); - try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(cachedCpPath))) { - out.writeInt(CP_CACHE_FORMAT_ID); - out.writeInt(workspace.getId()); - ObjectOutputStream obj = new ObjectOutputStream(out); - obj.writeObject(curationResult.getApplicationModel()); - } catch (Exception e) { + try { + writeAppModelWithWorkspaceId(curationResult.getApplicationModel(), workspace.getId(), cachedCpPath); + } catch (IOException e) { log.warn("Failed to write classpath cache", e); } } @@ -311,6 +281,37 @@ public CurationResult resolveAppModel() throws BootstrapException { } } + /** + * Attempts to load an application model from a file system path set as a value of a system property. + * In test mode the system property will be {@link BootstrapConstants#SERIALIZED_TEST_APP_MODEL}, otherwise + * it will be {@link BootstrapConstants#SERIALIZED_APP_MODEL}. + *

    + * If the property was not set, the method will return null. + *

    + * If the model could not deserialized, an error will be logged and null returned. + * + * @return deserialized application model or null + */ + private CurationResult loadFromSystemProperty() { + // gradle tests and dev encode the result on the class path + final String serializedModel = test ? System.getProperty(BootstrapConstants.SERIALIZED_TEST_APP_MODEL) + : System.getProperty(BootstrapConstants.SERIALIZED_APP_MODEL); + if (serializedModel != null) { + final Path p = Paths.get(serializedModel); + if (Files.exists(p)) { + try (InputStream existing = Files.newInputStream(p)) { + return new CurationResult((ApplicationModel) new ObjectInputStream(existing).readObject()); + } catch (IOException | ClassNotFoundException e) { + log.error("Failed to load serialized app mode", e); + } + IoUtils.recursiveDelete(p); + } else { + log.error("Failed to locate serialized application model at " + serializedModel); + } + } + return null; + } + private boolean isWorkspaceDiscoveryEnabled() { return localProjectsDiscovery == null ? projectRoot != null && (test || devMode) : localProjectsDiscovery; @@ -336,34 +337,43 @@ private LocalProject loadWorkspace() throws AppModelResolverException { return project; } - private CurationResult createAppModelForJar(Path appArtifactPath) { - AppModelResolver modelResolver = getAppModelResolver(); - final ApplicationModel appModel; - ResolvedDependency appArtifact = this.appArtifact; - try { - if (appArtifact == null) { - appArtifact = ModelUtils.resolveAppArtifact(appArtifactPath); + /** + * Checks whether the project path is a JAR and if it is, creates an application model for it. + * If the project path is not a JAR, the method will return null. + * + * @param appArtifactPath application artifact path + * @return resolved application model or null + */ + private CurationResult createAppModelForJarOrNull(Path appArtifactPath) { + if (projectRoot != null + && (!Files.isDirectory(projectRoot) || projectRoot.getFileSystem().getClass().getName().contains("Zip"))) { + AppModelResolver modelResolver = getAppModelResolver(); + final ApplicationModel appModel; + ResolvedDependency appArtifact = this.appArtifact; + try { + if (appArtifact == null) { + appArtifact = ModelUtils.resolveAppArtifact(appArtifactPath); + } + modelResolver.relink(appArtifact, appArtifactPath); + //we need some way to figure out dependencies here + appModel = modelResolver.resolveManagedModel(appArtifact, List.of(), managingProject, + reloadableModules); + } catch (AppModelResolverException | IOException e) { + throw new RuntimeException("Failed to resolve initial application dependencies", e); } - modelResolver.relink(appArtifact, appArtifactPath); - //we need some way to figure out dependencies here - appModel = modelResolver.resolveManagedModel(appArtifact, List.of(), managingProject, - reloadableModules); - } catch (AppModelResolverException | IOException e) { - throw new RuntimeException("Failed to resolve initial application dependencies", e); + return new CurationResult(appModel); } - return new CurationResult(appModel); + return null; } private Path resolveCachedCpPath(LocalProject project) { - final String filePrefix = devMode ? "dev-" : (test ? "test-" : null); - return project.getOutputDir().resolve(QUARKUS).resolve(BOOTSTRAP) - .resolve(filePrefix == null ? APP_MODEL_DAT : filePrefix + APP_MODEL_DAT); - } - - private static void debug(String msg, Object... args) { - if (log.isDebugEnabled()) { - log.debug(String.format(msg, args)); + if (devMode) { + return BootstrapUtils.resolveSerializedAppModelPath(project.getOutputDir()); + } + if (test) { + return BootstrapUtils.getSerializedTestAppModelPath(project.getOutputDir()); } + return project.getOutputDir().resolve(QUARKUS).resolve(BOOTSTRAP).resolve(APP_MODEL_DAT); } public BootstrapAppModelFactory setMavenArtifactResolver(MavenArtifactResolver mavenArtifactResolver) { diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java index ca502db7afa0a..31da5fc9c7c2d 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java @@ -162,7 +162,7 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra this.modelBuildingResult = modelBuildingResult; this.workspace = workspace; if (workspace != null) { - workspace.addProject(this, rawModel.getPomFile().lastModified()); + workspace.addProject(this); } } @@ -178,7 +178,7 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra version = rawVersionIsUnresolved ? ModelUtils.resolveVersion(rawVersion, rawModel) : rawVersion; if (workspace != null) { - workspace.addProject(this, rawModel.getPomFile().lastModified()); + workspace.addProject(this); if (rawVersionIsUnresolved && version != null) { workspace.setResolvedVersion(version); } @@ -187,6 +187,10 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra } } + protected long getPomLastModified() { + return rawModel.getPomFile().lastModified(); + } + public LocalProject getLocalParent() { if (parent != null) { return parent; diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java index a570d9f80455f..660a7ccb920da 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java @@ -5,6 +5,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,8 +35,8 @@ public class LocalWorkspace implements WorkspaceModelResolver, WorkspaceReader, private final WorkspaceRepository wsRepo = new WorkspaceRepository(); private ArtifactKey lastFindVersionsKey; private List lastFindVersions; - private long lastModified; - private int id = 1; + private volatile long lastModified = -1; + private volatile int id = -1; // value of the resolved version in case the raw version contains a property like ${revision} (see "Maven CI Friendly Versions") private String resolvedVersion; @@ -45,12 +46,8 @@ public class LocalWorkspace implements WorkspaceModelResolver, WorkspaceReader, private BootstrapMavenContext mvnCtx; private LocalProject currentProject; - protected void addProject(LocalProject project, long lastModified) { + protected void addProject(LocalProject project) { projects.put(project.getKey(), project); - if (lastModified > this.lastModified) { - this.lastModified = lastModified; - } - id = 31 * id + (int) (lastModified ^ (lastModified >>> 32)); } public LocalProject getProject(String groupId, String artifactId) { @@ -61,14 +58,43 @@ public LocalProject getProject(ArtifactKey key) { return projects.get(key); } + /** + * The latest last modified time of all the POMs in the workspace. + * + * @return the latest last modified time of all the POMs in the workspace + */ public long getLastModified() { + if (lastModified < 0) { + initLastModifiedAndHash(); + } return lastModified; } + /** + * This is essentially a hash code derived from each module's key. + * + * @return a hash code derived from each module's key + */ public int getId() { + if (id < 0) { + initLastModifiedAndHash(); + } return id; } + private void initLastModifiedAndHash() { + long lastModified = 0; + final int[] hashes = new int[projects.size()]; + int i = 0; + for (var project : projects.values()) { + lastModified = Math.max(project.getPomLastModified(), lastModified); + hashes[i++] = project.getKey().hashCode(); + } + Arrays.sort(hashes); + this.id = Arrays.hashCode(hashes); + this.lastModified = lastModified; + } + @Override public Model resolveRawModel(String groupId, String artifactId, String versionConstraint) throws UnresolvableModelException { From a62f036f0b81ece2447bbe2f3163eaeeeb621c95 Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Thu, 5 Dec 2024 17:05:07 +0100 Subject: [PATCH 051/207] ArC: add InterceptionProxySubclass --- .../processor/InterceptionProxyGenerator.java | 9 +- .../main/java/io/quarkus/arc/ClientProxy.java | 8 +- .../arc/InterceptionProxySubclass.java | 33 ++++++++ ...rceptionProxySubclassNormalScopedTest.java | 83 +++++++++++++++++++ ...rceptionProxySubclassPseudoScopedTest.java | 75 +++++++++++++++++ 5 files changed, 201 insertions(+), 7 deletions(-) create mode 100644 independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InterceptionProxySubclass.java create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/producer/InterceptionProxySubclassNormalScopedTest.java create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/producer/InterceptionProxySubclassPseudoScopedTest.java diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptionProxyGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptionProxyGenerator.java index 49d790bb94d31..9ff06914aca7a 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptionProxyGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptionProxyGenerator.java @@ -24,7 +24,7 @@ import io.quarkus.arc.InjectableReferenceProvider; import io.quarkus.arc.InterceptionProxy; -import io.quarkus.arc.Subclass; +import io.quarkus.arc.InterceptionProxySubclass; import io.quarkus.arc.impl.InterceptedMethodMetadata; import io.quarkus.arc.processor.ResourceOutput.Resource; import io.quarkus.gizmo.BytecodeCreator; @@ -156,8 +156,8 @@ private void createInterceptionSubclass(ClassOutput classOutput, InterceptionPro String superClass = isInterface ? Object.class.getName() : pseudoBeanClassName; String[] interfaces = isInterface - ? new String[] { pseudoBeanClassName, Subclass.class.getName() } - : new String[] { Subclass.class.getName() }; + ? new String[] { pseudoBeanClassName, InterceptionProxySubclass.class.getName() } + : new String[] { InterceptionProxySubclass.class.getName() }; try (ClassCreator clazz = ClassCreator.builder() .classOutput(classOutput) @@ -352,6 +352,9 @@ private void createInterceptionSubclass(ClassOutput classOutput, InterceptionPro ctor.writeInstanceField(constructedField.getFieldDescriptor(), ctor.getThis(), ctor.load(true)); ctor.returnVoid(); + + MethodCreator getDelegate = clazz.getMethodCreator("arc_delegate", Object.class); + getDelegate.returnValue(getDelegate.readInstanceField(delegate.getFieldDescriptor(), getDelegate.getThis())); } } } diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ClientProxy.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ClientProxy.java index 8af0bdf78951d..be10c658e31c4 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ClientProxy.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ClientProxy.java @@ -42,14 +42,14 @@ public interface ClientProxy { * This method should only be used with caution. If you unwrap a client proxy then certain key functionality will not work * as expected. * - * @param - * @param obj + * @param the type of the object to unwrap + * @param obj the object to unwrap * @return the contextual instance if the object represents a client proxy, the object otherwise */ @SuppressWarnings("unchecked") static T unwrap(T obj) { - if (obj instanceof ClientProxy) { - return (T) ((ClientProxy) obj).arc_contextualInstance(); + if (obj instanceof ClientProxy proxy) { + return (T) proxy.arc_contextualInstance(); } return obj; } diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InterceptionProxySubclass.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InterceptionProxySubclass.java new file mode 100644 index 0000000000000..6b4afb3cf432f --- /dev/null +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InterceptionProxySubclass.java @@ -0,0 +1,33 @@ +package io.quarkus.arc; + +/** + * Represents an interception proxy. Typically, interception is performed by creating a subclass + * of the original class and arranging bean instantiation such that the contextual instance + * is in fact an instance of the subclass, but that isn't always possible. In case of + * {@link InterceptionProxy}, interception is performed by a proxy that delegates to the actual + * contextual instance. Such proxy implements this interface. + */ +public interface InterceptionProxySubclass extends Subclass { + /** + * @return the contextual instance + */ + Object arc_delegate(); + + /** + * Attempts to unwrap the object if it represents an interception proxy. + *

    + * This method should only be used with caution. If you unwrap an interception proxy, + * then certain key functionality will not work as expected. + * + * @param the type of the object to unwrap + * @param obj the object to unwrap + * @return the contextual instance if the object represents an interception proxy, the object otherwise + */ + @SuppressWarnings("unchecked") + static T unwrap(T obj) { + if (obj instanceof InterceptionProxySubclass proxy) { + return (T) proxy.arc_delegate(); + } + return obj; + } +} diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/producer/InterceptionProxySubclassNormalScopedTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/producer/InterceptionProxySubclassNormalScopedTest.java new file mode 100644 index 0000000000000..e636ea4d69908 --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/producer/InterceptionProxySubclassNormalScopedTest.java @@ -0,0 +1,83 @@ +package io.quarkus.arc.test.interceptors.producer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import jakarta.annotation.Priority; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.inject.Produces; +import jakarta.interceptor.AroundInvoke; +import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InterceptorBinding; +import jakarta.interceptor.InvocationContext; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ClientProxy; +import io.quarkus.arc.InterceptionProxy; +import io.quarkus.arc.InterceptionProxySubclass; +import io.quarkus.arc.test.ArcTestContainer; + +public class InterceptionProxySubclassNormalScopedTest { + @RegisterExtension + public ArcTestContainer container = new ArcTestContainer(MyBinding.class, MyInterceptor.class, MyProducer.class); + + @Test + public void test() { + MyNonbean nonbean = Arc.container().instance(MyNonbean.class).get(); + assertEquals("intercepted: hello", nonbean.hello()); + + assertInstanceOf(ClientProxy.class, nonbean); + assertNotNull(ClientProxy.unwrap(nonbean)); + assertNotSame(nonbean, ClientProxy.unwrap(nonbean)); + + MyNonbean unwrapped = ClientProxy.unwrap(nonbean); + + assertInstanceOf(InterceptionProxySubclass.class, unwrapped); + assertNotNull(InterceptionProxySubclass.unwrap(unwrapped)); + assertNotSame(unwrapped, InterceptionProxySubclass.unwrap(unwrapped)); + assertNotSame(nonbean, InterceptionProxySubclass.unwrap(unwrapped)); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR }) + @InterceptorBinding + @interface MyBinding { + } + + @MyBinding + @Priority(1) + @Interceptor + static class MyInterceptor { + @AroundInvoke + Object intercept(InvocationContext ctx) throws Exception { + return "intercepted: " + ctx.proceed(); + } + } + + static class MyNonbean { + @MyBinding + String hello() { + return "hello"; + } + } + + @Dependent + static class MyProducer { + @Produces + @ApplicationScoped + MyNonbean produce(InterceptionProxy proxy) { + return proxy.create(new MyNonbean()); + } + } +} diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/producer/InterceptionProxySubclassPseudoScopedTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/producer/InterceptionProxySubclassPseudoScopedTest.java new file mode 100644 index 0000000000000..8babcdb5ca801 --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/producer/InterceptionProxySubclassPseudoScopedTest.java @@ -0,0 +1,75 @@ +package io.quarkus.arc.test.interceptors.producer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import jakarta.annotation.Priority; +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Singleton; +import jakarta.interceptor.AroundInvoke; +import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InterceptorBinding; +import jakarta.interceptor.InvocationContext; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.InterceptionProxy; +import io.quarkus.arc.InterceptionProxySubclass; +import io.quarkus.arc.test.ArcTestContainer; + +public class InterceptionProxySubclassPseudoScopedTest { + @RegisterExtension + public ArcTestContainer container = new ArcTestContainer(MyBinding.class, MyInterceptor.class, MyProducer.class); + + @Test + public void test() { + MyNonbean nonbean = Arc.container().instance(MyNonbean.class).get(); + assertEquals("intercepted: hello", nonbean.hello()); + + assertInstanceOf(InterceptionProxySubclass.class, nonbean); + assertNotNull(InterceptionProxySubclass.unwrap(nonbean)); + assertNotSame(nonbean, InterceptionProxySubclass.unwrap(nonbean)); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR }) + @InterceptorBinding + @interface MyBinding { + } + + @MyBinding + @Priority(1) + @Interceptor + static class MyInterceptor { + @AroundInvoke + Object intercept(InvocationContext ctx) throws Exception { + return "intercepted: " + ctx.proceed(); + } + } + + static class MyNonbean { + @MyBinding + String hello() { + return "hello"; + } + } + + @Dependent + static class MyProducer { + @Produces + @Singleton + MyNonbean produce(InterceptionProxy proxy) { + return proxy.create(new MyNonbean()); + } + } +} From 8989e17d1c633d7eaeb74b0aadec981f181b4a8f Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Fri, 6 Dec 2024 15:31:32 -0300 Subject: [PATCH 052/207] Convert amazon-lambda-common to use @ConfigMapping --- .../amazon-lambda/common-deployment/pom.xml | 3 --- .../deployment/DevServicesLambdaProcessor.java | 6 +++--- .../amazon/lambda/deployment/LambdaConfig.java | 6 ++++-- .../deployment/MockEventServerConfig.java | 18 ++++++++---------- .../amazon-lambda/common-runtime/pom.xml | 3 --- .../deployment/AmazonLambdaProcessor.java | 2 +- extensions/amazon-lambda/runtime/pom.xml | 3 --- .../lambda/runtime/AmazonLambdaRecorder.java | 8 ++++---- .../lambda/runtime/LambdaBuildTimeConfig.java | 10 +++++----- .../amazon/lambda/runtime/LambdaConfig.java | 8 ++++---- 10 files changed, 29 insertions(+), 38 deletions(-) diff --git a/extensions/amazon-lambda/common-deployment/pom.xml b/extensions/amazon-lambda/common-deployment/pom.xml index 6fa00eea9b452..0fd84942a5f72 100644 --- a/extensions/amazon-lambda/common-deployment/pom.xml +++ b/extensions/amazon-lambda/common-deployment/pom.xml @@ -61,9 +61,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/DevServicesLambdaProcessor.java b/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/DevServicesLambdaProcessor.java index c30f5e707a21a..84c3f128445fb 100644 --- a/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/DevServicesLambdaProcessor.java +++ b/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/DevServicesLambdaProcessor.java @@ -63,7 +63,7 @@ public void startEventServer(LaunchModeBuildItem launchMode, return; if (legacyTestingEnabled()) return; - if (!config.mockEventServer.enabled) { + if (!config.mockEventServer().enabled()) { return; } if (server != null) { @@ -77,8 +77,8 @@ public void startEventServer(LaunchModeBuildItem launchMode, } server = supplier.get(); - int port = launchMode.getLaunchMode() == LaunchMode.TEST ? config.mockEventServer.testPort - : config.mockEventServer.devPort; + int port = launchMode.getLaunchMode() == LaunchMode.TEST ? config.mockEventServer().testPort() + : config.mockEventServer().devPort(); startMode = launchMode.getLaunchMode(); server.start(port); int actualPort = server.getPort(); diff --git a/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/LambdaConfig.java b/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/LambdaConfig.java index e9dcc8e4c3e61..36c15e3e3a77e 100644 --- a/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/LambdaConfig.java +++ b/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/LambdaConfig.java @@ -2,13 +2,15 @@ import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; @ConfigRoot(phase = ConfigPhase.BUILD_TIME) -public class LambdaConfig { +@ConfigMapping(prefix = "quarkus.lambda") +public interface LambdaConfig { /** * Configuration for the mock event server that is run * in dev mode and test mode */ - MockEventServerConfig mockEventServer; + MockEventServerConfig mockEventServer(); } diff --git a/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/MockEventServerConfig.java b/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/MockEventServerConfig.java index 85cde4c70a1fb..c2aa666e9810f 100644 --- a/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/MockEventServerConfig.java +++ b/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/MockEventServerConfig.java @@ -1,29 +1,27 @@ package io.quarkus.amazon.lambda.deployment; -import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; +import io.smallrye.config.WithDefault; /** * Configuration for the mock event server that is run * in dev mode and test mode */ -@ConfigGroup -public class MockEventServerConfig { +public interface MockEventServerConfig { /** * Setting to true will start event server even if quarkus.devservices.enabled=false */ - @ConfigItem(defaultValue = "true") - public boolean enabled; + @WithDefault("true") + boolean enabled(); /** * Port to access mock event server in dev mode */ - @ConfigItem(defaultValue = "8080") - public int devPort; + @WithDefault("8080") + int devPort(); /** * Port to access mock event server in dev mode */ - @ConfigItem(defaultValue = "8081") - public int testPort; + @WithDefault("8081") + int testPort(); } diff --git a/extensions/amazon-lambda/common-runtime/pom.xml b/extensions/amazon-lambda/common-runtime/pom.xml index eb8a8bab3501b..36b98ed34d715 100644 --- a/extensions/amazon-lambda/common-runtime/pom.xml +++ b/extensions/amazon-lambda/common-runtime/pom.xml @@ -72,9 +72,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java b/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java index d7b631b826e24..6ce046aa7da98 100644 --- a/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java +++ b/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java @@ -333,7 +333,7 @@ void startPoolLoopDevOrTest(AmazonLambdaRecorder recorder, void recordExpectedExceptions(LambdaBuildTimeConfig config, BuildProducer registerForReflection, AmazonLambdaStaticRecorder recorder) { - Set> classes = config.expectedExceptions.map(Set::copyOf).orElseGet(Set::of); + Set> classes = config.expectedExceptions().map(Set::copyOf).orElseGet(Set::of); classes.stream() .map(clazz -> ReflectiveClassBuildItem.builder(clazz).constructors(false) .reason(getClass().getName() + " expectedExceptions") diff --git a/extensions/amazon-lambda/runtime/pom.xml b/extensions/amazon-lambda/runtime/pom.xml index 0a565e1dbe5e1..e12340e996247 100644 --- a/extensions/amazon-lambda/runtime/pom.xml +++ b/extensions/amazon-lambda/runtime/pom.xml @@ -51,9 +51,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java index 49dc6d9d92a2b..6ff6371ae775b 100644 --- a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java +++ b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java @@ -120,12 +120,12 @@ public void chooseHandlerClass(List>> unnam Class> handlerClass = null; Class handlerStreamClass = null; - if (config.handler.isPresent()) { - handlerClass = namedHandlerClasses.get(config.handler.get()); - handlerStreamClass = namedStreamHandlerClasses.get(config.handler.get()); + if (config.handler().isPresent()) { + handlerClass = namedHandlerClasses.get(config.handler().get()); + handlerStreamClass = namedStreamHandlerClasses.get(config.handler().get()); if (handlerClass == null && handlerStreamClass == null) { - String errorMessage = "Unable to find handler class with name " + config.handler.get() + String errorMessage = "Unable to find handler class with name " + config.handler().get() + " make sure there is a handler class in the deployment with the correct @Named annotation"; throw new RuntimeException(errorMessage); } diff --git a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaBuildTimeConfig.java b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaBuildTimeConfig.java index 4a035af4fb7ee..5bf355cef4911 100644 --- a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaBuildTimeConfig.java +++ b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaBuildTimeConfig.java @@ -3,12 +3,13 @@ import java.util.List; import java.util.Optional; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; -@ConfigRoot(name = "lambda", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) -public class LambdaBuildTimeConfig { +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +@ConfigMapping(prefix = "quarkus.lambda") +public interface LambdaBuildTimeConfig { /** * The exception classes expected to be thrown by the handler. @@ -17,6 +18,5 @@ public class LambdaBuildTimeConfig { * but will otherwise be handled normally by the lambda runtime. This is useful for avoiding unnecessary * stack traces while preserving the ability to log unexpected exceptions. */ - @ConfigItem - public Optional>> expectedExceptions; + Optional>> expectedExceptions(); } diff --git a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaConfig.java b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaConfig.java index 8335b3f3d3a08..0aceb7a4f08ef 100644 --- a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaConfig.java +++ b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaConfig.java @@ -2,12 +2,13 @@ import java.util.Optional; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; @ConfigRoot(phase = ConfigPhase.RUN_TIME) -public class LambdaConfig { +@ConfigMapping(prefix = "quarkus.lambda") +public interface LambdaConfig { /** * The handler name. Handler names are specified on handler classes using the {@link @jakarta.inject.Named} annotation. @@ -18,6 +19,5 @@ public class LambdaConfig { * then the named handler will be used. * */ - @ConfigItem - public Optional handler; + Optional handler(); } From 54252c1b5f0976985cdf6d81ad2ffa7e18767735 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Fri, 6 Dec 2024 21:15:51 +0100 Subject: [PATCH 053/207] Make sure excluded dependencies do not appear among ResolvedDependency.getDependencies() --- .../model/ApplicationModelBuilder.java | 45 ++++++++--- .../dependency/ResolvedDependencyBuilder.java | 7 +- independent-projects/bootstrap/core/pom.xml | 5 ++ .../resolver/CollectDependenciesBase.java | 24 ++++-- ...nditionalDependenciesDevModelTestCase.java | 79 +++++++++++++++++++ 5 files changed, 142 insertions(+), 18 deletions(-) diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModelBuilder.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModelBuilder.java index 7689f9aa6eb9e..290a1241c10ab 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModelBuilder.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModelBuilder.java @@ -298,15 +298,6 @@ private static GACT toArtifactKey(String artifact) { return new GACT(artifact.split(":")); } - private static boolean matches(ArtifactCoordsPattern[] patterns, ArtifactCoords coords) { - for (int i = 0; i < patterns.length; ++i) { - if (patterns[i].matches(coords)) { - return true; - } - } - return false; - } - List buildDependencies() { for (ArtifactKey key : parentFirstArtifacts) { final ResolvedDependencyBuilder d = dependencies.get(key); @@ -330,13 +321,47 @@ List buildDependencies() { final List result = new ArrayList<>(dependencies.size()); final ArtifactCoordsPattern[] excludePatterns = excludedArtifacts.toArray(new ArtifactCoordsPattern[0]); for (ResolvedDependencyBuilder db : this.dependencies.values()) { - if (!matches(excludePatterns, db.getArtifactCoords())) { + if (!matches(db.getArtifactCoords(), excludePatterns)) { + db.setDependencies(ensureNoMatches(db.getDependencies(), excludePatterns)); result.add(db.build()); } } return result; } + private static boolean matches(ArtifactCoords coords, ArtifactCoordsPattern[] patterns) { + for (int i = 0; i < patterns.length; ++i) { + if (patterns[i].matches(coords)) { + return true; + } + } + return false; + } + + private static Collection ensureNoMatches(Collection artifacts, + ArtifactCoordsPattern[] patterns) { + if (artifacts.isEmpty() || patterns.length == 0) { + return artifacts; + } + for (var dep : artifacts) { + if (matches(dep, patterns)) { + return excludeMatches(artifacts, patterns); + } + } + return artifacts; + } + + private static Collection excludeMatches(Collection artifacts, + ArtifactCoordsPattern[] patterns) { + final List result = new ArrayList<>(artifacts.size() - 1); + for (var artifact : artifacts) { + if (!matches(artifact, patterns)) { + result.add(artifact); + } + } + return result; + } + public DefaultApplicationModel build() { return new DefaultApplicationModel(this); } diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependencyBuilder.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependencyBuilder.java index 1f6d115bcc84a..f4a82193cc107 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependencyBuilder.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependencyBuilder.java @@ -19,7 +19,7 @@ public static ResolvedDependencyBuilder newInstance() { PathCollection resolvedPaths; WorkspaceModule workspaceModule; private volatile ArtifactCoords coords; - private Set deps = Set.of(); + private Collection deps = Set.of(); @Override public PathCollection getResolvedPaths() { @@ -74,6 +74,11 @@ public ResolvedDependencyBuilder addDependencies(Collection deps return this; } + public ResolvedDependencyBuilder setDependencies(Collection deps) { + this.deps = deps; + return this; + } + @Override public Collection getDependencies() { return deps; diff --git a/independent-projects/bootstrap/core/pom.xml b/independent-projects/bootstrap/core/pom.xml index 1fd1e4571a880..979084d2e47d5 100644 --- a/independent-projects/bootstrap/core/pom.xml +++ b/independent-projects/bootstrap/core/pom.xml @@ -60,6 +60,11 @@ junit-jupiter test + + org.assertj + assertj-core + test + org.jboss.shrinkwrap shrinkwrap-depchain diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/CollectDependenciesBase.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/CollectDependenciesBase.java index dc86cd8b16d82..6027533372e5d 100644 --- a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/CollectDependenciesBase.java +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/CollectDependenciesBase.java @@ -1,12 +1,11 @@ package io.quarkus.bootstrap.resolver; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; import java.nio.file.Path; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; import org.eclipse.aether.util.artifact.JavaScopes; import org.junit.jupiter.api.BeforeEach; @@ -15,6 +14,7 @@ import io.quarkus.maven.dependency.ArtifactDependency; import io.quarkus.maven.dependency.Dependency; import io.quarkus.maven.dependency.DependencyFlags; +import io.quarkus.maven.dependency.ResolvedDependency; /** * @@ -47,10 +47,20 @@ public void testCollectedDependencies() throws Exception { expected.addAll(expectedResult); expected.addAll(deploymentDeps); } - // stripping the resolved paths - final List resolvedDeps = getTestResolver().resolveModel(root.toArtifact()).getDependencies() - .stream().map(ArtifactDependency::new).collect(Collectors.toList()); - assertEquals(new HashSet<>(expected), new HashSet<>(resolvedDeps)); + final Collection buildDeps = getTestResolver().resolveModel(root.toArtifact()).getDependencies(); + assertThat(stripResolvedPaths(buildDeps)).containsExactlyInAnyOrderElementsOf(expected); + assertBuildDependencies(buildDeps); + } + + protected void assertBuildDependencies(Collection buildDeps) { + } + + private static List stripResolvedPaths(Collection deps) { + final List result = new ArrayList<>(deps.size()); + for (var dep : deps) { + result.add(new ArtifactDependency(dep)); + } + return result; } protected BootstrapAppModelResolver getTestResolver() throws Exception { diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesDevModelTestCase.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesDevModelTestCase.java index 4f5a56898aa64..906df90e3efef 100644 --- a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesDevModelTestCase.java +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesDevModelTestCase.java @@ -1,12 +1,20 @@ package io.quarkus.bootstrap.resolver.test; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; + import io.quarkus.bootstrap.app.QuarkusBootstrap; +import io.quarkus.bootstrap.model.ApplicationModelBuilder; import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; import io.quarkus.bootstrap.resolver.CollectDependenciesBase; import io.quarkus.bootstrap.resolver.TsArtifact; import io.quarkus.bootstrap.resolver.TsQuarkusExt; +import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; +import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.DependencyFlags; +import io.quarkus.maven.dependency.ResolvedDependency; public class ConditionalDependenciesDevModelTestCase extends CollectDependenciesBase { @@ -25,7 +33,11 @@ protected QuarkusBootstrap.Mode getBootstrapMode() { @Override protected void setupDependencies() { + final TsArtifact excludedLib = TsArtifact.jar("excluded-lib"); + install(excludedLib, false); + final TsQuarkusExt extA = new TsQuarkusExt("ext-a"); + extA.getRuntime().addDependency(excludedLib); install(extA, false); addCollectedDeploymentDep(extA.getDeployment()); @@ -35,6 +47,7 @@ protected void setupDependencies() { | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); final TsQuarkusExt extB = new TsQuarkusExt("ext-b"); + extB.setDescriptorProp(ApplicationModelBuilder.EXCLUDED_ARTIFACTS, TsArtifact.DEFAULT_GROUP_ID + ":excluded-lib"); install(extB, false); addCollectedDep(extB.getRuntime(), DependencyFlags.RUNTIME_EXTENSION_ARTIFACT); addCollectedDeploymentDep(extB.getDeployment()); @@ -97,4 +110,70 @@ protected void setupDependencies() { | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); addCollectedDeploymentDep(extG.getDeployment()); } + + @Override + protected void assertBuildDependencies(Collection buildDeps) { + if (!IncubatingApplicationModelResolver.isIncubatingEnabled(null)) { + return; + } + for (var d : buildDeps) { + switch (d.getArtifactId()) { + case "ext-a": + case "ext-b": + case "ext-c": + case "ext-d": + case "ext-h": + case "lib-e": + case "lib-e-build-time": + assertThat(d.getDependencies()).isEmpty(); + break; + case "ext-a-deployment": + case "ext-b-deployment": + case "ext-c-deployment": + case "ext-d-deployment": + case "ext-h-deployment": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, + d.getArtifactId().substring(0, d.getArtifactId().length() - "-deployment".length()), + TsArtifact.DEFAULT_VERSION)); + break; + case "ext-e": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "lib-e", TsArtifact.DEFAULT_VERSION)); + break; + case "ext-e-deployment": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-e", TsArtifact.DEFAULT_VERSION), + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "lib-e-build-time", TsArtifact.DEFAULT_VERSION)); + break; + case "ext-f": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-c", TsArtifact.DEFAULT_VERSION), + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-e", TsArtifact.DEFAULT_VERSION)); + break; + case "ext-f-deployment": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-f", TsArtifact.DEFAULT_VERSION), + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-c-deployment", TsArtifact.DEFAULT_VERSION), + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-e-deployment", TsArtifact.DEFAULT_VERSION)); + break; + case "ext-g": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-b", TsArtifact.DEFAULT_VERSION), + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "dev-only-lib", TsArtifact.DEFAULT_VERSION)); + break; + case "ext-g-deployment": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-g", TsArtifact.DEFAULT_VERSION), + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-b-deployment", TsArtifact.DEFAULT_VERSION)); + break; + case "dev-only-lib": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-h", TsArtifact.DEFAULT_VERSION)); + break; + default: + throw new RuntimeException("unexpected dependency " + d.toCompactCoords()); + } + } + } } From 89c7131536f3875e536f278cad2e5f020626d48e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Sat, 7 Dec 2024 11:56:30 +0100 Subject: [PATCH 054/207] fix(oidc): Dont start KC Dev Svc when known provider configured --- .../KeycloakDevServicesRequiredBuildItem.java | 23 +++++++++---- .../KeycloakDevServiceRequiredBuildStep.java | 5 +-- .../KeycloakDevServiceRequiredBuildStep.java | 4 +-- ...dcClientKeycloakDevServiceStartupTest.java | 33 +++++++++++++++++++ .../KeycloakDevServiceRequiredBuildStep.java | 3 +- 5 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/OidcClientKeycloakDevServiceStartupTest.java diff --git a/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesRequiredBuildItem.java b/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesRequiredBuildItem.java index 49cd131711bb1..5093a9f369185 100644 --- a/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesRequiredBuildItem.java +++ b/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesRequiredBuildItem.java @@ -4,10 +4,11 @@ import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.jboss.logging.Logger; import org.keycloak.representations.idm.RealmRepresentation; @@ -24,6 +25,7 @@ public final class KeycloakDevServicesRequiredBuildItem extends MultiBuildItem { private static final Logger LOG = Logger.getLogger(KeycloakDevServicesProcessor.class); public static final String OIDC_AUTH_SERVER_URL_CONFIG_KEY = "quarkus.oidc.auth-server-url"; + private static final String OIDC_PROVIDER_CONFIG_KEY = "quarkus.oidc.provider"; private final KeycloakDevServicesConfigurator devServicesConfigurator; private final String authServerUrl; @@ -39,8 +41,17 @@ String getAuthServerUrl() { } public static KeycloakDevServicesRequiredBuildItem of(KeycloakDevServicesConfigurator devServicesConfigurator, - String authServerUrl, String... dontStartConfigProperties) { - if (shouldStartDevService(dontStartConfigProperties, authServerUrl)) { + String authServerUrl, String... additionalDontStartConfigProperties) { + final Set dontStartConfigProperties = new HashSet<>(Arrays.asList(additionalDontStartConfigProperties)); + dontStartConfigProperties.add(authServerUrl); + dontStartConfigProperties.add(OIDC_AUTH_SERVER_URL_CONFIG_KEY); + dontStartConfigProperties.add(OIDC_PROVIDER_CONFIG_KEY); + return of(devServicesConfigurator, authServerUrl, dontStartConfigProperties); + } + + private static KeycloakDevServicesRequiredBuildItem of(KeycloakDevServicesConfigurator devServicesConfigurator, + String authServerUrl, Set dontStartConfigProperties) { + if (shouldStartDevService(dontStartConfigProperties)) { return new KeycloakDevServicesRequiredBuildItem(devServicesConfigurator, authServerUrl); } return null; @@ -69,10 +80,8 @@ public void customizeDefaultRealm(RealmRepresentation realmRepresentation) { }; } - private static boolean shouldStartDevService(String[] dontStartConfigProperties, String authServerUrl) { - return Stream - .concat(Stream.of(authServerUrl), Arrays.stream(dontStartConfigProperties)) - .allMatch(KeycloakDevServicesRequiredBuildItem::shouldStartDevService); + private static boolean shouldStartDevService(Set dontStartConfigProperties) { + return dontStartConfigProperties.stream().allMatch(KeycloakDevServicesRequiredBuildItem::shouldStartDevService); } private static boolean shouldStartDevService(String dontStartConfigProperty) { diff --git a/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java b/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java index 5ba594617a5b6..bff9cd44584b0 100644 --- a/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java +++ b/extensions/oidc-client-registration/deployment/src/main/java/io/quarkus/oidc/client/registration/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java @@ -1,7 +1,5 @@ package io.quarkus.oidc.client.registration.deployment.devservices.keycloak; -import static io.quarkus.devservices.keycloak.KeycloakDevServicesRequiredBuildItem.OIDC_AUTH_SERVER_URL_CONFIG_KEY; - import java.util.List; import java.util.Map; @@ -55,8 +53,7 @@ public void customizeDefaultRealm(RealmRepresentation realmRepresentation) { } }; - return KeycloakDevServicesRequiredBuildItem.of(devServicesConfigurator, - OIDC_CLIENT_REG_AUTH_SERVER_URL_CONFIG_KEY, OIDC_AUTH_SERVER_URL_CONFIG_KEY); + return KeycloakDevServicesRequiredBuildItem.of(devServicesConfigurator, OIDC_CLIENT_REG_AUTH_SERVER_URL_CONFIG_KEY); } @BuildStep(onlyIf = IsDevelopment.class) diff --git a/extensions/oidc-client/deployment/src/main/java/io/quarkus/oidc/client/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java b/extensions/oidc-client/deployment/src/main/java/io/quarkus/oidc/client/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java index 099afd16de833..5ca43f77ad4bd 100644 --- a/extensions/oidc-client/deployment/src/main/java/io/quarkus/oidc/client/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java +++ b/extensions/oidc-client/deployment/src/main/java/io/quarkus/oidc/client/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java @@ -1,7 +1,5 @@ package io.quarkus.oidc.client.deployment.devservices.keycloak; -import static io.quarkus.devservices.keycloak.KeycloakDevServicesRequiredBuildItem.OIDC_AUTH_SERVER_URL_CONFIG_KEY; - import java.util.HashMap; import io.quarkus.deployment.IsDevelopment; @@ -35,7 +33,7 @@ KeycloakDevServicesRequiredBuildItem requireKeycloakDevService(KeycloakDevServic configProperties.put(OIDC_CLIENT_SECRET_CONFIG_KEY, ctx.oidcClientSecret()); } return configProperties; - }, OIDC_CLIENT_AUTH_SERVER_URL_CONFIG_KEY, OIDC_CLIENT_TOKEN_PATH_CONFIG_KEY, OIDC_AUTH_SERVER_URL_CONFIG_KEY); + }, OIDC_CLIENT_AUTH_SERVER_URL_CONFIG_KEY, OIDC_CLIENT_TOKEN_PATH_CONFIG_KEY); } @BuildStep(onlyIf = IsDevelopment.class) diff --git a/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/OidcClientKeycloakDevServiceStartupTest.java b/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/OidcClientKeycloakDevServiceStartupTest.java new file mode 100644 index 0000000000000..bbb6243429eda --- /dev/null +++ b/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/OidcClientKeycloakDevServiceStartupTest.java @@ -0,0 +1,33 @@ +package io.quarkus.oidc.client; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +/** + * Test Keycloak Dev Service is not started when known social provider is configured + * in Quarkus OIDC extension. + */ +public class OidcClientKeycloakDevServiceStartupTest { + + @RegisterExtension + static final QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot(jar -> jar + .addAsResource(new StringAsset(""" + quarkus.oidc.provider=slack + quarkus.oidc.client-id=irrelevant-client-id + """), "application.properties")) + .setLogRecordPredicate(logRecord -> logRecord != null && logRecord.getMessage() != null + && logRecord.getMessage().contains("Dev Services for Keycloak started")) + .assertLogRecords(logRecords -> assertTrue(logRecords.isEmpty())); + + @Test + public void testDevServiceNotStarted() { + // needs to be here so that log asserter runs after all tests + } + +} diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java index a9ac5fa48a7cd..3087bdc421efd 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServiceRequiredBuildStep.java @@ -21,7 +21,6 @@ public class KeycloakDevServiceRequiredBuildStep { private static final Logger LOG = Logger.getLogger(KeycloakDevServiceRequiredBuildStep.class); private static final String CONFIG_PREFIX = "quarkus.oidc."; private static final String TENANT_ENABLED_CONFIG_KEY = CONFIG_PREFIX + "tenant-enabled"; - private static final String PROVIDER_CONFIG_KEY = CONFIG_PREFIX + "provider"; private static final String APPLICATION_TYPE_CONFIG_KEY = CONFIG_PREFIX + "application-type"; private static final String CLIENT_ID_CONFIG_KEY = CONFIG_PREFIX + "client-id"; private static final String CLIENT_SECRET_CONFIG_KEY = CONFIG_PREFIX + "credentials.secret"; @@ -42,7 +41,7 @@ KeycloakDevServicesRequiredBuildItem requireKeycloakDevService(KeycloakDevServic configProperties.put(CLIENT_SECRET_CONFIG_KEY, ctx.oidcClientSecret()); } return configProperties; - }, OIDC_AUTH_SERVER_URL_CONFIG_KEY, PROVIDER_CONFIG_KEY); + }, OIDC_AUTH_SERVER_URL_CONFIG_KEY); } private static boolean isOidcTenantEnabled() { From 75f11fb2ca7ceb12b0409db364d9583c708eec8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Sat, 7 Dec 2024 14:12:47 +0100 Subject: [PATCH 055/207] feat(rest,resteasy): apply custom ex. mappers on other ex. during auth --- .../AbstractCustomExceptionMapperTest.java | 164 ++++++++++++++++++ .../LazyAuthCustomExceptionMapperTest.java | 18 ++ ...roactiveAuthCustomExceptionMapperTest.java | 17 ++ .../ResteasyStandaloneRecorder.java | 22 ++- .../AbstractCustomExceptionMapperTest.java | 157 +++++++++++++++++ .../LazyAuthCustomExceptionMapperTest.java | 18 ++ ...roactiveAuthCustomExceptionMapperTest.java | 17 ++ .../runtime/ResteasyReactiveRecorder.java | 22 ++- .../security/HttpSecurityRecorder.java | 22 +++ 9 files changed, 452 insertions(+), 5 deletions(-) create mode 100644 extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/AbstractCustomExceptionMapperTest.java create mode 100644 extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/LazyAuthCustomExceptionMapperTest.java create mode 100644 extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/ProactiveAuthCustomExceptionMapperTest.java create mode 100644 extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/AbstractCustomExceptionMapperTest.java create mode 100644 extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/LazyAuthCustomExceptionMapperTest.java create mode 100644 extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/ProactiveAuthCustomExceptionMapperTest.java diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/AbstractCustomExceptionMapperTest.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/AbstractCustomExceptionMapperTest.java new file mode 100644 index 0000000000000..55ef288f5c5da --- /dev/null +++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/AbstractCustomExceptionMapperTest.java @@ -0,0 +1,164 @@ +package io.quarkus.resteasy.test.security; + +import java.util.Map; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +import org.hamcrest.Matchers; +import org.jboss.resteasy.spi.UnhandledException; +import org.junit.jupiter.api.Test; + +import io.quarkus.security.identity.AuthenticationRequestContext; +import io.quarkus.security.identity.IdentityProvider; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.identity.SecurityIdentityAugmentor; +import io.quarkus.security.identity.request.UsernamePasswordAuthenticationRequest; +import io.quarkus.security.runtime.QuarkusPrincipal; +import io.quarkus.security.runtime.QuarkusSecurityIdentity; +import io.quarkus.vertx.http.runtime.security.HttpSecurityUtils; +import io.restassured.RestAssured; +import io.smallrye.mutiny.Uni; +import io.vertx.ext.web.RoutingContext; + +/** + * Tests internal server errors and other custom exceptions raised during + * proactive authentication can be handled by the exception mappers. + * For lazy authentication, it is important that these exceptions raised during authentication + * required by HTTP permissions are also propagated. + */ +public abstract class AbstractCustomExceptionMapperTest { + + @Test + public void testNoExceptions() { + RestAssured.given() + .auth().preemptive().basic("gaston", "gaston-password") + .get("/hello") + .then() + .statusCode(200) + .body(Matchers.is("Hello Gaston")); + RestAssured.given() + .get("/hello") + .then() + .statusCode(401); + } + + @Test + public void testUnhandledRuntimeException() { + // UnhandledRuntimeException has no exception mapper therefore RESTEasy would wrap it in UnhandledException + // if we started RESTEasy even though there is no matching exception mapper + RestAssured.given() + .auth().preemptive().basic("gaston", "gaston-password") + .header("fail-unhandled", "true") + .get("/hello") + .then() + .statusCode(500) + .body(Matchers.not(Matchers.is(UnhandledException.class.getName()))) + .body(Matchers.containsString(UnhandledRuntimeException.class.getName())) + .body(Matchers.containsString("Expected unhandled failure")); + } + + @Test + public void testCustomExceptionInIdentityProvider() { + RestAssured.given() + .auth().preemptive().basic("gaston", "gaston-password") + .header("fail-authentication", "true") + .get("/hello") + .then() + .statusCode(500) + .body(Matchers.is("Expected authentication failure")); + } + + @Test + public void testCustomExceptionInIdentityAugmentor() { + RestAssured.given() + .auth().preemptive().basic("gaston", "gaston-password") + .header("fail-augmentation", "true") + .get("/hello") + .then() + .statusCode(500) + .body(Matchers.is("Expected identity augmentation failure")); + } + + @Path("/hello") + public static class HelloResource { + @GET + public String hello(@Context SecurityContext context) { + var principalName = context.getUserPrincipal() == null ? "" : " " + context.getUserPrincipal().getName(); + return "Hello" + principalName; + } + + } + + @Provider + public static class CustomRuntimeExceptionMapper implements ExceptionMapper { + @Override + public Response toResponse(CustomRuntimeException exception) { + return Response.serverError().entity(exception.getMessage()).build(); + } + } + + @ApplicationScoped + public static class CustomIdentityAugmentor implements SecurityIdentityAugmentor { + @Override + public Uni augment(SecurityIdentity securityIdentity, + AuthenticationRequestContext authenticationRequestContext) { + return augment(securityIdentity, authenticationRequestContext, Map.of()); + } + + @Override + public Uni augment(SecurityIdentity identity, AuthenticationRequestContext context, + Map attributes) { + final RoutingContext routingContext = HttpSecurityUtils.getRoutingContextAttribute(attributes); + if (routingContext.request().headers().contains("fail-augmentation")) { + return Uni.createFrom().failure(new CustomRuntimeException("Expected identity augmentation failure")); + } + return Uni.createFrom().item(identity); + } + } + + public static class CustomRuntimeException extends RuntimeException { + public CustomRuntimeException(String message) { + super(message); + } + } + + public static class UnhandledRuntimeException extends RuntimeException { + public UnhandledRuntimeException(String message) { + super(message); + } + } + + @ApplicationScoped + public static class BasicIdentityProvider implements IdentityProvider { + + @Override + public Class getRequestType() { + return UsernamePasswordAuthenticationRequest.class; + } + + @Override + public Uni authenticate(UsernamePasswordAuthenticationRequest authRequest, + AuthenticationRequestContext authRequestCtx) { + if (!"gaston".equals(authRequest.getUsername())) { + return Uni.createFrom().nullItem(); + } + + final RoutingContext routingContext = HttpSecurityUtils.getRoutingContextAttribute(authRequest); + if (routingContext.request().headers().contains("fail-authentication")) { + return Uni.createFrom().failure(new CustomRuntimeException("Expected authentication failure")); + } + if (routingContext.request().headers().contains("fail-unhandled")) { + return Uni.createFrom().failure(new UnhandledRuntimeException("Expected unhandled failure")); + } + return Uni.createFrom() + .item(QuarkusSecurityIdentity.builder().setPrincipal(new QuarkusPrincipal("Gaston")).build()); + } + } +} diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/LazyAuthCustomExceptionMapperTest.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/LazyAuthCustomExceptionMapperTest.java new file mode 100644 index 0000000000000..5085343e29649 --- /dev/null +++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/LazyAuthCustomExceptionMapperTest.java @@ -0,0 +1,18 @@ +package io.quarkus.resteasy.test.security; + +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class LazyAuthCustomExceptionMapperTest extends AbstractCustomExceptionMapperTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest().withApplicationRoot(jar -> jar + .addAsResource(new StringAsset(""" + quarkus.http.auth.permission.authentication.paths=* + quarkus.http.auth.permission.authentication.policy=authenticated + quarkus.http.auth.proactive=false + """), "application.properties")); + +} diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/ProactiveAuthCustomExceptionMapperTest.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/ProactiveAuthCustomExceptionMapperTest.java new file mode 100644 index 0000000000000..c4bd59e5e8a31 --- /dev/null +++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/ProactiveAuthCustomExceptionMapperTest.java @@ -0,0 +1,17 @@ +package io.quarkus.resteasy.test.security; + +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class ProactiveAuthCustomExceptionMapperTest extends AbstractCustomExceptionMapperTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest().withApplicationRoot(jar -> jar + .addAsResource(new StringAsset(""" + quarkus.http.auth.permission.authentication.paths=* + quarkus.http.auth.permission.authentication.policy=authenticated + """), "application.properties")); + +} diff --git a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/ResteasyStandaloneRecorder.java b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/ResteasyStandaloneRecorder.java index 9de7cb651a3b1..8511466a0500c 100644 --- a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/ResteasyStandaloneRecorder.java +++ b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/ResteasyStandaloneRecorder.java @@ -1,6 +1,9 @@ package io.quarkus.resteasy.runtime.standalone; import static io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder.DefaultAuthFailureHandler.extractRootCause; +import static io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder.DefaultAuthFailureHandler.isOtherAuthenticationFailure; +import static io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder.DefaultAuthFailureHandler.markIfOtherAuthenticationFailure; +import static io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder.DefaultAuthFailureHandler.removeMarkAsOtherAuthenticationFailure; import java.lang.annotation.Annotation; import java.lang.reflect.Proxy; @@ -37,6 +40,7 @@ import io.quarkus.security.AuthenticationFailedException; import io.quarkus.security.AuthenticationRedirectException; import io.quarkus.security.ForbiddenException; +import io.quarkus.security.UnauthorizedException; import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig; import io.quarkus.vertx.http.runtime.HttpCompressionHandler; import io.quarkus.vertx.http.runtime.HttpConfiguration; @@ -163,8 +167,16 @@ public void handle(RoutingContext request) { } } - if (request.failure() instanceof AuthenticationException - || request.failure() instanceof ForbiddenException) { + final Throwable failure = request.failure(); + final boolean isOtherAuthFailure = isOtherAuthenticationFailure(request) + && isFailureHandledByExceptionMappers(failure); + if (isOtherAuthFailure) { + // prevent circular reference for unhandled exceptions + // (which is unnecessary if everything here is done right) + removeMarkAsOtherAuthenticationFailure(request); + super.handle(request); + } else if (failure instanceof AuthenticationException || failure instanceof UnauthorizedException + || failure instanceof ForbiddenException) { super.handle(request); } else { request.next(); @@ -179,6 +191,11 @@ protected void setCurrentIdentityAssociation(RoutingContext routingContext) { } } + private boolean isFailureHandledByExceptionMappers(Throwable failure) { + return failure != null && deployment != null + && deployment.getProviderFactory().getExceptionMapper(failure.getClass()) != null; + } + public Handler defaultAuthFailureHandler() { return new Handler() { @Override @@ -204,6 +221,7 @@ public void handle(RoutingContext event) { @Override public void accept(RoutingContext event, Throwable throwable) { + markIfOtherAuthenticationFailure(event, throwable); if (!event.failed()) { event.fail(extractRootCause(throwable)); } diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/AbstractCustomExceptionMapperTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/AbstractCustomExceptionMapperTest.java new file mode 100644 index 0000000000000..a553cd1823209 --- /dev/null +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/AbstractCustomExceptionMapperTest.java @@ -0,0 +1,157 @@ +package io.quarkus.resteasy.reactive.server.test.security; + +import java.util.Map; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; + +import org.hamcrest.Matchers; +import org.jboss.resteasy.reactive.server.ServerExceptionMapper; +import org.junit.jupiter.api.Test; + +import io.quarkus.security.identity.AuthenticationRequestContext; +import io.quarkus.security.identity.IdentityProvider; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.identity.SecurityIdentityAugmentor; +import io.quarkus.security.identity.request.UsernamePasswordAuthenticationRequest; +import io.quarkus.security.runtime.QuarkusPrincipal; +import io.quarkus.security.runtime.QuarkusSecurityIdentity; +import io.quarkus.vertx.http.runtime.security.HttpSecurityUtils; +import io.restassured.RestAssured; +import io.smallrye.mutiny.Uni; +import io.vertx.ext.web.RoutingContext; + +/** + * Tests internal server errors and other custom exceptions raised during + * proactive authentication can be handled by the exception mappers. + * For lazy authentication, it is important that these exceptions raised during authentication + * required by HTTP permissions are also propagated. + */ +public abstract class AbstractCustomExceptionMapperTest { + + @Test + public void testNoExceptions() { + RestAssured.given() + .auth().preemptive().basic("gaston", "gaston-password") + .get("/hello") + .then() + .statusCode(200) + .body(Matchers.is("Hello Gaston")); + RestAssured.given() + .get("/hello") + .then() + .statusCode(401); + } + + @Test + public void testUnhandledRuntimeException() { + RestAssured.given() + .auth().preemptive().basic("gaston", "gaston-password") + .header("fail-unhandled", "true") + .get("/hello") + .then() + .statusCode(500) + .body(Matchers.containsString(UnhandledRuntimeException.class.getName())) + .body(Matchers.containsString("Expected unhandled failure")); + } + + @Test + public void testCustomExceptionInIdentityProvider() { + RestAssured.given() + .auth().preemptive().basic("gaston", "gaston-password") + .header("fail-authentication", "true") + .get("/hello") + .then() + .statusCode(500) + .body(Matchers.is("Expected authentication failure")); + } + + @Test + public void testCustomExceptionInIdentityAugmentor() { + RestAssured.given() + .auth().preemptive().basic("gaston", "gaston-password") + .header("fail-augmentation", "true") + .get("/hello") + .then() + .statusCode(500) + .body(Matchers.is("Expected identity augmentation failure")); + } + + @Path("/hello") + public static class HelloResource { + @GET + public String hello(@Context SecurityContext context) { + var principalName = context.getUserPrincipal() == null ? "" : " " + context.getUserPrincipal().getName(); + return "Hello" + principalName; + } + } + + public static class Mappers { + @ServerExceptionMapper(CustomRuntimeException.class) + public Response toResponse(CustomRuntimeException exception) { + return Response.serverError().entity(exception.getMessage()).build(); + } + } + + @ApplicationScoped + public static class CustomIdentityAugmentor implements SecurityIdentityAugmentor { + @Override + public Uni augment(SecurityIdentity securityIdentity, + AuthenticationRequestContext authenticationRequestContext) { + return augment(securityIdentity, authenticationRequestContext, Map.of()); + } + + @Override + public Uni augment(SecurityIdentity identity, AuthenticationRequestContext context, + Map attributes) { + final RoutingContext routingContext = HttpSecurityUtils.getRoutingContextAttribute(attributes); + if (routingContext.request().headers().contains("fail-augmentation")) { + return Uni.createFrom().failure(new CustomRuntimeException("Expected identity augmentation failure")); + } + return Uni.createFrom().item(identity); + } + } + + public static class CustomRuntimeException extends RuntimeException { + public CustomRuntimeException(String message) { + super(message); + } + } + + public static class UnhandledRuntimeException extends RuntimeException { + public UnhandledRuntimeException(String message) { + super(message); + } + } + + @ApplicationScoped + public static class BasicIdentityProvider implements IdentityProvider { + + @Override + public Class getRequestType() { + return UsernamePasswordAuthenticationRequest.class; + } + + @Override + public Uni authenticate(UsernamePasswordAuthenticationRequest authRequest, + AuthenticationRequestContext authRequestCtx) { + if (!"gaston".equals(authRequest.getUsername())) { + return Uni.createFrom().nullItem(); + } + + final RoutingContext routingContext = HttpSecurityUtils.getRoutingContextAttribute(authRequest); + if (routingContext.request().headers().contains("fail-authentication")) { + return Uni.createFrom().failure(new CustomRuntimeException("Expected authentication failure")); + } + if (routingContext.request().headers().contains("fail-unhandled")) { + return Uni.createFrom().failure(new UnhandledRuntimeException("Expected unhandled failure")); + } + return Uni.createFrom() + .item(QuarkusSecurityIdentity.builder().setPrincipal(new QuarkusPrincipal("Gaston")).build()); + } + } +} diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/LazyAuthCustomExceptionMapperTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/LazyAuthCustomExceptionMapperTest.java new file mode 100644 index 0000000000000..c57a3eeabbbe9 --- /dev/null +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/LazyAuthCustomExceptionMapperTest.java @@ -0,0 +1,18 @@ +package io.quarkus.resteasy.reactive.server.test.security; + +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class LazyAuthCustomExceptionMapperTest extends AbstractCustomExceptionMapperTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest().withApplicationRoot(jar -> jar + .addAsResource(new StringAsset(""" + quarkus.http.auth.permission.authentication.paths=* + quarkus.http.auth.permission.authentication.policy=authenticated + quarkus.http.auth.proactive=false + """), "application.properties")); + +} diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/ProactiveAuthCustomExceptionMapperTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/ProactiveAuthCustomExceptionMapperTest.java new file mode 100644 index 0000000000000..afe82d74700a0 --- /dev/null +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/ProactiveAuthCustomExceptionMapperTest.java @@ -0,0 +1,17 @@ +package io.quarkus.resteasy.reactive.server.test.security; + +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class ProactiveAuthCustomExceptionMapperTest extends AbstractCustomExceptionMapperTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest().withApplicationRoot(jar -> jar + .addAsResource(new StringAsset(""" + quarkus.http.auth.permission.authentication.paths=* + quarkus.http.auth.permission.authentication.policy=authenticated + """), "application.properties")); + +} diff --git a/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java b/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java index 0d28c5159b7ed..9b438d2452ccd 100644 --- a/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java +++ b/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java @@ -1,6 +1,9 @@ package io.quarkus.resteasy.reactive.server.runtime; import static io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder.DefaultAuthFailureHandler.extractRootCause; +import static io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder.DefaultAuthFailureHandler.isOtherAuthenticationFailure; +import static io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder.DefaultAuthFailureHandler.markIfOtherAuthenticationFailure; +import static io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder.DefaultAuthFailureHandler.removeMarkAsOtherAuthenticationFailure; import java.io.Closeable; import java.lang.reflect.InvocationTargetException; @@ -66,6 +69,7 @@ import io.quarkus.security.AuthenticationFailedException; import io.quarkus.security.AuthenticationRedirectException; import io.quarkus.security.ForbiddenException; +import io.quarkus.security.UnauthorizedException; import io.quarkus.security.identity.CurrentIdentityAssociation; import io.quarkus.vertx.http.runtime.CurrentVertxRequest; import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig; @@ -231,9 +235,15 @@ public void handle(RoutingContext event) { } } - if (event.failure() instanceof AuthenticationException - || event.failure() instanceof ForbiddenException) { - restInitialHandler.beginProcessing(event, event.failure()); + final Throwable failure = event.failure(); + final boolean isOtherAuthFailure = isOtherAuthenticationFailure(event) + && isFailureHandledByExceptionMappers(failure); + if (isOtherAuthFailure) { + removeMarkAsOtherAuthenticationFailure(event); + restInitialHandler.beginProcessing(event, failure); + } else if (failure instanceof AuthenticationException + || failure instanceof UnauthorizedException || failure instanceof ForbiddenException) { + restInitialHandler.beginProcessing(event, failure); } else { event.next(); } @@ -241,6 +251,11 @@ public void handle(RoutingContext event) { }; } + private boolean isFailureHandledByExceptionMappers(Throwable throwable) { + return currentDeployment != null + && currentDeployment.getExceptionMapper().getExceptionMapper(throwable.getClass(), null, null) != null; + } + /** * This is Quarkus specific. *

    * For Redpanda: - * See https://docs.redpanda.com/current/get-started/quick-start/ and https://hub.docker.com/r/vectorized/redpanda + * See https://docs.redpanda.com/current/get-started/quick-start/ and https://hub.docker.com/r/redpandadata/redpanda *

    * For Strimzi: * See https://github.com/strimzi/test-container and https://quay.io/repository/strimzi-test-container/test-container @@ -48,7 +48,7 @@ public class KafkaDevServicesBuildTimeConfig { public Provider provider = Provider.REDPANDA; public enum Provider { - REDPANDA("docker.io/vectorized/redpanda:v24.1.2"), + REDPANDA("docker.io/redpandadata/redpanda:v24.1.2"), STRIMZI("quay.io/strimzi-test-container/test-container:latest-kafka-3.7.0"), KAFKA_NATIVE("quay.io/ogunalp/kafka-native:latest"); From f39fd218dda5b21b77d55dc5a1ff624a52ed1857 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Tue, 10 Dec 2024 11:02:33 +0100 Subject: [PATCH 074/207] Bring back the dependencies menu item in Dev UI --- .../io/quarkus/devui/deployment/menu/DependenciesProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/menu/DependenciesProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/menu/DependenciesProcessor.java index 5708cb57c99e5..43d11dc5fe48c 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/menu/DependenciesProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/menu/DependenciesProcessor.java @@ -84,7 +84,7 @@ void createBuildTimeActions(BuildProducer buildTimeAct private boolean isEnabled() { var value = ConfigProvider.getConfig().getConfigValue("quarkus.bootstrap.incubating-model-resolver"); // if it's not false and if it's false it doesn't come from the default value - return value == null || !"false".equals(value.getValue()) || "default values".equals(value.getSourceName()); + return value == null || !"false".equals(value.getValue()) || "DefaultValuesConfigSource".equals(value.getSourceName()); } private void buildTree(ApplicationModel model, Root root, Optional> allGavs, Optional toTarget) { From 53bbff41bd48ad2451eb92cbc5cb6d7b52d9ec67 Mon Sep 17 00:00:00 2001 From: Michael Edgar Date: Sun, 8 Dec 2024 20:56:14 -0500 Subject: [PATCH 075/207] OpenAPI: check super class for inherited auto-security resource methods Signed-off-by: Michael Edgar --- .../deployment/SmallRyeOpenApiProcessor.java | 47 +++++++++++---- .../deployment/filter/ClassAndMethod.java | 5 +- .../deployment/filter/OperationFilter.java | 4 +- .../AutoSecurityAuthenticateTestCase.java | 57 +++++++++---------- ...OpenApiResourceAuthenticatedInherited.java | 15 +++++ 5 files changed, 83 insertions(+), 45 deletions(-) create mode 100644 extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited.java diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java index 00d2a9ad6c697..8f46b46da752a 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java @@ -595,7 +595,7 @@ private Map> getRolesAllowedMethodReferences(OpenApiFiltere .flatMap(Collection::stream) .flatMap(t -> getMethods(t, index)) .collect(Collectors.toMap( - e -> createUniqueMethodReference(e.getKey().declaringClass(), e.getKey()), + e -> createUniqueMethodReference(e.getKey().classInfo(), e.getKey().method()), e -> List.of(e.getValue().value().asStringArray()), (v1, v2) -> { if (!Objects.equals(v1, v2)) { @@ -615,7 +615,7 @@ private List getPermissionsAllowedMethodReferences( .getAnnotations(DotName.createSimple(PermissionsAllowed.class)) .stream() .flatMap(t -> getMethods(t, index)) - .map(e -> createUniqueMethodReference(e.getKey().declaringClass(), e.getKey())) + .map(e -> createUniqueMethodReference(e.getKey().classInfo(), e.getKey().method())) .distinct() .toList(); } @@ -626,18 +626,18 @@ private List getAuthenticatedMethodReferences(OpenApiFilteredIndexViewBu .getAnnotations(DotName.createSimple(Authenticated.class.getName())) .stream() .flatMap(t -> getMethods(t, index)) - .map(e -> createUniqueMethodReference(e.getKey().declaringClass(), e.getKey())) + .map(e -> createUniqueMethodReference(e.getKey().classInfo(), e.getKey().method())) .distinct() .toList(); } - private static Stream> getMethods(AnnotationInstance annotation, + private static Stream> getMethods(AnnotationInstance annotation, IndexView index) { if (annotation.target().kind() == Kind.METHOD) { MethodInfo method = annotation.target().asMethod(); if (isValidOpenAPIMethodForAutoAdd(method)) { - return Stream.of(Map.entry(method, annotation)); + return Stream.of(Map.entry(new ClassAndMethod(method.declaringClass(), method), annotation)); } } else if (annotation.target().kind() == Kind.CLASS) { ClassInfo classInfo = annotation.target().asClass(); @@ -647,7 +647,23 @@ private static Stream> getMethods(Anno // drop methods that specify the annotation directly .filter(method -> !method.hasDeclaredAnnotation(annotation.name())) .filter(method -> isValidOpenAPIMethodForAutoAdd(method)) - .map(method -> Map.entry(method, annotation)); + .map(method -> { + final ClassInfo resourceClass; + + if (method.declaringClass().isInterface()) { + /* + * smallrye-open-api processes interfaces as the resource class as long as + * there is a concrete implementation available. Using the interface method's + * declaring class here allows us to match on the hash that will be set by + * #handleOperation during scanning. + */ + resourceClass = method.declaringClass(); + } else { + resourceClass = classInfo; + } + + return Map.entry(new ClassAndMethod(resourceClass, method), annotation); + }); } return Stream.empty(); @@ -678,7 +694,7 @@ private Map getClassNamesMethodReferences( .getAllKnownSubclasses(declaringClass.name()), classNames); } else { String ref = createUniqueMethodReference(declaringClass, method); - classNames.put(ref, new ClassAndMethod(declaringClass.simpleName(), method.name())); + classNames.put(ref, new ClassAndMethod(declaringClass, method)); } } } @@ -688,16 +704,15 @@ private Map getClassNamesMethodReferences( void addMethodImplementationClassNames(MethodInfo method, Type[] params, Collection classes, Map classNames) { for (ClassInfo impl : classes) { - String simpleClassName = impl.simpleName(); MethodInfo implMethod = impl.method(method.name(), params); if (implMethod != null) { classNames.put(createUniqueMethodReference(impl, implMethod), - new ClassAndMethod(simpleClassName, implMethod.name())); + new ClassAndMethod(impl, implMethod)); } classNames.put(createUniqueMethodReference(impl, method), - new ClassAndMethod(simpleClassName, method.name())); + new ClassAndMethod(impl, method)); } } @@ -769,7 +784,6 @@ private static boolean isOpenAPIEndpoint(MethodInfo method) { } private static List getMethods(ClassInfo declaringClass, IndexView index) { - List methods = new ArrayList<>(); methods.addAll(declaringClass.methods()); @@ -782,8 +796,17 @@ private static List getMethods(ClassInfo declaringClass, IndexView i } } } - return methods; + DotName superClassName = declaringClass.superName(); + if (superClassName != null) { + ClassInfo superClass = index.getClassByName(superClassName); + + if (superClass != null) { + methods.addAll(getMethods(superClass, index)); + } + } + + return methods; } private static Set getAllOpenAPIEndpoints() { diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/ClassAndMethod.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/ClassAndMethod.java index d5f1bce941d38..737adf0d6d5b8 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/ClassAndMethod.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/ClassAndMethod.java @@ -1,5 +1,8 @@ package io.quarkus.smallrye.openapi.deployment.filter; -public record ClassAndMethod(String className, String methodName) { +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.MethodInfo; + +public record ClassAndMethod(ClassInfo classInfo, MethodInfo method) { } diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/OperationFilter.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/OperationFilter.java index 640a919febf5d..296a2c4746e5a 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/OperationFilter.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/OperationFilter.java @@ -106,11 +106,11 @@ private void maybeSetSummaryAndTag(Operation operation, String methodRef) { if (doAutoOperation && operation.getSummary() == null) { // Auto add a summary - operation.setSummary(capitalizeFirstLetter(splitCamelCase(classMethod.methodName()))); + operation.setSummary(capitalizeFirstLetter(splitCamelCase(classMethod.method().name()))); } if (doAutoTag && (operation.getTags() == null || operation.getTags().isEmpty())) { - operation.addTag(splitCamelCase(classMethod.className())); + operation.addTag(splitCamelCase(classMethod.classInfo().simpleName())); } } diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityAuthenticateTestCase.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityAuthenticateTestCase.java index ff27f0614a282..7cef904c30b9c 100644 --- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityAuthenticateTestCase.java +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityAuthenticateTestCase.java @@ -1,5 +1,7 @@ package io.quarkus.smallrye.openapi.test.jaxrs; +import static org.hamcrest.Matchers.notNullValue; + import org.hamcrest.Matchers; import org.jboss.shrinkwrap.api.asset.StringAsset; import org.junit.jupiter.api.Test; @@ -8,50 +10,45 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class AutoSecurityAuthenticateTestCase { +class AutoSecurityAuthenticateTestCase { + @RegisterExtension static QuarkusUnitTest runner = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(ResourceBean2.class, OpenApiResourceAuthenticatedAtClassLevel.class, + OpenApiResourceAuthenticatedInherited.class, OpenApiResourceAuthenticatedAtMethodLevel.class, OpenApiResourceAuthenticatedAtMethodLevel2.class) .addAsResource( - new StringAsset("quarkus.smallrye-openapi.security-scheme=jwt\n" - + "quarkus.smallrye-openapi.security-scheme-name=JWTCompanyAuthentication\n" - + "quarkus.smallrye-openapi.security-scheme-description=JWT Authentication"), - + new StringAsset(""" + quarkus.smallrye-openapi.security-scheme=jwt + quarkus.smallrye-openapi.security-scheme-name=JWTCompanyAuthentication + quarkus.smallrye-openapi.security-scheme-description=JWT Authentication + """), "application.properties")); @Test - public void testAutoSecurityRequirement() { + void testAutoSecurityRequirement() { RestAssured.given().header("Accept", "application/json") .when().get("/q/openapi") .then() .log().body() .and() - .body("components.securitySchemes.JWTCompanyAuthentication", Matchers.hasEntry("type", "http")) - .and() - .body("components.securitySchemes.JWTCompanyAuthentication", - Matchers.hasEntry("description", "JWT Authentication")) - .and() - .body("components.securitySchemes.JWTCompanyAuthentication", Matchers.hasEntry("scheme", "bearer")) - .and() - .body("components.securitySchemes.JWTCompanyAuthentication", Matchers.hasEntry("bearerFormat", "JWT")) - .and() - .body("paths.'/resource2/test-security/annotated'.get.security.JWTCompanyAuthentication", - Matchers.notNullValue()) - .and() - .body("paths.'/resource2/test-security/naked'.get.security.JWTCompanyAuthentication", Matchers.notNullValue()) - .and() - .body("paths.'/resource2/test-security/classLevel/1'.get.security.JWTCompanyAuthentication", - Matchers.notNullValue()) - .and() - .body("paths.'/resource2/test-security/classLevel/2'.get.security.JWTCompanyAuthentication", - Matchers.notNullValue()) - .and() - .body("paths.'/resource2/test-security/classLevel/3'.get.security.MyOwnName", - Matchers.notNullValue()) - .and() - .body("paths.'/resource3/test-security/annotated'.get.security.AtClassLevel", Matchers.notNullValue()); + .body("components.securitySchemes.JWTCompanyAuthentication", Matchers.allOf( + Matchers.hasEntry("type", "http"), + Matchers.hasEntry("description", "JWT Authentication"), + Matchers.hasEntry("scheme", "bearer"), + Matchers.hasEntry("bearerFormat", "JWT"))) + .body("paths.'/resource2/test-security/annotated'.get.security.JWTCompanyAuthentication", notNullValue()) + .body("paths.'/resource2/test-security/naked'.get.security.JWTCompanyAuthentication", notNullValue()) + .body("paths.'/resource2/test-security/classLevel/1'.get.security.JWTCompanyAuthentication", notNullValue()) + .body("paths.'/resource2/test-security/classLevel/2'.get.security.JWTCompanyAuthentication", notNullValue()) + .body("paths.'/resource2/test-security/classLevel/3'.get.security.MyOwnName", notNullValue()) + .body("paths.'/resource3/test-security/annotated'.get.security.AtClassLevel", notNullValue()) + .body("paths.'/resource-inherited/test-security/classLevel/1'.get.security.JWTCompanyAuthentication", + notNullValue()) + .body("paths.'/resource-inherited/test-security/classLevel/2'.get.security.JWTCompanyAuthentication", + notNullValue()) + .body("paths.'/resource-inherited/test-security/classLevel/3'.get.security.MyOwnName", notNullValue()); } diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited.java new file mode 100644 index 0000000000000..eecfd48644c34 --- /dev/null +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited.java @@ -0,0 +1,15 @@ +package io.quarkus.smallrye.openapi.test.jaxrs; + +import jakarta.ws.rs.Path; + +import org.eclipse.microprofile.openapi.annotations.servers.Server; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; + +import io.quarkus.security.Authenticated; + +@Path("/resource-inherited") +@Tag(name = "test") +@Server(url = "serverUrl") +@Authenticated +public class OpenApiResourceAuthenticatedInherited extends OpenApiResourceAuthenticatedAtClassLevel { +} From 8f0701f40e13e69b065bfa384629a468a6d11ee2 Mon Sep 17 00:00:00 2001 From: Michael Edgar Date: Tue, 10 Dec 2024 06:02:32 -0500 Subject: [PATCH 076/207] Update auto `@Authenticated` test for multi-level resource inheritance Signed-off-by: Michael Edgar --- .../AutoSecurityAuthenticateTestCase.java | 13 +++++++--- ...enApiResourceAuthenticatedInherited1.java} | 4 +-- ...penApiResourceAuthenticatedInherited2.java | 25 +++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) rename extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/{OpenApiResourceAuthenticatedInherited.java => OpenApiResourceAuthenticatedInherited1.java} (70%) create mode 100644 extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited2.java diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityAuthenticateTestCase.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityAuthenticateTestCase.java index 7cef904c30b9c..76e542bdf0b52 100644 --- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityAuthenticateTestCase.java +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityAuthenticateTestCase.java @@ -16,7 +16,7 @@ class AutoSecurityAuthenticateTestCase { static QuarkusUnitTest runner = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(ResourceBean2.class, OpenApiResourceAuthenticatedAtClassLevel.class, - OpenApiResourceAuthenticatedInherited.class, + OpenApiResourceAuthenticatedInherited1.class, OpenApiResourceAuthenticatedInherited2.class, OpenApiResourceAuthenticatedAtMethodLevel.class, OpenApiResourceAuthenticatedAtMethodLevel2.class) .addAsResource( new StringAsset(""" @@ -44,11 +44,16 @@ void testAutoSecurityRequirement() { .body("paths.'/resource2/test-security/classLevel/2'.get.security.JWTCompanyAuthentication", notNullValue()) .body("paths.'/resource2/test-security/classLevel/3'.get.security.MyOwnName", notNullValue()) .body("paths.'/resource3/test-security/annotated'.get.security.AtClassLevel", notNullValue()) - .body("paths.'/resource-inherited/test-security/classLevel/1'.get.security.JWTCompanyAuthentication", + .body("paths.'/resource-inherited1/test-security/classLevel/1'.get.security.JWTCompanyAuthentication", notNullValue()) - .body("paths.'/resource-inherited/test-security/classLevel/2'.get.security.JWTCompanyAuthentication", + .body("paths.'/resource-inherited1/test-security/classLevel/2'.get.security.JWTCompanyAuthentication", notNullValue()) - .body("paths.'/resource-inherited/test-security/classLevel/3'.get.security.MyOwnName", notNullValue()); + .body("paths.'/resource-inherited1/test-security/classLevel/3'.get.security.MyOwnName", notNullValue()) + .body("paths.'/resource-inherited2/test-security/classLevel/1'.get.security.JWTCompanyAuthentication", + notNullValue()) + .body("paths.'/resource-inherited2/test-security/classLevel/2'.get.security.CustomOverride", + notNullValue()) + .body("paths.'/resource-inherited2/test-security/classLevel/3'.get.security.MyOwnName", notNullValue()); } diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited1.java similarity index 70% rename from extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited.java rename to extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited1.java index eecfd48644c34..c36256db65adb 100644 --- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited.java +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited1.java @@ -7,9 +7,9 @@ import io.quarkus.security.Authenticated; -@Path("/resource-inherited") +@Path("/resource-inherited1") @Tag(name = "test") @Server(url = "serverUrl") @Authenticated -public class OpenApiResourceAuthenticatedInherited extends OpenApiResourceAuthenticatedAtClassLevel { +public class OpenApiResourceAuthenticatedInherited1 extends OpenApiResourceAuthenticatedAtClassLevel { } diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited2.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited2.java new file mode 100644 index 0000000000000..8e03fcb10b884 --- /dev/null +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceAuthenticatedInherited2.java @@ -0,0 +1,25 @@ +package io.quarkus.smallrye.openapi.test.jaxrs; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement; +import org.eclipse.microprofile.openapi.annotations.servers.Server; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; + +import io.quarkus.security.Authenticated; + +@Path("/resource-inherited2") +@Tag(name = "test") +@Server(url = "serverUrl") +@Authenticated +public class OpenApiResourceAuthenticatedInherited2 extends OpenApiResourceAuthenticatedInherited1 { + + @GET + @Path("/test-security/classLevel/2") + @SecurityRequirement(name = "CustomOverride") + public String secureEndpoint2() { + return "secret"; + } + +} From f7f887294288e06b6fb617f284d7e931852bd279 Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Tue, 10 Dec 2024 09:02:51 -0300 Subject: [PATCH 077/207] Add documentation about GeneratedStaticResourceBuildItem and GeneratedResourceBuildItem --- .../src/main/asciidoc/writing-extensions.adoc | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/docs/src/main/asciidoc/writing-extensions.adoc b/docs/src/main/asciidoc/writing-extensions.adoc index 5e6f84dcf8340..d0d4760156db0 100644 --- a/docs/src/main/asciidoc/writing-extensions.adoc +++ b/docs/src/main/asciidoc/writing-extensions.adoc @@ -1584,6 +1584,73 @@ If bytecode recording isn't sufficient, link:https://github.com/quarkusio/gizmo/ Extensions often need a way to determine whether a given class is part of the application's runtime classpath. The proper way for an extension to perform this check is to use `io.quarkus.bootstrap.classloading.QuarkusClassLoader.isClassPresentAtRuntime`. +[[generating-resources]] +=== Generating Resources + +It is possible to generate resources using extensions, in some scenarios you need to generate a resource into `META-INF` directory, the resource can be a service for SPI or a simple HTML, CSS, Javascript files. + +[source,java] +---- +/** + * This build step aggregates all the produced service providers + * and outputs them as resources. + */ +@BuildStep +public void produceServiceFiles( + BuildProducer generatedStaticResourceProducer, + BuildProducer generatedResourceProducer +) throws IOException { + + generatedResourceProducer.produce( // <1> + new GeneratedResourceBuildItem( + "META-INF/services/io.quarkus.services.GreetingService", + """ + public class HelloService implements GreetingService { + + @Override + public void do() { + System.out.println("Hello!"); + } + } + """.getBytes(StandardCharsets.UTF_8))); + + + generatedStaticResourceProducer.produce( // <2> + new GeneratedStaticResourceBuildItem( + "/index.js", + "console.log('Hello World!')".getBytes(StandardCharsets.UTF_8)) + ); +} +---- + +1. Producing a SPI service implementation as a resource in META-INF/services +2. Producing a static resource (e.g., JavaScript file) served by Vertx + +==== Key Points + +. **`GeneratedResourceBuildItem`** +* Generates resources that are persisted in production mode. +* In development and other non-production modes, the resources are kept in memory and loaded using the `QuarkusClassLoader`. + +. **`GeneratedStaticResourceBuildItem`** +* Generates static resources (e.g., files like JavaScript, HTML, or CSS) served by Vertx. +* In development mode, Quarkus serves these resources using a Vertx handler backed by a classloader-based filesystem. + +==== Differences Between `GeneratedResourceBuildItem` and `GeneratedStaticResourceBuildItem` + +While both are used to generate resources, their purposes and behaviors differ: + +* **`GeneratedResourceBuildItem`** +* Used for resources required at runtime (e.g., SPI service definitions). +* Persisted only in production mode; otherwise, stored in memory. + +* **`GeneratedStaticResourceBuildItem`** +* Designed for serving static resources via HTTP (e.g., JavaScript or CSS files). +* In development mode, these resources are served dynamically using Vertx. +* Generates a `GeneratedResourceBuildItem`. +* Generates a `AdditionalStaticResourceBuildItem` only on normal mode. + +By using these build items appropriately, you can generate and manage resources effectively within your Quarkus extension. //// TODO: config integration //// From 156d6ab359af77e7bdccc1e72b4271db48717114 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 10 Dec 2024 14:21:20 +0100 Subject: [PATCH 078/207] Revert "Bump org.mariadb.jdbc:mariadb-java-client from 3.5.0 to 3.5.1" This reverts commit fec0f5029f497237127289b4dcc60dd860885a27. --- bom/application/pom.xml | 2 +- ...endPamAuthPacketFactory_Substitutions.java | 23 --------------- .../SendPamAuthPacket_Substitutions.java | 28 ++++++++++++++----- 3 files changed, 22 insertions(+), 31 deletions(-) delete mode 100644 extensions/jdbc/jdbc-mariadb/runtime/src/main/java/io/quarkus/jdbc/mariadb/runtime/graal/SendPamAuthPacketFactory_Substitutions.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index d384a92a9f560..898b2172d4f54 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -119,7 +119,7 @@ 2.3.230 42.7.4 - 3.5.1 + 3.5.0 8.3.0 12.8.1.jre11 1.6.7 diff --git a/extensions/jdbc/jdbc-mariadb/runtime/src/main/java/io/quarkus/jdbc/mariadb/runtime/graal/SendPamAuthPacketFactory_Substitutions.java b/extensions/jdbc/jdbc-mariadb/runtime/src/main/java/io/quarkus/jdbc/mariadb/runtime/graal/SendPamAuthPacketFactory_Substitutions.java deleted file mode 100644 index d775c42f26c41..0000000000000 --- a/extensions/jdbc/jdbc-mariadb/runtime/src/main/java/io/quarkus/jdbc/mariadb/runtime/graal/SendPamAuthPacketFactory_Substitutions.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.quarkus.jdbc.mariadb.runtime.graal; - -import org.mariadb.jdbc.Configuration; -import org.mariadb.jdbc.HostAddress; -import org.mariadb.jdbc.plugin.AuthenticationPlugin; -import org.mariadb.jdbc.plugin.authentication.standard.SendPamAuthPacketFactory; - -import com.oracle.svm.core.annotate.Substitute; -import com.oracle.svm.core.annotate.TargetClass; - -/** - * The SendPamAuthPacketFactory class is not supported in native mode. - */ -@TargetClass(SendPamAuthPacketFactory.class) -public final class SendPamAuthPacketFactory_Substitutions { - - @Substitute - public AuthenticationPlugin initialize(String authenticationData, byte[] seed, Configuration conf, - HostAddress hostAddress) { - throw new UnsupportedOperationException("Authentication strategy 'dialog' is not supported in GraalVM"); - } - -} diff --git a/extensions/jdbc/jdbc-mariadb/runtime/src/main/java/io/quarkus/jdbc/mariadb/runtime/graal/SendPamAuthPacket_Substitutions.java b/extensions/jdbc/jdbc-mariadb/runtime/src/main/java/io/quarkus/jdbc/mariadb/runtime/graal/SendPamAuthPacket_Substitutions.java index 8365c7b36f3bf..b03ac4cb81651 100644 --- a/extensions/jdbc/jdbc-mariadb/runtime/src/main/java/io/quarkus/jdbc/mariadb/runtime/graal/SendPamAuthPacket_Substitutions.java +++ b/extensions/jdbc/jdbc-mariadb/runtime/src/main/java/io/quarkus/jdbc/mariadb/runtime/graal/SendPamAuthPacket_Substitutions.java @@ -1,15 +1,29 @@ package io.quarkus.jdbc.mariadb.runtime.graal; -import org.mariadb.jdbc.plugin.authentication.standard.SendPamAuthPacket; +import java.io.IOException; +import java.sql.SQLException; -import com.oracle.svm.core.annotate.Delete; +import org.mariadb.jdbc.Configuration; +import org.mariadb.jdbc.HostAddress; +import org.mariadb.jdbc.client.Context; +import org.mariadb.jdbc.client.ReadableByteBuf; +import org.mariadb.jdbc.client.socket.Reader; +import org.mariadb.jdbc.client.socket.Writer; + +import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -/** - * The SendPamAuthPacket class is not supported in native mode. - */ -@Delete -@TargetClass(SendPamAuthPacket.class) +@TargetClass(className = "org.mariadb.jdbc.plugin.authentication.standard.SendPamAuthPacket") public final class SendPamAuthPacket_Substitutions { + @Substitute + public void initialize(String authenticationData, byte[] seed, Configuration conf, HostAddress hostAddress) { + throw new UnsupportedOperationException("Authentication strategy 'dialog' is not supported in GraalVM"); + } + + @Substitute + public ReadableByteBuf process(Writer out, Reader in, Context context) + throws SQLException, IOException { + throw new UnsupportedOperationException("Authentication strategy 'dialog' is not supported in GraalVM"); + } } From 1b2e53b9d3ecdf0993e8595c43b318ae449ce067 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 10 Dec 2024 14:21:38 +0100 Subject: [PATCH 079/207] Revert "Bump org.mariadb.jdbc:mariadb-java-client from 3.4.1 to 3.5.0" This reverts commit bc38e9348cfc2496d2a43d9fb28e7e100276c014. --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 898b2172d4f54..65b06f26d1307 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -119,7 +119,7 @@ 2.3.230 42.7.4 - 3.5.0 + 3.4.1 8.3.0 12.8.1.jre11 1.6.7 From 2225847a0fab55e57c0e1720771a3499e041c71a Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Tue, 10 Dec 2024 10:22:21 -0300 Subject: [PATCH 080/207] Remove glitch --- docs/src/main/asciidoc/writing-extensions.adoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/writing-extensions.adoc b/docs/src/main/asciidoc/writing-extensions.adoc index d0d4760156db0..5ef15c1907b8b 100644 --- a/docs/src/main/asciidoc/writing-extensions.adoc +++ b/docs/src/main/asciidoc/writing-extensions.adoc @@ -1640,11 +1640,13 @@ public void produceServiceFiles( While both are used to generate resources, their purposes and behaviors differ: -* **`GeneratedResourceBuildItem`** +**`GeneratedResourceBuildItem`:** + * Used for resources required at runtime (e.g., SPI service definitions). * Persisted only in production mode; otherwise, stored in memory. -* **`GeneratedStaticResourceBuildItem`** +**`GeneratedStaticResourceBuildItem`:** + * Designed for serving static resources via HTTP (e.g., JavaScript or CSS files). * In development mode, these resources are served dynamically using Vertx. * Generates a `GeneratedResourceBuildItem`. From 304406f2db9c1c3459f39db61285346222eb51e1 Mon Sep 17 00:00:00 2001 From: vkn Date: Tue, 10 Dec 2024 14:32:06 +0100 Subject: [PATCH 081/207] Enable mongodb micrometer metrics --- .../mongodb/deployment/MongoClientProcessor.java | 15 +++++++++++++++ .../metrics/MicrometerCommandListener.java | 14 ++++++++++++++ .../mongodb/runtime/MongoClientRecorder.java | 5 +++++ .../panache/MongodbPanacheResourceTest.java | 1 + 4 files changed, 35 insertions(+) create mode 100644 extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/metrics/MicrometerCommandListener.java diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java index 6413be3720314..128f205661287 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java @@ -124,6 +124,21 @@ AdditionalIndexedClassesBuildItem includeMongoCommandListener(MongoClientBuildTi return new AdditionalIndexedClassesBuildItem(); } + @BuildStep + AdditionalIndexedClassesBuildItem includeMongoCommandMetricListener( + MongoClientBuildTimeConfig buildTimeConfig, + Optional metricsCapability) { + if (!buildTimeConfig.metricsEnabled) { + return new AdditionalIndexedClassesBuildItem(); + } + boolean withMicrometer = metricsCapability.map(cap -> cap.metricsSupported(MetricsFactory.MICROMETER)) + .orElse(false); + if (withMicrometer) { + return new AdditionalIndexedClassesBuildItem(MongoClientRecorder.getMicrometerCommandListenerClassName()); + } + return new AdditionalIndexedClassesBuildItem(); + } + @BuildStep public void registerDnsProvider(BuildProducer nativeProducer) { nativeProducer.produce(new NativeImageResourceBuildItem("META-INF/services/" + DnsClientProvider.class.getName())); diff --git a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/metrics/MicrometerCommandListener.java b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/metrics/MicrometerCommandListener.java new file mode 100644 index 0000000000000..4ee642491a9c7 --- /dev/null +++ b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/metrics/MicrometerCommandListener.java @@ -0,0 +1,14 @@ +package io.quarkus.mongodb.metrics; + +import jakarta.inject.Inject; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandListener; + +public class MicrometerCommandListener extends MongoMetricsCommandListener { + @Inject + public MicrometerCommandListener(MeterRegistry registry) { + super(registry); + } + +} diff --git a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java index 01fa1bf4caebd..79cc3f97e10f2 100644 --- a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java +++ b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java @@ -14,6 +14,7 @@ import com.mongodb.event.ConnectionPoolListener; import io.quarkus.arc.Arc; +import io.quarkus.mongodb.metrics.MicrometerCommandListener; import io.quarkus.mongodb.metrics.MicrometerConnectionPoolListener; import io.quarkus.mongodb.metrics.MongoMetricsConnectionPoolListener; import io.quarkus.mongodb.reactive.ReactiveMongoClient; @@ -99,6 +100,10 @@ public ConnectionPoolListener get() { }; } + public static String getMicrometerCommandListenerClassName() { + return MicrometerCommandListener.class.getName(); + } + public Supplier createMPMetricsConnectionPoolListener() { return new Supplier() { @Override diff --git a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java index d07a9733a4744..976dcc1e75243 100644 --- a/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java +++ b/integration-tests/mongodb-panache/src/test/java/io/quarkus/it/mongodb/panache/MongodbPanacheResourceTest.java @@ -357,6 +357,7 @@ private void callPersonEndpoint(String endpoint) { .when().get("/q/metrics") .then() .statusCode(200) + .body(CoreMatchers.containsString("mongodb_driver_commands_seconds_max")) .body(CoreMatchers.containsString("mongodb_driver_pool_checkedout")) .body(CoreMatchers.containsString("mongodb_driver_pool_size")) .body(CoreMatchers.containsString("mongodb_driver_pool_waitqueuesize")); From bbd7d5115acfaf0032d2f7c7310cc4ae05d707a0 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Tue, 10 Dec 2024 10:45:30 -0300 Subject: [PATCH 082/207] Allow triggering the prepare-release workflow manually for Quarkiverse extensions This allows you to retry failed releases without the need to revert changes to `.github/project.yml` --- .../quarkiverse/java/.github/workflows/release-prepare.yml | 3 ++- ...us-my-quarkiverse-ext_.github_workflows_release-prepare.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-prepare.yml b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-prepare.yml index aedad9370a2dc..e2da7080b29b7 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-prepare.yml +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-prepare.yml @@ -1,6 +1,7 @@ name: Quarkiverse Prepare Release on: + workflow_dispatch: pull_request: types: [ closed ] paths: @@ -13,6 +14,6 @@ concurrency: jobs: prepare-release: name: Prepare Release - if: ${{ github.event.pull_request.merged == true}} + if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true}} uses: quarkiverse/.github/.github/workflows/prepare-release.yml@main secrets: inherit diff --git a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-prepare.yml b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-prepare.yml index aedad9370a2dc..e2da7080b29b7 100644 --- a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-prepare.yml +++ b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-prepare.yml @@ -1,6 +1,7 @@ name: Quarkiverse Prepare Release on: + workflow_dispatch: pull_request: types: [ closed ] paths: @@ -13,6 +14,6 @@ concurrency: jobs: prepare-release: name: Prepare Release - if: ${{ github.event.pull_request.merged == true}} + if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true}} uses: quarkiverse/.github/.github/workflows/prepare-release.yml@main secrets: inherit From 2691a9a7d117db43639b0ed48736b51bb4d4b711 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Tue, 10 Dec 2024 13:37:17 +0100 Subject: [PATCH 083/207] Arc - add test for injection point modification with repeatable annotations --- ...alifiersInjectionPointTransformerTest.java | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/buildextension/injectionPoints/RepeatingQualifiersInjectionPointTransformerTest.java diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/buildextension/injectionPoints/RepeatingQualifiersInjectionPointTransformerTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/buildextension/injectionPoints/RepeatingQualifiersInjectionPointTransformerTest.java new file mode 100644 index 0000000000000..0ff289cf9fd52 --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/buildextension/injectionPoints/RepeatingQualifiersInjectionPointTransformerTest.java @@ -0,0 +1,126 @@ +package io.quarkus.arc.test.buildextension.injectionPoints; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import jakarta.enterprise.util.AnnotationLiteral; +import jakarta.inject.Qualifier; +import jakarta.inject.Singleton; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.ClassType; +import org.jboss.jandex.DotName; +import org.jboss.jandex.Type; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.processor.InjectionPointsTransformer; +import io.quarkus.arc.test.ArcTestContainer; + +public class RepeatingQualifiersInjectionPointTransformerTest { + + public static final String FIRST_STRING = "neverwhere"; + public static final String SECOND_STRING = "london"; + + @RegisterExtension + public ArcTestContainer container = ArcTestContainer.builder() + .beanClasses(Foo.class, Bar.class, Location.class, Locations.class, ShapeableBean.class) + .injectionPointsTransformers(new MyTransformer()) + .build(); + + @Test + public void testQualifiersHandledCorrectly() { + Assertions.assertTrue(Arc.container().select(ShapeableBean.class).isResolvable()); + } + + @Inherited + @Target({ TYPE, METHOD, FIELD, PARAMETER }) + @Retention(RUNTIME) + public @interface Locations { + Location[] value(); + } + + @Qualifier + @Inherited + @Target({ TYPE, METHOD, FIELD, PARAMETER }) + @Retention(RUNTIME) + @Repeatable(Locations.class) + public @interface Location { + String value(); + + class Literal extends AnnotationLiteral implements Location { + + private final String value; + + public Literal(String value) { + this.value = value; + } + + @Override + public String value() { + return value; + } + } + } + + @Singleton + public static class Foo { + + } + + @Singleton + @Location(FIRST_STRING) + @Location(SECOND_STRING) + public static class Bar { + + } + + @Singleton + public static class ShapeableBean { + + // Bar bean exists only with repeated qualifiers - transformer adds those + // Foo bean exists only without qualifiers - transformer removes all qualifiers + public ShapeableBean(@Location("doesn't") @Location("matter") Foo foo, Bar bar) { + + } + } + + static class MyTransformer implements InjectionPointsTransformer { + + @Override + public boolean appliesTo(Type requiredType) { + // applies to all Foo/Bar injection points + return requiredType.equals(ClassType.create(Foo.class)) || requiredType.equals(ClassType.create(Bar.class)); + } + + @Override + public void transform(TransformationContext transformationContext) { + if (AnnotationTarget.Kind.METHOD_PARAMETER == transformationContext.getAnnotationTarget().kind()) { + if (transformationContext.getAnnotationTarget().asMethodParameter().type().name() + .equals(DotName.createSimple(Foo.class))) { + transformationContext.transform().removeAll().done(); + } else { + // add repeating qualifiers + transformationContext.transform() + .add(AnnotationInstance.builder(Location.class).value(FIRST_STRING).build()) + .add(AnnotationInstance.builder(Location.class).value(SECOND_STRING).build()) + .done(); + } + } else { + throw new IllegalStateException( + "Unexpected injection point kind: " + transformationContext.getAnnotationTarget().kind()); + } + } + } +} From 4f8ade895ab2d1b2cd28dd79e883aa8ff03a770c Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Tue, 10 Dec 2024 16:38:53 +0100 Subject: [PATCH 084/207] SmallRye Fault Tolerance: upgrade to 6.7.1 --- bom/application/pom.xml | 2 +- docs/src/main/asciidoc/smallrye-fault-tolerance.adoc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index d384a92a9f560..4854f60d75b57 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -52,7 +52,7 @@ 4.0.0 4.0.5 2.11.0 - 6.7.0 + 6.7.1 4.6.1 2.1.2 1.0.13 diff --git a/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc b/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc index 42c47a9d441ee..71a0d095308b8 100644 --- a/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc +++ b/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc @@ -576,7 +576,7 @@ implementation("io.quarkus:quarkus-smallrye-fault-tolerance") == Additional resources SmallRye Fault Tolerance has more features than shown here. -Please check the link:https://smallrye.io/docs/smallrye-fault-tolerance/6.7.0/index.html[SmallRye Fault Tolerance documentation] to learn about them. +Please check the link:https://smallrye.io/docs/smallrye-fault-tolerance/6.7.1/index.html[SmallRye Fault Tolerance documentation] to learn about them. In Quarkus, you can use the SmallRye Fault Tolerance optional features out of the box. @@ -608,7 +608,7 @@ quarkus.fault-tolerance.mp-compatibility=true ---- ==== -The link:https://smallrye.io/docs/smallrye-fault-tolerance/6.7.0/reference/programmatic-api.html[programmatic API] is present and integrated with the declarative, annotation-based API. +The link:https://smallrye.io/docs/smallrye-fault-tolerance/6.7.1/reference/programmatic-api.html[programmatic API] is present and integrated with the declarative, annotation-based API. You can use the `Guard`, `TypedGuard` and `@ApplyGuard` APIs out of the box. Support for Kotlin is present (assuming you use the Quarkus extension for Kotlin), so you can guard your `suspend` functions with fault tolerance annotations. From 0fdcf2afef3adf968501fb771652502d8a7672d1 Mon Sep 17 00:00:00 2001 From: Alex Martel <13215031+manofthepeace@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:29:16 -0500 Subject: [PATCH 085/207] Reapply "Mark Quartz extension as stable" This reverts commit 84609f6914d63c82cf0a1d3591fac794aac5d3bb. --- docs/src/main/asciidoc/quartz.adoc | 3 --- .../src/main/resources/META-INF/quarkus-extension.yaml | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/src/main/asciidoc/quartz.adoc b/docs/src/main/asciidoc/quartz.adoc index bfdf94fc25eef..329160c926b81 100644 --- a/docs/src/main/asciidoc/quartz.adoc +++ b/docs/src/main/asciidoc/quartz.adoc @@ -7,15 +7,12 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc include::_attributes.adoc[] :categories: miscellaneous :summary: You need clustering support for your scheduled tasks? This guide explains how to use the Quartz extension for that. -:extension-status: preview :topics: scheduling,cronjob,quartz :extensions: io.quarkus:quarkus-quartz Modern applications often need to run specific tasks periodically. In this guide, you learn how to schedule periodic clustered tasks using the http://www.quartz-scheduler.org/[Quartz] extension. -include::{includes}/extension-status.adoc[] - TIP: If you only need to run in-memory scheduler use the xref:scheduler.adoc[Scheduler] extension. == Prerequisites diff --git a/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml index 0f47b14af6efc..7cc90a39328b3 100644 --- a/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/extensions/quartz/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -10,6 +10,6 @@ metadata: guide: "https://quarkus.io/guides/quartz" categories: - "miscellaneous" - status: "preview" + status: "stable" config: - - "quarkus.quartz." \ No newline at end of file + - "quarkus.quartz." From ee668b2bbf5a32d9858a145cd398201e9a93368a Mon Sep 17 00:00:00 2001 From: mariofusco Date: Tue, 10 Dec 2024 18:13:38 +0100 Subject: [PATCH 086/207] Generate reflection free Jackson deserializers for classes without an empty constructor --- .../processor/JacksonCodeGenerator.java | 23 ++++- .../processor/JacksonDeserializerFactory.java | 94 ++++++++++++------- .../deployment/test/SimpleJsonResource.java | 2 +- 3 files changed, 81 insertions(+), 38 deletions(-) diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonCodeGenerator.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonCodeGenerator.java index b06abe3deaf15..7380036811cd9 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonCodeGenerator.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonCodeGenerator.java @@ -13,12 +13,14 @@ import java.util.function.Function; import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.ArrayType; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.FieldInfo; import org.jboss.jandex.IndexView; import org.jboss.jandex.MethodInfo; +import org.jboss.jandex.MethodParameterInfo; import org.jboss.jandex.ParameterizedType; import org.jboss.jandex.Type; import org.jboss.jandex.TypeVariable; @@ -240,6 +242,10 @@ protected FieldSpecs fieldSpecsFromField(ClassInfo classInfo, FieldInfo fieldInf return null; } + protected FieldSpecs fieldSpecsFromFieldParam(MethodParameterInfo paramInfo) { + return new FieldSpecs(paramInfo); + } + protected static class FieldSpecs { final String fieldName; @@ -262,17 +268,28 @@ protected static class FieldSpecs { FieldSpecs(FieldInfo fieldInfo, MethodInfo methodInfo) { if (fieldInfo != null) { this.fieldInfo = fieldInfo; - fieldInfo.annotations().forEach(a -> annotations.put(a.name().toString(), a)); + readAnnotations(fieldInfo); } if (methodInfo != null) { this.methodInfo = methodInfo; - methodInfo.annotations().forEach(a -> annotations.put(a.name().toString(), a)); + readAnnotations(methodInfo); } this.fieldType = fieldType(); this.fieldName = fieldName(); this.jsonName = jsonName(); } + FieldSpecs(MethodParameterInfo paramInfo) { + readAnnotations(paramInfo); + this.fieldType = paramInfo.type(); + this.fieldName = paramInfo.name(); + this.jsonName = jsonName(); + } + + private void readAnnotations(AnnotationTarget target) { + target.annotations().forEach(a -> annotations.put(a.name().toString(), a)); + } + public boolean isPublicField() { return fieldInfo != null && Modifier.isPublic(fieldInfo.flags()); } @@ -295,7 +312,7 @@ private String jsonName() { return value.asString(); } } - return fieldName(); + return fieldName; } private String fieldName() { diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonDeserializerFactory.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonDeserializerFactory.java index ebc47ab056de6..3723d52927ddf 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonDeserializerFactory.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonDeserializerFactory.java @@ -201,20 +201,20 @@ protected String[] getInterfacesNames(ClassInfo classInfo) { @Override protected boolean createSerializationMethod(ClassInfo classInfo, ClassCreator classCreator, String beanClassName) { - if (!classInfo.hasNoArgsConstructor()) { - return false; - } - MethodCreator deserialize = classCreator .getMethodCreator("deserialize", Object.class, JsonParser.class, DeserializationContext.class) .setModifiers(ACC_PUBLIC) .addException(IOException.class) .addException(JacksonException.class); - ResultHandle deserializedHandle = deserialize - .newInstance(MethodDescriptor.ofConstructor(classInfo.name().toString())); + DeserializationData deserData = new DeserializationData(classInfo, classCreator, deserialize, + getJsonNode(deserialize), parseTypeParameters(classInfo, classCreator), new HashSet<>()); + ResultHandle deserializedHandle = createDeserializedObject(deserData); + if (deserializedHandle == null) { + return false; + } - boolean valid = deserializeObject(classInfo, deserializedHandle, classCreator, deserialize); + boolean valid = deserializeObjectFields(deserData, deserializedHandle); deserialize.returnValue(deserializedHandle); return valid; } @@ -229,13 +229,35 @@ private static ResultHandle getJsonNode(MethodCreator deserialize) { return deserialize.checkCast(treeNode, JsonNode.class); } - private boolean deserializeObject(ClassInfo classInfo, ResultHandle objHandle, ClassCreator classCreator, - MethodCreator deserialize) { - ResultHandle jsonNode = getJsonNode(deserialize); + private ResultHandle createDeserializedObject(DeserializationData deserData) { + if (deserData.classInfo.hasNoArgsConstructor()) { + return deserData.methodCreator.newInstance(MethodDescriptor.ofConstructor(deserData.classInfo.name().toString())); + } - ResultHandle fieldsIterator = deserialize - .invokeVirtualMethod(ofMethod(JsonNode.class, "fields", Iterator.class), jsonNode); - BytecodeCreator loopCreator = deserialize.whileLoop(c -> iteratorHasNext(c, fieldsIterator)).block(); + var ctorOpt = deserData.classInfo.constructors().stream().filter(ctor -> Modifier.isPublic(ctor.flags())).findFirst(); + if (!ctorOpt.isPresent()) { + return null; + } + MethodInfo ctor = ctorOpt.get(); + ResultHandle[] params = new ResultHandle[ctor.parameters().size()]; + int i = 0; + for (MethodParameterInfo paramInfo : ctor.parameters()) { + FieldSpecs fieldSpecs = fieldSpecsFromFieldParam(paramInfo); + deserData.constructorFields.add(fieldSpecs.jsonName); + ResultHandle fieldValue = deserData.methodCreator.invokeVirtualMethod( + ofMethod(JsonNode.class, "get", JsonNode.class, String.class), deserData.jsonNode, + deserData.methodCreator.load(fieldSpecs.jsonName)); + params[i++] = readValueFromJson(deserData.classCreator, deserData.methodCreator, + deserData.methodCreator.getMethodParam(1), fieldSpecs, deserData.typeParametersIndex, fieldValue); + } + return deserData.methodCreator.newInstance(ctor, params); + } + + private boolean deserializeObjectFields(DeserializationData deserData, ResultHandle objHandle) { + + ResultHandle fieldsIterator = deserData.methodCreator + .invokeVirtualMethod(ofMethod(JsonNode.class, "fields", Iterator.class), deserData.jsonNode); + BytecodeCreator loopCreator = deserData.methodCreator.whileLoop(c -> iteratorHasNext(c, fieldsIterator)).block(); ResultHandle nextField = loopCreator .invokeInterfaceMethod(ofMethod(Iterator.class, "next", Object.class), fieldsIterator); ResultHandle mapEntry = loopCreator.checkCast(nextField, Map.Entry.class); @@ -250,8 +272,8 @@ private boolean deserializeObject(ClassInfo classInfo, ResultHandle objHandle, C .invokeInterfaceMethod(ofMethod(Map.Entry.class, "getKey", Object.class), mapEntry); Switch.StringSwitch strSwitch = fieldReader.stringSwitch(fieldName); - return deserializeFields(classCreator, classInfo, deserialize.getMethodParam(1), objHandle, fieldValue, new HashSet<>(), - strSwitch, parseTypeParameters(classInfo, classCreator)); + return deserializeFields(deserData, deserData.methodCreator.getMethodParam(1), objHandle, fieldValue, + deserData.constructorFields, strSwitch); } private BranchResult iteratorHasNext(BytecodeCreator creator, ResultHandle iterator) { @@ -294,50 +316,50 @@ private static void createContextualMethod(ClassCreator classCreator) { createContextual.returnValue(deserializer); } - private boolean deserializeFields(ClassCreator classCreator, ClassInfo classInfo, ResultHandle deserializationContext, - ResultHandle objHandle, ResultHandle fieldValue, Set deserializedFields, Switch.StringSwitch strSwitch, - Map typeParametersIndex) { + private boolean deserializeFields(DeserializationData deserData, ResultHandle deserializationContext, + ResultHandle objHandle, ResultHandle fieldValue, Set deserializedFields, Switch.StringSwitch strSwitch) { AtomicBoolean valid = new AtomicBoolean(true); - for (FieldInfo fieldInfo : classFields(classInfo)) { - if (!deserializeFieldSpecs(classCreator, classInfo, deserializationContext, objHandle, fieldValue, - deserializedFields, strSwitch, typeParametersIndex, fieldSpecsFromField(classInfo, fieldInfo), valid)) + for (FieldInfo fieldInfo : classFields(deserData.classInfo)) { + if (!deserializeFieldSpecs(deserData, deserializationContext, objHandle, fieldValue, + deserializedFields, strSwitch, fieldSpecsFromField(deserData.classInfo, fieldInfo), valid)) return false; } - for (MethodInfo methodInfo : classMethods(classInfo)) { - if (!deserializeFieldSpecs(classCreator, classInfo, deserializationContext, objHandle, fieldValue, - deserializedFields, strSwitch, typeParametersIndex, fieldSpecsFromMethod(methodInfo), valid)) + for (MethodInfo methodInfo : classMethods(deserData.classInfo)) { + if (!deserializeFieldSpecs(deserData, deserializationContext, objHandle, fieldValue, + deserializedFields, strSwitch, fieldSpecsFromMethod(methodInfo), valid)) return false; } return valid.get(); } - private boolean deserializeFieldSpecs(ClassCreator classCreator, ClassInfo classInfo, ResultHandle deserializationContext, + private boolean deserializeFieldSpecs(DeserializationData deserData, ResultHandle deserializationContext, ResultHandle objHandle, ResultHandle fieldValue, Set deserializedFields, Switch.StringSwitch strSwitch, - Map typeParametersIndex, FieldSpecs fieldSpecs, AtomicBoolean valid) { - if (fieldSpecs != null && deserializedFields.add(fieldSpecs.fieldName)) { + FieldSpecs fieldSpecs, AtomicBoolean valid) { + if (fieldSpecs != null && deserializedFields.add(fieldSpecs.jsonName)) { if (fieldSpecs.hasUnknownAnnotation()) { return false; } strSwitch.caseOf(fieldSpecs.jsonName, - bytecode -> valid.compareAndSet(true, deserializeField(classCreator, classInfo, bytecode, objHandle, - fieldValue, typeParametersIndex, fieldSpecs, deserializationContext))); + bytecode -> valid.compareAndSet(true, deserializeField(deserData, bytecode, objHandle, + fieldValue, fieldSpecs, deserializationContext))); } return true; } - private boolean deserializeField(ClassCreator classCreator, ClassInfo classInfo, BytecodeCreator bytecode, - ResultHandle objHandle, ResultHandle fieldValue, Map typeParametersIndex, FieldSpecs fieldSpecs, + private boolean deserializeField(DeserializationData deserData, BytecodeCreator bytecode, + ResultHandle objHandle, ResultHandle fieldValue, FieldSpecs fieldSpecs, ResultHandle deserializationContext) { - ResultHandle valueHandle = readValueFromJson(classCreator, bytecode, deserializationContext, fieldSpecs, - typeParametersIndex, fieldValue); + ResultHandle valueHandle = readValueFromJson(deserData.classCreator, bytecode, deserializationContext, fieldSpecs, + deserData.typeParametersIndex, fieldValue); if (valueHandle == null) { return false; } - writeValueToObject(classInfo, objHandle, fieldSpecs, bytecode, fieldSpecs.toValueWriterHandle(bytecode, valueHandle)); + writeValueToObject(deserData.classInfo, objHandle, fieldSpecs, bytecode, + fieldSpecs.toValueWriterHandle(bytecode, valueHandle)); return true; } @@ -445,4 +467,8 @@ private MethodDescriptor readMethodForPrimitiveFields(String typeName) { protected boolean shouldGenerateCodeFor(ClassInfo classInfo) { return super.shouldGenerateCodeFor(classInfo) && classInfo.hasNoArgsConstructor(); } + + private record DeserializationData(ClassInfo classInfo, ClassCreator classCreator, MethodCreator methodCreator, + ResultHandle jsonNode, Map typeParametersIndex, Set constructorFields) { + } } diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/SimpleJsonResource.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/SimpleJsonResource.java index 2b79bbadada79..950521f563e59 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/SimpleJsonResource.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/SimpleJsonResource.java @@ -112,7 +112,7 @@ public Dog echoDog(Dog dog) { @POST @Path("/record-echo") @Consumes(MediaType.APPLICATION_JSON) - public StateRecord echoDog(StateRecord stateRecord) { + public StateRecord echoRecord(StateRecord stateRecord) { return stateRecord; } From 7433129ad176609f53fc4da643c6782c5800400c Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Tue, 10 Dec 2024 22:02:09 +0100 Subject: [PATCH 087/207] Minor change to add Dependency.isAnyFlagSet(int flags) and make FlagDependencyIterator use that --- .../bootstrap/model/ApplicationModel.java | 19 ++++++++++- .../model/DefaultApplicationModel.java | 32 +++++++++++++------ .../quarkus/maven/dependency/Dependency.java | 15 ++++++++- .../test/DevModeTestApplicationModel.java | 2 +- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModel.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModel.java index d9eb54f92c73e..76e223bf92fdc 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModel.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModel.java @@ -40,13 +40,30 @@ public interface ApplicationModel { */ Iterable getDependencies(int flags); + /** + * Returns application dependencies that have any of the flags combined in the value of the {@code flags} arguments set. + * + * @param flags dependency flags to match + * @return application dependencies that matched the flags + */ + Iterable getDependenciesWithAnyFlag(int flags); + /** * Returns application dependencies that have any of the flags passed in as arguments set. * * @param flags dependency flags to match * @return application dependencies that matched the flags */ - Iterable getDependenciesWithAnyFlag(int... flags); + default Iterable getDependenciesWithAnyFlag(int... flags) { + if (flags.length == 0) { + throw new IllegalArgumentException("Flags are empty"); + } + int combined = flags[0]; + for (int i = 1; i < flags.length; ++i) { + combined |= flags[i]; + } + return getDependenciesWithAnyFlag(combined); + } /** * Runtime dependencies of an application diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/DefaultApplicationModel.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/DefaultApplicationModel.java index 3e6cc090723d6..08246386a6c0d 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/DefaultApplicationModel.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/DefaultApplicationModel.java @@ -53,11 +53,12 @@ public Collection getRuntimeDependencies() { @Override public Iterable getDependencies(int flags) { - return new FlagDependencyIterator(new int[] { flags }); + return new FlagDependencyIterator(flags, false); } - public Iterable getDependenciesWithAnyFlag(int... flags) { - return new FlagDependencyIterator(flags); + @Override + public Iterable getDependenciesWithAnyFlag(int flags) { + return new FlagDependencyIterator(flags, true); } @Override @@ -118,10 +119,20 @@ private Set collectKeys(int flags) { private class FlagDependencyIterator implements Iterable { - private final int[] flags; - - private FlagDependencyIterator(int[] flags) { + private final int flags; + private final boolean any; + + /** + * Iterates over application model dependencies that match requested flags. + * The {@code any} boolean argument controls whether any or all the flags have to match + * for a dependency to be selected. + * + * @param flags flags to match + * @param any whether any or all of the flags have to be matched + */ + private FlagDependencyIterator(int flags, boolean any) { this.flags = flags; + this.any = any; } @Override @@ -152,11 +163,14 @@ public ResolvedDependency next() { private void moveOn() { next = null; - while (index < dependencies.size()) { + while (index < dependencies.size() && next == null) { var d = dependencies.get(index++); - if (d.hasAnyFlag(flags)) { + if (any) { + if (d.isAnyFlagSet(flags)) { + next = d; + } + } else if (d.isFlagSet(flags)) { next = d; - break; } } } diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/Dependency.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/Dependency.java index 2a95f37474117..2a6df30caab3c 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/Dependency.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/Dependency.java @@ -62,14 +62,27 @@ default boolean isClassLoaderParentFirst() { /** * Checks whether a dependency has a given flag set. + * If the value of the {@code flag} argument combines multiple flags, + * the implementation will return {@code true} only if the dependency + * has all the flags set. * - * @param flag flag to check + * @param flag flag (or flags) to check * @return true if the flag is set, otherwise false */ default boolean isFlagSet(int flag) { return (getFlags() & flag) == flag; } + /** + * Checks whether a dependency has any of the flags combined in the value of {@code flags} set. + * + * @param flags flags to check + * @return true, if any of the flags is set, otherwise - false + */ + default boolean isAnyFlagSet(int flags) { + return (getFlags() & flags) > 0; + } + /** * Checks whether any of the flags are set on a dependency * diff --git a/test-framework/junit5-internal/src/main/java/io/quarkus/test/DevModeTestApplicationModel.java b/test-framework/junit5-internal/src/main/java/io/quarkus/test/DevModeTestApplicationModel.java index 5864ff6f5fa68..ba8633abac8b1 100644 --- a/test-framework/junit5-internal/src/main/java/io/quarkus/test/DevModeTestApplicationModel.java +++ b/test-framework/junit5-internal/src/main/java/io/quarkus/test/DevModeTestApplicationModel.java @@ -41,7 +41,7 @@ public Iterable getDependencies(int flags) { } @Override - public Iterable getDependenciesWithAnyFlag(int... flags) { + public Iterable getDependenciesWithAnyFlag(int flags) { return delegate.getDependenciesWithAnyFlag(flags); } From 79e2beb1ca15356b34fb10734b4b701e435f8c3c Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 10 Dec 2024 19:38:30 +0000 Subject: [PATCH 088/207] Priority of REST Client Config changed to Quarkus FQN, config key, simple name --- .../AbstractRestClientConfigBuilder.java | 182 +++++++++++++----- .../config/RestClientConfigTest.java | 78 ++++++++ .../key/SharedOneConfigKeyRestClient.java | 7 + .../key/SharedThreeConfigKeyRestClient.java | 7 + .../key/SharedTwoConfigKeyRestClient.java | 7 + .../simple/one/SimpleNameRestClient.java | 7 + .../simple/two/SimpleNameRestClient.java | 7 + .../src/test/resources/application.properties | 9 + 8 files changed, 255 insertions(+), 49 deletions(-) create mode 100644 extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedOneConfigKeyRestClient.java create mode 100644 extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedThreeConfigKeyRestClient.java create mode 100644 extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedTwoConfigKeyRestClient.java create mode 100644 extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/simple/one/SimpleNameRestClient.java create mode 100644 extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/simple/two/SimpleNameRestClient.java diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/AbstractRestClientConfigBuilder.java b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/AbstractRestClientConfigBuilder.java index a4e2e0f7bcdbc..7ed5887381a76 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/AbstractRestClientConfigBuilder.java +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/AbstractRestClientConfigBuilder.java @@ -2,11 +2,14 @@ import static io.smallrye.config.ConfigValue.CONFIG_SOURCE_COMPARATOR; +import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.OptionalInt; import java.util.function.Function; +import java.util.function.Supplier; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; @@ -17,7 +20,6 @@ import io.smallrye.config.ConfigValue; import io.smallrye.config.FallbackConfigSourceInterceptor; import io.smallrye.config.Priorities; -import io.smallrye.config.RelocateConfigSourceInterceptor; import io.smallrye.config.SmallRyeConfigBuilder; /** @@ -70,49 +72,66 @@ public SmallRyeConfigBuilder configBuilder(final SmallRyeConfigBuilder builder) Map quarkusFallbacks = new HashMap<>(); Map microProfileFallbacks = new HashMap<>(); - // relocates [All Combinations] -> quarkus.rest-client."FQN".* - Map relocates = new HashMap<>(); + Map> relocates = new HashMap<>(); + for (RegisteredRestClient restClient : restClients) { if (runtime) { RestClientsConfig.RestClientKeysProvider.KEYS.add(restClient.getFullName()); } - // FQN -> Simple Name String quotedFullName = "\"" + restClient.getFullName() + "\""; - quarkusFallbacks.put(quotedFullName, restClient.getSimpleName()); - relocates.put(restClient.getSimpleName(), quotedFullName); - // Simple Name -> Quoted Simple Name String quotedSimpleName = "\"" + restClient.getSimpleName() + "\""; - quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName); - relocates.put(quotedSimpleName, quotedFullName); - String configKey = restClient.getConfigKey(); + + // relocates [All Combinations] -> quarkus.rest-client."FQN".* + List fullNameRelocates = new ArrayList<>(); + relocates.put(quotedFullName, fullNameRelocates); + if (configKey != null && !restClient.isConfigKeyEqualsNames()) { String quotedConfigKey = "\"" + configKey + "\""; if (!quotedConfigKey.equals(quotedFullName) && !quotedConfigKey.equals(quotedSimpleName)) { if (restClient.isConfigKeyComposed()) { - // Quoted Simple Name -> Quoted Config Key - quarkusFallbacks.put(quotedSimpleName, quotedConfigKey); - relocates.put(quotedConfigKey, quotedFullName); + // FQN -> Quoted Config Key -> Quoted Simple Name -> Simple Name + quarkusFallbacks.put(quotedFullName, quotedConfigKey); + quarkusFallbacks.put(quotedConfigKey, restClient.getSimpleName()); + quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName); + fullNameRelocates.add(quotedConfigKey); + fullNameRelocates.add(restClient.getSimpleName()); + fullNameRelocates.add(quotedSimpleName); } else { - // Quoted Simple Name -> Config Key - quarkusFallbacks.put(quotedSimpleName, configKey); - relocates.put(configKey, quotedFullName); - // Config Key -> Quoted Config Key + // FQN -> Config Key -> Quoted Config Key -> Quoted Simple Name -> Simple Name + quarkusFallbacks.put(quotedFullName, configKey); quarkusFallbacks.put(configKey, quotedConfigKey); - relocates.put(quotedConfigKey, quotedFullName); + quarkusFallbacks.put(quotedConfigKey, restClient.getSimpleName()); + quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName); + fullNameRelocates.add(configKey); + fullNameRelocates.add(quotedConfigKey); + fullNameRelocates.add(restClient.getSimpleName()); + fullNameRelocates.add(quotedSimpleName); } + } else { + // FQN -> Quoted Simple Name -> Simple Name + quarkusFallbacks.put(quotedFullName, restClient.getSimpleName()); + quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName); + fullNameRelocates.add(restClient.getSimpleName()); + fullNameRelocates.add(quotedSimpleName); } + } else { + // FQN -> Quoted Simple Name -> Simple Name + quarkusFallbacks.put(quotedFullName, restClient.getSimpleName()); + quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName); + fullNameRelocates.add(restClient.getSimpleName()); + fullNameRelocates.add(quotedSimpleName); } // FQN -> FQN/mp-rest String mpRestFullName = restClient.getFullName() + "/mp-rest/"; microProfileFallbacks.put(quotedFullName, mpRestFullName); - relocates.put(mpRestFullName, quotedFullName); + fullNameRelocates.add(mpRestFullName); if (configKey != null && !configKey.equals(restClient.getFullName())) { String mpConfigKey = configKey + "/mp-rest/"; microProfileFallbacks.put(mpRestFullName, mpConfigKey); - relocates.put(mpConfigKey, quotedFullName); + fullNameRelocates.add(mpConfigKey); } } @@ -145,12 +164,7 @@ public OptionalInt getPriority() { builder.withInterceptorFactories(new ConfigSourceInterceptorFactory() { @Override public ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorContext context) { - return new RelocateConfigSourceInterceptor(new Relocates(relocates)) { - @Override - public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { - return context.proceed(name); - } - }; + return new Relocates(relocates); } }); return builder; @@ -298,35 +312,105 @@ public String apply(final String name) { /** * Relocates every possible name (Quarkus and MP) to - * quarkus.rest-client."[FQN of the REST Interface]".* + * quarkus.rest-client."[FQN of the REST Interface]".*. The same configKey can relocate + * to many quarkus.rest-client."[FQN of the REST Interface]".*. */ - private record Relocates(Map names) implements Function { + private static class Relocates implements ConfigSourceInterceptor { + private final Map> relocates; + + Relocates(final Map> relocates) { + this.relocates = new HashMap<>(); + // Inverts the Map to make it easier to search + for (Map.Entry> entry : relocates.entrySet()) { + for (String from : entry.getValue()) { + this.relocates.putIfAbsent(from, new ArrayList<>()); + this.relocates.get(from).add(entry.getKey()); + } + } + } + @Override - public String apply(final String name) { - int indexOfRestClient = indexOfRestClient(name); - if (indexOfRestClient != -1) { - for (Map.Entry entry : names.entrySet()) { - String original = entry.getKey(); - String target = entry.getValue(); - int endOfConfigKey = indexOfRestClient + original.length(); - if (name.regionMatches(indexOfRestClient, original, 0, original.length())) { - if (name.length() > endOfConfigKey && name.charAt(endOfConfigKey) == '.') { - return REST_CLIENT_PREFIX + target + name.substring(endOfConfigKey); + public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { + return context.proceed(name); + } + + @Override + public Iterator iterateNames(final ConfigSourceInterceptorContext context) { + List relocatedNames = new ArrayList<>(relocates.size()); + List>> iterators = new ArrayList<>(); + iterators.add(new Supplier>() { + @Override + public Iterator get() { + Iterator names = context.iterateNames(); + + return new Iterator<>() { + @Override + public boolean hasNext() { + return names.hasNext(); } - } + + @Override + public String next() { + String name = names.next(); + int indexOfRestClient = indexOfRestClient(name); + if (indexOfRestClient != -1) { + for (Map.Entry> entry : relocates.entrySet()) { + String original = entry.getKey(); + int endOfConfigKey = indexOfRestClient + original.length(); + if (name.regionMatches(indexOfRestClient, original, 0, original.length())) { + if (name.length() > endOfConfigKey && name.charAt(endOfConfigKey) == '.') { + for (String relocatedName : entry.getValue()) { + relocatedNames.add( + REST_CLIENT_PREFIX + relocatedName + name.substring(endOfConfigKey)); + } + return name; + } + } + } + } + int slash = name.indexOf("/"); + if (slash != -1) { + if (name.regionMatches(slash + 1, "mp-rest/", 0, 8)) { + String property = name.substring(slash + 9); + if (MICROPROFILE_NAMES.containsKey(property)) { + relocatedNames.add(REST_CLIENT_PREFIX + "\"" + name.substring(0, slash) + "\"." + + MICROPROFILE_NAMES.getOrDefault(property, property)); + } + return name; + } + } + return name; + } + }; } - } - int slash = name.indexOf("/"); - if (slash != -1) { - if (name.regionMatches(slash + 1, "mp-rest/", 0, 8)) { - String property = name.substring(slash + 9); - if (MICROPROFILE_NAMES.containsKey(property)) { - return REST_CLIENT_PREFIX + "\"" + name.substring(0, slash) + "\"." - + MICROPROFILE_NAMES.getOrDefault(property, property); + }); + iterators.add(new Supplier>() { + @Override + public Iterator get() { + return relocatedNames.iterator(); + } + }); + Iterator>> iterator = iterators.iterator(); + return new Iterator<>() { + Iterator names = iterator.next().get(); + + @Override + public boolean hasNext() { + if (names.hasNext()) { + return true; + } else { + if (iterator.hasNext()) { + names = iterator.next().get(); + } + return names.hasNext(); } } - } - return name; + + @Override + public String next() { + return names.next(); + } + }; } } diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/RestClientConfigTest.java b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/RestClientConfigTest.java index 2a8c2621726c5..7b73ed5ae3942 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/RestClientConfigTest.java +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/RestClientConfigTest.java @@ -13,6 +13,9 @@ import org.junit.jupiter.api.Test; import io.quarkus.restclient.config.RestClientsConfig.RestClientConfig; +import io.quarkus.restclient.config.key.SharedOneConfigKeyRestClient; +import io.quarkus.restclient.config.key.SharedThreeConfigKeyRestClient; +import io.quarkus.restclient.config.key.SharedTwoConfigKeyRestClient; import io.quarkus.runtime.configuration.ConfigUtils; import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfigBuilder; @@ -233,6 +236,81 @@ public List getRestClients() { assertThat(restClientConfig.uri().get()).isEqualTo("http://localhost:8082"); } + @Test + void restClientDuplicateSimpleName() { + SmallRyeConfig config = ConfigUtils.emptyConfigBuilder() + .withMapping(RestClientsConfig.class) + .withCustomizers(new SmallRyeConfigBuilderCustomizer() { + @Override + public void configBuilder(final SmallRyeConfigBuilder builder) { + new AbstractRestClientConfigBuilder() { + @Override + public List getRestClients() { + return List.of( + new RegisteredRestClient( + io.quarkus.restclient.config.simple.one.SimpleNameRestClient.class, "one"), + new RegisteredRestClient( + io.quarkus.restclient.config.simple.two.SimpleNameRestClient.class, "two")); + } + }.configBuilder(builder); + } + }) + .build(); + assertNotNull(config); + + RestClientsConfig restClientsConfig = config.getConfigMapping(RestClientsConfig.class); + assertEquals(2, restClientsConfig.clients().size()); + assertThat(restClientsConfig.getClient(io.quarkus.restclient.config.simple.one.SimpleNameRestClient.class).uri().get()) + .isEqualTo("http://localhost:8081"); + assertThat(restClientsConfig.getClient(io.quarkus.restclient.config.simple.two.SimpleNameRestClient.class).uri().get()) + .isEqualTo("http://localhost:8082"); + } + + @Test + void restClientSharedConfigKey() { + SmallRyeConfig config = ConfigUtils.emptyConfigBuilder() + .withMapping(RestClientsConfig.class) + .withCustomizers(new SmallRyeConfigBuilderCustomizer() { + @Override + public void configBuilder(final SmallRyeConfigBuilder builder) { + new AbstractRestClientConfigBuilder() { + @Override + public List getRestClients() { + return List.of( + new RegisteredRestClient(SharedOneConfigKeyRestClient.class, "shared"), + new RegisteredRestClient(SharedTwoConfigKeyRestClient.class, "shared"), + new RegisteredRestClient(SharedThreeConfigKeyRestClient.class, "shared")); + } + }.configBuilder(builder); + } + }) + .build(); + assertNotNull(config); + + RestClientsConfig restClientsConfig = config.getConfigMapping(RestClientsConfig.class); + assertEquals(3, restClientsConfig.clients().size()); + + RestClientConfig restClientConfigOne = restClientsConfig.getClient(SharedOneConfigKeyRestClient.class); + assertThat(restClientConfigOne.uri().get()).isEqualTo("http://localhost:8081"); + assertEquals(2, restClientConfigOne.headers().size()); + assertEquals("one", restClientConfigOne.headers().get("two")); + assertEquals("two", restClientConfigOne.headers().get("one")); + + RestClientConfig restClientConfigTwo = restClientsConfig + .getClient(SharedTwoConfigKeyRestClient.class); + assertThat(restClientConfigTwo.uri().get()).isEqualTo("http://localhost:8082"); + assertEquals(2, restClientConfigTwo.headers().size()); + assertEquals("one", restClientConfigTwo.headers().get("two")); + assertEquals("two", restClientConfigTwo.headers().get("one")); + + RestClientConfig restClientConfigThree = restClientsConfig + .getClient(SharedThreeConfigKeyRestClient.class); + assertThat(restClientConfigThree.uri().get()).isEqualTo("http://localhost:8083"); + assertEquals(2, restClientConfigThree.headers().size()); + assertEquals("one", restClientConfigThree.headers().get("two")); + assertEquals("two", restClientConfigThree.headers().get("one")); + } + @Test void buildTimeConfig() { SmallRyeConfig config = ConfigUtils.emptyConfigBuilder() diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedOneConfigKeyRestClient.java b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedOneConfigKeyRestClient.java new file mode 100644 index 0000000000000..53350e34da0b5 --- /dev/null +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedOneConfigKeyRestClient.java @@ -0,0 +1,7 @@ +package io.quarkus.restclient.config.key; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient(configKey = "shared") +public interface SharedOneConfigKeyRestClient { +} diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedThreeConfigKeyRestClient.java b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedThreeConfigKeyRestClient.java new file mode 100644 index 0000000000000..cc87e958a0b23 --- /dev/null +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedThreeConfigKeyRestClient.java @@ -0,0 +1,7 @@ +package io.quarkus.restclient.config.key; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient(configKey = "shared") +public interface SharedThreeConfigKeyRestClient { +} diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedTwoConfigKeyRestClient.java b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedTwoConfigKeyRestClient.java new file mode 100644 index 0000000000000..ec04debb91ab7 --- /dev/null +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/key/SharedTwoConfigKeyRestClient.java @@ -0,0 +1,7 @@ +package io.quarkus.restclient.config.key; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient(configKey = "shared") +public interface SharedTwoConfigKeyRestClient { +} diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/simple/one/SimpleNameRestClient.java b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/simple/one/SimpleNameRestClient.java new file mode 100644 index 0000000000000..695b709324a0c --- /dev/null +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/simple/one/SimpleNameRestClient.java @@ -0,0 +1,7 @@ +package io.quarkus.restclient.config.simple.one; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient(configKey = "one") +public interface SimpleNameRestClient { +} diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/simple/two/SimpleNameRestClient.java b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/simple/two/SimpleNameRestClient.java new file mode 100644 index 0000000000000..586746a2a82c5 --- /dev/null +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/simple/two/SimpleNameRestClient.java @@ -0,0 +1,7 @@ +package io.quarkus.restclient.config.simple.two; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient(configKey = "two") +public interface SimpleNameRestClient { +} diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/test/resources/application.properties b/extensions/resteasy-classic/rest-client-config/runtime/src/test/resources/application.properties index fb083bea6f36b..8e4560a7ddb65 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/src/test/resources/application.properties +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/test/resources/application.properties @@ -54,3 +54,12 @@ mp.key/mp-rest/proxyAddress=mp.key mp.key/mp-rest/queryParamStyle=COMMA_SEPARATED MPConfigKeyRestClient/mp-rest/uri=http://localhost:8082 + +quarkus.rest-client.one.uri=http://localhost:8081 +quarkus.rest-client.two.uri=http://localhost:8082 + +quarkus.rest-client."io.quarkus.restclient.config.key.SharedOneConfigKeyRestClient".uri=http://localhost:8081 +quarkus.rest-client."io.quarkus.restclient.config.key.SharedTwoConfigKeyRestClient".uri=http://localhost:8082 +io.quarkus.restclient.config.key.SharedThreeConfigKeyRestClient/mp-rest/uri=http://localhost:8083 +quarkus.rest-client.shared.headers.two=one +quarkus.rest-client.shared.headers.one=two From 1e2de7e9ad32d275bf813b90b9721a34dab084cf Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 10 Dec 2024 23:27:45 +0100 Subject: [PATCH 089/207] Make JFR ITs artifactIds consistent with conventions Noticed while building the tree. --- integration-tests/jfr-blocking/pom.xml | 4 ++-- integration-tests/jfr-opentelemetry/pom.xml | 4 ++-- integration-tests/jfr-reactive/pom.xml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/integration-tests/jfr-blocking/pom.xml b/integration-tests/jfr-blocking/pom.xml index b032c6feaf2a9..9e9009997ebf6 100644 --- a/integration-tests/jfr-blocking/pom.xml +++ b/integration-tests/jfr-blocking/pom.xml @@ -8,8 +8,8 @@ quarkus-integration-tests-parent 999-SNAPSHOT - jfr-blocking-integration-tests - Quarkus - Integration Tests - Jfr Blocking + quarkus-integration-test-jfr-blocking + Quarkus - Integration Tests - JFR Blocking true diff --git a/integration-tests/jfr-opentelemetry/pom.xml b/integration-tests/jfr-opentelemetry/pom.xml index c319f162d875b..8740c2cc352a8 100644 --- a/integration-tests/jfr-opentelemetry/pom.xml +++ b/integration-tests/jfr-opentelemetry/pom.xml @@ -7,8 +7,8 @@ quarkus-integration-tests-parent 999-SNAPSHOT - jf-opentelemetry-integration-tests - Quarkus - Integration Tests - Jfr OpenTelemetry + quarkus-integration-test-jfr-opentelemetry + Quarkus - Integration Tests - JFR OpenTelemetry true diff --git a/integration-tests/jfr-reactive/pom.xml b/integration-tests/jfr-reactive/pom.xml index a8b55e033febb..2b17ec29178a2 100644 --- a/integration-tests/jfr-reactive/pom.xml +++ b/integration-tests/jfr-reactive/pom.xml @@ -8,8 +8,8 @@ quarkus-integration-tests-parent 999-SNAPSHOT - jfr-reactive-integration-tests - Quarkus - Integration Tests - Jfr Reactive + quarkus-integration-test-jfr-reactive + Quarkus - Integration Tests - JFR Reactive true From e483a1962c225c2d5777ac700f6cbb20428cc922 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 22:59:48 +0000 Subject: [PATCH 090/207] Bump grpc.version from 1.68.2 to 1.69.0 Bumps `grpc.version` from 1.68.2 to 1.69.0. Updates `io.grpc:grpc-bom` from 1.68.2 to 1.69.0 - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.68.2...v1.69.0) Updates `io.grpc:protoc-gen-grpc-java` from 1.68.2 to 1.69.0 - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.68.2...v1.69.0) --- updated-dependencies: - dependency-name: io.grpc:grpc-bom dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.grpc:protoc-gen-grpc-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5e27a8f5998dc..3101339049d40 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ 7.2.2.Final - 1.68.2 + 1.69.0 1.2.2 3.25.5 ${protoc.version} From 6d5405db96cd7aab50da0c2cd2facb914ef83a6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 23:02:15 +0000 Subject: [PATCH 091/207] Bump io.micrometer:micrometer-bom from 1.14.1 to 1.14.2 Bumps [io.micrometer:micrometer-bom](https://github.com/micrometer-metrics/micrometer) from 1.14.1 to 1.14.2. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.1...v1.14.2) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 4854f60d75b57..72596940f5102 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -32,7 +32,7 @@ 2.8.0-alpha 1.27.0-alpha 5.3.3 - 1.14.1 + 1.14.2 2.2.2 0.22.0 22.2 From 21a96570c1d16c56489000893cd276ae4542ced7 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 10 Dec 2024 18:47:58 +0200 Subject: [PATCH 092/207] Improve JFR integration in Quarkus REST We are now able to capture events for all HTTP requests that are meant to be handled by Quarkus REST, whether they were successfully handled or not. Fixes: #44976 --- .../quarkus/jfr/deployment/JfrProcessor.java | 20 ++- .../http/rest/JfrReactiveServerFilter.java | 45 ------ .../rest/ReactiveServerRecorderProducer.java | 38 ----- .../jfr/runtime/http/rest/Recorder.java | 12 -- .../ClassicServerFilter.java} | 10 +- .../ClassicServerRecorder.java} | 14 +- .../ClassicServerRecorderProducer.java | 6 +- .../rest/reactive/ReactiveServerFilters.java | 50 +++++++ .../rest/reactive/ReactiveServerRecorder.java | 98 +++++++++++++ .../ReactiveServerRecorderProducer.java | 18 +++ .../http/rest/reactive/RequestInfo.java | 4 + .../http/rest/reactive/ResourceInfo.java | 4 + .../reactive/ServerStartRecordingHandler.java | 48 +++++++ .../deployment/ResteasyReactiveProcessor.java | 12 +- .../spi/GlobalHandlerCustomizerBuildItem.java | 22 +++ .../java/io/quarkus/jfr/it/AppResource.java | 10 ++ .../java/io/quarkus/jfr/it/JfrResource.java | 21 ++- .../test/java/io/quarkus/jfr/it/JfrTest.java | 132 ++++++++++++++++-- 18 files changed, 429 insertions(+), 135 deletions(-) delete mode 100644 extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/JfrReactiveServerFilter.java delete mode 100644 extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ReactiveServerRecorderProducer.java delete mode 100644 extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/Recorder.java rename extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/{JfrClassicServerFilter.java => classic/ClassicServerFilter.java} (76%) rename extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/{ServerRecorder.java => classic/ClassicServerRecorder.java} (81%) rename extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/{ => classic}/ClassicServerRecorderProducer.java (83%) create mode 100644 extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerFilters.java create mode 100644 extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerRecorder.java create mode 100644 extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerRecorderProducer.java create mode 100644 extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/RequestInfo.java create mode 100644 extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ResourceInfo.java create mode 100644 extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ServerStartRecordingHandler.java create mode 100644 extensions/resteasy-reactive/rest/spi-deployment/src/main/java/io/quarkus/resteasy/reactive/server/spi/GlobalHandlerCustomizerBuildItem.java diff --git a/extensions/jfr/deployment/src/main/java/io/quarkus/jfr/deployment/JfrProcessor.java b/extensions/jfr/deployment/src/main/java/io/quarkus/jfr/deployment/JfrProcessor.java index d5494245b1874..caad3d89959e1 100644 --- a/extensions/jfr/deployment/src/main/java/io/quarkus/jfr/deployment/JfrProcessor.java +++ b/extensions/jfr/deployment/src/main/java/io/quarkus/jfr/deployment/JfrProcessor.java @@ -12,11 +12,13 @@ import io.quarkus.jfr.runtime.OTelIdProducer; import io.quarkus.jfr.runtime.QuarkusIdProducer; import io.quarkus.jfr.runtime.config.JfrRuntimeConfig; -import io.quarkus.jfr.runtime.http.rest.ClassicServerRecorderProducer; -import io.quarkus.jfr.runtime.http.rest.JfrClassicServerFilter; -import io.quarkus.jfr.runtime.http.rest.JfrReactiveServerFilter; -import io.quarkus.jfr.runtime.http.rest.ReactiveServerRecorderProducer; +import io.quarkus.jfr.runtime.http.rest.classic.ClassicServerFilter; +import io.quarkus.jfr.runtime.http.rest.classic.ClassicServerRecorderProducer; +import io.quarkus.jfr.runtime.http.rest.reactive.ReactiveServerFilters; +import io.quarkus.jfr.runtime.http.rest.reactive.ReactiveServerRecorderProducer; +import io.quarkus.jfr.runtime.http.rest.reactive.ServerStartRecordingHandler; import io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem; +import io.quarkus.resteasy.reactive.server.spi.GlobalHandlerCustomizerBuildItem; import io.quarkus.resteasy.reactive.spi.CustomContainerRequestFilterBuildItem; @BuildSteps @@ -52,7 +54,8 @@ void registerRequestIdProducer(Capabilities capabilities, @BuildStep void registerRestIntegration(Capabilities capabilities, BuildProducer filterBeans, - BuildProducer additionalBeans) { + BuildProducer additionalBeans, + BuildProducer globalHandlerCustomizerProducer) { if (capabilities.isPresent(Capability.RESTEASY_REACTIVE)) { @@ -61,7 +64,10 @@ void registerRestIntegration(Capabilities capabilities, .build()); filterBeans - .produce(new CustomContainerRequestFilterBuildItem(JfrReactiveServerFilter.class.getName())); + .produce(new CustomContainerRequestFilterBuildItem(ReactiveServerFilters.class.getName())); + + globalHandlerCustomizerProducer + .produce(new GlobalHandlerCustomizerBuildItem(new ServerStartRecordingHandler.Customizer())); } } @@ -76,7 +82,7 @@ void registerResteasyClassicIntegration(Capabilities capabilities, .build()); resteasyJaxrsProviderBuildItemBuildProducer - .produce(new ResteasyJaxrsProviderBuildItem(JfrClassicServerFilter.class.getName())); + .produce(new ResteasyJaxrsProviderBuildItem(ClassicServerFilter.class.getName())); } } diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/JfrReactiveServerFilter.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/JfrReactiveServerFilter.java deleted file mode 100644 index 46f14bdead66e..0000000000000 --- a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/JfrReactiveServerFilter.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.quarkus.jfr.runtime.http.rest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.container.ContainerResponseContext; -import jakarta.ws.rs.core.Response; - -import org.jboss.logging.Logger; -import org.jboss.resteasy.reactive.server.ServerRequestFilter; -import org.jboss.resteasy.reactive.server.ServerResponseFilter; - -public class JfrReactiveServerFilter { - - private static final Logger LOG = Logger.getLogger(JfrReactiveServerFilter.class); - - @Inject - Recorder recorder; - - @ServerRequestFilter - public void requestFilter() { - if (LOG.isDebugEnabled()) { - LOG.debug("Enter Jfr Reactive Request Filter"); - } - recorder.recordStartEvent(); - recorder.startPeriodEvent(); - } - - @ServerResponseFilter - public void responseFilter(ContainerResponseContext responseContext) { - if (LOG.isDebugEnabled()) { - LOG.debug("Enter Jfr Reactive Response Filter"); - } - if (isRecordable(responseContext)) { - recorder.endPeriodEvent(); - recorder.recordEndEvent(); - } else { - if (LOG.isDebugEnabled()) { - LOG.debug("Recording REST event was skipped"); - } - } - } - - private boolean isRecordable(ContainerResponseContext responseContext) { - return responseContext.getStatus() != Response.Status.NOT_FOUND.getStatusCode(); - } -} diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ReactiveServerRecorderProducer.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ReactiveServerRecorderProducer.java deleted file mode 100644 index 393e50c84848e..0000000000000 --- a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ReactiveServerRecorderProducer.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.quarkus.jfr.runtime.http.rest; - -import jakarta.enterprise.context.Dependent; -import jakarta.enterprise.context.RequestScoped; -import jakarta.enterprise.inject.Produces; -import jakarta.inject.Inject; -import jakarta.ws.rs.core.Context; - -import org.jboss.resteasy.reactive.server.SimpleResourceInfo; - -import io.quarkus.jfr.runtime.IdProducer; -import io.vertx.core.http.HttpServerRequest; - -@Dependent -public class ReactiveServerRecorderProducer { - - @Context - HttpServerRequest vertxRequest; - - @Context - SimpleResourceInfo resourceInfo; - - @Inject - IdProducer idProducer; - - @Produces - @RequestScoped - public Recorder create() { - String httpMethod = vertxRequest.method().name(); - String uri = vertxRequest.path(); - Class resourceClass = resourceInfo.getResourceClass(); - String resourceClassName = (resourceClass == null) ? null : resourceClass.getName(); - String resourceMethodName = resourceInfo.getMethodName(); - String client = vertxRequest.remoteAddress().toString(); - - return new ServerRecorder(httpMethod, uri, resourceClassName, resourceMethodName, client, idProducer); - } -} diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/Recorder.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/Recorder.java deleted file mode 100644 index fc8535b773d67..0000000000000 --- a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/Recorder.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.quarkus.jfr.runtime.http.rest; - -public interface Recorder { - - void recordStartEvent(); - - void recordEndEvent(); - - void startPeriodEvent(); - - void endPeriodEvent(); -} diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/JfrClassicServerFilter.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/classic/ClassicServerFilter.java similarity index 76% rename from extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/JfrClassicServerFilter.java rename to extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/classic/ClassicServerFilter.java index e019c5dfb6710..2e67e40201571 100644 --- a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/JfrClassicServerFilter.java +++ b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/classic/ClassicServerFilter.java @@ -1,4 +1,4 @@ -package io.quarkus.jfr.runtime.http.rest; +package io.quarkus.jfr.runtime.http.rest.classic; import java.io.IOException; @@ -14,16 +14,16 @@ import io.quarkus.arc.Arc; @Provider -public class JfrClassicServerFilter implements ContainerRequestFilter, ContainerResponseFilter { +public class ClassicServerFilter implements ContainerRequestFilter, ContainerResponseFilter { - private static final Logger LOG = Logger.getLogger(JfrClassicServerFilter.class); + private static final Logger LOG = Logger.getLogger(ClassicServerFilter.class); @Override public void filter(ContainerRequestContext requestContext) throws IOException { if (LOG.isDebugEnabled()) { LOG.debug("Enter Jfr Classic Request Filter"); } - Recorder recorder = Arc.container().instance(Recorder.class).get(); + ClassicServerRecorder recorder = Arc.container().instance(ClassicServerRecorder.class).get(); recorder.recordStartEvent(); recorder.startPeriodEvent(); } @@ -36,7 +36,7 @@ public void filter(ContainerRequestContext requestContext, ContainerResponseCont } if (isRecordable(responseContext)) { - Recorder recorder = Arc.container().instance(Recorder.class).get(); + ClassicServerRecorder recorder = Arc.container().instance(ClassicServerRecorder.class).get(); recorder.endPeriodEvent(); recorder.recordEndEvent(); } else { diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ServerRecorder.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/classic/ClassicServerRecorder.java similarity index 81% rename from extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ServerRecorder.java rename to extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/classic/ClassicServerRecorder.java index 3f2dc0428fdc6..fed42a45de64e 100644 --- a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ServerRecorder.java +++ b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/classic/ClassicServerRecorder.java @@ -1,9 +1,12 @@ -package io.quarkus.jfr.runtime.http.rest; +package io.quarkus.jfr.runtime.http.rest.classic; import io.quarkus.jfr.runtime.IdProducer; import io.quarkus.jfr.runtime.http.AbstractHttpEvent; +import io.quarkus.jfr.runtime.http.rest.RestEndEvent; +import io.quarkus.jfr.runtime.http.rest.RestPeriodEvent; +import io.quarkus.jfr.runtime.http.rest.RestStartEvent; -public class ServerRecorder implements Recorder { +public class ClassicServerRecorder { private final String httpMethod; private final String uri; @@ -13,7 +16,8 @@ public class ServerRecorder implements Recorder { private final IdProducer idProducer; private RestPeriodEvent durationEvent; - public ServerRecorder(String httpMethod, String uri, String resourceClass, String resourceMethod, String client, + public ClassicServerRecorder(String httpMethod, String uri, String resourceClass, String resourceMethod, + String client, IdProducer idProducer) { this.httpMethod = httpMethod; this.uri = uri; @@ -23,7 +27,6 @@ public ServerRecorder(String httpMethod, String uri, String resourceClass, Strin this.idProducer = idProducer; } - @Override public void recordStartEvent() { RestStartEvent startEvent = new RestStartEvent(); @@ -34,7 +37,6 @@ public void recordStartEvent() { } } - @Override public void recordEndEvent() { RestEndEvent endEvent = new RestEndEvent(); @@ -45,13 +47,11 @@ public void recordEndEvent() { } } - @Override public void startPeriodEvent() { durationEvent = new RestPeriodEvent(); durationEvent.begin(); } - @Override public void endPeriodEvent() { durationEvent.end(); diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ClassicServerRecorderProducer.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/classic/ClassicServerRecorderProducer.java similarity index 83% rename from extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ClassicServerRecorderProducer.java rename to extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/classic/ClassicServerRecorderProducer.java index 9ee161e302ade..355df43b5571e 100644 --- a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/ClassicServerRecorderProducer.java +++ b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/classic/ClassicServerRecorderProducer.java @@ -1,4 +1,4 @@ -package io.quarkus.jfr.runtime.http.rest; +package io.quarkus.jfr.runtime.http.rest.classic; import java.lang.reflect.Method; @@ -25,7 +25,7 @@ public class ClassicServerRecorderProducer { @Produces @RequestScoped - public Recorder create() { + public ClassicServerRecorder create() { String httpMethod = vertxRequest.method().name(); String uri = vertxRequest.path(); Class resourceClass = resourceInfo.getResourceClass(); @@ -34,6 +34,6 @@ public Recorder create() { String resourceMethodName = (resourceMethod == null) ? null : resourceMethod.getName(); String client = vertxRequest.remoteAddress().toString(); - return new ServerRecorder(httpMethod, uri, resourceClassName, resourceMethodName, client, idProducer); + return new ClassicServerRecorder(httpMethod, uri, resourceClassName, resourceMethodName, client, idProducer); } } diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerFilters.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerFilters.java new file mode 100644 index 0000000000000..b7d1566dfb9be --- /dev/null +++ b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerFilters.java @@ -0,0 +1,50 @@ +package io.quarkus.jfr.runtime.http.rest.reactive; + +import org.jboss.logging.Logger; +import org.jboss.resteasy.reactive.server.ServerRequestFilter; +import org.jboss.resteasy.reactive.server.ServerResponseFilter; +import org.jboss.resteasy.reactive.server.SimpleResourceInfo; + +public class ReactiveServerFilters { + + private static final Logger LOG = Logger.getLogger(ReactiveServerFilters.class); + + private final ReactiveServerRecorder recorder; + + public ReactiveServerFilters(ReactiveServerRecorder recorder) { + this.recorder = recorder; + } + + /** + * Executed if request processing proceeded correctly. + * We now have to update the start event with the resource class and method data and also commit the event. + */ + @ServerRequestFilter + public void requestFilter(SimpleResourceInfo resourceInfo) { + Class resourceClass = resourceInfo.getResourceClass(); + if (resourceClass != null) { // should always be the case + String resourceClassName = resourceClass.getName(); + String resourceMethodName = resourceInfo.getMethodName(); + recorder + .updateResourceInfo(new ResourceInfo(resourceClassName, resourceMethodName)) + .commitStartEventIfNecessary(); + } + + } + + /** + * This will execute regardless of a processing failure or not. + * If there was a failure, we need to check if the start event was not commited + * (which happens when request was not matched to any resource method) and if so, commit it. + */ + @ServerResponseFilter + public void responseFilter() { + if (LOG.isDebugEnabled()) { + LOG.debug("Enter Jfr Reactive Response Filter"); + } + recorder + .recordEndEvent() + .endPeriodEvent(); + } + +} diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerRecorder.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerRecorder.java new file mode 100644 index 0000000000000..151736f520d0d --- /dev/null +++ b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerRecorder.java @@ -0,0 +1,98 @@ +package io.quarkus.jfr.runtime.http.rest.reactive; + +import io.quarkus.jfr.runtime.IdProducer; +import io.quarkus.jfr.runtime.http.AbstractHttpEvent; +import io.quarkus.jfr.runtime.http.rest.RestEndEvent; +import io.quarkus.jfr.runtime.http.rest.RestPeriodEvent; +import io.quarkus.jfr.runtime.http.rest.RestStartEvent; + +class ReactiveServerRecorder { + + private final RequestInfo requestInfo; + private final IdProducer idProducer; + + private volatile ResourceInfo resourceInfo; + + private volatile RestStartEvent startEvent; + // TODO: we can perhaps get rid of this volatile if access patterns to this and startEvent allow it + private volatile boolean startEventHandled; + + private volatile RestPeriodEvent durationEvent; + + public ReactiveServerRecorder(RequestInfo requestInfo, IdProducer idProducer) { + this.requestInfo = requestInfo; + this.idProducer = idProducer; + } + + public ReactiveServerRecorder createStartEvent() { + startEvent = new RestStartEvent(); + return this; + } + + public ReactiveServerRecorder createAndStartPeriodEvent() { + durationEvent = new RestPeriodEvent(); + durationEvent.begin(); + return this; + } + + public ReactiveServerRecorder updateResourceInfo(ResourceInfo resourceInfo) { + this.resourceInfo = resourceInfo; + return this; + } + + public ReactiveServerRecorder commitStartEventIfNecessary() { + startEventHandled = true; + var se = startEvent; + if (se.shouldCommit()) { + setHttpInfo(startEvent); + se.commit(); + } + return this; + } + + /** + * Because this can be called when a start event has not been completely handled + * (this happens when request processing failed because a Resource method could not be identified), + * we need to handle that event as well. + */ + public ReactiveServerRecorder recordEndEvent() { + if (!startEventHandled) { + commitStartEventIfNecessary(); + } + + RestEndEvent endEvent = new RestEndEvent(); + if (endEvent.shouldCommit()) { + setHttpInfo(endEvent); + endEvent.commit(); + } + + return this; + } + + public ReactiveServerRecorder endPeriodEvent() { + if (durationEvent != null) { + durationEvent.end(); + if (durationEvent.shouldCommit()) { + setHttpInfo(durationEvent); + durationEvent.commit(); + } + } else { + // this shouldn't happen, but if it does due to an error on our side, the request processing shouldn't be botched because of it + } + + return this; + } + + private void setHttpInfo(AbstractHttpEvent event) { + event.setTraceId(idProducer.getTraceId()); + event.setSpanId(idProducer.getSpanId()); + event.setHttpMethod(requestInfo.httpMethod()); + event.setUri(requestInfo.uri()); + event.setClient(requestInfo.remoteAddress()); + var ri = resourceInfo; + if (resourceInfo != null) { + event.setResourceClass(ri.resourceClass()); + event.setResourceMethod(ri.resourceMethod()); + } + } +} diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerRecorderProducer.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerRecorderProducer.java new file mode 100644 index 0000000000000..62cd81ce11bc5 --- /dev/null +++ b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ReactiveServerRecorderProducer.java @@ -0,0 +1,18 @@ +package io.quarkus.jfr.runtime.http.rest.reactive; + +import jakarta.enterprise.context.RequestScoped; + +import io.quarkus.jfr.runtime.IdProducer; +import io.vertx.core.http.HttpServerRequest; + +public class ReactiveServerRecorderProducer { + + @RequestScoped + public ReactiveServerRecorder create(IdProducer idProducer, HttpServerRequest vertxRequest) { + String httpMethod = vertxRequest.method().name(); + String uri = vertxRequest.path(); + String client = vertxRequest.remoteAddress().toString(); + + return new ReactiveServerRecorder(new RequestInfo(httpMethod, uri, client), idProducer); + } +} diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/RequestInfo.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/RequestInfo.java new file mode 100644 index 0000000000000..41a9baa19add4 --- /dev/null +++ b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/RequestInfo.java @@ -0,0 +1,4 @@ +package io.quarkus.jfr.runtime.http.rest.reactive; + +record RequestInfo(String httpMethod, String uri, String remoteAddress) { +} diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ResourceInfo.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ResourceInfo.java new file mode 100644 index 0000000000000..219b842e679c7 --- /dev/null +++ b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ResourceInfo.java @@ -0,0 +1,4 @@ +package io.quarkus.jfr.runtime.http.rest.reactive; + +record ResourceInfo(String resourceClass, String resourceMethod) { +} diff --git a/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ServerStartRecordingHandler.java b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ServerStartRecordingHandler.java new file mode 100644 index 0000000000000..74ec6fd7f61c0 --- /dev/null +++ b/extensions/jfr/runtime/src/main/java/io/quarkus/jfr/runtime/http/rest/reactive/ServerStartRecordingHandler.java @@ -0,0 +1,48 @@ +package io.quarkus.jfr.runtime.http.rest.reactive; + +import java.util.Collections; +import java.util.List; + +import org.jboss.logging.Logger; +import org.jboss.resteasy.reactive.common.model.ResourceClass; +import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; +import org.jboss.resteasy.reactive.server.model.HandlerChainCustomizer; +import org.jboss.resteasy.reactive.server.model.ServerResourceMethod; +import org.jboss.resteasy.reactive.server.spi.ServerRestHandler; + +import io.quarkus.arc.Arc; +import io.quarkus.jfr.runtime.http.rest.RestStartEvent; + +/** + * Kicks off the creation of a {@link RestStartEvent}. + * This is done very early as to be able to capture events such as 405, 406, etc. + */ +public class ServerStartRecordingHandler implements ServerRestHandler { + + private static final ServerStartRecordingHandler INSTANCE = new ServerStartRecordingHandler(); + + private static final Logger LOG = Logger.getLogger(ServerStartRecordingHandler.class); + + @Override + public void handle(ResteasyReactiveRequestContext requestContext) { + if (LOG.isDebugEnabled()) { + LOG.debug("Enter Jfr Reactive Request Filter"); + } + requestContext.requireCDIRequestScope(); + ReactiveServerRecorder recorder = Arc.container().instance(ReactiveServerRecorder.class).get(); + recorder + .createStartEvent() + .createAndStartPeriodEvent(); + } + + public static class Customizer implements HandlerChainCustomizer { + @Override + public List handlers(Phase phase, ResourceClass resourceClass, + ServerResourceMethod serverResourceMethod) { + if (phase == Phase.AFTER_PRE_MATCH) { + return Collections.singletonList(INSTANCE); + } + return Collections.emptyList(); + } + } +} diff --git a/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java b/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java index 35ce4ab24bdde..88419520a3ea5 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java +++ b/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java @@ -191,6 +191,7 @@ import io.quarkus.resteasy.reactive.server.spi.AllowNotRestParametersBuildItem; import io.quarkus.resteasy.reactive.server.spi.AnnotationsTransformerBuildItem; import io.quarkus.resteasy.reactive.server.spi.ContextTypeBuildItem; +import io.quarkus.resteasy.reactive.server.spi.GlobalHandlerCustomizerBuildItem; import io.quarkus.resteasy.reactive.server.spi.HandlerConfigurationProviderBuildItem; import io.quarkus.resteasy.reactive.server.spi.MethodScannerBuildItem; import io.quarkus.resteasy.reactive.server.spi.NonBlockingReturnTypeBuildItem; @@ -1232,6 +1233,11 @@ public void additionalReflection(BeanArchiveIndexBuildItem beanArchiveIndexBuild } } + @BuildStep + public GlobalHandlerCustomizerBuildItem securityContextOverrideHandler() { + return new GlobalHandlerCustomizerBuildItem(new SecurityContextOverrideHandler.Customizer()); + } + @BuildStep @Record(value = ExecutionTime.STATIC_INIT, useIdentityComparisonForParameters = false) public void setupDeployment(BeanContainerBuildItem beanContainerBuildItem, @@ -1260,7 +1266,8 @@ public void setupDeployment(BeanContainerBuildItem beanContainerBuildItem, ContextResolversBuildItem contextResolversBuildItem, ResteasyReactiveServerConfig serverConfig, LaunchModeBuildItem launchModeBuildItem, - List resumeOn404Items) + List resumeOn404Items, + List globalHandlerCustomizers) throws NoSuchMethodException { if (!resourceScanningResultBuildItem.isPresent()) { @@ -1361,7 +1368,8 @@ public void setupDeployment(BeanContainerBuildItem beanContainerBuildItem, .setSerialisers(serialisers) .setPreExceptionMapperHandler(determinePreExceptionMapperHandler(preExceptionMapperHandlerBuildItems)) .setApplicationPath(applicationPath) - .setGlobalHandlerCustomizers(Collections.singletonList(new SecurityContextOverrideHandler.Customizer())) //TODO: should be pluggable + .setGlobalHandlerCustomizers(globalHandlerCustomizers.stream().map( + GlobalHandlerCustomizerBuildItem::getCustomizer).toList()) .setResourceClasses(resourceClasses) .setDevelopmentMode(launchModeBuildItem.getLaunchMode() == LaunchMode.DEVELOPMENT) .setLocatableResourceClasses(subResourceClasses) diff --git a/extensions/resteasy-reactive/rest/spi-deployment/src/main/java/io/quarkus/resteasy/reactive/server/spi/GlobalHandlerCustomizerBuildItem.java b/extensions/resteasy-reactive/rest/spi-deployment/src/main/java/io/quarkus/resteasy/reactive/server/spi/GlobalHandlerCustomizerBuildItem.java new file mode 100644 index 0000000000000..851a390b1987c --- /dev/null +++ b/extensions/resteasy-reactive/rest/spi-deployment/src/main/java/io/quarkus/resteasy/reactive/server/spi/GlobalHandlerCustomizerBuildItem.java @@ -0,0 +1,22 @@ +package io.quarkus.resteasy.reactive.server.spi; + +import org.jboss.resteasy.reactive.server.model.HandlerChainCustomizer; + +import io.quarkus.builder.item.MultiBuildItem; + +/** + * Allows for extension to register global handler customizers. + * These are useful for adding handlers that run before and after pre matching + */ +public final class GlobalHandlerCustomizerBuildItem extends MultiBuildItem { + + private final HandlerChainCustomizer customizer; + + public GlobalHandlerCustomizerBuildItem(HandlerChainCustomizer customizer) { + this.customizer = customizer; + } + + public HandlerChainCustomizer getCustomizer() { + return customizer; + } +} diff --git a/integration-tests/jfr-reactive/src/main/java/io/quarkus/jfr/it/AppResource.java b/integration-tests/jfr-reactive/src/main/java/io/quarkus/jfr/it/AppResource.java index 0d69b1780272c..3045bbc4dd113 100644 --- a/integration-tests/jfr-reactive/src/main/java/io/quarkus/jfr/it/AppResource.java +++ b/integration-tests/jfr-reactive/src/main/java/io/quarkus/jfr/it/AppResource.java @@ -2,8 +2,11 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MediaType; import io.quarkus.jfr.runtime.IdProducer; import io.smallrye.mutiny.Uni; @@ -31,6 +34,13 @@ public IdResponse blocking() { return new IdResponse(idProducer.getTraceId(), idProducer.getSpanId()); } + @POST + @Path("consuming") + @Consumes(MediaType.APPLICATION_JSON) + public IdResponse consuming(IdResponse idResponse) { + return new IdResponse(idProducer.getTraceId(), idProducer.getSpanId()); + } + @GET @Path("error") public void error() { diff --git a/integration-tests/jfr-reactive/src/main/java/io/quarkus/jfr/it/JfrResource.java b/integration-tests/jfr-reactive/src/main/java/io/quarkus/jfr/it/JfrResource.java index 4749eb3e42ce9..76c3a9c949310 100644 --- a/integration-tests/jfr-reactive/src/main/java/io/quarkus/jfr/it/JfrResource.java +++ b/integration-tests/jfr-reactive/src/main/java/io/quarkus/jfr/it/JfrResource.java @@ -6,9 +6,11 @@ import java.text.ParseException; import java.util.List; import java.util.Optional; +import java.util.function.Predicate; import jakarta.enterprise.context.ApplicationScoped; import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; @@ -50,9 +52,22 @@ public void stopJfr(@PathParam("name") String name) throws IOException { } @GET - @Path("check/{name}/{traceId}") + @Path("check/{name}/traceId/{traceId}") @Produces(MediaType.APPLICATION_JSON) - public JfrRestEventResponse check(@PathParam("name") String name, @PathParam("traceId") String traceId) throws IOException { + public JfrRestEventResponse checkForTraceId(@PathParam("name") String name, @PathParam("traceId") String traceId) + throws IOException { + return doCheck(name, (e) -> e.hasField("traceId") && e.getString("traceId").equals(traceId)); + } + + @GET + @Path("check/{name}/uri") + @Produces(MediaType.APPLICATION_JSON) + public JfrRestEventResponse checkForPath(@PathParam("name") String name, @HeaderParam("uri") String uri) + throws IOException { + return doCheck(name, (e) -> e.hasField("uri") && e.getString("uri").equals(uri)); + } + + private JfrRestEventResponse doCheck(String name, Predicate predicate) throws IOException { java.nio.file.Path dumpFile = Files.createTempFile("dump", "jfr"); Recording recording = getRecording(name); recording.dump(dumpFile); @@ -73,7 +88,7 @@ public JfrRestEventResponse check(@PathParam("name") String name, @PathParam("tr Log.debug(e); } } - if (e.hasField("traceId") && e.getString("traceId").equals(traceId)) { + if (predicate.test(e)) { if (RestPeriodEvent.class.getAnnotation(Name.class).value().equals(e.getEventType().getName())) { periodEvent = e; } else if (RestStartEvent.class.getAnnotation(Name.class).value().equals(e.getEventType().getName())) { diff --git a/integration-tests/jfr-reactive/src/test/java/io/quarkus/jfr/it/JfrTest.java b/integration-tests/jfr-reactive/src/test/java/io/quarkus/jfr/it/JfrTest.java index 81d7bb23b6d23..1b2999974dd94 100644 --- a/integration-tests/jfr-reactive/src/test/java/io/quarkus/jfr/it/JfrTest.java +++ b/integration-tests/jfr-reactive/src/test/java/io/quarkus/jfr/it/JfrTest.java @@ -16,7 +16,6 @@ public class JfrTest { private static final String CLIENT = "127.0.0.1:\\d{1,5}"; - private static final String HTTP_METHOD = "GET"; private static final String RESOURCE_CLASS = "io.quarkus.jfr.it.AppResource"; @Test @@ -46,14 +45,14 @@ public void blockingTest() { final String resourceMethod = "blocking"; ValidatableResponse validatableResponse = given() - .when().get("/jfr/check/" + jfrName + "/" + response.traceId) + .when().get("/jfr/check/" + jfrName + "/traceId/" + response.traceId) .then() .statusCode(200) .body("start", notNullValue()) .body("start.uri", is(url)) .body("start.traceId", is(response.traceId)) .body("start.spanId", is(response.spanId)) - .body("start.httpMethod", is(HTTP_METHOD)) + .body("start.httpMethod", is("GET")) .body("start.resourceClass", is(RESOURCE_CLASS)) .body("start.resourceMethod", is(resourceMethod)) .body("start.client", matchesRegex(CLIENT)) @@ -61,7 +60,7 @@ public void blockingTest() { .body("end.uri", is(url)) .body("end.traceId", is(response.traceId)) .body("end.spanId", is(response.spanId)) - .body("end.httpMethod", is(HTTP_METHOD)) + .body("end.httpMethod", is("GET")) .body("end.resourceClass", is(RESOURCE_CLASS)) .body("end.resourceMethod", is(resourceMethod)) .body("end.client", matchesRegex(CLIENT)) @@ -69,7 +68,7 @@ public void blockingTest() { .body("period.uri", is(url)) .body("period.traceId", is(response.traceId)) .body("period.spanId", is(response.spanId)) - .body("period.httpMethod", is(HTTP_METHOD)) + .body("period.httpMethod", is("GET")) .body("period.resourceClass", is(RESOURCE_CLASS)) .body("period.resourceMethod", is(resourceMethod)) .body("period.client", matchesRegex(CLIENT)); @@ -101,14 +100,14 @@ public void reactiveTest() { final String resourceMethod = "reactive"; ValidatableResponse validatableResponse = given() - .when().get("/jfr/check/" + jfrName + "/" + response.traceId) + .when().get("/jfr/check/" + jfrName + "/traceId/" + response.traceId) .then() .statusCode(200) .body("start", notNullValue()) .body("start.uri", is(url)) .body("start.traceId", is(response.traceId)) .body("start.spanId", is(response.spanId)) - .body("start.httpMethod", is(HTTP_METHOD)) + .body("start.httpMethod", is("GET")) .body("start.resourceClass", is(RESOURCE_CLASS)) .body("start.resourceMethod", is(resourceMethod)) .body("start.client", matchesRegex(CLIENT)) @@ -116,7 +115,7 @@ public void reactiveTest() { .body("end.uri", is(url)) .body("end.traceId", is(response.traceId)) .body("end.spanId", is(response.spanId)) - .body("end.httpMethod", is(HTTP_METHOD)) + .body("end.httpMethod", is("GET")) .body("end.resourceClass", is(RESOURCE_CLASS)) .body("end.resourceMethod", is(resourceMethod)) .body("end.client", matchesRegex(CLIENT)) @@ -124,7 +123,7 @@ public void reactiveTest() { .body("period.uri", is(url)) .body("period.traceId", is(response.traceId)) .body("period.spanId", is(response.spanId)) - .body("period.httpMethod", is(HTTP_METHOD)) + .body("period.httpMethod", is("GET")) .body("period.resourceClass", is(RESOURCE_CLASS)) .body("period.resourceMethod", is(resourceMethod)) .body("period.client", matchesRegex(CLIENT)); @@ -156,14 +155,14 @@ public void errorTest() { final String resourceMethod = "error"; ValidatableResponse validatableResponse = given() - .when().get("/jfr/check/" + jfrName + "/" + traceId) + .when().get("/jfr/check/" + jfrName + "/traceId/" + traceId) .then() .statusCode(200) .body("start", notNullValue()) .body("start.uri", is(url)) .body("start.traceId", is(traceId)) .body("start.spanId", nullValue()) - .body("start.httpMethod", is(HTTP_METHOD)) + .body("start.httpMethod", is("GET")) .body("start.resourceClass", is(RESOURCE_CLASS)) .body("start.resourceMethod", is(resourceMethod)) .body("start.client", matchesRegex(CLIENT)) @@ -171,7 +170,7 @@ public void errorTest() { .body("end.uri", is(url)) .body("end.traceId", is(traceId)) .body("end.spanId", is(nullValue())) - .body("end.httpMethod", is(HTTP_METHOD)) + .body("end.httpMethod", is("GET")) .body("end.resourceClass", is(RESOURCE_CLASS)) .body("end.resourceMethod", is(resourceMethod)) .body("end.client", matchesRegex(CLIENT)) @@ -179,7 +178,7 @@ public void errorTest() { .body("period.uri", is(url)) .body("period.traceId", is(traceId)) .body("period.spanId", is(nullValue())) - .body("period.httpMethod", is(HTTP_METHOD)) + .body("period.httpMethod", is("GET")) .body("period.resourceClass", is(RESOURCE_CLASS)) .body("period.resourceMethod", is(resourceMethod)) .body("period.client", matchesRegex(CLIENT)); @@ -214,4 +213,111 @@ public void nonExistURL() { Assertions.assertEquals(0, count); } + + @Test + public void invalidHttpMethod() { + String jfrName = "invalidHttpMethodTest"; + + given() + .when().get("/jfr/start/" + jfrName) + .then() + .statusCode(204); + + String url = "/app/blocking"; + given() + .when() + .post(url) + .then() + .statusCode(405); + + given() + .when().get("/jfr/stop/" + jfrName) + .then() + .statusCode(204); + + given() + .header("uri", url) + .when().get("/jfr/check/" + jfrName + "/uri") + .then() + .statusCode(200) + .body("start", notNullValue()) + .body("start.uri", is(url)) + .body("start.traceId", notNullValue()) + .body("start.spanId", nullValue()) + .body("start.httpMethod", is("POST")) + .body("start.resourceClass", nullValue()) + .body("start.resourceMethod", nullValue()) + .body("start.client", matchesRegex(CLIENT)) + .body("end", notNullValue()) + .body("end.uri", is(url)) + .body("end.traceId", notNullValue()) + .body("end.spanId", nullValue()) + .body("end.httpMethod", is("POST")) + .body("end.resourceClass", nullValue()) + .body("end.resourceMethod", nullValue()) + .body("end.client", matchesRegex(CLIENT)) + .body("period", notNullValue()) + .body("period.uri", is(url)) + .body("period.traceId", notNullValue()) + .body("period.spanId", nullValue()) + .body("period.httpMethod", is("POST")) + .body("period.resourceClass", nullValue()) + .body("period.resourceMethod", nullValue()) + .body("period.client", matchesRegex(CLIENT)); + } + + @Test + public void unhandledContentType() { + String jfrName = "unhandledContentType"; + + given() + .when().get("/jfr/start/" + jfrName) + .then() + .statusCode(204); + + String url = "/app/consuming"; + given() + .contentType("text/plain") + .body("whatever") + .when() + .post(url) + .then() + .statusCode(415); + + given() + .when().get("/jfr/stop/" + jfrName) + .then() + .statusCode(204); + + given() + .header("uri", url) + .when().get("/jfr/check/" + jfrName + "/uri") + .then() + .statusCode(200) + .body("start", notNullValue()) + .body("start.uri", is(url)) + .body("start.traceId", notNullValue()) + .body("start.spanId", nullValue()) + .body("start.httpMethod", is("POST")) + .body("start.resourceClass", nullValue()) + .body("start.resourceMethod", nullValue()) + .body("start.client", matchesRegex(CLIENT)) + .body("end", notNullValue()) + .body("end.uri", is(url)) + .body("end.traceId", notNullValue()) + .body("end.spanId", nullValue()) + .body("end.httpMethod", is("POST")) + .body("end.resourceClass", nullValue()) + .body("end.resourceMethod", nullValue()) + .body("end.client", matchesRegex(CLIENT)) + .body("period", notNullValue()) + .body("period.uri", is(url)) + .body("period.traceId", notNullValue()) + .body("period.spanId", nullValue()) + .body("period.httpMethod", is("POST")) + .body("period.resourceClass", nullValue()) + .body("period.resourceMethod", nullValue()) + .body("period.client", matchesRegex(CLIENT)); + } + } From e4a3279c2a2e6e8934648dfbb843141e9afef834 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 10 Dec 2024 08:50:37 +0200 Subject: [PATCH 093/207] Properly create REST Client template path when @Url is used Fixes: #44974 --- .../JaxrsClientReactiveProcessor.java | 32 +++++++++++++++---- .../reactive/client/impl/WebTargetImpl.java | 11 +++++++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java index 2f4ac2e80302f..bf1a4a4099909 100644 --- a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java +++ b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java @@ -955,8 +955,7 @@ A more full example of generated client (with sub-resource) can is at the bottom classContext.constructor.getThis(), baseTarget)); if (observabilityIntegrationNeeded) { - String templatePath = MULTIPLE_SLASH_PATTERN.matcher(restClientInterface.getPath() + method.getPath()) - .replaceAll("/"); + String templatePath = templatePath(restClientInterface, method); classContext.constructor.invokeVirtualMethod( MethodDescriptor.ofMethod(WebTargetImpl.class, "setPreClientSendHandler", void.class, ClientRestHandler.class), @@ -1012,11 +1011,25 @@ A more full example of generated client (with sub-resource) can is at the bottom + jandexMethod.name()); } - ResultHandle newInputTarget = methodParamNotNull.invokeVirtualMethod( - MethodDescriptor.ofMethod(WebTargetImpl.class, "withNewUri", WebTargetImpl.class, - java.net.URI.class), - methodParamNotNull.readInstanceField(inputTargetField, methodParamNotNull.getThis()), - newUri); + ResultHandle newInputTarget; + if (observabilityIntegrationNeeded) { + // we need to apply the ClientObservabilityHandler to the inputTarget field without altering it + newInputTarget = methodParamNotNull.invokeVirtualMethod( + MethodDescriptor.ofMethod(WebTargetImpl.class, "withNewUri", WebTargetImpl.class, + java.net.URI.class, ClientRestHandler.class), + methodParamNotNull.readInstanceField(inputTargetField, methodParamNotNull.getThis()), + newUri, + methodParamNotNull.newInstance( + MethodDescriptor.ofConstructor(ClientObservabilityHandler.class, String.class), + methodParamNotNull.load(templatePath(restClientInterface, method)))); + } else { + // just read the inputTarget field and call withNewUri on it + newInputTarget = methodParamNotNull.invokeVirtualMethod( + MethodDescriptor.ofMethod(WebTargetImpl.class, "withNewUri", WebTargetImpl.class, + java.net.URI.class), + methodParamNotNull.readInstanceField(inputTargetField, methodParamNotNull.getThis()), + newUri); + } ResultHandle newBaseTarget = methodParamNotNull.invokeVirtualMethod( baseTargetProducer.getMethodDescriptor(), methodParamNotNull.getThis(), newInputTarget); @@ -1247,6 +1260,11 @@ A more full example of generated client (with sub-resource) can is at the bottom } + private String templatePath(RestClientInterface restClientInterface, ResourceMethod method) { + return MULTIPLE_SLASH_PATTERN.matcher(restClientInterface.getPath() + method.getPath()) + .replaceAll("/"); + } + /** * The @Encoded annotation is only supported in path/query/matrix/form params. */ diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/WebTargetImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/WebTargetImpl.java index 5ef736be1dd04..b96030232bf3a 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/WebTargetImpl.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/WebTargetImpl.java @@ -259,6 +259,11 @@ public WebTargetImpl withNewUri(URI uri) { return newInstance(client, UriBuilder.fromUri(uri), configuration); } + @SuppressWarnings("unused") // this is used in the REST Client to support @BaseUrl and observability is enabled + public WebTargetImpl withNewUri(URI uri, ClientRestHandler preClientSendHandler) { + return newInstance(client, UriBuilder.fromUri(uri), configuration, preClientSendHandler); + } + @SuppressWarnings("unused") public WebTargetImpl queryParams(MultivaluedMap parameters) throws IllegalArgumentException, NullPointerException { @@ -297,6 +302,12 @@ public WebTargetImpl queryParamNoTemplate(String name, Object... values) throws protected WebTargetImpl newInstance(HttpClient client, UriBuilder uriBuilder, ConfigurationImpl configuration) { + return newInstance(client, uriBuilder, configuration, preClientSendHandler); + } + + protected WebTargetImpl newInstance(HttpClient client, UriBuilder uriBuilder, + ConfigurationImpl configuration, + ClientRestHandler preClientSendHandler) { WebTargetImpl result = new WebTargetImpl(restClient, client, uriBuilder, configuration, handlerChain.setPreClientSendHandler(preClientSendHandler), requestContext); From 07a16033d2621cc4c733b0fc4c518834b70863a2 Mon Sep 17 00:00:00 2001 From: brunobat Date: Mon, 9 Dec 2024 16:06:37 +0000 Subject: [PATCH 094/207] Add test for case where RestClient uses @Url and observability features --- .../binder/RestClientUriParameterTest.java | 96 +++++++++++++++++++ .../binder/UriTagWithHttpRootTest.java | 8 ++ 2 files changed, 104 insertions(+) create mode 100644 extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/RestClientUriParameterTest.java diff --git a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/RestClientUriParameterTest.java b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/RestClientUriParameterTest.java new file mode 100644 index 0000000000000..5bfc407260dd3 --- /dev/null +++ b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/RestClientUriParameterTest.java @@ -0,0 +1,96 @@ +package io.quarkus.micrometer.deployment.binder; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.search.Search; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import io.quarkus.rest.client.reactive.Url; +import io.quarkus.test.QuarkusUnitTest; + +public class RestClientUriParameterTest { + + final static SimpleMeterRegistry registry = new SimpleMeterRegistry(); + + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest() + .withApplicationRoot( + jar -> jar.addClasses(Resource.class, Client.class)) + .overrideConfigKey("quarkus.rest-client.\"client\".url", "http://does-not-exist.io"); + + @RestClient + Client client; + + @ConfigProperty(name = "quarkus.http.test-port") + Integer testPort; + + @BeforeAll + static void setRegistry() { + Metrics.addRegistry(registry); + } + + @AfterAll() + static void removeRegistry() { + Metrics.removeRegistry(registry); + } + + @Test + public void testOverride() { + String result = client.getById("http://localhost:" + testPort, "bar"); + assertEquals("bar", result); + + Timer clientTimer = registry.find("http.client.requests").timer(); + assertNotNull(clientTimer); + assertEquals("/example/{id}", clientTimer.getId().getTag("uri")); + } + + private Search getMeter(String name) { + return registry.find(name); + } + + @Path("/example") + @RegisterRestClient(baseUri = "http://dummy") + public interface Client { + + @GET + @Path("/{id}") + String getById(@Url String baseUri, @PathParam("id") String id); + } + + @Path("/example") + public static class Resource { + + @RestClient + Client client; + + @GET + @Path("/{id}") + @Produces(MediaType.TEXT_PLAIN) + public String example() { + return "bar"; + } + + @GET + @Path("/call") + @Produces(MediaType.TEXT_PLAIN) + public String call() { + return client.getById("http://localhost:8080", "1"); + } + } +} diff --git a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/UriTagWithHttpRootTest.java b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/UriTagWithHttpRootTest.java index d153fdb65fc5b..8bca89242a0e7 100644 --- a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/UriTagWithHttpRootTest.java +++ b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/UriTagWithHttpRootTest.java @@ -44,6 +44,14 @@ public class UriTagWithHttpRootTest { @Inject MeterRegistry registry; + @Test + public void testClient() throws InterruptedException { + when().get("/ping/one").then().statusCode(200); + Util.waitForMeters(registry.find("http.server.requests").timers(), 1); + Util.waitForMeters(registry.find("http.client.requests").timers(), 1); + Assertions.assertEquals(1, registry.find("http.client.requests").tag("uri", "/pong/{message}").timers().size()); + } + @Test public void testRequestUris() throws Exception { RestAssured.basePath = "/"; From 37c50ee34bf634bd0dc51be574051caad6e963c0 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 11 Dec 2024 13:28:59 +0200 Subject: [PATCH 095/207] Make sure Redis dev-service doesn't start in test that doesn't need it --- .../micrometer/deployment/binder/RestClientUriParameterTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/RestClientUriParameterTest.java b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/RestClientUriParameterTest.java index 5bfc407260dd3..c1fe6f1afcee3 100644 --- a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/RestClientUriParameterTest.java +++ b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/RestClientUriParameterTest.java @@ -32,6 +32,7 @@ public class RestClientUriParameterTest { static final QuarkusUnitTest TEST = new QuarkusUnitTest() .withApplicationRoot( jar -> jar.addClasses(Resource.class, Client.class)) + .overrideConfigKey("quarkus.redis.devservices.enabled", "false") .overrideConfigKey("quarkus.rest-client.\"client\".url", "http://does-not-exist.io"); @RestClient From 419d902653a606ad5eefcf2b75b619d43b016385 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Wed, 11 Dec 2024 12:14:25 +0000 Subject: [PATCH 096/207] Fallback shared named between Kubernetes-Openshift and Kubernetes-Knative --- .../config/OpenShiftConfigFallbackTest.java | 5 - .../KubernetesConfigBuilderCustomizer.java | 100 +++++++++--------- .../KubernetesConfigFallbackTest.java | 21 ++++ 3 files changed, 70 insertions(+), 56 deletions(-) diff --git a/extensions/kubernetes/openshift/deployment/src/test/java/io/quarkus/openshift/deployment/config/OpenShiftConfigFallbackTest.java b/extensions/kubernetes/openshift/deployment/src/test/java/io/quarkus/openshift/deployment/config/OpenShiftConfigFallbackTest.java index f67261d858adf..b0c8aa6082a49 100644 --- a/extensions/kubernetes/openshift/deployment/src/test/java/io/quarkus/openshift/deployment/config/OpenShiftConfigFallbackTest.java +++ b/extensions/kubernetes/openshift/deployment/src/test/java/io/quarkus/openshift/deployment/config/OpenShiftConfigFallbackTest.java @@ -25,7 +25,6 @@ public class OpenShiftConfigFallbackTest { static final QuarkusProdModeTest TEST = new QuarkusProdModeTest() .setApplicationName("config") .setApplicationVersion("0.1-SNAPSHOT") - .overrideConfigKey("quarkus.kubernetes.replicas", "10") .overrideConfigKey("quarkus.openshift.version", "999-SNAPSHOT") .overrideConfigKey("quarkus.openshift.labels.app", "openshift") .overrideConfigKey("quarkus.openshift.route.expose", "true") @@ -51,10 +50,6 @@ void configFallback() throws Exception { YamlConfigSource kubernetes = new YamlConfigSource(kubernetesDir.resolve("kubernetes.yml").toUri().toURL()); YamlConfigSource openshift = new YamlConfigSource(kubernetesDir.resolve("openshift.yml").toUri().toURL()); - // spec.replicas is only for Kubernetes and Openshift, no fallback - assertEquals("10", kubernetes.getValue("spec.replicas")); - assertEquals("1", openshift.getValue("spec.replicas")); - // In both, each should retain the value assertEquals("0.1-SNAPSHOT", kubernetes.getValue("spec.template.metadata.labels.\"app.kubernetes.io/version\"")); assertEquals("999-SNAPSHOT", openshift.getValue("spec.template.metadata.labels.\"app.kubernetes.io/version\"")); diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesConfigBuilderCustomizer.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesConfigBuilderCustomizer.java index bc7f984e8b74e..1e8f7a2ad0577 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesConfigBuilderCustomizer.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesConfigBuilderCustomizer.java @@ -2,12 +2,10 @@ import static io.smallrye.config.ConfigMappingInterface.getProperties; import static io.smallrye.config.ConfigMappingLoader.getConfigMapping; -import static io.smallrye.config.ProfileConfigSourceInterceptor.convertProfile; +import static io.smallrye.config.ConfigValue.CONFIG_SOURCE_COMPARATOR; -import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; -import java.util.List; import java.util.OptionalInt; import java.util.Set; import java.util.function.Function; @@ -17,7 +15,6 @@ import io.smallrye.config.ConfigSourceInterceptorFactory; import io.smallrye.config.ConfigValue; import io.smallrye.config.FallbackConfigSourceInterceptor; -import io.smallrye.config.NameIterator; import io.smallrye.config.Priorities; import io.smallrye.config.PropertyName; import io.smallrye.config.RelocateConfigSourceInterceptor; @@ -25,19 +22,21 @@ import io.smallrye.config.SmallRyeConfigBuilderCustomizer; public class KubernetesConfigBuilderCustomizer implements SmallRyeConfigBuilderCustomizer { + private static final Set IGNORE_OPENSHIFT_NAMES = ignoreOpenshiftNames(); + private static final Set IGNORE_KNATIVE_NAMES = ignoreKnativeNames(); + @Override public void configBuilder(final SmallRyeConfigBuilder builder) { - Set ignoreNames = ignoreNames(); - builder.withInterceptorFactories(new ConfigSourceInterceptorFactory() { @Override public ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorContext context) { return new Fallbacks(new Function() { @Override public String apply(final String name) { - if (name.startsWith("quarkus.openshift.") && !ignoreNames.contains(new PropertyName(name))) { + if (name.startsWith("quarkus.openshift.") && !IGNORE_OPENSHIFT_NAMES.contains(new PropertyName(name))) { return "quarkus.kubernetes." + name.substring(18); - } else if (name.startsWith("quarkus.knative.") && !ignoreNames.contains(new PropertyName(name))) { + } else if (name.startsWith("quarkus.knative.") + && !IGNORE_KNATIVE_NAMES.contains(new PropertyName(name))) { return "quarkus.kubernetes." + name.substring(16); } return name; @@ -64,7 +63,8 @@ public ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorConte return new RelocateConfigSourceInterceptor(new Function() { @Override public String apply(final String name) { - if (name.startsWith("quarkus.kubernetes.") && !ignoreNames.contains(new PropertyName(name))) { + if (name.startsWith("quarkus.kubernetes.") + && !IGNORE_OPENSHIFT_NAMES.contains(new PropertyName(name))) { return "quarkus.openshift." + name.substring(19); } return name; @@ -84,7 +84,7 @@ public ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorConte return new RelocateConfigSourceInterceptor(new Function() { @Override public String apply(final String name) { - if (name.startsWith("quarkus.kubernetes.") && !ignoreNames.contains(new PropertyName(name))) { + if (name.startsWith("quarkus.kubernetes.") && !IGNORE_KNATIVE_NAMES.contains(new PropertyName(name))) { return "quarkus.knative." + name.substring(19); } return name; @@ -134,73 +134,71 @@ public ConfigValue getValue(final ConfigSourceInterceptorContext context, final } } - // TODO - This will become public in a new version of SmallRye Config - can be removed later - private static final Comparator CONFIG_SOURCE_COMPARATOR = new Comparator() { - @Override - public int compare(ConfigValue original, ConfigValue candidate) { - int result = Integer.compare(original.getConfigSourceOrdinal(), candidate.getConfigSourceOrdinal()); - if (result != 0) { - return result; - } - result = Integer.compare(original.getConfigSourcePosition(), candidate.getConfigSourcePosition()) * -1; - if (result != 0) { - return result; - } - // If both properties are profiled, prioritize the one with the most specific profile. - if (original.getName().charAt(0) == '%' && candidate.getName().charAt(0) == '%') { - List originalProfiles = convertProfile( - new NameIterator(original.getName()).getNextSegment().substring(1)); - List candidateProfiles = convertProfile( - new NameIterator(candidate.getName()).getNextSegment().substring(1)); - return Integer.compare(originalProfiles.size(), candidateProfiles.size()) * -1; - } - return result; - } - }; - /** - * Collect the properties names that are not shared between kubernetes, openshift and - * knative to ignore when performing the fallback functions. + * Collect the properties names that are not shared between kubernetes and openshift + * to ignore when performing the fallback functions. * * @return a Set of properties names to ignore */ - private static Set ignoreNames() { - Set kubernetes = getProperties(getConfigMapping(KubernetesConfig.class)) - .get(KubernetesConfig.class).get("").keySet(); - Set openshift = getProperties(getConfigMapping(OpenShiftConfig.class)) - .get(OpenShiftConfig.class).get("").keySet(); - Set knative = getProperties(getConfigMapping(KnativeConfig.class)) - .get(KnativeConfig.class).get("").keySet(); + private static Set ignoreOpenshiftNames() { + Set kubernetes = getProperties(getConfigMapping(KubernetesConfig.class)).get(KubernetesConfig.class).get("") + .keySet(); + Set openshift = getProperties(getConfigMapping(OpenShiftConfig.class)).get(OpenShiftConfig.class).get("") + .keySet(); Set ignored = new HashSet<>(); for (String name : kubernetes) { - if (!openshift.contains(name) || !knative.contains(name)) { + if (!openshift.contains(name)) { ignored.add(new PropertyName("quarkus.kubernetes." + name)); ignored.add(new PropertyName("quarkus.openshift." + name)); - ignored.add(new PropertyName("quarkus.knative." + name)); } } + for (String name : openshift) { - if (!kubernetes.contains(name) || !knative.contains(name)) { + if (!kubernetes.contains(name)) { + ignored.add(new PropertyName("quarkus.kubernetes." + name)); + ignored.add(new PropertyName("quarkus.openshift." + name)); + } + } + + // These are shared, but must work independently + ignored.add(new PropertyName("quarkus.kubernetes.deploy")); + ignored.add(new PropertyName("quarkus.openshift.deploy")); + ignored.add(new PropertyName("quarkus.kubernetes.deploy-strategy")); + ignored.add(new PropertyName("quarkus.openshift.deploy-strategy")); + return ignored; + } + + /** + * Collect the properties names that are not shared between kubernetes and knative to + * ignore when performing the fallback functions. + * + * @return a Set of properties names to ignore + */ + private static Set ignoreKnativeNames() { + Set kubernetes = getProperties(getConfigMapping(KubernetesConfig.class)).get(KubernetesConfig.class).get("") + .keySet(); + Set knative = getProperties(getConfigMapping(KnativeConfig.class)).get(KnativeConfig.class).get("").keySet(); + + Set ignored = new HashSet<>(); + for (String name : kubernetes) { + if (!knative.contains(name)) { ignored.add(new PropertyName("quarkus.kubernetes." + name)); ignored.add(new PropertyName("quarkus.openshift." + name)); - ignored.add(new PropertyName("quarkus.knative." + name)); } } + for (String name : knative) { - if (!kubernetes.contains(name) || !openshift.contains(name)) { + if (!kubernetes.contains(name)) { ignored.add(new PropertyName("quarkus.kubernetes." + name)); ignored.add(new PropertyName("quarkus.openshift." + name)); - ignored.add(new PropertyName("quarkus.knative." + name)); } } // These are shared, but must work independently ignored.add(new PropertyName("quarkus.kubernetes.deploy")); - ignored.add(new PropertyName("quarkus.openshift.deploy")); ignored.add(new PropertyName("quarkus.knative.deploy")); ignored.add(new PropertyName("quarkus.kubernetes.deploy-strategy")); - ignored.add(new PropertyName("quarkus.openshift.deploy-strategy")); ignored.add(new PropertyName("quarkus.knative.deploy-strategy")); return ignored; } diff --git a/extensions/kubernetes/vanilla/deployment/src/test/java/io/quarkus/kubernetes/deployment/KubernetesConfigFallbackTest.java b/extensions/kubernetes/vanilla/deployment/src/test/java/io/quarkus/kubernetes/deployment/KubernetesConfigFallbackTest.java index 3e3a42c8e9e2a..35387e5433ef3 100644 --- a/extensions/kubernetes/vanilla/deployment/src/test/java/io/quarkus/kubernetes/deployment/KubernetesConfigFallbackTest.java +++ b/extensions/kubernetes/vanilla/deployment/src/test/java/io/quarkus/kubernetes/deployment/KubernetesConfigFallbackTest.java @@ -2,6 +2,7 @@ import static io.smallrye.config.PropertiesConfigSourceLoader.inClassPath; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.Duration; @@ -10,6 +11,7 @@ import org.junit.jupiter.api.Test; import io.quarkus.runtime.configuration.DurationConverter; +import io.smallrye.config.PropertiesConfigSource; import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfigBuilder; @@ -46,4 +48,23 @@ void fallback() { assertEquals(knative.labels().get(entry.getKey()), entry.getValue()); } } + + @Test + void sharedOnlyBetweenKubernetesAndOpenshift() { + SmallRyeConfig config = new SmallRyeConfigBuilder() + .addDiscoveredCustomizers() + .withConverter(Duration.class, 100, new DurationConverter()) + .withMappingIgnore("quarkus.**") + .withMapping(KubernetesConfig.class) + .withMapping(OpenShiftConfig.class) + .withMapping(KnativeConfig.class) + .withSources(new PropertiesConfigSource(Map.of("quarkus.kubernetes.init-task-defaults.enabled", "false"), "")) + .build(); + + KubernetesConfig kubernetes = config.getConfigMapping(KubernetesConfig.class); + OpenShiftConfig openShift = config.getConfigMapping(OpenShiftConfig.class); + + assertFalse(kubernetes.initTaskDefaults().enabled()); + assertFalse(openShift.initTaskDefaults().enabled()); + } } From adf11bd89e2aec1adbeccb5cf7c64653dd95366a Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Tue, 10 Dec 2024 08:50:11 +0100 Subject: [PATCH 097/207] Upgrade to quarkus-http 5.3.4 --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index a3a607f0e509c..7e73fb185de40 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -31,7 +31,7 @@ 6.2.11.Final 2.8.0-alpha 1.27.0-alpha - 5.3.3 + 5.3.4 1.14.2 2.2.2 0.22.0 From e24f716c80164545a5ec96fe46e9dcc4385226fe Mon Sep 17 00:00:00 2001 From: vkn Date: Wed, 11 Dec 2024 14:42:27 +0100 Subject: [PATCH 098/207] Migrate tests to micrometer metrics --- extensions/mongodb-client/deployment/pom.xml | 7 ++- .../deployment/MongoClientProcessor.java | 3 +- .../io/quarkus/mongodb/MongoLazyTest.java | 41 ++++++--------- .../io/quarkus/mongodb/MongoMetricsTest.java | 50 +++++++----------- .../deployment/MongoClientProcessorTest.java | 51 +++++++++++++++++++ .../mongodb/runtime/MongoClientRecorder.java | 5 -- 6 files changed, 93 insertions(+), 64 deletions(-) create mode 100644 extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/deployment/MongoClientProcessorTest.java diff --git a/extensions/mongodb-client/deployment/pom.xml b/extensions/mongodb-client/deployment/pom.xml index 8bd99d1840900..e97646dc79fd8 100644 --- a/extensions/mongodb-client/deployment/pom.xml +++ b/extensions/mongodb-client/deployment/pom.xml @@ -63,7 +63,12 @@ io.quarkus - quarkus-smallrye-metrics-deployment + quarkus-micrometer-deployment + true + + + io.quarkus + quarkus-micrometer-registry-prometheus-deployment test diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java index 128f205661287..2dd946cf874e2 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java @@ -64,6 +64,7 @@ import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.metrics.MetricsCapabilityBuildItem; import io.quarkus.mongodb.MongoClientName; +import io.quarkus.mongodb.metrics.MicrometerCommandListener; import io.quarkus.mongodb.reactive.ReactiveMongoClient; import io.quarkus.mongodb.runtime.MongoClientBeanUtil; import io.quarkus.mongodb.runtime.MongoClientCustomizer; @@ -134,7 +135,7 @@ AdditionalIndexedClassesBuildItem includeMongoCommandMetricListener( boolean withMicrometer = metricsCapability.map(cap -> cap.metricsSupported(MetricsFactory.MICROMETER)) .orElse(false); if (withMicrometer) { - return new AdditionalIndexedClassesBuildItem(MongoClientRecorder.getMicrometerCommandListenerClassName()); + return new AdditionalIndexedClassesBuildItem(MicrometerCommandListener.class.getName()); } return new AdditionalIndexedClassesBuildItem(); } diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoLazyTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoLazyTest.java index c8c1d01716668..10c1cae82bf3a 100644 --- a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoLazyTest.java +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoLazyTest.java @@ -4,58 +4,47 @@ import jakarta.inject.Inject; -import org.eclipse.microprofile.metrics.Metric; -import org.eclipse.microprofile.metrics.MetricID; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.Tag; -import org.eclipse.microprofile.metrics.annotation.RegistryType; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import com.mongodb.client.MongoClient; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.MeterRegistry; import io.quarkus.arc.Arc; -import io.quarkus.mongodb.metrics.ConnectionPoolGauge; import io.quarkus.mongodb.reactive.ReactiveMongoClient; import io.quarkus.test.QuarkusUnitTest; /** Variation of {@link io.quarkus.mongodb.MongoMetricsTest} to verify lazy client initialization. */ -public class MongoLazyTest extends MongoTestBase { +class MongoLazyTest extends MongoTestBase { @Inject - @RegistryType(type = MetricRegistry.Type.VENDOR) - MetricRegistry registry; + MeterRegistry meterRegistry; @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() - .withApplicationRoot((jar) -> jar.addClasses(MongoTestBase.class)) + .withApplicationRoot(jar -> jar.addClasses(MongoTestBase.class)) .withConfigurationResource("application-metrics-mongo.properties"); @Test void testLazyClientCreation() { // Clients are created lazily, this metric should not be present yet - assertThat(getGaugeValueOrNull("mongodb.connection-pool.size", getTags())).isNull(); - assertThat(getGaugeValueOrNull("mongodb.connection-pool.checked-out-count", getTags())).isNull(); + assertThat(getMetric("mongodb.driver.pool.size")).isNull(); + assertThat(getMetric("mongodb.driver.pool.checkedout")).isNull(); + assertThat(getMetric("mongodb.driver.commands")).isNull(); // doing this here instead of in another method in order to avoid messing with the initialization stats assertThat(Arc.container().instance(MongoClient.class).get()).isNull(); assertThat(Arc.container().instance(ReactiveMongoClient.class).get()).isNull(); } - private Long getGaugeValueOrNull(String metricName, Tag[] tags) { - MetricID metricID = new MetricID(metricName, tags); - Metric metric = registry.getMetrics().get(metricID); - - if (metric == null) { - return null; - } - return ((ConnectionPoolGauge) metric).getValue(); + private Double getMetric(String name) { + Meter metric = meterRegistry.getMeters() + .stream() + .filter(mtr -> mtr.getId().getName().contains(name)) + .findFirst() + .orElse(null); + return metric == null ? null : metric.measure().iterator().next().getValue(); } - private Tag[] getTags() { - return new Tag[] { - new Tag("host", "127.0.0.1"), - new Tag("port", "27018"), - }; - } } diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoMetricsTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoMetricsTest.java index dab2253817afe..cc54cb1b61d8a 100644 --- a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoMetricsTest.java +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoMetricsTest.java @@ -1,38 +1,32 @@ package io.quarkus.mongodb; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; import jakarta.inject.Inject; -import org.eclipse.microprofile.metrics.Metric; -import org.eclipse.microprofile.metrics.MetricID; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.Tag; -import org.eclipse.microprofile.metrics.annotation.RegistryType; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import com.mongodb.client.MongoClient; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.MeterRegistry; import io.quarkus.arc.Arc; -import io.quarkus.mongodb.metrics.ConnectionPoolGauge; import io.quarkus.mongodb.reactive.ReactiveMongoClient; import io.quarkus.test.QuarkusUnitTest; -public class MongoMetricsTest extends MongoTestBase { +class MongoMetricsTest extends MongoTestBase { @Inject MongoClient client; @Inject - @RegistryType(type = MetricRegistry.Type.VENDOR) - MetricRegistry registry; + MeterRegistry meterRegistry; @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() - .withApplicationRoot((jar) -> jar.addClasses(MongoTestBase.class)) + .withApplicationRoot(jar -> jar.addClasses(MongoTestBase.class)) .withConfigurationResource("application-metrics-mongo.properties"); @AfterEach @@ -45,38 +39,32 @@ void cleanup() { @Test void testMetricsInitialization() { // Clients are created lazily, this metric should not be present yet - assertThat(getGaugeValueOrNull("mongodb.connection-pool.size", getTags())).isNull(); - assertThat(getGaugeValueOrNull("mongodb.connection-pool.checked-out-count", getTags())).isNull(); + assertThat(getMetric("mongodb.driver.pool.size")).isNull(); + assertThat(getMetric("mongodb.driver.pool.checkedout")).isNull(); // Just need to execute something so that a connection is opened String name = client.listDatabaseNames().first(); - assertEquals(1L, getGaugeValueOrNull("mongodb.connection-pool.size", getTags())); - assertEquals(0L, getGaugeValueOrNull("mongodb.connection-pool.checked-out-count", getTags())); + assertThat(getMetric("mongodb.driver.pool.size")).isOne(); + assertThat(getMetric("mongodb.driver.commands")).isOne(); + assertThat(getMetric("mongodb.driver.pool.checkedout")).isZero(); client.close(); - assertEquals(0L, getGaugeValueOrNull("mongodb.connection-pool.size", getTags())); - assertEquals(0L, getGaugeValueOrNull("mongodb.connection-pool.checked-out-count", getTags())); + assertThat(getMetric("mongodb.driver.pool.size")).isNull(); + assertThat(getMetric("mongodb.driver.pool.checkedout")).isNull(); // doing this here instead of in another method in order to avoid messing with the initialization stats assertThat(Arc.container().instance(MongoClient.class).get()).isNotNull(); assertThat(Arc.container().instance(ReactiveMongoClient.class).get()).isNull(); } - private Long getGaugeValueOrNull(String metricName, Tag[] tags) { - MetricID metricID = new MetricID(metricName, tags); - Metric metric = registry.getMetrics().get(metricID); - - if (metric == null) { - return null; - } - return ((ConnectionPoolGauge) metric).getValue(); + private Double getMetric(String metricName) { + Meter metric = meterRegistry.getMeters() + .stream() + .filter(mtr -> mtr.getId().getName().contains(metricName)) + .findFirst() + .orElse(null); + return metric == null ? null : metric.measure().iterator().next().getValue(); } - private Tag[] getTags() { - return new Tag[] { - new Tag("host", "127.0.0.1"), - new Tag("port", "27018"), - }; - } } diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/deployment/MongoClientProcessorTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/deployment/MongoClientProcessorTest.java new file mode 100644 index 0000000000000..86dae2cdda77f --- /dev/null +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/deployment/MongoClientProcessorTest.java @@ -0,0 +1,51 @@ +package io.quarkus.mongodb.deployment; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import io.quarkus.deployment.builditem.AdditionalIndexedClassesBuildItem; +import io.quarkus.deployment.metrics.MetricsCapabilityBuildItem; +import io.quarkus.runtime.metrics.MetricsFactory; + +class MongoClientProcessorTest { + private final MongoClientProcessor buildStep = new MongoClientProcessor(); + + @ParameterizedTest + @CsvSource({ + "true, true, true", // Metrics enabled and Micrometer supported + "true, false, false", // Metrics enabled but Micrometer not supported + "false, true, false", // Metrics disabled and Micrometer supported + "false, false, false" // Metrics disabled and Micrometer not supported + }) + void testIncludeMongoCommandMetricListener(boolean metricsEnabled, boolean micrometerSupported, boolean expectedResult) { + MongoClientBuildTimeConfig config = config(metricsEnabled); + Optional capability = capability(metricsEnabled, micrometerSupported); + + AdditionalIndexedClassesBuildItem result = buildStep.includeMongoCommandMetricListener(config, capability); + + if (expectedResult) { + assertThat(result.getClassesToIndex()) + .containsExactly("io.quarkus.mongodb.metrics.MicrometerCommandListener"); + } else { + assertThat(result.getClassesToIndex()).isEmpty(); + } + } + + private static Optional capability(boolean metricsEnabled, boolean micrometerSupported) { + MetricsCapabilityBuildItem capability = metricsEnabled + ? new MetricsCapabilityBuildItem(factory -> MetricsFactory.MICROMETER.equals(factory) && micrometerSupported) + : null; + return Optional.ofNullable(capability); + } + + private static MongoClientBuildTimeConfig config(boolean metricsEnabled) { + MongoClientBuildTimeConfig buildTimeConfig = new MongoClientBuildTimeConfig(); + buildTimeConfig.metricsEnabled = metricsEnabled; + return buildTimeConfig; + } + +} diff --git a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java index 79cc3f97e10f2..01fa1bf4caebd 100644 --- a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java +++ b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java @@ -14,7 +14,6 @@ import com.mongodb.event.ConnectionPoolListener; import io.quarkus.arc.Arc; -import io.quarkus.mongodb.metrics.MicrometerCommandListener; import io.quarkus.mongodb.metrics.MicrometerConnectionPoolListener; import io.quarkus.mongodb.metrics.MongoMetricsConnectionPoolListener; import io.quarkus.mongodb.reactive.ReactiveMongoClient; @@ -100,10 +99,6 @@ public ConnectionPoolListener get() { }; } - public static String getMicrometerCommandListenerClassName() { - return MicrometerCommandListener.class.getName(); - } - public Supplier createMPMetricsConnectionPoolListener() { return new Supplier() { @Override From f8b87362a5158b081b130266bdf31a24953a66d7 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Wed, 11 Dec 2024 14:25:32 +0000 Subject: [PATCH 099/207] Update OIDC MTLS test to use generated certificates --- build-parent/pom.xml | 5 ++++ integration-tests/oidc-mtls/pom.xml | 28 +++++++++++++++++- .../src/main/resources/application.properties | 10 +++---- .../src/main/resources/server-keystore.jks | Bin 2423 -> 0 bytes .../src/main/resources/server-truststore.jks | Bin 925 -> 0 bytes .../java/io/quarkus/it/oidc/OidcMtlsTest.java | 14 ++++----- .../src/test/resources/client-keystore.jks | Bin 2214 -> 0 bytes .../src/test/resources/client-truststore.jks | Bin 2423 -> 0 bytes 8 files changed, 44 insertions(+), 13 deletions(-) delete mode 100644 integration-tests/oidc-mtls/src/main/resources/server-keystore.jks delete mode 100644 integration-tests/oidc-mtls/src/main/resources/server-truststore.jks delete mode 100644 integration-tests/oidc-mtls/src/test/resources/client-keystore.jks delete mode 100644 integration-tests/oidc-mtls/src/test/resources/client-truststore.jks diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 62dea85311132..887efb2b3105e 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -660,6 +660,11 @@ + + io.smallrye.certs + smallrye-certificate-generator-maven-plugin + ${smallrye-certificate-generator.version} + diff --git a/integration-tests/oidc-mtls/pom.xml b/integration-tests/oidc-mtls/pom.xml index 2edad5c91ad20..719118f28efca 100644 --- a/integration-tests/oidc-mtls/pom.xml +++ b/integration-tests/oidc-mtls/pom.xml @@ -27,7 +27,6 @@ io.quarkus quarkus-tls-registry - io.quarkus quarkus-junit5 @@ -88,6 +87,33 @@ + io.smallrye.certs + smallrye-certificate-generator-maven-plugin + + + generate-test-resources + + generate + + + + + + + oidc + + PEM + PKCS12 + + password + backend-service + 2 + true + + + + + maven-surefire-plugin true diff --git a/integration-tests/oidc-mtls/src/main/resources/application.properties b/integration-tests/oidc-mtls/src/main/resources/application.properties index 69d52fd93aa24..939e259a700ac 100644 --- a/integration-tests/oidc-mtls/src/main/resources/application.properties +++ b/integration-tests/oidc-mtls/src/main/resources/application.properties @@ -1,11 +1,11 @@ quarkus.http.tls-configuration-name=oidc-mtls -quarkus.tls.oidc-mtls.key-store.jks.path=server-keystore.jks -quarkus.tls.oidc-mtls.key-store.jks.password=secret -quarkus.tls.oidc-mtls.trust-store.jks.path=server-truststore.jks -quarkus.tls.oidc-mtls.trust-store.jks.password=password +quarkus.tls.oidc-mtls.key-store.p12.path=target/certificates/oidc-keystore.p12 +quarkus.tls.oidc-mtls.key-store.p12.password=password +quarkus.tls.oidc-mtls.trust-store.p12.path=target/certificates/oidc-server-truststore.p12 +quarkus.tls.oidc-mtls.trust-store.p12.password=password quarkus.http.auth.inclusive=true quarkus.http.ssl.client-auth=REQUIRED quarkus.http.insecure-requests=DISABLED -quarkus.native.additional-build-args=-H:IncludeResources=.*\\.jks +quarkus.native.additional-build-args=-H:IncludeResources=target/certificates/.*\\.p12 diff --git a/integration-tests/oidc-mtls/src/main/resources/server-keystore.jks b/integration-tests/oidc-mtls/src/main/resources/server-keystore.jks deleted file mode 100644 index da33e8e7a16683d421c7a541bf0013521efb605e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2423 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 aH~3Ca%|*I@e88To>+D>~J`lt~rv3-)J!2gJ diff --git a/integration-tests/oidc-mtls/src/main/resources/server-truststore.jks b/integration-tests/oidc-mtls/src/main/resources/server-truststore.jks deleted file mode 100644 index 8ec8e126507b61e0e602b71d9f67b3d7e3c7cae3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 925 zcmezO_TO6u1_mY|W(3o$xs}0Ue&dE&8D>0B0 z=QXr6G&C?YG&M3ZGLI7HHL^4`0AdK2=Jq!+Dj|EBk(GhDiIJbdpox)-sfm%1VUF3s zo}9*=J}DCyv6d_>miqhX+0BER7vzr=weLB0SI~-EN4Tx;+oAX3sZu+AreC;W+rDov z-#5*V51%D8KX(20xaE+MMC5UqlCZ}&*8kY~jW=TIFRK(mcF!wJ^TT7)vd&p~1Uy)$ z`pW;@Uk~HZlKvCjci1|P$j&@8Uwi5_z2paTO5a=hS@rqWe0&n}OLbn_nKBuLad&4PoF%w@U!d89 z+LCrv&mDH_wWWUYJ`36D%^-U7h-9RXpo^<=ZFc0HX`&2UWMlL9lv%uVR}CpmJg{;8 zx_~1U?x&fU85tNCD;mff$O0oymXAe@MTGhL(rFKW9uTVSSw3Zn;O1#zMYmj$0}+^R zfPu)!z}8XzuI^>`BBZaSb80!?+r7pc#`09np_Lozt4zJ}{d+W?|#aPK1E8H9tc&p84 z9$uW3|Ks-G6^q-888qdu-^`O)?fLIsY>e9J3v8=pk6rP))@~NVdhf7^xr%i0hj$v? zKacmOG&aO636*{EblS9x!(U?iHAU{$t+Riy#c;{YELD{*se2PT}_AU?Y+Xxvefqh07{ov?f?J) diff --git a/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/OidcMtlsTest.java b/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/OidcMtlsTest.java index ce4b2cd482cad..458c37b26b1ea 100644 --- a/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/OidcMtlsTest.java +++ b/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/OidcMtlsTest.java @@ -27,7 +27,7 @@ @QuarkusTest public class OidcMtlsTest { - @TestHTTPResource(ssl = true) + @TestHTTPResource(tls = true) URL url; KeycloakTestClient keycloakClient = new KeycloakTestClient(); @@ -46,7 +46,7 @@ public void testGetIdentityNames() throws Exception { .indefinitely(); assertEquals(200, resp.statusCode()); String name = resp.bodyAsString(); - assertEquals("Identities: CN=client, alice", name); + assertEquals("Identities: CN=backend-service, alice", name); // HTTP 401, invalid token resp = webClient.get("/service/name") @@ -63,18 +63,18 @@ private WebClientOptions createWebClientOptions() throws Exception { WebClientOptions webClientOptions = new WebClientOptions().setDefaultHost(url.getHost()) .setDefaultPort(url.getPort()).setSsl(true).setVerifyHost(false); - byte[] keyStoreData = getFileContent(Paths.get("client-keystore.jks")); + byte[] keyStoreData = getFileContent(Paths.get("target/certificates/oidc-client-keystore.p12")); KeyStoreOptions keyStoreOptions = new KeyStoreOptions() .setPassword("password") .setValue(Buffer.buffer(keyStoreData)) - .setType("JKS"); + .setType("PKCS12"); webClientOptions.setKeyCertOptions(keyStoreOptions); - byte[] trustStoreData = getFileContent(Paths.get("client-truststore.jks")); + byte[] trustStoreData = getFileContent(Paths.get("target/certificates/oidc-client-truststore.p12")); KeyStoreOptions trustStoreOptions = new KeyStoreOptions() - .setPassword("secret") + .setPassword("password") .setValue(Buffer.buffer(trustStoreData)) - .setType("JKS"); + .setType("PKCS12"); webClientOptions.setTrustOptions(trustStoreOptions); return webClientOptions; diff --git a/integration-tests/oidc-mtls/src/test/resources/client-keystore.jks b/integration-tests/oidc-mtls/src/test/resources/client-keystore.jks deleted file mode 100644 index cf6d6ba454864d18322799afac37f520673193d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2214 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 aH~3Ca%|*I@e88To>+D>~J`lt~rv3-)J!2gJ From 0c54cccdf8df147e17fb84f0884e9904229400a3 Mon Sep 17 00:00:00 2001 From: Rolfe Dlugy-Hegwer Date: Wed, 11 Dec 2024 15:58:33 -0500 Subject: [PATCH 100/207] Copyedit security-keycloak-authorization.adoc --- .../security-keycloak-authorization.adoc | 277 ++++++++++++------ 1 file changed, 195 insertions(+), 82 deletions(-) diff --git a/docs/src/main/asciidoc/security-keycloak-authorization.adoc b/docs/src/main/asciidoc/security-keycloak-authorization.adoc index 275bace269635..2ddeb8377effb 100644 --- a/docs/src/main/asciidoc/security-keycloak-authorization.adoc +++ b/docs/src/main/asciidoc/security-keycloak-authorization.adoc @@ -1,39 +1,62 @@ //// -This guide is maintained in the main Quarkus repository -and pull requests should be submitted there: +This guide is maintained in the main Quarkus repository. +To contribute, submit a pull request here: https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc //// = Using OpenID Connect (OIDC) and Keycloak to centralize authorization include::_attributes.adoc[] :diataxis-type: howto :categories: security -:keywords: sso oidc security keycloak -:topics: security,authentication,authorization,keycloak,sso,oidc -:extensions: io.quarkus:quarkus-oidc,io.quarkus:quarkus-keycloak-authorization +:keywords: sso, oidc, security, keycloak +:topics: security, authentication, authorization, keycloak, sso, oidc +:extensions: io.quarkus:quarkus-oidc, io.quarkus:quarkus-keycloak-authorization -Learn how to enable bearer token authorization in your Quarkus application using link:https://www.keycloak.org/docs/latest/authorization_services/index.html[Keycloak Authorization Services] for secure access to protected resources. +Learn how to enable bearer token authorization in your Quarkus application by using link:https://www.keycloak.org/docs/latest/authorization_services/index.html[Keycloak Authorization Services] for secure access to protected resources. -The `quarkus-keycloak-authorization` extension relies on `quarkus-oidc`. -It includes a policy enforcer that regulates access to secured resources. -Access is governed by permissions set in Keycloak. -Currently, this extension is compatible solely with Quarkus xref:security-oidc-bearer-token-authentication.adoc[OIDC service applications]. +== Overview -It provides a flexible and dynamic authorization capability based on Resource-Based Access Control. +The `quarkus-keycloak-authorization` extension builds on the `quarkus-oidc` extension to offer advanced authorization capabilities. It includes a policy enforcer that dynamically regulates access to secured resources. Access is governed by permissions defined in Keycloak, supporting flexible and dynamic Resource-Based Access Control (RBAC). -Rather than explicitly enforcing access through specific mechanisms such as role-based access control (RBAC), `quarkus-keycloak-authorization` determines request permissions based on resource attributes such as name, identifier, or Uniform Resource Identifier (URI). -This process involves sending a `quarkus-oidc`-verified bearer access token to Keycloak Authorization Services for an authorization decision. +Use the `quarkus-keycloak-authorization` extension only if you are using Keycloak and Keycloak Authorization Services is enabled in your environment to handle authorization decisions. -Use `quarkus-keycloak-authorization` only if you work with Keycloak and have Keycloak Authorization Services enabled to make authorization decisions. -Use `quarkus-oidc` if you do not work with Keycloak or work with Keycloak but do not have its Keycloak Authorization Services enabled to make authorization decisions. +If you are not using Keycloak, or if Keycloak is configured without Keycloak Authorization Services, use the `quarkus-oidc` extension instead. -By shifting authorization responsibilities outside your application, you enhance security through various access control methods while eliminating the need for frequent re-deployments whenever security needs evolve. -In this case, Keycloak acts as a centralized authorization hub, managing your protected resources and their corresponding permissions effectively. +.How it works -For more information, see the xref:security-oidc-bearer-token-authentication.adoc[OIDC Bearer token authentication] guide. -It is important to realize that the Bearer token authentication mechanism does the authentication and creates a security identity. -Meanwhile, the `quarkus-keycloak-authorization` extension applies a Keycloak Authorization Policy to this identity based on the current request path and other policy settings. +The `quarkus-keycloak-authorization` extension centralizes authorization responsibilities in Keycloak, enhancing security and simplifying application maintenance. The extension: -For more information, see https://www.keycloak.org/docs/latest/authorization_services/index.html#_enforcer_overview[Keycloak Authorization Services documentation]. +1. Uses the `quarkus-oidc` extension to verify bearer tokens. +2. Sends verified tokens to Keycloak Authorization Services. +3. Allows Keycloak to evaluate resource-based permissions dynamically, by using attributes such as resource name, identifier, or URI. + +By externalizing authorization decisions, you can: + +- Implement diverse access control strategies without modifying application code. +- Reduce redeployment needs as security requirements evolve. + +.Compatibility + +This extension is compatible only with Quarkus xref:security-oidc-bearer-token-authentication.adoc[OIDC service applications]. It complements explicit mechanisms such as role-based access control with dynamic authorization policies. + +.Key Features + +- **Centralized Management**: Delegate authorization decisions to Keycloak for consistent security policies across applications. +- **Dynamic Permissions**: Define access control dynamically by using resource attributes. +- **Simplified Maintenance**: Reduce the need to update and redeploy applications when access policies change. + +.Setting Up + +Before using this extension, ensure the following: + +1. Keycloak Authorization Services is enabled in your Keycloak instance. +2. Your Quarkus application includes the `quarkus-keycloak-authorization` extension. + +For detailed steps, see the xref:security-oidc-bearer-token-authentication.adoc[OIDC Bearer Token Authentication] guide. + +.Additional resources + +To learn more about Keycloak Authorization Services and the policy enforcer, visit the official documentation: +https://www.keycloak.org/docs/latest/authorization_services/index.html#_enforcer_overview[Keycloak Authorization Services Documentation]. == Prerequisites @@ -42,30 +65,55 @@ include::{includes}/prerequisites.adoc[] * https://stedolan.github.io/jq/[jq tool] * https://www.keycloak.org[Keycloak] + == Architecture -In this example, we build a very simple microservice that offers two endpoints: +This example demonstrates a simple microservice setup with two protected endpoints: * `/api/users/me` * `/api/admin` -These endpoints are protected. -Access is granted only when a client sends a bearer token with the request. -This token must be valid, having a correct signature, expiration date, and audience. -Additionally, the microservice must trust the token. +.Token-based access control + +Access to these endpoints is controlled by using bearer tokens. To gain access, the following conditions must be met: + +- **Valid token**: The token must have a correct signature, a valid expiration date, and the appropriate audience. +- **Trust**: The microservice must trust the issuing Keycloak server. -The bearer token is issued by a Keycloak server and represents the subject for which the token was issued. -For being an OAuth 2.0 Authorization Server, the token also references the client acting on behalf of the user. +The bearer tokens issued by the Keycloak server serve as: -The `/api/users/me` endpoint can be accessed by any user with a valid token. -As a response, it returns a JSON document with details about the user obtained from the information carried on the token. -This endpoint is protected with RBAC, and only users granted with the `user` role can access this endpoint. +- **User identifiers**: Indicating the subject (user) for whom the token was issued. +- **Client references**: Identifying the client application acting on behalf of the user, per OAuth 2.0 Authorization Server standards. -The `/api/admin` endpoint is protected with RBAC, and only users granted the `admin` role can access it. +.Endpoints and access policies -This is a very simple example of using RBAC policies to govern access to your resources. -However, Keycloak supports other policies that you can use to perform even more fine-grained access control. -By using this example, you'll see that your application is completely decoupled from your authorization policies, with enforcement purely based on the accessed resource. +For `/api/users/me`: + +- **Access policy**: Open to users with a valid bearer token and the `user` role. +- **Response**: Returns user details as a JSON object derived from the token. + +Example response: +[source,json] +---- +{ + "user": { + "id": "1234", + "username": "johndoe", + "email": "johndoe@example.com" + } +} +---- + +For `/api/admin`: + +- *Access policy*: Restricted to users with a valid bearer token and the `admin` role. + +.Decoupled authorization + +This example highlights the use of role-based access control (RBAC) policies to protect resources. Key points include: + +- *Policy flexibility*: Keycloak supports various policy types, such as attribute-based and custom policies, enabling fine-grained control. +- *Decoupled application logic*: Authorization policies are managed entirely by Keycloak, allowing your application to focus on its core functionality. == Solution @@ -78,23 +126,22 @@ The solution is in the `security-keycloak-authorization-quickstart` link:{quicks == Creating the project -First, we need a new project. -Create a new project with the following command: +To get started, create a new project by using the following command: :create-app-artifact-id: security-keycloak-authorization-quickstart :create-app-extensions: oidc,keycloak-authorization,rest-jackson include::{includes}/devtools/create-app.adoc[] -This command generates a project, importing the `keycloak-authorization` extension. -This extension implements a Keycloak Adapter for Quarkus applications and provides all the necessary capabilities to integrate with a Keycloak server and perform bearer token authorization. +This command generates a new project with the `keycloak-authorization` extension. The extension integrates a Keycloak Adapter into your Quarkus application, providing the necessary capabilities to interact with a Keycloak server and perform bearer token authorization. -If you already have your Quarkus project configured, you can add the `oidc` and `keycloak-authorization` extensions -to your project by running the following command in your project base directory: +.Adding extensions to an existing project + +If you already have an existing Quarkus project, you can add the `oidc` and `keycloak-authorization` extensions by running the following command in your project’s base directory: :add-extension-extensions: oidc,keycloak-authorization include::{includes}/devtools/extension-add.adoc[] -This adds the following dependencies to your build file: +This command adds the following dependencies to your build file: [source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] .pom.xml @@ -116,8 +163,9 @@ implementation("io.quarkus:quarkus-oidc") implementation("io.quarkus:quarkus-keycloak-authorization") ---- -Let's start by implementing the `/api/users/me` endpoint. -As you can see in the following source code, it is a regular Jakarta REST resource: +.Implementing the `/api/users/me` endpoint + +Start by implementing the `/api/users/me` endpoint. The following code defines a Jakarta REST resource that provides user details: [source,java] ---- @@ -159,7 +207,9 @@ public class UsersResource { } ---- -The source code for the `/api/admin` endpoint is also very simple: +.Implementing the `/api/admin` endpoint + +Next, define the `/api/admin` endpoint. The following code represents a simple Jakarta REST resource protected with authentication: [source,java] ---- @@ -184,49 +234,81 @@ public class AdminResource { } ---- -Be aware that we have not defined annotations such as `@RolesAllowed` to explicitly enforce access to a resource. -Instead, the extension is responsible for mapping the URIs of the protected resources in Keycloak and evaluating the permissions accordingly, granting or denying access depending on the permissions granted by Keycloak. +.Role-based access control with Keycloak + +Notice that explicit annotations such as `@RolesAllowed` are not defined to enforce access control for the resources. Instead, the `keycloak-authorization` extension dynamically maps the URIs of protected resources in Keycloak. + +Access control is managed as follows: -=== Configuring the application +- Keycloak evaluates permissions for each request based on its configured policies. +- The extension enforces these permissions, granting or denying access based on the roles or policies defined in Keycloak. -The OpenID Connect extension allows you to define the adapter configuration by using the `application.properties` file, which is usually located in the `src/main/resources` directory. +This decouples access control logic from the application code, making it easier to manage and update access policies directly in Keycloak. + +== Configuring the application + +You can use the OpenID Connect extension to configure the adapter settings through the `application.properties` file, typically located in the `src/main/resources` directory. Below is an example configuration: [source,properties] ---- # OIDC Configuration -%prod.quarkus.oidc.auth-server-url=https://localhost:8543/realms/quarkus -quarkus.oidc.client-id=backend-service -quarkus.oidc.credentials.secret=secret -quarkus.oidc.tls.verification=none +%prod.quarkus.oidc.auth-server-url=https://localhost:8543/realms/quarkus <1> +quarkus.oidc.client-id=backend-service <2> +quarkus.oidc.credentials.secret=secret <3> +quarkus.oidc.tls.verification=none <4> # Enable Policy Enforcement -quarkus.keycloak.policy-enforcer.enable=true +quarkus.keycloak.policy-enforcer.enable=true <5> -# Tell Dev Services for Keycloak to import the realm file -# This property is not effective when running the application in JVM or native modes -quarkus.keycloak.devservices.realm-path=quarkus-realm.json +# Import the realm file with Dev Services for Keycloak +# Note: This property is effective only in dev mode, not in JVM or native modes +quarkus.keycloak.devservices.realm-path=quarkus-realm.json <6> ---- +<1> Specifies the URL of the Keycloak server and the realm used for authentication. +<2> Identifies the client application within the Keycloak realm. +<3> Defines the client secret for authentication with the Keycloak server. +<4> Disables TLS verification for development purposes. Not recommended for production. +<5> Enables the Keycloak policy enforcer to manage access control based on defined permissions. +<6> Configures Dev Services to import a specified realm file, effective only in dev mode and not in JVM or native modes. -NOTE: Adding a `%prod.` profile prefix to `quarkus.oidc.auth-server-url` ensures that Dev Services for Keycloak launches a container for you when the application is run in dev mode. -For more information, see the <> section. +[NOTE] +==== +Adding the `%prod.` profile prefix to `quarkus.oidc.auth-server-url` ensures that Dev Services for Keycloak automatically launches a container in development mode. For more details, see the <> section. +==== -NOTE: By default, applications that use the `quarkus-oidc` extension are marked as a `service` type application (see `quarkus.oidc.application-type`). -This extension also supports only `web-app` type applications but only if the access token returned as part of the authorization code grant response is marked as a source of roles: `quarkus.oidc.roles.source=accesstoken` (`web-app` type applications check ID token roles by default). +[NOTE] +==== +By default, applications using the `quarkus-oidc` extension are treated as `service` type applications. However, the extension also supports `web-app` type applications under the following conditions: + +- The access token returned during the authorization code grant flow must be the source of roles (`quarkus.oidc.roles.source=accesstoken`). +- Note: For `web-app` type applications, ID token roles are checked by default. +==== == Starting and configuring the Keycloak server -NOTE: Do not start the Keycloak server when you run the application in dev mode. +[NOTE] +==== +Do not start the Keycloak server when you run the application in dev mode. Dev Services for Keycloak launches a container. For more information, see the <> section. +==== To start a Keycloak server, use the following Docker command: [source,bash,subs=attributes+] ---- -docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8543:8443 -v "$(pwd)"/config/keycloak-keystore.jks:/etc/keycloak-keystore.jks quay.io/keycloak/keycloak:{keycloak.version} start --hostname-strict=false --https-key-store-file=/etc/keycloak-keystore.jks +docker run --name keycloak \ + -e KEYCLOAK_ADMIN=admin \ + -e KEYCLOAK_ADMIN_PASSWORD=admin \ + -p 8543:8443 \ + -v "$(pwd)"/config/keycloak-keystore.jks:/etc/keycloak-keystore.jks \ + quay.io/keycloak/keycloak:{keycloak.version} \ <1> + start --hostname-strict=false --https-key-store-file=/etc/keycloak-keystore.jks <2> ---- -where `keycloak.version` must be `25.0.6` or later and the `keycloak-keystore.jks` can be found in https://github.com/quarkusio/quarkus-quickstarts/blob/main/security-keycloak-authorization-quickstart/config/keycloak-keystore.jks[quarkus-quickstarts/security-keycloak-authorization-quickstart/config]. +<1> For `keycloak.version`, ensure the version is `25.0.6` or later. +<2> For Keycloak keystore, use the `keycloak-keystore.jks` file located at https://github.com/quarkusio/quarkus-quickstarts/blob/main/security-keycloak-authorization-quickstart/config/keycloak-keystore.jks[quarkus-quickstarts/security-keycloak-authorization-quickstart/config]. + Try to access your Keycloak server at https://localhost:8543[localhost:8543]. @@ -236,52 +318,83 @@ The username and password are both `admin`. Import the link:{quickstarts-tree-url}/security-keycloak-authorization-quickstart/config/quarkus-realm.json[realm configuration file] to create a new realm. For more details, see the Keycloak documentation about how to https://www.keycloak.org/docs/latest/server_admin/index.html#_create-realm[create a new realm]. -After importing the realm you can see the resource permissions: +After importing the realm, you can see the resource permissions: image::keycloak-authorization-permissions.png[alt=Keycloak Authorization Permissions,role="center"] It explains why the endpoint has no `@RolesAllowed` annotations - the resource access permissions are set directly in Keycloak. +.Accessing the Keycloak server + +. Open your browser and navigate to https://localhost:8543[https://localhost:8543]. +. Log in to the Keycloak Administration Console by using the following credentials: + - **Username**: `admin` + - **Password**: `admin` + +.Importing the realm configuration + +To create a new realm, import the link:{quickstarts-tree-url}/security-keycloak-authorization-quickstart/config/quarkus-realm.json[realm configuration file]. For detailed steps on creating realms, refer to the Keycloak documentation: https://www.keycloak.org/docs/latest/server_admin/index.html#_create-realm[Create a new realm]. + +After importing the realm, you can review the resource permissions: + +image::keycloak-authorization-permissions.png[alt=Keycloak Authorization Permissions,role="center"] + +.Role of Keycloak in resource permissions + +The resource access permissions are configured directly in Keycloak, which eliminates the need for `@RolesAllowed` annotations in your application code. This approach centralizes access control management within Keycloak, simplifying application maintenance and security updates. + [[keycloak-dev-mode]] == Running the application in dev mode -To run the application in dev mode, use: +To run the application in development mode, use the following command: include::{includes}/devtools/dev.adoc[] -xref:security-openid-connect-dev-services.adoc[Dev Services for Keycloak] launches a Keycloak container and imports a `quarkus-realm.json`. +xref:security-openid-connect-dev-services.adoc[Dev Services for Keycloak] starts a Keycloak container and imports the `quarkus-realm.json` configuration file. Open a xref:dev-ui.adoc[Dev UI] available at http://localhost:8080/q/dev-ui[/q/dev-ui] and click a `Provider: Keycloak` link in an `OpenID Connect` `Dev UI` card. -When asked to log in to a `Single Page Application` provided by `OpenID Connect Dev UI`: +.Interacting with Dev UI + +. Open the xref:dev-ui.adoc[Dev UI] at http://localhost:8080/q/dev-ui[/q/dev-ui]. +. Click the `Provider: Keycloak` link within the `OpenID Connect` Dev UI card. + +.Testing user permissions + +When prompted to log in to a `Single Page Application` provided by `OpenID Connect Dev UI`, do the following: + +. Log in as `alice` (password: `alice`), who only has a `User Permission` to access the `/api/users/me` resource: +.. Access `/api/admin`, which returns `403`. +.. Access `/api/users/me`, which returns `200`. +. Log out and log in as `admin` (password: `admin`), who has both `Admin Permission` to access the `/api/admin` resource and `User Permission` to access the `/api/users/me` resource: +.. Access `/api/admin`, which returns `200`. +.. Access `/api/users/me`, which returns `200`. + +.Customizing the Keycloak realm - * Log in as `alice` (password: `alice`), who only has a `User Permission` to access the `/api/users/me` resource: - ** Access `/api/admin`, which returns `403`. - ** Access `/api/users/me`, which returns `200`. - * Log out and log in as `admin` (password: `admin`), who has both `Admin Permission` to access the `/api/admin` resource and `User Permission` to access the `/api/users/me` resource: - ** Access `/api/admin`, which returns `200`. - ** Access `/api/users/me`, which returns `200`. +If you started Dev Services for Keycloak without importing a realm file such as link:{quickstarts-tree-url}/security-keycloak-authorization-quickstart/config/quarkus-realm.json[quarkus-realm.json], create a default `quarkus` realm without Keycloak authorization policies: -If you have started xref:security-openid-connect-dev-services.adoc[Dev Services for Keycloak] without importing a realm file such as link:{quickstarts-tree-url}/security-keycloak-authorization-quickstart/config/quarkus-realm.json[quarkus-realm.json] that is already configured to support Keycloak Authorization, create a default `quarkus` realm without Keycloak authorization policies. -In this case, you must select the `Keycloak Admin` link in the `OpenId Connect` Dev UI card and configure link:https://www.keycloak.org/docs/latest/authorization_services/index.html[Keycloak Authorization Services] in the default `quarkus` realm. +. Select the `Keycloak Admin` link from the `OpenID Connect` Dev UI card. +. Log in to the Keycloak admin console. The username and password are both `admin`. +. Follow the instructions at link:https://www.keycloak.org/docs/latest/authorization_services/index.html[Keycloak Authorization Services documentation] to enable authorization policies in the `quarkus` realm. The `Keycloak Admin` link is easy to find in Dev UI: image::dev-ui-oidc-keycloak-card.png[alt=Dev UI OpenID Connect Card,role="center"] -When logging into the Keycloak admin console, the username and password are both `admin`. +.Adding custom JavaScript policies -If your application uses Keycloak authorization configured with link:https://www.keycloak.org/docs/latest/authorization_services/index.html#_policy_js[JavaScript policies] that are deployed in a JAR file, you can set up Dev Services for Keycloak to transfer this archive to the Keycloak container. -For instance: +If your application uses Keycloak authorization configured with link:https://www.keycloak.org/docs/latest/authorization_services/index.html#_policy_js[JavaScript policies] that are deployed in a JAR archive, Dev Services for Keycloak can transfer this archive to the Keycloak container. Use the following properties in `application.properties` to configure the transfer: [source,properties] ---- +# Alias the policies archive quarkus.keycloak.devservices.resource-aliases.policies=/policies.jar <1> +# Map the policies archive to a specific location in the container quarkus.keycloak.devservices.resource-mappings.policies=/opt/keycloak/providers/policies.jar <2> ---- -<1> `policies` alias is created for the `/policies.jar` classpath resource. -Policy archive can also be located in the file system. -<2> The policies archive is mapped to the `/opt/keycloak/providers/policies.jar` container location. +<1> Creates a `policies` alias for the `/policies.jar` classpath resource. The policies archive can also be located on the file system. +<2> Maps the policies archive to the `/opt/keycloak/providers/policies.jar` location inside the Keycloak container. == Running the application in JVM mode From c3feb68b0925412e162116c30cd32e0005f2aa6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 22:37:34 +0000 Subject: [PATCH 101/207] Bump com.google.http-client:google-http-client-bom from 1.45.2 to 1.45.3 Bumps [com.google.http-client:google-http-client-bom](https://github.com/googleapis/google-http-java-client) from 1.45.2 to 1.45.3. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v1.45.2...v1.45.3) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 7e73fb185de40..69e922cf03ccb 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -182,7 +182,7 @@ 3.48.3 2.36.0 0.27.2 - 1.45.2 + 1.45.3 2.1 4.7.6 1.1.4 From bedb8c5769951624e92a9a4f2f48c37413c34083 Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Wed, 11 Dec 2024 09:46:47 +1100 Subject: [PATCH 102/207] Add a Dev UI Screen for Agroal (DB) Signed-off-by: Phillip Kruger --- bom/application/pom.xml | 5 + extensions/agroal/deployment/pom.xml | 13 + .../devui/AgroalDevUIProcessor.java | 41 + .../resources/dev-ui/qwc-agroal-datasource.js | 700 ++++++++++++++++++ .../agroal/test/AgroalDevUITestCase.java | 64 ++ extensions/agroal/pom.xml | 1 + extensions/agroal/runtime-dev/pom.xml | 22 + .../runtime/dev/ui/DatabaseInspector.java | 376 ++++++++++ extensions/agroal/runtime/pom.xml | 13 + .../DataSourcesJdbcBuildTimeConfig.java | 36 + integration-tests/logging-panache/pom.xml | 5 + 11 files changed, 1276 insertions(+) create mode 100644 extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/devui/AgroalDevUIProcessor.java create mode 100644 extensions/agroal/deployment/src/main/resources/dev-ui/qwc-agroal-datasource.js create mode 100644 extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/AgroalDevUITestCase.java create mode 100644 extensions/agroal/runtime-dev/pom.xml create mode 100644 extensions/agroal/runtime-dev/src/main/java/io/quarkus/agroal/runtime/dev/ui/DatabaseInspector.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 7e73fb185de40..87922f8dc5953 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -724,6 +724,11 @@ quarkus-agroal ${project.version} + + io.quarkus + quarkus-agroal-dev + ${project.version} + io.quarkus quarkus-agroal-deployment diff --git a/extensions/agroal/deployment/pom.xml b/extensions/agroal/deployment/pom.xml index d98df477aa1a2..d645fa4e3b32e 100644 --- a/extensions/agroal/deployment/pom.xml +++ b/extensions/agroal/deployment/pom.xml @@ -29,6 +29,14 @@ io.quarkus quarkus-agroal + + + io.quarkus + quarkus-agroal-dev + io.quarkus quarkus-agroal-spi @@ -87,6 +95,11 @@ quarkus-smallrye-health-deployment test + + io.quarkus + quarkus-vertx-http-dev-ui-tests + test + diff --git a/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/devui/AgroalDevUIProcessor.java b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/devui/AgroalDevUIProcessor.java new file mode 100644 index 0000000000000..aeb86eca3df92 --- /dev/null +++ b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/devui/AgroalDevUIProcessor.java @@ -0,0 +1,41 @@ +package io.quarkus.agroal.deployment.devui; + +import io.quarkus.agroal.runtime.DataSourcesJdbcBuildTimeConfig; +import io.quarkus.agroal.runtime.dev.ui.DatabaseInspector; +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.BuildSteps; +import io.quarkus.deployment.builditem.LaunchModeBuildItem; +import io.quarkus.dev.spi.DevModeType; +import io.quarkus.devui.spi.JsonRPCProvidersBuildItem; +import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.devui.spi.page.Page; + +@BuildSteps(onlyIf = IsDevelopment.class) +class AgroalDevUIProcessor { + + @BuildStep + void devUI(DataSourcesJdbcBuildTimeConfig config, + BuildProducer cardPageProducer, + BuildProducer jsonRPCProviderProducer, + LaunchModeBuildItem launchMode) { + + if (launchMode.getDevModeType().isPresent() && launchMode.getDevModeType().get().equals(DevModeType.LOCAL)) { + if (config.devui().enabled()) { + CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); + + cardPageBuildItem.addPage(Page.webComponentPageBuilder() + .icon("font-awesome-solid:database") + .title("Database view") + .componentLink("qwc-agroal-datasource.js") + .metadata("allowSql", String.valueOf(config.devui().allowSql())) + .metadata("appendSql", config.devui().appendToDefaultSelect().orElse("")) + .metadata("allowedHost", config.devui().allowedDBHost().orElse(null))); + + cardPageProducer.produce(cardPageBuildItem); + jsonRPCProviderProducer.produce(new JsonRPCProvidersBuildItem(DatabaseInspector.class)); + } + } + } +} diff --git a/extensions/agroal/deployment/src/main/resources/dev-ui/qwc-agroal-datasource.js b/extensions/agroal/deployment/src/main/resources/dev-ui/qwc-agroal-datasource.js new file mode 100644 index 0000000000000..bd5e3346859e4 --- /dev/null +++ b/extensions/agroal/deployment/src/main/resources/dev-ui/qwc-agroal-datasource.js @@ -0,0 +1,700 @@ +import { QwcHotReloadElement, html, css} from 'qwc-hot-reload-element'; +import { RouterController } from 'router-controller'; +import { JsonRpc } from 'jsonrpc'; +import '@vaadin/combo-box'; +import '@vaadin/item'; +import '@vaadin/icon'; +import '@vaadin/list-box'; +import '@qomponent/qui-card'; +import '@vaadin/grid'; +import '@vaadin/tabs'; +import '@vaadin/tabsheet'; +import { columnBodyRenderer, columnHeaderRenderer } from '@vaadin/grid/lit.js'; +import '@qomponent/qui-code-block'; +import { notifier } from 'notifier'; +import '@vaadin/progress-bar'; +import '@vaadin/button'; +import '@qomponent/qui-alert'; +import '@vaadin/dialog'; +import { dialogFooterRenderer, dialogHeaderRenderer, dialogRenderer } from '@vaadin/dialog/lit.js'; + +/** + * Allows interaction with your Datasource + */ +export class QwcAgroalDatasource extends QwcHotReloadElement { + jsonRpc = new JsonRpc(this); + configJsonRpc = new JsonRpc("devui-configuration"); + + routerController = new RouterController(this); + + static styles = css` + .dataSources{ + display: flex; + flex-direction: column; + gap: 20px; + height: 100%; + padding-left: 10px; + } + .dataSourcesHeader { + display: flex; + align-items: baseline; + gap: 20px; + border-bottom-style: dotted; + border-bottom-color: var(--lumo-contrast-10pct); + padding-bottom: 10px; + justify-content: space-between; + padding-right: 20px; + } + .dataSourcesHeaderLeft { + display: flex; + align-items: baseline; + gap: 20px; + } + .tablesAndData { + display: flex; + height: 100%; + gap: 20px; + } + + .tableData { + width: 100%; + padding-right: 20px; + } + + .tablesCard { + min-width: 192px; + display: flex; + } + + .fill { + width: 100%; + height: 100%; + } + + .pkicon{ + height: var(--lumo-icon-size-s); + width: var(--lumo-icon-size-s); + } + + .sqlInput { + display: flex; + justify-content: space-between; + gap: 10px; + } + + #sql { + width: 100%; + } + .data { + display: flex; + flex-direction: column; + gap: 10px; + width: 100%; + height: 100%; + } + + .sqlInputButton{ + height: var(--lumo-icon-size-s); + width: var(--lumo-icon-size-s); + cursor: pointer; + color: var(--lumo-contrast-50pct); + } + + .pager { + display: flex; + justify-content: space-between; + } + + .hidden { + visibility: hidden; + } + + .download { + cursor: pointer; + text-decoration: none; + color: var(--lumo-body-text-color); + } + + .download:hover { + color: var(--lumo-primary-text-color); + text-decoration: underline; + } + + a, a:visited, a:focus, a:active { + text-decoration: none; + color: var(--lumo-body-text-color); + } + a:hover { + text-decoration: none; + color: var(--lumo-primary-text-color); + } + `; + + static properties = { + _dataSources: {state: true}, + _selectedDataSource: {state: true}, + _tables: {state: true}, + _selectedTable: {state: true}, + _selectedTableIndex:{state: true}, + _selectedTableCols:{state: false}, + _currentSQL: {state: true}, + _currentDataSet: {state: true}, + _isWatching: {state: true}, + _watchId: {state: false}, + _currentPageNumber: {state: true}, + _currentNumberOfPages: {state: true}, + _allowSql: {state: true}, + _appendSql: {state: true}, + _allowedHost: {state: true}, + _isAllowedDB: {state: true}, + _displaymessage: {state: true}, + _insertSQL: {state: true}, + _dialogOpened: {state: true} + }; + + constructor() { + super(); + this._dataSources = null; + this._selectedDataSource = null; + this._tables = null; + this._selectedTable = null; + this._selectedTableCols = null; + this._selectedTableIndex = 0; + this._currentSQL = null; + this._currentDataSet = null; + this._isWatching = false; + this._watchId = null; + this._currentPageNumber = 1; + this._currentNumberOfPages = 1; + this._pageSize = 12; + this._isAllowedDB = false; + this._appendSql = ""; + this._allowedHost = null; + this._displaymessage = null; + this._insertSQL = null; + this._dialogOpened = false; + } + + connectedCallback() { + super.connectedCallback(); + + var page = this.routerController.getCurrentPage(); + if(page && page.metadata){ + this._allowSql = (page.metadata.allowSql === "true"); + this._appendSql = page.metadata.appendSql; + this._allowedHost = page.metadata.allowedHost; + }else{ + this._allowSql = false; + this._appendSql = ""; + this._allowedHost = null; + } + + this.jsonRpc.getDataSources().then(jsonRpcResponse => { + this._dataSources = jsonRpcResponse.result.reduce((map, obj) => { + map[obj.name] = obj; + return map; + }, {}); + }); + } + + disconnectedCallback() { + if(this._isWatching)this._unwatch(); + super.disconnectedCallback(); + } + + render() { + if(this._dataSources){ + return html`

    +
    +
    + ${this._renderDatasourcesComboBox()} + ${this._renderSelectedDatasource()} +
    + ${this._renderExportButton()} +
    + ${this._renderDataOrWarning()} +
    + ${this._renderImportSqlDialog()}`; + } else { + return html`
    +
    Fetching data sources...
    + +
    `; + } + } + + _renderImportSqlDialog(){ + if(this._insertSQL){ + return html` + html` + + + + + + + + + `, + [] + )} + ${dialogRenderer(this._renderImportSqlDialogContents)} + >`; + } + } + + _saveInsertScript(){ + try { + const blob = new Blob([this.value], { type: 'text/sql' }); + const url = URL.createObjectURL(blob); + + const anchor = document.createElement('a'); + anchor.href = url; + anchor.download = 'insert.sql'; + document.body.appendChild(anchor); + anchor.click(); + + URL.revokeObjectURL(url); + anchor.remove(); + + notifier.showInfoMessage("File saved successfully"); + } catch (error) { + notifier.showErrorMessage("Failed to save file: " + error); + } + } + + _copyInsertScript(){ + navigator.clipboard.writeText(this._insertSQL).then( + () => { + notifier.showInfoMessage("Copied to clipboard successfully!"); + }, + (err) => { + notifier.showErrorMessage("Could not copy text: " + err); + } + ); + } + + _closeDialog(){ + this._insertSQL = null; + this._dialogOpened = false; + } + + _renderImportSqlDialogContents(){ + return html``; + } + + _renderDataOrWarning(){ + if(this._isAllowedDB){ + return html`
    +
    + ${this._renderTables()} +
    +
    + ${this._renderDataAndDefinition()} +
    +
    `; + }else{ + return html`This feature is not available for remote databases` + } + } + + _renderDatasourcesComboBox(){ + return html` + `; + } + + _renderSelectedDatasource(){ + if(this._selectedDataSource){ + return html`${this._selectedDataSource.jdbcUrl}`; + } + } + + _renderExportButton(){ + if(this._selectedDataSource){ + return html` + + import.sql + `; + } + } + + _renderTables(){ + if(this._tables){ + return html` +
    + + ${this._tables.map((table) => + html`${table.tableName}` + )} + +
    +
    `; + }else{ + return html`
    +
    Fetching tables...
    + +
    `; + } + + } + + _renderDataAndDefinition(){ + return html` + + + + + ${this._renderWatchButton()} + + + Data + Definition + + +
    ${this._renderTableData()}
    +
    ${this._renderTableDefinition()}
    +
    `; + } + + _renderWatchButton(){ + if(this._isWatching){ + return html` + + `; + }else{ + return html` + + `; + } + } + + _renderTableData(){ + if(this._selectedTable && this._currentDataSet && this._currentDataSet.cols){ + return html`
    + + ${this._currentDataSet.cols.map((col) => + this._renderTableHeader(col) + )} + No data. + + ${this._renderPager()} + ${this._renderSqlInput()} +
    + `; + }else if(this._displaymessage){ + return html`${this._displaymessage}`; + }else{ + return html`
    +
    Fetching data...
    + +
    `; + } + } + + _renderTableHeader(col){ + let heading = col; + if(this._selectedTable.primaryKeys.includes(col)){ + heading = col + " *"; + } + return html` this._cellRenderer(col, item), + [] + )}>`; + } + + _renderTableDefinition(){ + if(this._selectedTable){ + return html` + + + + + + `; + } + } + _renderPager() { + return html`
    + ${this._renderPreviousPageButton()} + ${this._currentPageNumber} of ${this._currentNumberOfPages} + ${this._renderNextPageButton()} +
    `; + } + + _renderPreviousPageButton(){ + let klas = "pageButton"; + if(this._currentPageNumber === 1){ + klas = "hidden"; + } + return html` + + `; + } + + _renderNextPageButton(){ + let klas = "pageButton"; + if(this._currentPageNumber === this._currentNumberOfPages){ + klas = "hidden"; + } + return html` + + `; + } + + _renderSqlInput(){ + if(this._allowSql){ + return html`
    + + + +
    `; + }else { + return html`Allow any SQL execution from here`; + } + } + + _handleAllowSqlChange(){ + this.configJsonRpc.updateProperty({ + 'name': '%dev.quarkus.datasource.dev-ui.allow-sql', + 'value': 'true' + }).then(e => { + this._allowSql = true; + });; + } + + _columnNameRenderer(col){ + if(this._selectedTable.primaryKeys.includes(col.columnName)){ + return html`${col.columnName} `; + }else{ + return html`${col.columnName}`; + } + } + + _cellRenderer(columnName, item){ + const value = item[columnName]; + if(value){ + let colDef = this._selectedTableCols.get(columnName); + let colType = colDef.columnType.toLowerCase(); + + if(colDef.binary){ + const byteCharacters = atob(value); + const byteNumbers = new Array(byteCharacters.length); + for (let i = 0; i < byteCharacters.length; i++) { + byteNumbers[i] = byteCharacters.charCodeAt(i); + } + const byteArray = new Uint8Array(byteNumbers); + + const blob = new Blob([byteArray], { type: 'application/octet-stream' }); + const url = URL.createObjectURL(blob); + + return html`download`; + }else if(colType === "bool" || colType === "boolean"){ // TODO: Can we do int(1) and asume this will be a boolean ? + if(value && value === "true"){ + return html``; + }else { + return html``; + } + } else { + if(value.startsWith("http://") || value.startsWith("https://")){ + return html`${value}`; + }else{ + return html`${value}`; + } + } + } + } + + _watch(){ + this._isWatching = true; + this._watchId = setInterval(() => { + this.hotReload(); + }, 3000); + } + + _unwatch(){ + this._isWatching = false; + clearInterval(this._watchId); + this._watchId = null; + } + + _onDataSourceChanged(event) { + const selectedValue = event.detail.value; + if(selectedValue in this._dataSources){ + this._selectedDataSource = this._dataSources[selectedValue]; + this._isAllowedDB = this._isAllowedHostDatabase(); + if(this._isAllowedDB){ + this._fetchTableDefinitions(); + } + } + } + + _onTableChanged(event){ + this._selectedTableIndex = event.detail.value; + this._selectedTable = this._tables[this._selectedTableIndex]; + this._clearSqlInput(); + } + + _previousPage(){ + if(this._currentPageNumber!=1){ + this._currentPageNumber = this._currentPageNumber - 1; + this._executeCurrentSQL(); + } + } + + _nextPage(){ + this._currentPageNumber = this._currentPageNumber + 1; + this._executeCurrentSQL(); + } + + _getNumberOfPages(){ + if(this._currentDataSet){ + if(this._currentDataSet.totalNumberOfElements > this._pageSize){ + return Math.ceil(this._currentDataSet.totalNumberOfElements/this._pageSize); + }else { + return 1; + } + } + } + + _executeCurrentSQL(){ + if(this._currentSQL){ + this.jsonRpc.executeSQL({ + datasource:this._selectedDataSource.name, + sql:this._currentSQL, + pageNumber: this._currentPageNumber, + pageSize: this._pageSize + }).then(jsonRpcResponse => { + if(jsonRpcResponse.result.error){ + notifier.showErrorMessage(jsonRpcResponse.result.error); + } else if (jsonRpcResponse.result.message){ + notifier.showInfoMessage(jsonRpcResponse.result.message); + this._clearSqlInput(); + } else { + this._currentDataSet = jsonRpcResponse.result; + this._currentNumberOfPages = this._getNumberOfPages(); + } + }); + } + } + + _fetchTableDefinitions() { + if(this._selectedDataSource){ + this._insertSQL = null; + this.jsonRpc.getTables({datasource:this._selectedDataSource.name}).then(jsonRpcResponse => { + this._tables = jsonRpcResponse.result; + this._selectedTable = this._tables[this._selectedTableIndex]; + if(this._selectedTable){ + this._displaymessage = null; + this._selectedTableCols = this._selectedTable.columns.reduce((acc, obj) => { + acc.set(obj.columnName, obj); + return acc; + }, new Map()); + this._executeCurrentSQL(); + }else { + this._displaymessage = "No tables found"; + } + }); + } + } + + _createImportSql(){ + if(this._selectedDataSource){ + this.jsonRpc.getInsertScript({datasource:this._selectedDataSource.name}).then(jsonRpcResponse => { + this._insertSQL = jsonRpcResponse.result; + this._dialogOpened = true; + }); + } + } + + _executeClicked(){ + let newValue = this.shadowRoot.getElementById('sql').getAttribute('value'); + this._executeSQL(newValue); + } + + _clearSqlInput(){ + if(this._selectedTable){ + if(this._appendSql){ + this._executeSQL("select * from " + this._selectedTable.tableName + " " + this._appendSql); + }else{ + this._executeSQL("select * from " + this._selectedTable.tableName); + } + } + } + + _shiftEnterPressed(event){ + this._executeSQL(event.detail.content); + } + + _executeSQL(sql){ + this._currentSQL = sql.trim(); + this._executeCurrentSQL(); + } + + _startsWithIgnoreCaseAndSpaces(str, searchString) { + return str.trim().toLowerCase().startsWith(searchString.toLowerCase()); + } + + hotReload(){ + this._fetchTableDefinitions(); + } + + _isAllowedHostDatabase() { + + let jdbcUrl = this._selectedDataSource.jdbcUrl; + try { + if (jdbcUrl.startsWith("jdbc:h2:mem:") || jdbcUrl.startsWith("jdbc:h2:file:")) { + return true; + } + + if (jdbcUrl.startsWith("jdbc:derby:memory:")) { + return true; + } + + if (jdbcUrl.startsWith("jdbc:derby:")) { + const derbyUri = jdbcUrl.replace("jdbc:", ""); + if (derbyUri.startsWith("localhost") || derbyUri.startsWith("127.0.0.1")) { + return true; + } + if(this._allowedHost && this._allowedHost!="" && derbyUri.startsWith(this._allowedHost)){ + return true; + } + } + + const urlPattern = /^jdbc:[^:]+:\/\/([^:/]+)(:\d+)?/; + const match = jdbcUrl.match(urlPattern); + + if (match) { + const host = match[1]; + if(host === "localhost" || host === "127.0.0.1" || host === "::1"){ + return true; + } + if(this._allowedHost && this._allowedHost!="" && host === this._allowedHost){ + return true; + } + } + + return false; + } catch (e) { + console.error(e); + return false; + } + } +} +customElements.define('qwc-agroal-datasource', QwcAgroalDatasource); diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/AgroalDevUITestCase.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/AgroalDevUITestCase.java new file mode 100644 index 0000000000000..b4c0611cf5249 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/AgroalDevUITestCase.java @@ -0,0 +1,64 @@ +package io.quarkus.agroal.test; + +import java.util.Map; +import java.util.function.Supplier; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.fasterxml.jackson.databind.JsonNode; + +import io.quarkus.devui.tests.DevUIJsonRPCTest; +import io.quarkus.test.QuarkusDevModeTest; + +public class AgroalDevUITestCase extends DevUIJsonRPCTest { + + @RegisterExtension + public static final QuarkusDevModeTest test = new QuarkusDevModeTest() + .setArchiveProducer(new Supplier<>() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class) + .addClass(DevModeResource.class) + .add(new StringAsset("quarkus.datasource.db-kind=h2\n" + + "quarkus.datasource.username=USERNAME-NAMED\n" + + "quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:testing\n" + + "quarkus.datasource.jdbc.driver=org.h2.Driver\n"), "application.properties"); + } + }); + + public AgroalDevUITestCase() { + super("io.quarkus.quarkus-agroal"); + } + + @Test + public void testGetDataSources() throws Exception { + JsonNode datasources = super.executeJsonRPCMethod("getDataSources"); + + Assertions.assertNotNull(datasources); + Assertions.assertTrue(datasources.isArray()); + Assertions.assertEquals(1, datasources.size()); + + JsonNode datasource = datasources.get(0); + Assertions.assertNotNull(datasource); + + JsonNode nameNode = datasource.get("name"); + Assertions.assertNotNull(nameNode); + String name = nameNode.asText(); + Assertions.assertNotNull(name); + Assertions.assertEquals(DEFAULT_DATASOURCE, name); + } + + @Test + public void testGetTables() throws Exception { + JsonNode tables = super.executeJsonRPCMethod("getTables", Map.of("datasource", DEFAULT_DATASOURCE)); + Assertions.assertNotNull(tables); + Assertions.assertTrue(tables.isArray()); + } + + private static final String DEFAULT_DATASOURCE = ""; +} diff --git a/extensions/agroal/pom.xml b/extensions/agroal/pom.xml index 2ebcce6c78b23..4ae2ad530ee32 100644 --- a/extensions/agroal/pom.xml +++ b/extensions/agroal/pom.xml @@ -17,5 +17,6 @@ spi deployment runtime + runtime-dev diff --git a/extensions/agroal/runtime-dev/pom.xml b/extensions/agroal/runtime-dev/pom.xml new file mode 100644 index 0000000000000..a5f8c9be98dc6 --- /dev/null +++ b/extensions/agroal/runtime-dev/pom.xml @@ -0,0 +1,22 @@ + + + + quarkus-agroal-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-agroal-dev + Quarkus - Agroal - Runtime Dev mode + JDBC Datasources and connection pooling - Dev mode only + + + + ${project.groupId} + quarkus-agroal + + + \ No newline at end of file diff --git a/extensions/agroal/runtime-dev/src/main/java/io/quarkus/agroal/runtime/dev/ui/DatabaseInspector.java b/extensions/agroal/runtime-dev/src/main/java/io/quarkus/agroal/runtime/dev/ui/DatabaseInspector.java new file mode 100644 index 0000000000000..2b58c7fff364d --- /dev/null +++ b/extensions/agroal/runtime-dev/src/main/java/io/quarkus/agroal/runtime/dev/ui/DatabaseInspector.java @@ -0,0 +1,376 @@ +package io.quarkus.agroal.runtime.dev.ui; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.Date; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; + +import io.agroal.api.AgroalDataSource; +import io.agroal.api.configuration.AgroalDataSourceConfiguration; +import io.quarkus.agroal.runtime.AgroalDataSourceSupport; +import io.quarkus.agroal.runtime.DataSources; +import io.quarkus.arc.Arc; +import io.quarkus.datasource.common.runtime.DataSourceUtil; +import io.quarkus.logging.Log; +import io.quarkus.runtime.LaunchMode; + +public final class DatabaseInspector { + + @Inject + Instance dataSources; + + private final Map checkedDataSources = new HashMap<>(); + + private boolean isDev = false; + private boolean allowSql = false; + private String allowedHost = null; + + public DatabaseInspector() { + LaunchMode currentMode = LaunchMode.current(); + this.isDev = currentMode == LaunchMode.DEVELOPMENT && !LaunchMode.isRemoteDev(); + + Config config = ConfigProvider.getConfig(); + this.allowSql = config.getOptionalValue("quarkus.datasource.dev-ui.allow-sql", Boolean.class) + .orElse(false); + + this.allowedHost = config.getOptionalValue("quarkus.datasource.dev-ui.allowed-db-host", String.class) + .orElse(null); + + } + + @PostConstruct + protected void init() { + if (!dataSources.isResolvable()) { + // No configured Agroal datasource at build time. + return; + } + + if (isDev) { + AgroalDataSourceSupport agroalSupport = Arc.container().instance(AgroalDataSourceSupport.class) + .get(); + for (String name : agroalSupport.entries.keySet()) { + DataSource ds = dataSources.get().getDataSource(name); + if (ds != null) { + checkedDataSources.put(name, ds); + } + } + } + } + + public List getDataSources() { + if (isDev) { + List datasources = new ArrayList<>(); + + for (String ds : checkedDataSources.keySet()) { + datasources.add(getDatasource(ds)); + } + + return datasources; + } + return List.of(); + } + + private Datasource getDatasource(String datasource) { + if (isDev) { + AgroalDataSource ads = (AgroalDataSource) checkedDataSources.get(datasource); + if (isAllowedDatabase(ads)) { + AgroalDataSourceConfiguration configuration = ads.getConfiguration(); + + String jdbcUrl = configuration.connectionPoolConfiguration().connectionFactoryConfiguration().jdbcUrl(); + boolean isDefault = DataSourceUtil.isDefault(datasource); + + return new Datasource(datasource, jdbcUrl, isDefault); + } + } + return null; + } + + public List getTables(String datasource) { + if (isDev) { + List
    tableList = new ArrayList<>(); + try { + AgroalDataSource ads = (AgroalDataSource) checkedDataSources.get(datasource); + if (isAllowedDatabase(ads)) { + try (Connection connection = ads.getConnection()) { + DatabaseMetaData metaData = connection.getMetaData(); + + // Get all tables + try (ResultSet tables = metaData.getTables(null, null, "%", new String[] { "TABLE" })) { + while (tables.next()) { + String tableName = tables.getString("TABLE_NAME"); + String tableSchema = tables.getString("TABLE_SCHEM"); + + // Get the Primary Keys + List primaryKeyList = getPrimaryKeys(metaData, tableSchema, tableName); + + // Get columns for each table + List columnList = new ArrayList<>(); + try (ResultSet columns = metaData.getColumns(null, tableSchema, tableName, "%")) { + while (columns.next()) { + String columnName = columns.getString("COLUMN_NAME"); + String columnType = columns.getString("TYPE_NAME"); + int columnSize = columns.getInt("COLUMN_SIZE"); + String nullable = columns.getString("IS_NULLABLE"); + int dataType = columns.getInt("DATA_TYPE"); + columnList + .add(new Column(columnName, columnType, columnSize, nullable, + isBinary(dataType))); + + } + } + tableList.add(new Table(tableSchema, tableName, primaryKeyList, columnList)); + } + } + } + } + } catch (SQLException ex) { + throw new RuntimeException(ex); + } + + return tableList; + } + return null; + } + + public DataSet executeSQL(String datasource, String sql, Integer pageNumber, Integer pageSize) { + if (isDev && sqlIsValid(sql)) { + try { + AgroalDataSource ads = (AgroalDataSource) checkedDataSources.get(datasource); + if (isAllowedDatabase(ads)) { + try (Connection connection = ads.getConnection()) { + // Create a scrollable ResultSet + try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY)) { + boolean hasResultSet = statement.execute(sql); + if (hasResultSet) { + try (ResultSet resultSet = statement.executeQuery(sql)) { + + // Get the total number of rows + resultSet.last(); + int totalNumberOfElements = resultSet.getRow(); + + // Get the column metadata + List cols = new ArrayList<>(); + ResultSetMetaData metaData = resultSet.getMetaData(); + int columnCount = metaData.getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + String columnName = metaData.getColumnName(i); + cols.add(columnName); + } + + int startRow = (pageNumber - 1) * pageSize + 1; + + List> rows = new ArrayList<>(); + + if (resultSet.absolute(startRow)) { + int rowCount = 0; + + do { + Map row = new HashMap<>(); + for (int i = 1; i <= columnCount; i++) { + String columnName = metaData.getColumnName(i); + boolean isBinary = isBinary(metaData.getColumnType(i)); + if (!isBinary) { + Object columnValue = resultSet.getObject(i); + row.put(columnName, String.valueOf(columnValue)); + } else { + byte[] binary = resultSet.getBytes(i); + if (!resultSet.wasNull()) { + row.put(columnName, Base64.getEncoder().encodeToString(binary)); + } else { + row.put(columnName, null); + } + } + } + rows.add(row); + rowCount++; + } while (resultSet.next() && rowCount < pageSize); + } + return new DataSet(cols, rows, null, null, totalNumberOfElements); + } + } else { + // Query did not return a ResultSet (e.g., DELETE, UPDATE) + int updateCount = statement.getUpdateCount(); + String message = "Query executed successfully. Rows affected: " + updateCount; + return new DataSet(null, null, null, message, -1); + } + } catch (Exception e) { + return new DataSet(null, null, e.getMessage(), null, -1); + } + } + } else { + return new DataSet(null, null, "Only supported for Local Databases", null, -1); + } + } catch (SQLException ex) { + return new DataSet(null, null, ex.getMessage(), null, -1); + } + } else { + return new DataSet(null, null, "Unknown Error", null, -1); + } + } + + public String getInsertScript(String datasource) { + if (isDev) { + try { + AgroalDataSource ads = (AgroalDataSource) checkedDataSources.get(datasource); + if (isAllowedDatabase(ads)) { + try (Connection connection = ads.getConnection(); + StringWriter writer = new StringWriter()) { + DatabaseMetaData metaData = connection.getMetaData(); + try (ResultSet tables = metaData.getTables(null, null, "%", new String[] { "TABLE" })) { + while (tables.next()) { + String tableName = tables.getString("TABLE_NAME"); + exportTable(connection, writer, tableName); + } + } + + return writer.toString(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + } catch (SQLException ex) { + throw new RuntimeException(ex); + } + } + return null; + } + + private void exportTable(Connection conn, StringWriter writer, String tableName) throws SQLException, IOException { + try (Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName)) { + + ResultSetMetaData metaData = rs.getMetaData(); + int columnCount = metaData.getColumnCount(); + + while (rs.next()) { + StringBuilder insertQuery = new StringBuilder("INSERT INTO " + tableName + " ("); + + for (int i = 1; i <= columnCount; i++) { + insertQuery.append(metaData.getColumnName(i)); + if (i < columnCount) + insertQuery.append(", "); + } + + insertQuery.append(") VALUES ("); + + for (int i = 1; i <= columnCount; i++) { + Object value = rs.getObject(i); + if (value == null) { + insertQuery.append("NULL"); + } else if (value instanceof String || value instanceof Date || value instanceof Timestamp) { + insertQuery.append("'").append(value.toString().replace("'", "''")).append("'"); + } else { + insertQuery.append(value.toString()); + } + if (i < columnCount) + insertQuery.append(", "); + } + + insertQuery.append(");\n"); + writer.write(insertQuery.toString()); + } + } + } + + private boolean sqlIsValid(String sql) { + if (sql == null || sql.isEmpty()) + return false; + if (allowSql) { + return true; + } else { + String lsql = sql.toLowerCase().trim(); + return lsql.startsWith("select") + && !lsql.contains("update ") + && !lsql.contains("delete ") + && !lsql.contains("insert ") + && !lsql.contains("create ") + && !lsql.contains("drop "); // Having a sql with those nested is invalid anyway + } + } + + private List getPrimaryKeys(DatabaseMetaData metaData, String tableSchema, String tableName) throws SQLException { + List primaryKeyList = new ArrayList<>(); + try (ResultSet primaryKeys = metaData.getPrimaryKeys(null, tableSchema, tableName)) { + while (primaryKeys.next()) { + String primaryKeyColumn = primaryKeys.getString("COLUMN_NAME"); + primaryKeyList.add(primaryKeyColumn); + } + } + return primaryKeyList; + } + + private boolean isAllowedDatabase(AgroalDataSource ads) { + AgroalDataSourceConfiguration configuration = ads.getConfiguration(); + String jdbcUrl = configuration.connectionPoolConfiguration().connectionFactoryConfiguration().jdbcUrl(); + + try { + if (jdbcUrl.startsWith("jdbc:h2:mem:") || jdbcUrl.startsWith("jdbc:h2:file:") + || jdbcUrl.startsWith("jdbc:h2:tcp://localhost") + || (this.allowedHost != null && !this.allowedHost.isBlank() + && jdbcUrl.startsWith("jdbc:h2:tcp://" + this.allowedHost)) + || jdbcUrl.startsWith("jdbc:derby:memory:")) { + return true; + } + + String cleanUrl = jdbcUrl.replace("jdbc:", ""); + URI uri = new URI(cleanUrl); + + String host = uri.getHost(); + + return host != null && ((host.equals("localhost") || host.equals("127.0.0.1") || host.equals("::1")) || + (this.allowedHost != null && !this.allowedHost.isBlank() && host.equalsIgnoreCase(this.allowedHost))); + + } catch (URISyntaxException e) { + Log.warn(e.getMessage()); + } + + return false; + } + + private boolean isBinary(int dataType) { + return dataType == Types.BLOB || + dataType == Types.VARBINARY || + dataType == Types.LONGVARBINARY || + dataType == Types.BINARY || + dataType == Types.JAVA_OBJECT || + dataType == Types.OTHER; + } + + private static record Column(String columnName, String columnType, int columnSize, String nullable, boolean binary) { + } + + private static record Table(String tableSchema, String tableName, List primaryKeys, List columns) { + } + + private static record Datasource(String name, String jdbcUrl, boolean isDefault) { + } + + private static record DataSet(List cols, List> data, String error, String message, + int totalNumberOfElements) { + } +} diff --git a/extensions/agroal/runtime/pom.xml b/extensions/agroal/runtime/pom.xml index 1706cf5f5d53c..72a2be3bbbfc6 100644 --- a/extensions/agroal/runtime/pom.xml +++ b/extensions/agroal/runtime/pom.xml @@ -90,6 +90,19 @@ io.quarkus.agroal + + + process-resources + + extension-descriptor + + + + ${project.groupId}:${project.artifactId}-dev:${project.version} + + + + maven-compiler-plugin diff --git a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourcesJdbcBuildTimeConfig.java b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourcesJdbcBuildTimeConfig.java index b8a76bf2158d4..c239b2be94d7f 100644 --- a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourcesJdbcBuildTimeConfig.java +++ b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourcesJdbcBuildTimeConfig.java @@ -1,6 +1,7 @@ package io.quarkus.agroal.runtime; import java.util.Map; +import java.util.Optional; import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.runtime.annotations.ConfigDocMapKey; @@ -8,7 +9,9 @@ import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; import io.smallrye.config.WithDefaults; +import io.smallrye.config.WithName; import io.smallrye.config.WithParentName; import io.smallrye.config.WithUnnamedKey; @@ -25,6 +28,13 @@ public interface DataSourcesJdbcBuildTimeConfig { @WithUnnamedKey(DataSourceUtil.DEFAULT_DATASOURCE_NAME) Map dataSources(); + /** + * Dev UI. + */ + @WithDefaults + @WithName("dev-ui") + DevUIBuildTimeConfig devui(); + @ConfigGroup public interface DataSourceJdbcOuterNamedBuildTimeConfig { @@ -33,4 +43,30 @@ public interface DataSourceJdbcOuterNamedBuildTimeConfig { */ DataSourceJdbcBuildTimeConfig jdbc(); } + + @ConfigGroup + public interface DevUIBuildTimeConfig { + + /** + * Activate or disable the dev ui page. + */ + @WithDefault("true") + public boolean enabled(); + + /** + * Allow sql queries in the Dev UI page + */ + @WithDefault("false") + public boolean allowSql(); + + /** + * Append this to the select done to fetch the table values. eg: LIMIT 100 or TOP 100 + */ + public Optional appendToDefaultSelect(); + + /** + * Allowed database host. By default only localhost is allowed. Any provided host here will also be allowed + */ + public Optional allowedDBHost(); + } } diff --git a/integration-tests/logging-panache/pom.xml b/integration-tests/logging-panache/pom.xml index 8dd1c543b970e..c37ecaffc2397 100644 --- a/integration-tests/logging-panache/pom.xml +++ b/integration-tests/logging-panache/pom.xml @@ -30,6 +30,11 @@ quarkus-jdbc-h2 test + + io.quarkus + quarkus-agroal-dev + test + io.quarkus quarkus-resteasy From 1a3ec4859ae93bf7670004f6727a4849e88bfa1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Phillip=20Kr=C3=BCger?= Date: Thu, 12 Dec 2024 10:42:16 +1100 Subject: [PATCH 103/207] Remove duplicate stop button in Continuous Testing Dev UI --- .../src/main/resources/dev-ui/qwc/qwc-continuous-testing.js | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-continuous-testing.js b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-continuous-testing.js index 70451790bf5ca..72e3a7ab694b4 100644 --- a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-continuous-testing.js +++ b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-continuous-testing.js @@ -345,7 +345,6 @@ export class QwcContinuousTesting extends QwcHotReloadElement { @click="${!this._testsEnabled ? this._start : this._stop}" ?disabled=${this._busy}> - ${!this._testsEnabled ? 'Start' : 'Stop'} `; } From c57799cfcb7db70b576069b1c7b7c9c660444887 Mon Sep 17 00:00:00 2001 From: Inaki Villar Date: Thu, 12 Dec 2024 00:44:09 +0100 Subject: [PATCH 104/207] avoiding calculate conditional dependencies again for the same configuration,mode and project --- ...ApplicationDeploymentClasspathBuilder.java | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ApplicationDeploymentClasspathBuilder.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ApplicationDeploymentClasspathBuilder.java index 7fc07fdf4f152..e54be14cff418 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ApplicationDeploymentClasspathBuilder.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ApplicationDeploymentClasspathBuilder.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -228,32 +229,39 @@ private void setUpDeploymentConfiguration() { configuration.setCanBeConsumed(false); Configuration enforcedPlatforms = this.getPlatformConfiguration(); configuration.extendsFrom(enforcedPlatforms); + Map> calculatedDependenciesByModeAndConfiguration = new HashMap<>(); ListProperty dependencyListProperty = project.getObjects().listProperty(Dependency.class); configuration.getDependencies().addAllLater(dependencyListProperty.value(project.provider(() -> { - ConditionalDependenciesEnabler cdEnabler = new ConditionalDependenciesEnabler(project, mode, - enforcedPlatforms); - final Collection> allExtensions = cdEnabler.getAllExtensions(); - Set> extensions = collectFirstMetQuarkusExtensions(getRawRuntimeConfiguration(), - allExtensions); - // Add conditional extensions - for (ExtensionDependency knownExtension : allExtensions) { - if (knownExtension.isConditional()) { - extensions.add(knownExtension); + String key = String.format("%s%s%s", mode, configuration.getName(), project.getName()); + if (!calculatedDependenciesByModeAndConfiguration.containsKey(key)) { + ConditionalDependenciesEnabler cdEnabler = new ConditionalDependenciesEnabler(project, mode, + enforcedPlatforms); + final Collection> allExtensions = cdEnabler.getAllExtensions(); + Set> extensions = collectFirstMetQuarkusExtensions(getRawRuntimeConfiguration(), + allExtensions); + // Add conditional extensions + for (ExtensionDependency knownExtension : allExtensions) { + if (knownExtension.isConditional()) { + extensions.add(knownExtension); + } } - } - final Set alreadyProcessed = new HashSet<>(extensions.size()); - final DependencyHandler dependencies = project.getDependencies(); - final Set deploymentDependencies = new HashSet<>(); - for (ExtensionDependency extension : extensions) { - if (!alreadyProcessed.add(extension.getExtensionId())) { - continue; - } + final Set alreadyProcessed = new HashSet<>(extensions.size()); + final DependencyHandler dependencies = project.getDependencies(); + final Set deploymentDependencies = new HashSet<>(); + for (ExtensionDependency extension : extensions) { + if (!alreadyProcessed.add(extension.getExtensionId())) { + continue; + } - deploymentDependencies.add( - DependencyUtils.createDeploymentDependency(dependencies, extension)); + deploymentDependencies.add( + DependencyUtils.createDeploymentDependency(dependencies, extension)); + } + calculatedDependenciesByModeAndConfiguration.put(key, deploymentDependencies); + return deploymentDependencies; + } else { + return calculatedDependenciesByModeAndConfiguration.get(key); } - return deploymentDependencies; }))); }); } From 2511875038e8149d8b24915bb7bef0120753810b Mon Sep 17 00:00:00 2001 From: Holly Cummins Date: Thu, 12 Dec 2024 14:02:58 +1100 Subject: [PATCH 105/207] Remove ambiguity in wording of assertion --- .../devtools/testing/codestarts/QuarkusCodestartTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/codestarts/QuarkusCodestartTest.java b/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/codestarts/QuarkusCodestartTest.java index 56eaab4e5d9ce..dc74497729923 100644 --- a/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/codestarts/QuarkusCodestartTest.java +++ b/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/codestarts/QuarkusCodestartTest.java @@ -155,7 +155,7 @@ public void buildAllProjects() throws IOException { */ public void buildProject(Language language) throws IOException { final int exitCode = WrapperRunner.run(getProjectWithRealDataDir(language)); - Assertions.assertThat(exitCode).as("Run project return status is zero").isZero(); + Assertions.assertThat(exitCode).as("Run project return status should be zero").isZero(); } /** From 167327ff533737f3880ed36f3bb357a4da6490b5 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 12 Dec 2024 08:07:12 +0200 Subject: [PATCH 106/207] Fix documentation of providers field of REST Client Fixes: #45068 --- .../java/io/quarkus/restclient/config/RestClientsConfig.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java index 1c3f23709530d..c57d27ee67ed5 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java @@ -177,8 +177,7 @@ public interface RestClientsConfig { Optional followRedirects(); /** - * Map where keys are fully-qualified provider classnames to include in the client, and values are their integer - * priorities. The equivalent of the `@RegisterProvider` annotation. + * Fully-qualified provider classnames to include in the client. The equivalent of the `@RegisterProvider` annotation. *

    * Can be overwritten by client-specific settings. */ From 85e99ffa66641e24b845bdf9fb8db5227d375249 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 12 Dec 2024 14:01:12 +0200 Subject: [PATCH 107/207] Use Content-Type header from PreMatching filter during media type negotiation Fixes: #45058 --- .../server/handlers/MediaTypeMapper.java | 18 ++- .../PreMatchContentTypeInHeaderTest.java | 114 ++++++++++++++++++ 2 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchContentTypeInHeaderTest.java diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java index 054febcab4d5c..79780144bb854 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java @@ -58,15 +58,11 @@ public MediaTypeMapper(List runtimeResources) { @Override public void handle(ResteasyReactiveRequestContext requestContext) throws Exception { - String contentType = requestContext.serverRequest().getRequestHeader(HttpHeaders.CONTENT_TYPE); - // if there's no Content-Type it's */* - MediaType contentMediaType = contentType != null ? MediaType.valueOf(contentType) : MediaType.WILDCARD_TYPE; // find the best matching consumes type. Note that the arguments are reversed from their definition // of desired/provided, but we do want the result to be a media type we consume, since that's how we key // our methods, rather than the single media type we get from the client. This way we ensure we get the // best match. - MediaType consumes = MediaTypeHelper.getBestMatch(Collections.singletonList(contentMediaType), - consumesTypes); + MediaType consumes = MediaTypeHelper.getBestMatch(contentTypeFromRequest(requestContext), consumesTypes); Holder selectedHolder = resourcesByConsumes.get(consumes); // if we haven't found anything, try selecting the wildcard type, if any if (selectedHolder == null) { @@ -97,6 +93,18 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti requestContext.restart(selectedResource); } + private List contentTypeFromRequest(ResteasyReactiveRequestContext requestContext) { + List contentTypeList = requestContext.getHttpHeaders().getRequestHeader(HttpHeaders.CONTENT_TYPE); + if (contentTypeList.isEmpty()) { + return Collections.singletonList(MediaType.WILDCARD_TYPE); + } + List result = new ArrayList<>(contentTypeList.size()); + for (String s : contentTypeList) { + result.add(MediaType.valueOf(s)); + } + return result; + } + public MediaType selectMediaType(ResteasyReactiveRequestContext requestContext, Holder holder) { MediaType selected = null; List accepts = requestContext.getHttpHeaders().getRequestHeader(HttpHeaders.ACCEPT); diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchContentTypeInHeaderTest.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchContentTypeInHeaderTest.java new file mode 100644 index 0000000000000..e17f34ad9c259 --- /dev/null +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchContentTypeInHeaderTest.java @@ -0,0 +1,114 @@ +package org.jboss.resteasy.reactive.server.vertx.test.matching; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; + +import java.io.IOException; +import java.util.function.Supplier; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerRequestFilter; +import jakarta.ws.rs.container.PreMatching; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.ext.Provider; + +import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class PreMatchContentTypeInHeaderTest { + + @RegisterExtension + static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest() + .setArchiveProducer(new Supplier<>() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class); + } + }); + + @Test + public void filterNotSettingContentType() { + given() + .header("Content-Type", "application/json") + .body("[]") + .when() + .post("/test") + .then() + .statusCode(200) + .body(is("json-[]")); + + given() + .header("Content-Type", "text/plain") + .body("input") + .when() + .post("/test") + .then() + .statusCode(200) + .body(is("text-input")); + } + + @Test + public void filterSettingContentTypeToText() { + given() + .header("Content-Type", "application/json") + .header("test-content-type", "text/plain") + .body("[]") + .when() + .post("/test") + .then() + .statusCode(200) + .body(is("text-[]")); + } + + @Test + public void filterSettingContentTypeToJson() { + given() + .header("Content-Type", "text/plain") + .header("test-content-type", "application/json") + .body("input") + .when() + .post("/test") + .then() + .statusCode(200) + .body(is("json-input")); + } + + @Path("test") + public static class TestResource { + + @POST + @Consumes(MediaType.TEXT_PLAIN) + public String fromText(String input) { + return "text-" + input; + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + public String fromJson(String input) { + return "json-" + input; + } + } + + public record Result(String message) { + + } + + @Provider + @PreMatching + public static class Filter implements ContainerRequestFilter { + + @Override + public void filter(ContainerRequestContext context) throws IOException { + String testContentType = context.getHeaderString("test-content-type"); + if (testContentType != null) { + context.getHeaders().putSingle("Content-Type", testContentType); + } + } + } +} From 314abb1deb0fa22784a44d7d0b4614615d8649ce Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Thu, 12 Dec 2024 13:25:12 +0100 Subject: [PATCH 108/207] Sanitize remote URL in Info extension This is a follow-up of #44965. --- .../io/quarkus/info/deployment/GitUtil.java | 30 +++++++++++++++++++ .../info/deployment/InfoProcessor.java | 3 +- .../quarkus/info/deployment/GitUtilTest.java | 26 ++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 extensions/info/deployment/src/main/java/io/quarkus/info/deployment/GitUtil.java create mode 100644 extensions/info/deployment/src/test/java/io/quarkus/info/deployment/GitUtilTest.java diff --git a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/GitUtil.java b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/GitUtil.java new file mode 100644 index 0000000000000..e6aa16603a5a3 --- /dev/null +++ b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/GitUtil.java @@ -0,0 +1,30 @@ +package io.quarkus.info.deployment; + +class GitUtil { + + static String sanitizeRemoteUrl(String remoteUrl) { + if (remoteUrl == null || remoteUrl.isBlank()) { + return null; + } + + String sanitizedRemoteUrl = remoteUrl.trim(); + if (sanitizedRemoteUrl.startsWith("https://")) { + int atSign = sanitizedRemoteUrl.indexOf('@'); + if (atSign > 0) { + sanitizedRemoteUrl = "https://" + sanitizedRemoteUrl.substring(atSign + 1); + } + } else if (sanitizedRemoteUrl.startsWith("http://")) { + int atSign = sanitizedRemoteUrl.indexOf('@'); + if (atSign > 0) { + sanitizedRemoteUrl = "http://" + sanitizedRemoteUrl.substring(atSign + 1); + } + } else { + int atSign = sanitizedRemoteUrl.indexOf('@'); + if (atSign > 0) { + sanitizedRemoteUrl = sanitizedRemoteUrl.substring(atSign + 1); + } + } + + return sanitizedRemoteUrl; + } +} diff --git a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java index 1cafa5308a418..27e76b1996431 100644 --- a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java +++ b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java @@ -112,7 +112,8 @@ void gitInfo(InfoBuildTimeConfig config, commit.put("id", id); - data.put("remote", git.getRepository().getConfig().getString("remote", "origin", "url")); + data.put("remote", + GitUtil.sanitizeRemoteUrl(git.getRepository().getConfig().getString("remote", "origin", "url"))); data.put("tags", getTags(git, latestCommit)); } diff --git a/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/GitUtilTest.java b/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/GitUtilTest.java new file mode 100644 index 0000000000000..bdab391a44ce8 --- /dev/null +++ b/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/GitUtilTest.java @@ -0,0 +1,26 @@ +package io.quarkus.info.deployment; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; + +public class GitUtilTest { + + @Test + public void testSanitizeRemoteUrl() { + assertNull(GitUtil.sanitizeRemoteUrl(null)); + assertNull(GitUtil.sanitizeRemoteUrl("")); + assertNull(GitUtil.sanitizeRemoteUrl(" ")); + assertEquals("github.com:gsmet/quarkusio.github.io.git", + GitUtil.sanitizeRemoteUrl("git@github.com:gsmet/quarkusio.github.io.git")); + assertEquals("github.com:gsmet/quarkusio.github.io.git", + GitUtil.sanitizeRemoteUrl(" git@github.com:gsmet/quarkusio.github.io.git ")); + assertEquals("https://github.com/gsmet/quarkusio.github.io.git", + GitUtil.sanitizeRemoteUrl("https://github.com/gsmet/quarkusio.github.io.git")); + assertEquals("https://github.com/gsmet/quarkusio.github.io.git", + GitUtil.sanitizeRemoteUrl("https://gsmet:password@github.com/gsmet/quarkusio.github.io.git")); + assertEquals("http://github.com/gsmet/quarkusio.github.io.git", + GitUtil.sanitizeRemoteUrl("http://gsmet:password@github.com/gsmet/quarkusio.github.io.git")); + } +} From 671ed8819883e360d69fdb7bfe45c1901fbb1fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Thu, 12 Dec 2024 14:10:30 +0100 Subject: [PATCH 109/207] fix(oidc,security): OIDC must auth before mTLS when disabled inclusive auth --- .../security-authentication-mechanisms.adoc | 6 +- extensions/oidc/deployment/pom.xml | 5 + .../OidcMtlsDisabledInclusiveAuthTest.java | 107 ++++++++++++++++++ .../security/InclusiveAuthValidationTest.java | 2 +- .../vertx/http/runtime/AuthConfig.java | 2 + .../runtime/security/HttpAuthenticator.java | 2 +- .../security/MtlsAuthenticationMechanism.java | 13 ++- 7 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/OidcMtlsDisabledInclusiveAuthTest.java diff --git a/docs/src/main/asciidoc/security-authentication-mechanisms.adoc b/docs/src/main/asciidoc/security-authentication-mechanisms.adoc index 95a32393ed97b..f5cc1a250b9e0 100644 --- a/docs/src/main/asciidoc/security-authentication-mechanisms.adoc +++ b/docs/src/main/asciidoc/security-authentication-mechanisms.adoc @@ -602,7 +602,11 @@ quarkus.http.auth.inclusive=true If the authentication is inclusive then `SecurityIdentity` created by the first authentication mechanism can be injected into the application code. For example, if both <> and basic authentication mechanism authentications are required, -the <> authentication mechanism will create `SecurityIdentity` first. +the <> mechanism will create `SecurityIdentity` first. + +NOTE: The <> mechanism has the highest priority when inclusive authentication is enabled, to ensure +that an injected `SecurityIdentity` always represents <> and can be used to get access to `SecurityIdentity` +identities provided by other authentication mechanisms. Additional `SecurityIdentity` instances can be accessed as a `quarkus.security.identities` attribute on the first `SecurityIdentity`, however, accessing these extra identities directly may not be necessary, for example, diff --git a/extensions/oidc/deployment/pom.xml b/extensions/oidc/deployment/pom.xml index 8691bf75f1911..8e8796c16474f 100644 --- a/extensions/oidc/deployment/pom.xml +++ b/extensions/oidc/deployment/pom.xml @@ -93,6 +93,11 @@ quarkus-elytron-security-properties-file-deployment test + + io.smallrye.certs + smallrye-certificate-generator-junit5 + test + diff --git a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/OidcMtlsDisabledInclusiveAuthTest.java b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/OidcMtlsDisabledInclusiveAuthTest.java new file mode 100644 index 0000000000000..94b913a6b3c5a --- /dev/null +++ b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/OidcMtlsDisabledInclusiveAuthTest.java @@ -0,0 +1,107 @@ +package io.quarkus.oidc.test; + +import static org.hamcrest.Matchers.is; + +import java.io.File; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.oidc.BearerTokenAuthentication; +import io.quarkus.security.Authenticated; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.test.QuarkusDevModeTest; +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.keycloak.server.KeycloakTestResourceLifecycleManager; +import io.quarkus.vertx.http.runtime.security.annotation.MTLSAuthentication; +import io.restassured.RestAssured; +import io.restassured.specification.RequestSpecification; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; + +/** + * This test ensures OIDC runs before mTLS authentication mechanism when inclusive authentication is not enabled. + */ +@QuarkusTestResource(KeycloakTestResourceLifecycleManager.class) +@Certificates(baseDir = "target/certs", certificates = @Certificate(name = "mtls-test", password = "secret", formats = { + Format.PKCS12, Format.PEM }, client = true)) +public class OidcMtlsDisabledInclusiveAuthTest { + + private static final String BASE_URL = "https://localhost:8443/mtls-bearer/"; + private static final String CONFIGURATION = """ + quarkus.tls.key-store.pem.0.cert=server.crt + quarkus.tls.key-store.pem.0.key=server.key + quarkus.tls.trust-store.pem.certs=ca.crt + quarkus.http.ssl.client-auth=REQUIRED + quarkus.http.insecure-requests=disabled + quarkus.oidc.auth-server-url=${keycloak.url}/realms/quarkus + quarkus.oidc.client-id=quarkus-service-app + quarkus.oidc.credentials.secret=secret + quarkus.http.auth.proactive=false + """; + + @RegisterExtension + static final QuarkusDevModeTest config = new QuarkusDevModeTest() + .withApplicationRoot((jar) -> jar + .addClasses(MtlsBearerResource.class) + .addAsResource(new StringAsset(CONFIGURATION), "application.properties") + .addAsResource(new File("target/certs/mtls-test.key"), "server.key") + .addAsResource(new File("target/certs/mtls-test.crt"), "server.crt") + .addAsResource(new File("target/certs/mtls-test-server-ca.crt"), "ca.crt")); + + @Test + public void testOidcHasHighestPriority() { + givenWithCerts().get(BASE_URL + "only-mtls").then().statusCode(200).body(is("CN=localhost")); + givenWithCerts().auth().oauth2(getAccessToken()).get(BASE_URL + "only-bearer").then().statusCode(200).body(is("alice")); + // this needs to be OIDC because when inclusive auth is disabled, OIDC has higher priority + givenWithCerts().auth().oauth2(getAccessToken()).get(BASE_URL + "both").then().statusCode(200).body(is("alice")); + // OIDC must run first and thus authentication fails over invalid credentials + givenWithCerts().auth().oauth2("invalid-token").get(BASE_URL + "both").then().statusCode(401); + // mTLS authentication mechanism still runs when OIDC doesn't produce the identity + givenWithCerts().get(BASE_URL + "both").then().statusCode(200).body(is("CN=localhost")); + } + + private static RequestSpecification givenWithCerts() { + return RestAssured.given() + .keyStore("target/certs/mtls-test-client-keystore.p12", "secret") + .trustStore("target/certs/mtls-test-client-truststore.p12", "secret"); + } + + private static String getAccessToken() { + return KeycloakTestResourceLifecycleManager.getAccessToken("alice"); + } + + @Path("mtls-bearer") + public static class MtlsBearerResource { + + @Inject + SecurityIdentity securityIdentity; + + @GET + @Authenticated + @Path("both") + public String both() { + return securityIdentity.getPrincipal().getName(); + } + + @GET + @MTLSAuthentication + @Path("only-mtls") + public String onlyMTLS() { + return securityIdentity.getPrincipal().getName(); + } + + @GET + @BearerTokenAuthentication + @Path("only-bearer") + public String onlyBearer() { + return securityIdentity.getPrincipal().getName(); + } + } +} diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/InclusiveAuthValidationTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/InclusiveAuthValidationTest.java index 83285ca98d6ef..186b7a4b6dfc3 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/InclusiveAuthValidationTest.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/InclusiveAuthValidationTest.java @@ -89,7 +89,7 @@ public Set> getCredentialTypes() { @Override public int getPriority() { - return MtlsAuthenticationMechanism.PRIORITY + 1; + return MtlsAuthenticationMechanism.INCLUSIVE_AUTHENTICATION_PRIORITY + 1; } } } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/AuthConfig.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/AuthConfig.java index 08107d606038f..d251a34e732b7 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/AuthConfig.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/AuthConfig.java @@ -43,6 +43,8 @@ public class AuthConfig { * authentication, for example, OIDC bearer token authentication, must succeed. * In such cases, `SecurityIdentity` created by the first mechanism, mTLS, can be injected, identities created * by other mechanisms will be available on `SecurityIdentity`. + * The mTLS mechanism is always the first mechanism, because its priority is elevated when inclusive authentication + * is enabled. * The identities can be retrieved using utility method as in the example below: * *

    diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpAuthenticator.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpAuthenticator.java
    index 0dfbc8f392975..da171acff63df 100644
    --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpAuthenticator.java
    +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpAuthenticator.java
    @@ -160,7 +160,7 @@ public int compare(HttpAuthenticationMechanism mech1, HttpAuthenticationMechanis
                                         the highest priority. Please lower priority of the '%s' authentication mechanism under '%s'.
                                         """.formatted(MtlsAuthenticationMechanism.class.getName(),
                                         topMechanism.getClass().getName(),
    -                                    MtlsAuthenticationMechanism.PRIORITY));
    +                                    MtlsAuthenticationMechanism.INCLUSIVE_AUTHENTICATION_PRIORITY));
                     }
                 }
             }
    diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/MtlsAuthenticationMechanism.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/MtlsAuthenticationMechanism.java
    index fa7d77c449dec..e6316f0e1bc0e 100644
    --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/MtlsAuthenticationMechanism.java
    +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/MtlsAuthenticationMechanism.java
    @@ -17,6 +17,8 @@
      */
     package io.quarkus.vertx.http.runtime.security;
     
    +import static io.quarkus.vertx.http.runtime.security.HttpAuthenticationMechanism.DEFAULT_PRIORITY;
    +
     import java.security.cert.Certificate;
     import java.security.cert.X509Certificate;
     import java.util.Collections;
    @@ -25,6 +27,8 @@
     
     import javax.net.ssl.SSLPeerUnverifiedException;
     
    +import org.eclipse.microprofile.config.inject.ConfigProperty;
    +
     import io.netty.handler.codec.http.HttpResponseStatus;
     import io.quarkus.security.credential.CertificateCredential;
     import io.quarkus.security.identity.IdentityProviderManager;
    @@ -39,10 +43,15 @@
      * The authentication handler responsible for mTLS client authentication
      */
     public class MtlsAuthenticationMechanism implements HttpAuthenticationMechanism {
    -    public static final int PRIORITY = 3000;
    +    public static final int INCLUSIVE_AUTHENTICATION_PRIORITY = 3000;
         private static final String ROLES_MAPPER_ATTRIBUTE = "roles_mapper";
    +    private final boolean inclusiveAuthentication;
         private Function> certificateToRoles = null;
     
    +    MtlsAuthenticationMechanism(@ConfigProperty(name = "quarkus.http.auth.inclusive") boolean inclusiveAuthentication) {
    +        this.inclusiveAuthentication = inclusiveAuthentication;
    +    }
    +
         @Override
         public Uni authenticate(RoutingContext context,
                 IdentityProviderManager identityProviderManager) {
    @@ -86,7 +95,7 @@ public Uni getCredentialTransport(RoutingContext contex
     
         @Override
         public int getPriority() {
    -        return PRIORITY;
    +        return inclusiveAuthentication ? INCLUSIVE_AUTHENTICATION_PRIORITY : DEFAULT_PRIORITY;
         }
     
         void setCertificateToRolesMapper(Function> certificateToRoles) {
    
    From 6050efd4e6e3d7e1e932ca493e4204bfe3f50e07 Mon Sep 17 00:00:00 2001
    From: Auri Munoz 
    Date: Fri, 22 Nov 2024 13:49:46 +0100
    Subject: [PATCH 110/207] Don't ignore Spring Rest controllers interfaces if
     contains errors
    
    Related to #43704
    ---
     ...EndpointValidationPredicatesBuildItem.java | 33 +++++++++++++
     .../JaxrsClientReactiveProcessor.java         |  7 ++-
     ...EndpointValidationPredicatesBuildItem.java | 33 +++++++++++++
     .../deployment/ResteasyReactiveProcessor.java |  6 ++-
     .../web/deployment/SpringWebProcessor.java    | 26 ++++++++++
     ...ableSpringRestControllerInterfaceTest.java | 48 +++++++++++++++++++
     .../common/processor/EndpointIndexer.java     | 34 ++++++++++---
     7 files changed, 179 insertions(+), 8 deletions(-)
     create mode 100644 extensions/resteasy-classic/resteasy-common/spi/src/main/java/io/quarkus/resteasy/common/spi/EndpointValidationPredicatesBuildItem.java
     create mode 100644 extensions/resteasy-reactive/rest-common/spi-deployment/src/main/java/io/quarkus/resteasy/reactive/spi/EndpointValidationPredicatesBuildItem.java
     create mode 100644 extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/resteasy/reactive/test/UnbuildableSpringRestControllerInterfaceTest.java
    
    diff --git a/extensions/resteasy-classic/resteasy-common/spi/src/main/java/io/quarkus/resteasy/common/spi/EndpointValidationPredicatesBuildItem.java b/extensions/resteasy-classic/resteasy-common/spi/src/main/java/io/quarkus/resteasy/common/spi/EndpointValidationPredicatesBuildItem.java
    new file mode 100644
    index 0000000000000..2249040e483f4
    --- /dev/null
    +++ b/extensions/resteasy-classic/resteasy-common/spi/src/main/java/io/quarkus/resteasy/common/spi/EndpointValidationPredicatesBuildItem.java
    @@ -0,0 +1,33 @@
    +package io.quarkus.resteasy.common.spi;
    +
    +import java.util.function.Predicate;
    +
    +import org.jboss.jandex.ClassInfo;
    +
    +import io.quarkus.builder.item.MultiBuildItem;
    +
    +/**
    + * A build item that provides a {@link Predicate} to detect and validate classes defining REST endpoints.
    + * 

    + * This can include resources in RESTEasy or controllers in the Spring ecosystem. + * It acts as a Service Provider Interface (SPI) to allow customization of the validation logic for endpoint detection, + * enabling integration with various frameworks or specific application needs. + *

    + * + *

    + * The {@link Predicate} evaluates {@link ClassInfo} instances to determine whether a class defines a REST endpoint + * according to the provided logic. + *

    + */ +public final class EndpointValidationPredicatesBuildItem extends MultiBuildItem { + + private final Predicate predicate; + + public EndpointValidationPredicatesBuildItem(Predicate predicate) { + this.predicate = predicate; + } + + public Predicate getPredicate() { + return predicate; + } +} diff --git a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java index bf1a4a4099909..ba00737128b1c 100644 --- a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java +++ b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java @@ -50,6 +50,7 @@ import java.util.function.Predicate; import java.util.function.Supplier; import java.util.regex.Pattern; +import java.util.stream.Collectors; import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.RuntimeType; @@ -177,6 +178,7 @@ import io.quarkus.resteasy.reactive.common.deployment.ResourceScanningResultBuildItem; import io.quarkus.resteasy.reactive.common.deployment.SerializersUtil; import io.quarkus.resteasy.reactive.common.runtime.ResteasyReactiveConfig; +import io.quarkus.resteasy.reactive.spi.EndpointValidationPredicatesBuildItem; import io.quarkus.resteasy.reactive.spi.MessageBodyReaderBuildItem; import io.quarkus.resteasy.reactive.spi.MessageBodyReaderOverrideBuildItem; import io.quarkus.resteasy.reactive.spi.MessageBodyWriterBuildItem; @@ -289,7 +291,8 @@ void setupClientProxies(JaxrsClientReactiveRecorder recorder, List defaultProduces, List disableSmartDefaultProduces, List disableRemovalTrailingSlashProduces, - List parameterContainersBuildItems) { + List parameterContainersBuildItems, + List validationPredicatesBuildItems) { String defaultConsumesType = defaultMediaType(defaultConsumes, MediaType.APPLICATION_OCTET_STREAM); String defaultProducesType = defaultMediaType(defaultProduces, MediaType.TEXT_PLAIN); @@ -343,6 +346,8 @@ public boolean test(Map anns) { return anns.containsKey(NOT_BODY) || anns.containsKey(URL); } }) + .setValidateEndpoint(validationPredicatesBuildItems.stream().map(item -> item.getPredicate()) + .collect(Collectors.toUnmodifiableList())) .setResourceMethodCallback(new Consumer<>() { @Override public void accept(EndpointIndexer.ResourceMethodCallbackEntry entry) { diff --git a/extensions/resteasy-reactive/rest-common/spi-deployment/src/main/java/io/quarkus/resteasy/reactive/spi/EndpointValidationPredicatesBuildItem.java b/extensions/resteasy-reactive/rest-common/spi-deployment/src/main/java/io/quarkus/resteasy/reactive/spi/EndpointValidationPredicatesBuildItem.java new file mode 100644 index 0000000000000..d50365bfb0dfb --- /dev/null +++ b/extensions/resteasy-reactive/rest-common/spi-deployment/src/main/java/io/quarkus/resteasy/reactive/spi/EndpointValidationPredicatesBuildItem.java @@ -0,0 +1,33 @@ +package io.quarkus.resteasy.reactive.spi; + +import java.util.function.Predicate; + +import org.jboss.jandex.ClassInfo; + +import io.quarkus.builder.item.MultiBuildItem; + +/** + * A build item that provides a {@link Predicate} to detect and validate classes defining REST endpoints. + *

    + * This can include resources in RESTEasy or controllers in the Spring ecosystem. + * It acts as a Service Provider Interface (SPI) to allow customization of the validation logic for endpoint detection, + * enabling integration with various frameworks or specific application needs. + *

    + * + *

    + * The {@link Predicate} evaluates {@link ClassInfo} instances to determine whether a class defines a REST endpoint + * according to the provided logic. + *

    + */ +public final class EndpointValidationPredicatesBuildItem extends MultiBuildItem { + + private final Predicate predicate; + + public EndpointValidationPredicatesBuildItem(Predicate predicate) { + this.predicate = predicate; + } + + public Predicate getPredicate() { + return predicate; + } +} diff --git a/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java b/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java index 35ce4ab24bdde..be1d52d4dabd4 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java +++ b/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java @@ -198,6 +198,7 @@ import io.quarkus.resteasy.reactive.server.spi.ResumeOn404BuildItem; import io.quarkus.resteasy.reactive.spi.CustomExceptionMapperBuildItem; import io.quarkus.resteasy.reactive.spi.DynamicFeatureBuildItem; +import io.quarkus.resteasy.reactive.spi.EndpointValidationPredicatesBuildItem; import io.quarkus.resteasy.reactive.spi.ExceptionMapperBuildItem; import io.quarkus.resteasy.reactive.spi.JaxrsFeatureBuildItem; import io.quarkus.resteasy.reactive.spi.MessageBodyReaderBuildItem; @@ -468,7 +469,8 @@ public void setupEndpoints(ApplicationIndexBuildItem applicationIndexBuildItem, CompiledJavaVersionBuildItem compiledJavaVersionBuildItem, ResourceInterceptorsBuildItem resourceInterceptorsBuildItem, Capabilities capabilities, - Optional allowNotRestParametersBuildItem) { + Optional allowNotRestParametersBuildItem, + List validationPredicatesBuildItems) { if (!resourceScanningResultBuildItem.isPresent()) { // no detected @Path, bail out @@ -640,6 +642,8 @@ private boolean hasAnnotation(MethodInfo method, short paramPosition, DotName an }) .setResteasyReactiveRecorder(recorder) .setApplicationClassPredicate(applicationClassPredicate) + .setValidateEndpoint(validationPredicatesBuildItems.stream().map(item -> item.getPredicate()) + .collect(Collectors.toUnmodifiableList())) .setTargetJavaVersion(new TargetJavaVersion() { private final Status result; diff --git a/extensions/spring-web/core/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebProcessor.java b/extensions/spring-web/core/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebProcessor.java index 4699cc9593141..1c01a383fd1ab 100644 --- a/extensions/spring-web/core/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebProcessor.java +++ b/extensions/spring-web/core/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebProcessor.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Predicate; import jakarta.ws.rs.Priorities; import jakarta.ws.rs.core.HttpHeaders; @@ -34,6 +35,7 @@ import io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyIgnoreWarningBuildItem; import io.quarkus.gizmo.ClassOutput; import io.quarkus.jaxrs.spi.deployment.AdditionalJaxRsResourceMethodAnnotationsBuildItem; +import io.quarkus.resteasy.common.spi.EndpointValidationPredicatesBuildItem; import io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem; import io.quarkus.resteasy.reactive.spi.ExceptionMapperBuildItem; @@ -86,6 +88,30 @@ public AdditionalJaxRsResourceMethodAnnotationsBuildItem additionalJaxRsResource return new AdditionalJaxRsResourceMethodAnnotationsBuildItem(MAPPING_ANNOTATIONS); } + @BuildStep + EndpointValidationPredicatesBuildItem createSpringRestControllerPredicateForClassic() { + Predicate predicate = new Predicate<>() { + @Override + public boolean test(ClassInfo classInfo) { + return classInfo + .declaredAnnotation(REST_CONTROLLER_ANNOTATION) == null; + } + }; + return new EndpointValidationPredicatesBuildItem(predicate); + } + + @BuildStep + io.quarkus.resteasy.reactive.spi.EndpointValidationPredicatesBuildItem createSpringRestControllerPredicateForReactive() { + Predicate predicate = new Predicate<>() { + @Override + public boolean test(ClassInfo classInfo) { + return classInfo + .declaredAnnotation(REST_CONTROLLER_ANNOTATION) == null; + } + }; + return new io.quarkus.resteasy.reactive.spi.EndpointValidationPredicatesBuildItem(predicate); + } + @BuildStep public void ignoreReflectionHierarchy(BuildProducer ignore) { ignore.produce(new ReflectiveHierarchyIgnoreWarningBuildItem( diff --git a/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/resteasy/reactive/test/UnbuildableSpringRestControllerInterfaceTest.java b/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/resteasy/reactive/test/UnbuildableSpringRestControllerInterfaceTest.java new file mode 100644 index 0000000000000..9cdb6b44c8779 --- /dev/null +++ b/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/resteasy/reactive/test/UnbuildableSpringRestControllerInterfaceTest.java @@ -0,0 +1,48 @@ +package io.quarkus.spring.web.resteasy.reactive.test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import jakarta.ws.rs.QueryParam; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import io.quarkus.test.QuarkusProdModeTest; + +public class UnbuildableSpringRestControllerInterfaceTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .withApplicationRoot((jar) -> jar + .addClasses(UnbuildableControllerInterface.class)) + .setApplicationName("unbuildable-rest-controller-interface") + .setApplicationVersion("0.1-SNAPSHOT") + .assertBuildException(throwable -> { + assertThat(throwable).isInstanceOf(RuntimeException.class); + assertThat(throwable).hasMessageContaining( + "Cannot have more than one of @PathParam, @QueryParam, @HeaderParam, @FormParam, @CookieParam, @BeanParam, @Context on method"); + }); + + @Test + public void testBuildLogs() { + fail("Should not be called"); + } + + @RestController + @RequestMapping("/unbuildable") + public interface UnbuildableControllerInterface { + @GetMapping("/ping") + String ping(); + + @PostMapping("/hello") + String hello(@RequestParam(required = false) @QueryParam("dung") String params); + + } + +} diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java index 25633cdd60993..ae5576b31d7a2 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java @@ -88,6 +88,7 @@ import java.nio.charset.StandardCharsets; import java.util.AbstractMap; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -239,6 +240,7 @@ public abstract class EndpointIndexer> isDisabledCreator; private final Predicate> skipMethodParameter; + private final List> validateEndpoint; private final boolean skipNotRestParameters; private SerializerScanningResult serializerScanningResult; @@ -267,6 +269,7 @@ protected EndpointIndexer(Builder builder) { this.isDisabledCreator = builder.isDisabledCreator; this.skipMethodParameter = builder.skipMethodParameter; this.skipNotRestParameters = builder.skipNotRestParameters; + this.validateEndpoint = builder.defaultPredicate; } public Optional createEndpoints(ClassInfo classInfo, boolean considerApplication) { @@ -324,14 +327,18 @@ public Optional createEndpoints(ClassInfo classInfo, boolean cons return Optional.of(clazz); } catch (Exception e) { - if (Modifier.isInterface(classInfo.flags()) || Modifier.isAbstract(classInfo.flags())) { - //kinda bogus, but we just ignore failed interfaces for now - //they can have methods that are not valid until they are actually extended by a concrete type - log.debug("Ignoring interface " + classInfo.name(), e); - return Optional.empty(); + for (Predicate predicate : validateEndpoint) { + if (predicate.test(classInfo)) { + //kinda bogus, but we just ignore failed interfaces for now + //they can have methods that are not valid until they are actually extended by a concrete type + log.debug("Ignoring interface " + classInfo.name(), e); + } else { + throw new RuntimeException(e); + } } - throw new RuntimeException(e); + return Optional.empty(); } + } private String sanitizePath(String path) { @@ -1708,6 +1715,13 @@ public boolean handleMultipartForReturnType(AdditionalWriters additionalWriters, private Function> isDisabledCreator = null; private Predicate> skipMethodParameter = null; + private List> defaultPredicate = Arrays.asList(new Predicate<>() { + @Override + public boolean test(ClassInfo classInfo) { + return Modifier.isInterface(classInfo.flags()) + || Modifier.isAbstract(classInfo.flags()); + } + }); private boolean skipNotRestParameters = false; @@ -1844,6 +1858,14 @@ public B setSkipMethodParameter( return (B) this; } + public B setValidateEndpoint(List> validateEndpoint) { + List> predicates = new ArrayList<>(validateEndpoint.size() + 1); + predicates.addAll(validateEndpoint); + predicates.addAll(this.defaultPredicate); + this.defaultPredicate = predicates; + return (B) this; + } + public B skipNotRestParameters(boolean skipNotRestParameters) { this.skipNotRestParameters = skipNotRestParameters; return (B) this; From b903053112449bfcbf188fea152a15c6ac031332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 12 Dec 2024 17:36:56 +0100 Subject: [PATCH 111/207] Add configuration for the "created" category in the lottery --- .github/quarkus-github-lottery.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/quarkus-github-lottery.yml b/.github/quarkus-github-lottery.yml index e8f8e098d1896..3b59421c5b20b 100644 --- a/.github/quarkus-github-lottery.yml +++ b/.github/quarkus-github-lottery.yml @@ -7,6 +7,10 @@ buckets: delay: PT0S timeout: P3D maintenance: + created: + delay: PT0S + timeout: P1D + expiry: P14D feedback: labels: ["triage/needs-reproducer", "triage/needs-feedback"] needed: @@ -30,18 +34,22 @@ participants: maintenance: labels: ["area/hibernate-orm", "area/hibernate-search", "area/elasticsearch", "area/jdbc"] days: ["WEDNESDAY"] + created: + maxIssues: 3 feedback: needed: - maxIssues: 10 + maxIssues: 3 provided: - maxIssues: 10 + maxIssues: 3 stale: - maxIssues: 5 + maxIssues: 1 - username: "marko-bekhta" timezone: "Europe/Warsaw" maintenance: labels: ["area/hibernate-search", "area/elasticsearch", "area/hibernate-validator"] days: ["WEDNESDAY"] + created: + maxIssues: 3 feedback: needed: maxIssues: 10 @@ -57,6 +65,8 @@ participants: maintenance: labels: ["area/hibernate-validator", "area/jakarta"] days: ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"] + created: + maxIssues: 2 feedback: needed: maxIssues: 4 @@ -120,6 +130,8 @@ participants: maintenance: labels: ["area/core", "area/testing", "area/kotlin", "area/spring", "area/rest", "area/kubernetes"] days: ["WEDNESDAY", "FRIDAY"] + created: + maxIssues: 2 feedback: needed: maxIssues: 4 From c43e0dc24d6247d564c35b63da0f372c5667c753 Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Thu, 12 Dec 2024 14:01:48 -0300 Subject: [PATCH 112/207] Add validation for runtime within deployment modules --- .../config/scanner/AbstractConfigListener.java | 14 ++++++++++++++ .../config/scanner/ConfigMappingListener.java | 2 ++ .../config/scanner/LegacyConfigRootListener.java | 2 ++ 3 files changed, 18 insertions(+) diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/AbstractConfigListener.java b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/AbstractConfigListener.java index 4eb92d7e84277..6e99c7e9b3be1 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/AbstractConfigListener.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/AbstractConfigListener.java @@ -14,6 +14,8 @@ import io.quarkus.annotation.processor.documentation.config.discovery.EnumDefinition; import io.quarkus.annotation.processor.documentation.config.discovery.EnumDefinition.EnumConstant; import io.quarkus.annotation.processor.documentation.config.discovery.ResolvedType; +import io.quarkus.annotation.processor.documentation.config.model.ConfigPhase; +import io.quarkus.annotation.processor.documentation.config.model.ExtensionModule; import io.quarkus.annotation.processor.documentation.config.util.Types; import io.quarkus.annotation.processor.util.Config; import io.quarkus.annotation.processor.util.Utils; @@ -66,6 +68,18 @@ public void onResolvedEnum(TypeElement enumTypeElement) { configCollector.addResolvedEnum(enumDefinition); } + protected void validateRuntimeConfigOnDeploymentModules(ConfigPhase configPhase, TypeElement configRoot) { + if (configPhase.equals(ConfigPhase.RUN_TIME) || configPhase.equals(ConfigPhase.BUILD_AND_RUN_TIME_FIXED)) { + ExtensionModule.ExtensionModuleType type = config.getExtensionModule().type(); + if (type.equals(ExtensionModule.ExtensionModuleType.DEPLOYMENT)) { + throw new IllegalStateException(String.format( + "Error on %s: Configuration classes with ConfigPhase.RUN_TIME or " + + "ConfigPhase.BUILD_AND_RUNTIME_FIXED phases, must reside in the respective module.", + configRoot.getSimpleName().toString())); + } + } + } + protected void handleCommonPropertyAnnotations(DiscoveryConfigProperty.Builder builder, Map propertyAnnotations, ResolvedType resolvedType, String sourceElementName) { diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigMappingListener.java b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigMappingListener.java index cda99142c602e..ea4135f7adfe3 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigMappingListener.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigMappingListener.java @@ -75,6 +75,8 @@ public Optional onConfigRoot(TypeElement configRoot) { } } + validateRuntimeConfigOnDeploymentModules(configPhase, configRoot); + for (Map.Entry entry : configMappingAnnotion.getElementValues() .entrySet()) { if ("prefix()".equals(entry.getKey().toString())) { diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/LegacyConfigRootListener.java b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/LegacyConfigRootListener.java index 2410b8c62b9d6..f675f902fc9fe 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/LegacyConfigRootListener.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/LegacyConfigRootListener.java @@ -79,6 +79,8 @@ public Optional onConfigRoot(TypeElement configRoot) { } } + validateRuntimeConfigOnDeploymentModules(configPhase, configRoot); + String overriddenDocPrefix = null; if (configDocPrefixAnnotation != null) { for (Map.Entry entry : configDocPrefixAnnotation From 3e93de85bbee376764a3d22691df32573f032864 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:20:43 +0000 Subject: [PATCH 113/207] Bump com.gradle.develocity from 3.18.2 to 3.19 in /devtools/gradle Bumps com.gradle.develocity from 3.18.2 to 3.19. --- updated-dependencies: - dependency-name: com.gradle.develocity dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- devtools/gradle/settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/gradle/settings.gradle.kts b/devtools/gradle/settings.gradle.kts index 4d008c259a339..6532acd5a053f 100644 --- a/devtools/gradle/settings.gradle.kts +++ b/devtools/gradle/settings.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradle.develocity") version "3.18.2" + id("com.gradle.develocity") version "3.19" } develocity { From 8f5e156eef32335acdb74ea6f40ef647ee1abfb0 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Thu, 12 Dec 2024 22:00:42 +0000 Subject: [PATCH 114/207] Use `TestConfig` to load test config instead of property names --- .../deployment/dev/testing/TestConfig.java | 2 +- .../io/quarkus/test/common/LauncherUtil.java | 2 +- .../quarkus/test/common/TestConfigUtil.java | 4 ++++ .../test/junit/IntegrationTestUtil.java | 8 +++---- .../QuarkusIntegrationTestExtension.java | 21 +++++++++--------- .../QuarkusMainIntegrationTestExtension.java | 12 +++++----- .../DockerContainerLauncherProvider.java | 22 +++++++++---------- .../junit/launcher/JarLauncherProvider.java | 17 +++++++------- .../launcher/NativeImageLauncherProvider.java | 17 +++++++------- 9 files changed, 54 insertions(+), 51 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java index f4c3b9eb0f4ae..f93894a7a1e72 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java @@ -185,7 +185,7 @@ public interface TestConfig { * When the artifact is a {@code container}, this string is passed right after the {@code docker run} command. * When the artifact is a {@code native binary}, this string is passed right after the native binary name. */ - Optional> argLine(); + Optional<@WithConverter(TrimmedStringConverter.class) List> argLine(); /** * Additional environment variables to be set in the process that {@code @QuarkusIntegrationTest} launches. diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java index 63c687909ef0b..46586ca9b0178 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java @@ -34,6 +34,7 @@ public final class LauncherUtil { private LauncherUtil() { } + @Deprecated(forRemoval = true, since = "3.17") public static Config installAndGetSomeConfig() { return ConfigProvider.getConfig(); } @@ -227,7 +228,6 @@ static void updateConfigForPort(Integer effectivePort) { if (effectivePort != null) { System.setProperty("quarkus.http.port", effectivePort.toString()); //set the port as a system property in order to have it applied to Config System.setProperty("quarkus.http.test-port", effectivePort.toString()); // needed for RestAssuredManager - installAndGetSomeConfig(); // reinitialize the configuration to make sure the actual port is used System.clearProperty("test.url"); // make sure the old value does not interfere with setting the new one System.setProperty("test.url", TestHTTPResourceManager.getUri()); } diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/TestConfigUtil.java b/test-framework/common/src/main/java/io/quarkus/test/common/TestConfigUtil.java index 8c6e128b28ad7..8b394c258958b 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/TestConfigUtil.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/TestConfigUtil.java @@ -18,6 +18,7 @@ public final class TestConfigUtil { private TestConfigUtil() { } + @Deprecated(forRemoval = true, since = "3.17") public static List argLineValue(Config config) { String strValue = config.getOptionalValue("quarkus.test.arg-line", String.class) .orElse(config.getOptionalValue("quarkus.test.argLine", String.class) // legacy value @@ -37,17 +38,20 @@ public static List argLineValue(Config config) { return result; } + @Deprecated(forRemoval = true, since = "3.17") public static Map env(Config config) { return ((SmallRyeConfig) config).getOptionalValues("quarkus.test.env", String.class, String.class) .orElse(Collections.emptyMap()); } + @Deprecated(forRemoval = true, since = "3.17") public static Duration waitTimeValue(Config config) { return config.getOptionalValue("quarkus.test.wait-time", Duration.class) .orElseGet(() -> config.getOptionalValue("quarkus.test.jar-wait-time", Duration.class) // legacy value .orElseGet(() -> Duration.ofSeconds(DEFAULT_WAIT_TIME_SECONDS))); } + @Deprecated(forRemoval = true, since = "3.17") public static String integrationTestProfile(Config config) { return config.getOptionalValue("quarkus.test.integration-test-profile", String.class) .orElseGet(() -> config.getOptionalValue("quarkus.test.native-image-profile", String.class) diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestUtil.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestUtil.java index 41b99f9d82c99..2e0cadbf4f15e 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestUtil.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestUtil.java @@ -29,7 +29,7 @@ import jakarta.inject.Inject; import org.apache.commons.lang3.RandomStringUtils; -import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.jandex.Index; import org.junit.jupiter.api.extension.ExtensionContext; @@ -49,7 +49,6 @@ import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.logging.LoggingSetupRecorder; import io.quarkus.test.common.ArtifactLauncher; -import io.quarkus.test.common.LauncherUtil; import io.quarkus.test.common.PathTestHelper; import io.quarkus.test.common.TestClassIndexer; import io.quarkus.test.common.TestResourceManager; @@ -276,9 +275,8 @@ public void accept(String s, String s2) { } catch (Exception e) { // use the network the use has specified or else just generate one if none is configured - Config config = LauncherUtil.installAndGetSomeConfig(); - Optional networkIdOpt = config - .getOptionalValue("quarkus.test.container.network", String.class); + Optional networkIdOpt = ConfigProvider.getConfig().getOptionalValue("quarkus.test.container.network", + String.class); if (networkIdOpt.isPresent()) { networkId = networkIdOpt.get(); } else { diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java index 84f460e27704e..1c1b3c7429c00 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java @@ -19,7 +19,6 @@ import java.io.File; import java.lang.reflect.Field; import java.nio.file.Path; -import java.time.Duration; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -31,7 +30,7 @@ import java.util.function.Function; import java.util.stream.Collectors; -import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.AfterTestExecutionCallback; @@ -44,11 +43,11 @@ import io.quarkus.bootstrap.app.CuratedApplication; import io.quarkus.bootstrap.logging.InitialConfigurator; +import io.quarkus.deployment.dev.testing.TestConfig; import io.quarkus.runtime.logging.JBossVersion; import io.quarkus.runtime.test.TestHttpEndpointProvider; import io.quarkus.test.common.ArtifactLauncher; import io.quarkus.test.common.DevServicesContext; -import io.quarkus.test.common.LauncherUtil; import io.quarkus.test.common.PropertyTestUtil; import io.quarkus.test.common.RestAssuredURLManager; import io.quarkus.test.common.RunCommandLauncher; @@ -58,6 +57,7 @@ import io.quarkus.test.common.TestScopeManager; import io.quarkus.test.junit.callback.QuarkusTestMethodContext; import io.quarkus.test.junit.launcher.ArtifactLauncherProvider; +import io.smallrye.config.SmallRyeConfig; public class QuarkusIntegrationTestExtension extends AbstractQuarkusTestWithContextExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback, BeforeEachCallback, AfterEachCallback, @@ -193,10 +193,10 @@ private QuarkusTestExtensionState doProcessStart(Properties quarkusArtifactPrope String artifactType = getArtifactType(quarkusArtifactProperties); - Config config = LauncherUtil.installAndGetSomeConfig(); - String testProfile = TestConfigUtil.integrationTestProfile(config); + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + TestConfig testConfig = config.getConfigMapping(TestConfig.class); boolean isDockerLaunch = isContainer(artifactType) - || (isJar(artifactType) && "test-with-native-agent".equals(testProfile)); + || (isJar(artifactType) && "test-with-native-agent".equals(testConfig.integrationTestProfile())); ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult = handleDevServices(context, isDockerLaunch); @@ -269,20 +269,19 @@ public void close() throws Throwable { }); additionalProperties.putAll(resourceManagerProps); - ArtifactLauncher launcher = null; + ArtifactLauncher launcher; String testHost = System.getProperty("quarkus.http.test-host"); if ((testHost != null) && !testHost.isEmpty()) { launcher = new TestHostLauncher(); } else { - Duration waitDuration = TestConfigUtil.waitTimeValue(config); String target = TestConfigUtil.runTarget(config); // try to execute a run command published by an extension if it exists. We do this so that extensions that have a custom run don't have to create any special artifact type launcher = RunCommandLauncher.tryLauncher(devServicesLaunchResult.getCuratedApplication().getQuarkusBootstrap(), - target, waitDuration); + target, testConfig.waitTime()); if (launcher == null) { ServiceLoader loader = ServiceLoader.load(ArtifactLauncherProvider.class); for (ArtifactLauncherProvider launcherProvider : loader) { - if (launcherProvider.supportsArtifactType(artifactType, testProfile)) { + if (launcherProvider.supportsArtifactType(artifactType, testConfig.integrationTestProfile())) { launcher = launcherProvider.create( new DefaultArtifactLauncherCreateContext(quarkusArtifactProperties, context, requiredTestClass, @@ -378,7 +377,7 @@ private void throwBootFailureException() { private boolean isCallbacksEnabledForIntegrationTests() { return Optional.ofNullable(System.getProperty(ENABLED_CALLBACKS_PROPERTY)).map(Boolean::parseBoolean) - .or(() -> LauncherUtil.installAndGetSomeConfig().getOptionalValue(ENABLED_CALLBACKS_PROPERTY, Boolean.class)) + .or(() -> ConfigProvider.getConfig().getOptionalValue(ENABLED_CALLBACKS_PROPERTY, Boolean.class)) .orElse(false); } diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusMainIntegrationTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusMainIntegrationTestExtension.java index a7dea2f0c0fc1..b2b3c9ae6dae7 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusMainIntegrationTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusMainIntegrationTestExtension.java @@ -17,7 +17,7 @@ import java.util.Properties; import java.util.ServiceLoader; -import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; @@ -26,16 +26,16 @@ import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.extension.ParameterResolver; +import io.quarkus.deployment.dev.testing.TestConfig; import io.quarkus.runtime.logging.JBossVersion; import io.quarkus.test.common.ArtifactLauncher; -import io.quarkus.test.common.LauncherUtil; -import io.quarkus.test.common.TestConfigUtil; import io.quarkus.test.common.TestResourceManager; import io.quarkus.test.junit.launcher.ArtifactLauncherProvider; import io.quarkus.test.junit.main.Launch; import io.quarkus.test.junit.main.LaunchResult; import io.quarkus.test.junit.main.QuarkusMainLauncher; import io.quarkus.test.junit.util.CloseAdaptor; +import io.smallrye.config.SmallRyeConfig; public class QuarkusMainIntegrationTestExtension extends AbstractQuarkusTestWithContextExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver { @@ -157,13 +157,13 @@ private ArtifactLauncher.LaunchResult doProcessStart(ExtensionContext context, S testResourceManager.inject(context.getRequiredTestInstance()); - Config config = LauncherUtil.installAndGetSomeConfig(); - String testProfile = TestConfigUtil.integrationTestProfile(config); + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + TestConfig testConfig = config.getConfigMapping(TestConfig.class); ArtifactLauncher launcher = null; ServiceLoader loader = ServiceLoader.load(ArtifactLauncherProvider.class); for (ArtifactLauncherProvider launcherProvider : loader) { - if (launcherProvider.supportsArtifactType(artifactType, testProfile)) { + if (launcherProvider.supportsArtifactType(artifactType, testConfig.integrationTestProfile())) { launcher = launcherProvider.create( new DefaultArtifactLauncherCreateContext(quarkusArtifactProperties, context, requiredTestClass, devServicesLaunchResult)); diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java index 319ebcbaed462..e475c7e4e28aa 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java @@ -17,13 +17,14 @@ import java.util.OptionalInt; import java.util.ServiceLoader; +import org.eclipse.microprofile.config.ConfigProvider; + +import io.quarkus.deployment.dev.testing.TestConfig; import io.quarkus.deployment.images.ContainerImages; import io.quarkus.deployment.util.FileUtil; import io.quarkus.test.common.ArtifactLauncher; import io.quarkus.test.common.DefaultDockerContainerLauncher; import io.quarkus.test.common.DockerContainerArtifactLauncher; -import io.quarkus.test.common.LauncherUtil; -import io.quarkus.test.common.TestConfigUtil; import io.smallrye.config.SmallRyeConfig; public class DockerContainerLauncherProvider implements ArtifactLauncherProvider { @@ -38,6 +39,7 @@ public DockerContainerArtifactLauncher create(CreateContext context) { String containerImage = context.quarkusArtifactProperties().getProperty("metadata.container-image"); boolean pullRequired = Boolean .parseBoolean(context.quarkusArtifactProperties().getProperty("metadata.pull-required", "false")); + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); if ((containerImage != null) && !containerImage.isEmpty()) { DockerContainerArtifactLauncher launcher; ServiceLoader loader = ServiceLoader.load(DockerContainerArtifactLauncher.class); @@ -47,7 +49,6 @@ public DockerContainerArtifactLauncher create(CreateContext context) { } else { launcher = new DefaultDockerContainerLauncher(); } - SmallRyeConfig config = (SmallRyeConfig) LauncherUtil.installAndGetSomeConfig(); launcherInit(context, launcher, config, containerImage, pullRequired, Optional.empty(), volumeMounts(config), Collections.emptyList()); return launcher; @@ -59,10 +60,8 @@ public DockerContainerArtifactLauncher create(CreateContext context) { // adding a volume mapping pointing to the build output directory, // and then instructing the java process to run the run jar, // along with the native image agent arguments and any other additional parameters. - SmallRyeConfig config = (SmallRyeConfig) LauncherUtil.installAndGetSomeConfig(); - String testProfile = TestConfigUtil.integrationTestProfile(config); - - if ("test-with-native-agent".equals(testProfile)) { + TestConfig testConfig = config.getConfigMapping(TestConfig.class); + if ("test-with-native-agent".equals(testConfig.integrationTestProfile())) { DockerContainerArtifactLauncher launcher = new DefaultDockerContainerLauncher(); Optional entryPoint = Optional.of("java"); Map volumeMounts = new HashMap<>(volumeMounts(config)); @@ -83,13 +82,14 @@ public DockerContainerArtifactLauncher create(CreateContext context) { private void launcherInit(CreateContext context, DockerContainerArtifactLauncher launcher, SmallRyeConfig config, String containerImage, boolean pullRequired, Optional entryPoint, Map volumeMounts, List programArgs) { + TestConfig testConfig = config.getConfigMapping(TestConfig.class); launcher.init(new DefaultDockerInitContext( config.getValue("quarkus.http.test-port", OptionalInt.class).orElse(DEFAULT_PORT), config.getValue("quarkus.http.test-ssl-port", OptionalInt.class).orElse(DEFAULT_HTTPS_PORT), - TestConfigUtil.waitTimeValue(config), - TestConfigUtil.integrationTestProfile(config), - TestConfigUtil.argLineValue(config), - TestConfigUtil.env(config), + testConfig.waitTime(), + testConfig.integrationTestProfile(), + testConfig.argLine().orElse(List.of()), + testConfig.env(), context.devServicesLaunchResult(), containerImage, pullRequired, diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/JarLauncherProvider.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/JarLauncherProvider.java index ef360c7500053..3a6c6104227cf 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/JarLauncherProvider.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/JarLauncherProvider.java @@ -12,13 +12,13 @@ import java.util.OptionalInt; import java.util.ServiceLoader; -import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; +import io.quarkus.deployment.dev.testing.TestConfig; import io.quarkus.test.common.ArtifactLauncher; import io.quarkus.test.common.DefaultJarLauncher; import io.quarkus.test.common.JarArtifactLauncher; -import io.quarkus.test.common.LauncherUtil; -import io.quarkus.test.common.TestConfigUtil; +import io.smallrye.config.SmallRyeConfig; public class JarLauncherProvider implements ArtifactLauncherProvider { @@ -40,14 +40,15 @@ public JarArtifactLauncher create(CreateContext context) { launcher = new DefaultJarLauncher(); } - Config config = LauncherUtil.installAndGetSomeConfig(); + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + TestConfig testConfig = config.getConfigMapping(TestConfig.class); launcher.init(new DefaultJarInitContext( config.getValue("quarkus.http.test-port", OptionalInt.class).orElse(DEFAULT_PORT), config.getValue("quarkus.http.test-ssl-port", OptionalInt.class).orElse(DEFAULT_HTTPS_PORT), - TestConfigUtil.waitTimeValue(config), - TestConfigUtil.integrationTestProfile(config), - TestConfigUtil.argLineValue(config), - TestConfigUtil.env(config), + testConfig.waitTime(), + testConfig.integrationTestProfile(), + testConfig.argLine().orElse(List.of()), + testConfig.env(), context.devServicesLaunchResult(), context.buildOutputDirectory().resolve(pathStr))); return launcher; diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/NativeImageLauncherProvider.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/NativeImageLauncherProvider.java index e33465517c0c2..a9b2e2138e2cc 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/NativeImageLauncherProvider.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/NativeImageLauncherProvider.java @@ -11,13 +11,13 @@ import java.util.OptionalInt; import java.util.ServiceLoader; -import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; +import io.quarkus.deployment.dev.testing.TestConfig; import io.quarkus.test.common.ArtifactLauncher; import io.quarkus.test.common.DefaultNativeImageLauncher; -import io.quarkus.test.common.LauncherUtil; import io.quarkus.test.common.NativeImageLauncher; -import io.quarkus.test.common.TestConfigUtil; +import io.smallrye.config.SmallRyeConfig; public class NativeImageLauncherProvider implements ArtifactLauncherProvider { @Override @@ -38,14 +38,15 @@ public NativeImageLauncher create(CreateContext context) { launcher = new DefaultNativeImageLauncher(); } - Config config = LauncherUtil.installAndGetSomeConfig(); + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + TestConfig testConfig = config.getConfigMapping(TestConfig.class); launcher.init(new NativeImageLauncherProvider.DefaultNativeImageInitContext( config.getValue("quarkus.http.test-port", OptionalInt.class).orElse(DEFAULT_PORT), config.getValue("quarkus.http.test-ssl-port", OptionalInt.class).orElse(DEFAULT_HTTPS_PORT), - TestConfigUtil.waitTimeValue(config), - TestConfigUtil.integrationTestProfile(config), - TestConfigUtil.argLineValue(config), - TestConfigUtil.env(config), + testConfig.waitTime(), + testConfig.nativeImageProfile(), + testConfig.argLine().orElse(List.of()), + testConfig.env(), context.devServicesLaunchResult(), System.getProperty("native.image.path"), config.getOptionalValue("quarkus.package.output-directory", String.class).orElse(null), From 82d6147a2640d5df60117a1f862d68ff67e94842 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 22:15:31 +0000 Subject: [PATCH 115/207] Bump elasticsearch-opensource-components.version from 8.16.1 to 8.17.0 Bumps `elasticsearch-opensource-components.version` from 8.16.1 to 8.17.0. Updates `org.elasticsearch.client:elasticsearch-rest-client` from 8.16.1 to 8.17.0 - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/main/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v8.16.1...v8.17.0) Updates `co.elastic.clients:elasticsearch-java` from 8.16.1 to 8.17.0 - [Release notes](https://github.com/elastic/elasticsearch-java/releases) - [Changelog](https://github.com/elastic/elasticsearch-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch-java/compare/v8.16.1...v8.17.0) Updates `org.elasticsearch.client:elasticsearch-rest-client-sniffer` from 8.16.1 to 8.17.0 - [Release notes](https://github.com/elastic/elasticsearch/releases) - [Changelog](https://github.com/elastic/elasticsearch/blob/main/CHANGELOG.md) - [Commits](https://github.com/elastic/elasticsearch/compare/v8.16.1...v8.17.0) --- updated-dependencies: - dependency-name: org.elasticsearch.client:elasticsearch-rest-client dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: co.elastic.clients:elasticsearch-java dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.elasticsearch.client:elasticsearch-rest-client-sniffer dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 1d938ae0d487a..ba46095192459 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -99,7 +99,7 @@ 0.0.9.Final 2.5 8.0.0.Final - 8.16.1 + 8.17.0 2.2.21 2.2.5.Final 2.2.2.SP01 From 498a96a7278d15e024c140511fa22d311579a09a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 22:17:57 +0000 Subject: [PATCH 116/207] Bump flyway.version from 11.0.1 to 11.1.0 Bumps `flyway.version` from 11.0.1 to 11.1.0. Updates `org.flywaydb:flyway-core` from 11.0.1 to 11.1.0 - [Release notes](https://github.com/flyway/flyway/releases) - [Commits](https://github.com/flyway/flyway/compare/flyway-11.0.1...flyway-11.1.0) Updates `org.flywaydb:flyway-sqlserver` from 11.0.1 to 11.1.0 Updates `org.flywaydb:flyway-mysql` from 11.0.1 to 11.1.0 Updates `org.flywaydb:flyway-database-oracle` from 11.0.1 to 11.1.0 Updates `org.flywaydb:flyway-database-postgresql` from 11.0.1 to 11.1.0 Updates `org.flywaydb:flyway-database-db2` from 11.0.1 to 11.1.0 Updates `org.flywaydb:flyway-database-derby` from 11.0.1 to 11.1.0 Updates `org.flywaydb:flyway-database-mongodb` from 11.0.1 to 11.1.0 --- updated-dependencies: - dependency-name: org.flywaydb:flyway-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.flywaydb:flyway-sqlserver dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.flywaydb:flyway-mysql dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.flywaydb:flyway-database-oracle dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.flywaydb:flyway-database-postgresql dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.flywaydb:flyway-database-db2 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.flywaydb:flyway-database-derby dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.flywaydb:flyway-database-mongodb dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 1d938ae0d487a..c8ff760db7886 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -158,7 +158,7 @@ 3.2.0 4.2.2 3.1.1.Final - 11.0.1 + 11.1.0 3.0.4 4.29.1 From 90c98ce9df5aabbf6022743bd58cb706078bbad9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 22:20:11 +0000 Subject: [PATCH 117/207] Bump com.gradle:develocity-maven-extension from 1.22.2 to 1.23 Bumps com.gradle:develocity-maven-extension from 1.22.2 to 1.23. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index e512e56a78585..9c438a9c1d96d 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,7 +2,7 @@ com.gradle develocity-maven-extension - 1.22.2 + 1.23 com.gradle From e0f250950de3aa34ef7e0a57671bedc5bcf3adce Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Thu, 12 Dec 2024 11:42:46 +0100 Subject: [PATCH 118/207] More efficient dependency tree conflict resolver --- .../runnerjar/OptionalDepsTest.java | 70 ++++++++++-- .../maven/DependencyTreeConflictResolver.java | 101 ++++++++++++++++++ .../IncubatingApplicationModelResolver.java | 58 ++++++---- .../maven/OrderedDependencyVisitor.java | 59 ++++++++-- .../maven/OrderedDependencyVisitorTest.java | 13 +++ 5 files changed, 262 insertions(+), 39 deletions(-) create mode 100644 independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/DependencyTreeConflictResolver.java diff --git a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/OptionalDepsTest.java b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/OptionalDepsTest.java index 949b145da1b7b..2d64701a4593c 100644 --- a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/OptionalDepsTest.java +++ b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/OptionalDepsTest.java @@ -5,14 +5,16 @@ import java.util.HashSet; import java.util.Set; +import org.eclipse.aether.util.artifact.JavaScopes; + import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.resolver.TsArtifact; import io.quarkus.bootstrap.resolver.TsDependency; import io.quarkus.bootstrap.resolver.TsQuarkusExt; +import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.ArtifactDependency; import io.quarkus.maven.dependency.Dependency; import io.quarkus.maven.dependency.DependencyFlags; -import io.quarkus.maven.dependency.GACTV; public class OptionalDepsTest extends BootstrapFromOriginalJarTestBase { @@ -70,17 +72,73 @@ protected TsArtifact composeApplication() { @Override protected void assertAppModel(ApplicationModel model) throws Exception { final Set expected = new HashSet<>(); - expected.add(new ArtifactDependency(new GACTV("io.quarkus.bootstrap.test", "ext-a-deployment", "1"), "compile", + + expected.add(new ArtifactDependency( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-a", TsArtifact.DEFAULT_VERSION), + JavaScopes.COMPILE, + DependencyFlags.DIRECT, + DependencyFlags.OPTIONAL, + DependencyFlags.RUNTIME_EXTENSION_ARTIFACT, + DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT, + DependencyFlags.RUNTIME_CP, + DependencyFlags.DEPLOYMENT_CP)); + + expected.add(new ArtifactDependency( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-a-dep", TsArtifact.DEFAULT_VERSION), + JavaScopes.COMPILE, + DependencyFlags.OPTIONAL, + DependencyFlags.RUNTIME_CP, + DependencyFlags.DEPLOYMENT_CP)); + + expected.add(new ArtifactDependency( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-a-deployment", TsArtifact.DEFAULT_VERSION), + JavaScopes.COMPILE, + DependencyFlags.OPTIONAL, + DependencyFlags.DEPLOYMENT_CP)); + + expected.add(new ArtifactDependency( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "app-optional-dep", TsArtifact.DEFAULT_VERSION), + JavaScopes.COMPILE, DependencyFlags.OPTIONAL, + DependencyFlags.DIRECT, + DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP)); - expected.add(new ArtifactDependency(new GACTV("io.quarkus.bootstrap.test", "ext-b-deployment-dep", "1"), "compile", + + expected.add(new ArtifactDependency( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-b", TsArtifact.DEFAULT_VERSION), + JavaScopes.COMPILE, + DependencyFlags.OPTIONAL, + DependencyFlags.RUNTIME_EXTENSION_ARTIFACT, + DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT, + DependencyFlags.RUNTIME_CP, + DependencyFlags.DEPLOYMENT_CP)); + + expected.add(new ArtifactDependency(ArtifactCoords.jar( + TsArtifact.DEFAULT_GROUP_ID, "ext-b-deployment", TsArtifact.DEFAULT_VERSION), + JavaScopes.COMPILE, DependencyFlags.OPTIONAL, DependencyFlags.DEPLOYMENT_CP)); - expected.add(new ArtifactDependency(new GACTV("io.quarkus.bootstrap.test", "ext-b-deployment", "1"), "compile", + + expected.add(new ArtifactDependency( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-b-deployment-dep", TsArtifact.DEFAULT_VERSION), + JavaScopes.COMPILE, DependencyFlags.OPTIONAL, DependencyFlags.DEPLOYMENT_CP)); - expected.add(new ArtifactDependency(new GACTV("io.quarkus.bootstrap.test", "ext-d-deployment", "1"), "compile", + + expected.add(new ArtifactDependency( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-d", TsArtifact.DEFAULT_VERSION), + JavaScopes.COMPILE, + DependencyFlags.DIRECT, + DependencyFlags.RUNTIME_EXTENSION_ARTIFACT, + DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT, + DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP)); - assertEquals(expected, getDeploymentOnlyDeps(model)); + + expected.add(new ArtifactDependency( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-d-deployment", TsArtifact.DEFAULT_VERSION), + JavaScopes.COMPILE, + DependencyFlags.DEPLOYMENT_CP)); + + assertEquals(expected, getDependenciesWithFlag(model, DependencyFlags.DEPLOYMENT_CP)); } } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/DependencyTreeConflictResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/DependencyTreeConflictResolver.java new file mode 100644 index 0000000000000..999b9fb3d6cb2 --- /dev/null +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/DependencyTreeConflictResolver.java @@ -0,0 +1,101 @@ +package io.quarkus.bootstrap.resolver.maven; + +import static io.quarkus.bootstrap.util.DependencyUtils.getKey; +import static io.quarkus.bootstrap.util.DependencyUtils.hasWinner; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.aether.collection.DependencyGraphTransformationContext; +import org.eclipse.aether.graph.DefaultDependencyNode; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.util.artifact.JavaScopes; +import org.eclipse.aether.util.graph.transformer.ConflictResolver; + +import io.quarkus.maven.dependency.ArtifactKey; + +/** + * Dependency tree conflict resolver. + *

    + * The idea is to have a more efficient implementation than the + * {@link org.eclipse.aether.util.graph.transformer.ConflictIdSorter#transformGraph(DependencyNode, DependencyGraphTransformationContext)} + * for the use-cases the Quarkus deployment dependency resolver is designed for. + *

    + * Specifically, this conflict resolver does not properly handle version ranges, that are not expected to be present in the + * phase it used. + */ +class DependencyTreeConflictResolver { + + /** + * Resolves dependency version conflicts in the given dependency tree. + * + * @param root the root of the dependency tree + */ + static void resolveConflicts(DependencyNode root) { + new DependencyTreeConflictResolver(root).run(); + } + + final OrderedDependencyVisitor visitor; + + private DependencyTreeConflictResolver(DependencyNode root) { + visitor = new OrderedDependencyVisitor(root); + } + + private void run() { + visitor.next();// skip the root + final Map visited = new HashMap<>(); + while (visitor.hasNext()) { + var node = visitor.next(); + if (!hasWinner(node)) { + visited.compute(getKey(node.getArtifact()), this::resolveConflict); + } + } + } + + private VisitedDependency resolveConflict(ArtifactKey key, VisitedDependency prev) { + if (prev == null) { + return new VisitedDependency(visitor); + } + prev.resolveConflict(visitor); + return prev; + } + + private static class VisitedDependency { + final DependencyNode node; + final int subtreeIndex; + + private VisitedDependency(OrderedDependencyVisitor visitor) { + this.node = visitor.getCurrent(); + this.subtreeIndex = visitor.getSubtreeIndex(); + } + + private void resolveConflict(OrderedDependencyVisitor visitor) { + var otherNode = visitor.getCurrent(); + if (subtreeIndex != visitor.getSubtreeIndex()) { + final Dependency currentDep = node.getDependency(); + final Dependency otherDep = otherNode.getDependency(); + if (!currentDep.getScope().equals(otherDep.getScope()) + && getScopePriority(currentDep.getScope()) > getScopePriority(otherDep.getScope())) { + node.setScope(otherDep.getScope()); + } + if (currentDep.isOptional() && !otherDep.isOptional()) { + node.setOptional(false); + } + } + otherNode.setChildren(List.of()); + otherNode.setData(ConflictResolver.NODE_DATA_WINNER, new DefaultDependencyNode(node.getDependency())); + } + } + + private static int getScopePriority(String scope) { + return switch (scope) { + case JavaScopes.COMPILE -> 0; + case JavaScopes.RUNTIME -> 1; + case JavaScopes.PROVIDED -> 2; + case JavaScopes.TEST -> 3; + default -> 4; + }; + } +} diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java index 23fac1e5f4725..faf14cf8dc61e 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java @@ -25,12 +25,9 @@ import java.util.function.BiConsumer; import org.eclipse.aether.DefaultRepositorySystemSession; -import org.eclipse.aether.RepositoryException; -import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.collection.DependencyCollectionException; -import org.eclipse.aether.collection.DependencyGraphTransformationContext; import org.eclipse.aether.collection.DependencySelector; import org.eclipse.aether.graph.DefaultDependencyNode; import org.eclipse.aether.graph.Dependency; @@ -43,7 +40,6 @@ import org.eclipse.aether.util.artifact.JavaScopes; import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector; -import org.eclipse.aether.util.graph.transformer.ConflictIdSorter; import org.eclipse.aether.util.graph.transformer.ConflictResolver; import org.jboss.logging.Logger; @@ -251,7 +247,7 @@ public void resolve(CollectRequest collectRtDepsRequest) throws AppModelResolver if (!runtimeModelOnly) { injectDeploymentDeps(); } - root = normalize(resolver.getSession(), root); + DependencyTreeConflictResolver.resolveConflicts(root); populateModelBuilder(root); // clear the reloadable flags @@ -464,18 +460,6 @@ private void clearReloadableFlag(ResolvedDependencyBuilder dep) { } } - private static DependencyNode normalize(RepositorySystemSession session, DependencyNode root) - throws AppModelResolverException { - final DependencyGraphTransformationContext context = new SimpleDependencyGraphTransformationContext(session); - try { - // resolves version conflicts - root = new ConflictIdSorter().transformGraph(root, context); - return session.getDependencyGraphTransformer().transformGraph(root, context); - } catch (RepositoryException e) { - throw new AppModelResolverException("Failed to resolve dependency graph conflicts", e); - } - } - /** * Resolves a project's runtime dependencies. This is the first step in the Quarkus application model resolution. * These dependencies do not include Quarkus conditional dependencies. @@ -977,6 +961,8 @@ private void collectDeploymentDeps() { + "or the artifact does not have any dependencies while at least a dependency on the runtime artifact " + info.runtimeArtifact + " is expected"); } + ensureScopeAndOptionality(deploymentNode, runtimeNode.getDependency().getScope(), + runtimeNode.getDependency().isOptional()); replaceRuntimeExtensionNodes(deploymentNode); if (!presentInTargetGraph) { @@ -1058,9 +1044,13 @@ void activate() { return; } activated = true; + final AppDep parent = conditionalDep.parent; final DependencyNode originalNode = collectDependencies(conditionalDep.node.getArtifact(), - conditionalDep.parent.ext.exclusions, - conditionalDep.parent.node.getRepositories()); + parent.ext.exclusions, + parent.node.getRepositories()); + ensureScopeAndOptionality(originalNode, parent.ext.runtimeNode.getDependency().getScope(), + parent.ext.runtimeNode.getDependency().isOptional()); + final DefaultDependencyNode rtNode = (DefaultDependencyNode) conditionalDep.node; rtNode.setRepositories(originalNode.getRepositories()); // if this node has conditional dependencies on its own, they may have been activated by this time @@ -1077,10 +1067,10 @@ void activate() { visitRuntimeDeps(); conditionalDep.setFlags( (byte) (COLLECT_DEPLOYMENT_INJECTION_POINTS | (collectReloadableModules ? COLLECT_RELOADABLE_MODULES : 0))); - if (conditionalDep.parent.resolvedDep != null) { - conditionalDep.parent.resolvedDep.addDependency(conditionalDep.resolvedDep.getArtifactCoords()); + if (parent.resolvedDep != null) { + parent.resolvedDep.addDependency(conditionalDep.resolvedDep.getArtifactCoords()); } - conditionalDep.parent.ext.runtimeNode.getChildren().add(rtNode); + parent.ext.runtimeNode.getChildren().add(rtNode); } private void visitRuntimeDeps() { @@ -1103,6 +1093,30 @@ boolean isSatisfied() { } } + /** + * Makes sure the node's dependency scope and optionality (including its children) match the expected values. + * + * @param node dependency node + * @param scope expected scope + * @param optional expected optionality + */ + private static void ensureScopeAndOptionality(DependencyNode node, String scope, boolean optional) { + var dep = node.getDependency(); + if (optional == dep.isOptional() && scope.equals(dep.getScope())) { + return; + } + var visitor = new OrderedDependencyVisitor(node); + while (visitor.hasNext()) { + dep = visitor.next().getDependency(); + if (optional != dep.isOptional()) { + visitor.getCurrent().setOptional(optional); + } + if (!scope.equals(dep.getScope())) { + visitor.getCurrent().setScope(scope); + } + } + } + private static boolean isSameKey(Artifact a1, Artifact a2) { return a2.getArtifactId().equals(a1.getArtifactId()) && a2.getGroupId().equals(a1.getGroupId()) diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/OrderedDependencyVisitor.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/OrderedDependencyVisitor.java index ae23a0f8c98c6..4c221dc96e370 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/OrderedDependencyVisitor.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/OrderedDependencyVisitor.java @@ -13,8 +13,8 @@ */ class OrderedDependencyVisitor { - private final Deque> stack = new ArrayDeque<>(); - private List currentList; + private final Deque stack = new ArrayDeque<>(); + private DependencyList currentList; private int currentIndex = -1; private int currentDistance; private int totalOnCurrentDistance = 1; @@ -26,7 +26,7 @@ class OrderedDependencyVisitor { * @param root the root of the dependency tree */ OrderedDependencyVisitor(DependencyNode root) { - currentList = List.of(root); + currentList = new DependencyList(0, List.of(root)); } /** @@ -36,7 +36,7 @@ class OrderedDependencyVisitor { */ DependencyNode getCurrent() { ensureNonNegativeIndex(); - return currentList.get(currentIndex); + return currentList.deps.get(currentIndex); } /** @@ -62,8 +62,8 @@ private void ensureNonNegativeIndex() { */ boolean hasNext() { return !stack.isEmpty() - || currentIndex + 1 < currentList.size() - || !currentList.get(currentIndex).getChildren().isEmpty(); + || currentIndex + 1 < currentList.deps.size() + || !currentList.deps.get(currentIndex).getChildren().isEmpty(); } /** @@ -76,9 +76,9 @@ DependencyNode next() { throw new NoSuchElementException(); } if (currentIndex >= 0) { - var children = currentList.get(currentIndex).getChildren(); + var children = currentList.deps.get(currentIndex).getChildren(); if (!children.isEmpty()) { - stack.addLast(children); + stack.addLast(new DependencyList(getSubtreeIndexForChildren(), children)); totalOnNextDistance += children.size(); } if (--totalOnCurrentDistance == 0) { @@ -87,11 +87,33 @@ DependencyNode next() { totalOnNextDistance = 0; } } - if (++currentIndex == currentList.size()) { + if (++currentIndex == currentList.deps.size()) { currentList = stack.removeFirst(); currentIndex = 0; } - return currentList.get(currentIndex); + return currentList.deps.get(currentIndex); + } + + private int getSubtreeIndexForChildren() { + return currentDistance < 2 ? currentIndex + 1 : currentList.subtreeIndex; + } + + /** + * A dependency subtree index the current dependency belongs to. + * + *

    + * A dependency subtree index is an index of a direct dependency of the root of the dependency tree + * from which the dependency subtree originates. All the dependencies from a subtree that originates + * from a direct dependency of the root of the dependency tree will share the same subtree index. + * + *

    + * A dependency subtree index starts from {@code 1}. An exception is the root of the dependency tree, + * which will have the subtree index of {@code 0}. + * + * @return dependency subtree index the current dependency belongs to + */ + int getSubtreeIndex() { + return currentDistance == 0 ? 0 : (currentDistance < 2 ? currentIndex + 1 : currentList.subtreeIndex); } /** @@ -100,6 +122,21 @@ DependencyNode next() { * @param newNode dependency node that should replace the current one in the tree */ void replaceCurrent(DependencyNode newNode) { - currentList.set(currentIndex, newNode); + currentList.deps.set(currentIndex, newNode); + } + + /** + * A list of dependencies that are children of a {@link DependencyNode} + * that are associated with a dependency subtree index. + */ + private static class DependencyList { + + private final int subtreeIndex; + private final List deps; + + public DependencyList(int branchIndex, List deps) { + this.subtreeIndex = branchIndex; + this.deps = deps; + } } } diff --git a/independent-projects/bootstrap/maven-resolver/src/test/java/io/quarkus/bootstrap/resolver/maven/OrderedDependencyVisitorTest.java b/independent-projects/bootstrap/maven-resolver/src/test/java/io/quarkus/bootstrap/resolver/maven/OrderedDependencyVisitorTest.java index b77d7ef1d1932..300df5904403a 100644 --- a/independent-projects/bootstrap/maven-resolver/src/test/java/io/quarkus/bootstrap/resolver/maven/OrderedDependencyVisitorTest.java +++ b/independent-projects/bootstrap/maven-resolver/src/test/java/io/quarkus/bootstrap/resolver/maven/OrderedDependencyVisitorTest.java @@ -59,77 +59,90 @@ public void main() { assertThat(visitor.next()).isSameAs(root); assertThat(visitor.getCurrent()).isSameAs(root); assertThat(visitor.getCurrentDistance()).isEqualTo(0); + assertThat(visitor.getSubtreeIndex()).isEqualTo(0); assertThat(visitor.hasNext()).isTrue(); // distance 1, colors assertThat(visitor.next()).isSameAs(colors); assertThat(visitor.getCurrent()).isSameAs(colors); assertThat(visitor.getCurrentDistance()).isEqualTo(1); + assertThat(visitor.getSubtreeIndex()).isEqualTo(1); assertThat(visitor.hasNext()).isTrue(); // distance 1, pets assertThat(visitor.next()).isSameAs(pets); assertThat(visitor.getCurrent()).isSameAs(pets); assertThat(visitor.getCurrentDistance()).isEqualTo(1); + assertThat(visitor.getSubtreeIndex()).isEqualTo(2); assertThat(visitor.hasNext()).isTrue(); // distance 1, trees assertThat(visitor.next()).isSameAs(trees); assertThat(visitor.getCurrent()).isSameAs(trees); assertThat(visitor.getCurrentDistance()).isEqualTo(1); + assertThat(visitor.getSubtreeIndex()).isEqualTo(3); assertThat(visitor.hasNext()).isTrue(); // distance 2, colors, red assertThat(visitor.next()).isSameAs(red); assertThat(visitor.getCurrent()).isSameAs(red); assertThat(visitor.getCurrentDistance()).isEqualTo(2); + assertThat(visitor.getSubtreeIndex()).isEqualTo(1); assertThat(visitor.hasNext()).isTrue(); // distance 2, colors, green assertThat(visitor.next()).isSameAs(green); assertThat(visitor.getCurrent()).isSameAs(green); assertThat(visitor.getCurrentDistance()).isEqualTo(2); + assertThat(visitor.getSubtreeIndex()).isEqualTo(1); assertThat(visitor.hasNext()).isTrue(); // distance 2, colors, blue assertThat(visitor.next()).isSameAs(blue); assertThat(visitor.getCurrent()).isSameAs(blue); assertThat(visitor.getCurrentDistance()).isEqualTo(2); + assertThat(visitor.getSubtreeIndex()).isEqualTo(1); assertThat(visitor.hasNext()).isTrue(); // distance 2, pets, dog assertThat(visitor.next()).isSameAs(dog); assertThat(visitor.getCurrent()).isSameAs(dog); assertThat(visitor.getCurrentDistance()).isEqualTo(2); + assertThat(visitor.getSubtreeIndex()).isEqualTo(2); assertThat(visitor.hasNext()).isTrue(); // distance 2, pets, cat assertThat(visitor.next()).isSameAs(cat); assertThat(visitor.getCurrent()).isSameAs(cat); assertThat(visitor.getCurrentDistance()).isEqualTo(2); + assertThat(visitor.getSubtreeIndex()).isEqualTo(2); assertThat(visitor.hasNext()).isTrue(); // distance 2, trees, pine assertThat(visitor.next()).isSameAs(pine); assertThat(visitor.getCurrent()).isSameAs(pine); assertThat(visitor.getCurrentDistance()).isEqualTo(2); + assertThat(visitor.getSubtreeIndex()).isEqualTo(3); assertThat(visitor.hasNext()).isTrue(); // replace the current node visitor.replaceCurrent(oak); assertThat(visitor.getCurrent()).isSameAs(oak); assertThat(visitor.getCurrentDistance()).isEqualTo(2); + assertThat(visitor.getSubtreeIndex()).isEqualTo(3); assertThat(visitor.hasNext()).isTrue(); // distance 3, pets, dog, puppy assertThat(visitor.next()).isSameAs(puppy); assertThat(visitor.getCurrent()).isSameAs(puppy); assertThat(visitor.getCurrentDistance()).isEqualTo(3); + assertThat(visitor.getSubtreeIndex()).isEqualTo(2); assertThat(visitor.hasNext()).isTrue(); // distance 3, trees, oak, acorn assertThat(visitor.next()).isSameAs(acorn); assertThat(visitor.getCurrent()).isSameAs(acorn); assertThat(visitor.getCurrentDistance()).isEqualTo(3); + assertThat(visitor.getSubtreeIndex()).isEqualTo(3); assertThat(visitor.hasNext()).isFalse(); } From a84b2852c44480da970a782c2dccda0a02e9a485 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Fri, 13 Dec 2024 09:16:52 +0100 Subject: [PATCH 119/207] Configure the resolver for dev mode in QuarkusDevModeTest --- integration-tests/logging-panache/pom.xml | 5 ----- .../src/main/java/io/quarkus/test/QuarkusDevModeTest.java | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/integration-tests/logging-panache/pom.xml b/integration-tests/logging-panache/pom.xml index c37ecaffc2397..8dd1c543b970e 100644 --- a/integration-tests/logging-panache/pom.xml +++ b/integration-tests/logging-panache/pom.xml @@ -30,11 +30,6 @@ quarkus-jdbc-h2 test - - io.quarkus - quarkus-agroal-dev - test - io.quarkus quarkus-resteasy diff --git a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java index d2718b04f55cf..f9b6014cd5004 100644 --- a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java +++ b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusDevModeTest.java @@ -442,6 +442,7 @@ private static ApplicationModel resolveOriginalAppModel() { try { return BootstrapAppModelFactory.newInstance() .setTest(true) + .setDevMode(true) .setProjectRoot(Path.of("").normalize().toAbsolutePath()) .resolveAppModel() .getApplicationModel(); From 0879ce431e1cbdb599cf852c4fc142ea98dba22c Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 12 Dec 2024 20:45:16 +0200 Subject: [PATCH 120/207] Ensure that jakarta json types can be deserialized in native mode Fixes: #45084 --- .../jsonp/ServerJsonArrayHandler.java | 16 ++++++++++++- .../jsonp/ServerJsonObjectHandler.java | 15 +++++++++++- .../jsonp/ServerJsonStructureHandler.java | 15 +++++++++++- .../jsonp/ServerJsonValueHandler.java | 16 ++++++++++++- .../java/io/quarkus/it/qute/JsonResource.java | 24 +++++++++++++++++++ .../java/io/quarkus/it/qute/QuteTestCase.java | 12 ++++++++++ 6 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 integration-tests/qute/src/main/java/io/quarkus/it/qute/JsonResource.java diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonArrayHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonArrayHandler.java index 8ea6a5ec31d3f..750adf79c8678 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonArrayHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonArrayHandler.java @@ -1,6 +1,7 @@ package org.jboss.resteasy.reactive.server.providers.serialisers.jsonp; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Type; import jakarta.json.JsonArray; @@ -11,10 +12,12 @@ import org.jboss.resteasy.reactive.common.providers.serialisers.jsonp.JsonArrayHandler; import org.jboss.resteasy.reactive.common.providers.serialisers.jsonp.JsonpUtil; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -public class ServerJsonArrayHandler extends JsonArrayHandler implements ServerMessageBodyWriter { +public class ServerJsonArrayHandler extends JsonArrayHandler + implements ServerMessageBodyWriter, ServerMessageBodyReader { @Override public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, MediaType mediaType) { @@ -30,4 +33,15 @@ public void writeResponse(JsonArray o, Type genericType, ServerRequestContext co context.serverResponse().end(out.toByteArray()); } + @Override + public boolean isReadable(Class type, Type genericType, ResteasyReactiveResourceInfo lazyMethod, + MediaType mediaType) { + return JsonArray.class.isAssignableFrom(type); + } + + @Override + public JsonArray readFrom(Class type, Type genericType, MediaType mediaType, + ServerRequestContext context) throws WebApplicationException, IOException { + return JsonpUtil.reader(context.getInputStream(), mediaType).readArray(); + } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonObjectHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonObjectHandler.java index fcaa1d9091bc2..ba5dc772cdbd9 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonObjectHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonObjectHandler.java @@ -11,10 +11,12 @@ import org.jboss.resteasy.reactive.common.providers.serialisers.jsonp.JsonObjectHandler; import org.jboss.resteasy.reactive.common.providers.serialisers.jsonp.JsonpUtil; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -public class ServerJsonObjectHandler extends JsonObjectHandler implements ServerMessageBodyWriter { +public class ServerJsonObjectHandler extends JsonObjectHandler + implements ServerMessageBodyWriter, ServerMessageBodyReader { @Override public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, MediaType mediaType) { @@ -30,4 +32,15 @@ public void writeResponse(JsonObject o, Type genericType, ServerRequestContext c context.serverResponse().end(out.toByteArray()); } + @Override + public boolean isReadable(Class type, Type genericType, ResteasyReactiveResourceInfo lazyMethod, + MediaType mediaType) { + return JsonObject.class.isAssignableFrom(type); + } + + @Override + public JsonObject readFrom(Class type, Type genericType, MediaType mediaType, + ServerRequestContext context) throws WebApplicationException { + return JsonpUtil.reader(context.getInputStream(), mediaType).readObject(); + } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonStructureHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonStructureHandler.java index ef055f5905fe4..ac9c7e6de030c 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonStructureHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonStructureHandler.java @@ -1,6 +1,7 @@ package org.jboss.resteasy.reactive.server.providers.serialisers.jsonp; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Type; import jakarta.json.JsonObject; @@ -12,11 +13,12 @@ import org.jboss.resteasy.reactive.common.providers.serialisers.jsonp.JsonStructureHandler; import org.jboss.resteasy.reactive.common.providers.serialisers.jsonp.JsonpUtil; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; public class ServerJsonStructureHandler extends JsonStructureHandler - implements ServerMessageBodyWriter { + implements ServerMessageBodyWriter, ServerMessageBodyReader { @Override public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, MediaType mediaType) { @@ -32,4 +34,15 @@ public void writeResponse(JsonStructure o, Type genericType, ServerRequestContex context.serverResponse().end(out.toByteArray()); } + @Override + public boolean isReadable(Class type, Type genericType, ResteasyReactiveResourceInfo lazyMethod, + MediaType mediaType) { + return JsonStructure.class.isAssignableFrom(type) && !JsonObject.class.isAssignableFrom(type); + } + + @Override + public JsonStructure readFrom(Class type, Type genericType, MediaType mediaType, + ServerRequestContext context) throws WebApplicationException, IOException { + return JsonpUtil.reader(context.getInputStream(), mediaType).read(); + } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonValueHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonValueHandler.java index b75d0d68b8961..e74804914e9c3 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonValueHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/jsonp/ServerJsonValueHandler.java @@ -1,6 +1,7 @@ package org.jboss.resteasy.reactive.server.providers.serialisers.jsonp; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Type; import jakarta.json.JsonValue; @@ -11,10 +12,12 @@ import org.jboss.resteasy.reactive.common.providers.serialisers.jsonp.JsonValueHandler; import org.jboss.resteasy.reactive.common.providers.serialisers.jsonp.JsonpUtil; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -public class ServerJsonValueHandler extends JsonValueHandler implements ServerMessageBodyWriter { +public class ServerJsonValueHandler extends JsonValueHandler + implements ServerMessageBodyWriter, ServerMessageBodyReader { @Override public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, MediaType mediaType) { @@ -30,4 +33,15 @@ public void writeResponse(JsonValue o, Type genericType, ServerRequestContext co context.serverResponse().end(out.toByteArray()); } + @Override + public boolean isReadable(Class type, Type genericType, ResteasyReactiveResourceInfo lazyMethod, + MediaType mediaType) { + return JsonValue.class.isAssignableFrom(type); + } + + @Override + public JsonValue readFrom(Class type, Type genericType, MediaType mediaType, + ServerRequestContext context) throws WebApplicationException, IOException { + return JsonpUtil.reader(context.getInputStream(), mediaType).readValue(); + } } diff --git a/integration-tests/qute/src/main/java/io/quarkus/it/qute/JsonResource.java b/integration-tests/qute/src/main/java/io/quarkus/it/qute/JsonResource.java new file mode 100644 index 0000000000000..9699c5a7d1fc9 --- /dev/null +++ b/integration-tests/qute/src/main/java/io/quarkus/it/qute/JsonResource.java @@ -0,0 +1,24 @@ +package io.quarkus.it.qute; + +import jakarta.inject.Inject; +import jakarta.json.JsonObject; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import io.quarkus.qute.Template; +import io.quarkus.qute.TemplateInstance; + +@Path("json") +public class JsonResource { + + @Inject + Template hello; + + @POST + @Produces(MediaType.TEXT_HTML) + public TemplateInstance get(JsonObject request) { + return hello.data("name", request.get("name")); + } +} diff --git a/integration-tests/qute/src/test/java/io/quarkus/it/qute/QuteTestCase.java b/integration-tests/qute/src/test/java/io/quarkus/it/qute/QuteTestCase.java index 81c791ea56e18..5124c67bd95b7 100644 --- a/integration-tests/qute/src/test/java/io/quarkus/it/qute/QuteTestCase.java +++ b/integration-tests/qute/src/test/java/io/quarkus/it/qute/QuteTestCase.java @@ -28,6 +28,18 @@ public void testTemplates() throws InterruptedException { .body(containsString("Hello Ciri!")); RestAssured.when().get("/beer").then().body(containsString("Beer Pilsner, completed: true, done: true")); RestAssured.when().get("/defaultmethod").then().body(containsString("Hello MK")); + RestAssured + .given() + .contentType("application/json") + .body(""" + { + "name": "foo" + } + """) + .when().post("/json") + .then() + .statusCode(200) + .body(containsString("foo")); } @Test From 80d1a2d1553d236a754893048df2e2978f33fc79 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Thu, 12 Dec 2024 14:07:44 +0000 Subject: [PATCH 121/207] Generate certificates in the OIDC integration test --- integration-tests/oidc-mtls/pom.xml | 52 +++++++-------- integration-tests/oidc/pom.xml | 27 ++++++++ .../src/main/resources/application.properties | 15 +++-- .../src/main/resources/client-keystore.p12 | Bin 2712 -> 0 bytes .../src/main/resources/client-truststore.p12 | Bin 1254 -> 0 bytes .../src/main/resources/server-keystore.p12 | Bin 2712 -> 0 bytes .../src/main/resources/server-truststore.p12 | Bin 1238 -> 0 bytes .../oidc/src/main/resources/upconfig.json | 60 ------------------ .../AbstractBearerTokenAuthorizationTest.java | 4 +- ...KeycloakXTestResourceLifecycleManager.java | 4 +- .../it/keycloak/WebsocketOidcTestCase.java | 4 +- .../keycloak/client/KeycloakTestClient.java | 5 +- 12 files changed, 74 insertions(+), 97 deletions(-) delete mode 100644 integration-tests/oidc/src/main/resources/client-keystore.p12 delete mode 100644 integration-tests/oidc/src/main/resources/client-truststore.p12 delete mode 100644 integration-tests/oidc/src/main/resources/server-keystore.p12 delete mode 100644 integration-tests/oidc/src/main/resources/server-truststore.p12 delete mode 100644 integration-tests/oidc/src/main/resources/upconfig.json diff --git a/integration-tests/oidc-mtls/pom.xml b/integration-tests/oidc-mtls/pom.xml index 719118f28efca..7b6b331e319be 100644 --- a/integration-tests/oidc-mtls/pom.xml +++ b/integration-tests/oidc-mtls/pom.xml @@ -87,32 +87,32 @@ - io.smallrye.certs - smallrye-certificate-generator-maven-plugin - - - generate-test-resources - - generate - - - - - - - oidc - - PEM - PKCS12 - - password - backend-service - 2 - true - - - - + io.smallrye.certs + smallrye-certificate-generator-maven-plugin + + + generate-test-resources + + generate + + + + + + + oidc + + PEM + PKCS12 + + password + backend-service + 2 + true + + + + maven-surefire-plugin diff --git a/integration-tests/oidc/pom.xml b/integration-tests/oidc/pom.xml index ff0b6fdd56069..e63f4b8707ff2 100644 --- a/integration-tests/oidc/pom.xml +++ b/integration-tests/oidc/pom.xml @@ -132,6 +132,33 @@ + + io.smallrye.certs + smallrye-certificate-generator-maven-plugin + + + generate-test-resources + + generate + + + + + + + oidc + + PEM + PKCS12 + + password + backend-service + 2 + true + + + + diff --git a/integration-tests/oidc/src/main/resources/application.properties b/integration-tests/oidc/src/main/resources/application.properties index d8b1ec529ad7c..e4552113a34b4 100644 --- a/integration-tests/oidc/src/main/resources/application.properties +++ b/integration-tests/oidc/src/main/resources/application.properties @@ -1,23 +1,24 @@ quarkus.keycloak.devservices.create-realm=false quarkus.keycloak.devservices.start-command=start --https-client-auth=required --hostname-strict=false --https-key-store-file=/etc/server-keystore.p12 --https-trust-store-file=/etc/server-truststore.p12 --https-trust-store-password=password --spi-user-profile-declarative-user-profile-config-file=/opt/keycloak/upconfig.json -quarkus.keycloak.devservices.resource-aliases.keystore=server-keystore.p12 -quarkus.keycloak.devservices.resource-aliases.truststore=server-truststore.p12 +quarkus.keycloak.devservices.resource-aliases.keystore=target/certificates/oidc-keystore.p12 +quarkus.keycloak.devservices.resource-aliases.truststore=target/certificates/oidc-server-truststore.p12 quarkus.keycloak.devservices.resource-mappings.keystore=/etc/server-keystore.p12 quarkus.keycloak.devservices.resource-mappings.truststore=/etc/server-truststore.p12 quarkus.oidc.token.principal-claim=email -quarkus.oidc.tls.verification=required -quarkus.oidc.tls.trust-store-file=client-truststore.p12 +quarkus.oidc.tls.verification=certificate-validation +quarkus.oidc.tls.trust-store-file=target/certificates/oidc-client-truststore.p12 quarkus.oidc.tls.trust-store-password=password -quarkus.oidc.tls.key-store-file=client-keystore.p12 +quarkus.oidc.tls.key-store-file=target/certificates/oidc-client-keystore.p12 quarkus.oidc.tls.key-store-password=password %tls-registry.quarkus.oidc.tls.tls-configuration-name=oidc-tls -%tls-registry.quarkus.tls.oidc-tls.key-store.jks.path=client-keystore.p12 +%tls-registry.quarkus.tls.oidc-tls.key-store.jks.path=target/certificates/oidc-client-keystore.p12 %tls-registry.quarkus.tls.oidc-tls.key-store.jks.password=password -%tls-registry.quarkus.tls.oidc-tls.trust-store.jks.path=client-truststore.p12 +%tls-registry.quarkus.tls.oidc-tls.trust-store.jks.path=target/certificates/oidc-client-truststore.p12 %tls-registry.quarkus.tls.oidc-tls.trust-store.jks.password=password +%tls-registry.quarkus.tls.oidc-tls.hostname-verification-algorithm=NONE %tls-registry.quarkus.oidc.tls.verification= %tls-registry.quarkus.oidc.tls.trust-store-file= %tls-registry.quarkus.oidc.tls.trust-store-password= diff --git a/integration-tests/oidc/src/main/resources/client-keystore.p12 b/integration-tests/oidc/src/main/resources/client-keystore.p12 deleted file mode 100644 index 11df9af88cd7347c52c3133b1bb4c06dad923695..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2712 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 diff --git a/integration-tests/oidc/src/main/resources/client-truststore.p12 b/integration-tests/oidc/src/main/resources/client-truststore.p12 deleted file mode 100644 index 8a9cefe2f5506a9e6d069666946da65f351d4567..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1254 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 diff --git a/integration-tests/oidc/src/main/resources/server-truststore.p12 b/integration-tests/oidc/src/main/resources/server-truststore.p12 deleted file mode 100644 index d006d5d2dd43e1f3fb281ef9b0f70b62366d55d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1238 zcmV;{1S$J4f&|h60Ru3C1bhYwDuzgg_YDCD0ic2eZ3Kb@X)uBWWiWySVFn2*hDe6@ z4FLxRpn?QaFoFb50s#Opf&@nf2`Yw2hW8Bt2LUi<1_>&LNQU+thDZTr0|Wso1Q02uTHfVto}cs>t6EcWV+4SL1JHTWWGObIPYjLO($cJE!p6hQ zyi+RQq~7$Nt0^uplY-(Qg*6&o;t56~ILD{z`oq)>kGQ3aU4F?EVOGuP(4I7CGNb9H zTH2%*k*_ys=fAZ@84#4HBY(?RIWiCfX0q#fiz*Anw@O0D*vt?B{pey7)3H8giqX*t zoT3ziOQh{2IPUSW&+Uuz@+3-;(^QJI$S#}t`=Q8Bq(7B{WFq;I#E+cwSBc3cnMtgM z?#Orx%n<2uc)~A>{`G;Hm5z2WwDhRNUv1I~NLz7O1$QD-+SDA{u#V^x2`|$mq8`?Z z0Vhkh8FpP0!X8ob)ZDYc1Yxe|{`ls#`zpl<9AIVdJYRhDlb3lzS=`jOFK4-f#;#u3 zjo|d+yzb#twx(gwwUccyB)!L<8gqo2X~a72Q{sQ796U~JBN*s1L&~w~hCBzj?F{!` zSf@7eSq=g#DIM2uufUIge<0RokWUH8USq;@uG4{?P}0dJQckA99BxrachA&KuYkzx<`~)CrtP z@{uVebFGAQVA7=e+T)#Jf&8gJFYOvL=w7`OQw=)}`)_7!%waE?$18Pf*VwKa`D^s; zz>m%2vdIz=g|l$x;9-eiLMoV|h)rGHr@F+9QhO;@xw+Zb@ge@w>mYRN#yqaMJ5S?e zyXyfY!7D;EfU#NAbonIFa{)S@=!;7THxuf^N5D>={aVO4Cw%D8-N>fNn6c*%CifI$g8ony^L za~KHBLb*MoAjFT3^Yh{U(Qm25G?a~UeD3INpyWw3B})@0^e7e0Ic2^c)g%Tfb;yurIc`ywk#<4b3FNC9O71OfpC00bafVWNS|wp1wX zyU_TEQ5xQ0(1XIrK!>`w9r$zbKD_q?6k{F#kOL?OfWpAH=<&{v*odT2lL7)K5Nth0 A8vp start() { diff --git a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/WebsocketOidcTestCase.java b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/WebsocketOidcTestCase.java index 3a75d88294dc4..3c3323e40562d 100644 --- a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/WebsocketOidcTestCase.java +++ b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/WebsocketOidcTestCase.java @@ -27,7 +27,9 @@ public class WebsocketOidcTestCase { @TestHTTPResource("secured-hello") URI wsUri; - KeycloakTestClient client = new KeycloakTestClient(new Tls()); + KeycloakTestClient client = new KeycloakTestClient( + new Tls("target/certificates/oidc-client-keystore.p12", + "target/certificates/oidc-client-truststore.p12")); @Test public void websocketTest() throws Exception { diff --git a/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/client/KeycloakTestClient.java b/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/client/KeycloakTestClient.java index 55d2b70561e22..f510c3dac6ec3 100644 --- a/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/client/KeycloakTestClient.java +++ b/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/client/KeycloakTestClient.java @@ -455,6 +455,9 @@ public record Tls(String keystore, String keystorePassword, public Tls() { this("client-keystore.p12", "password", "client-truststore.p12", "password"); } - }; + public Tls(String keystore, String truststore) { + this(keystore, "password", truststore, "password"); + } + }; } From 99a12d951930c717321ca610120af3445048c0a2 Mon Sep 17 00:00:00 2001 From: Ankush Saini Date: Fri, 13 Dec 2024 12:54:40 +0530 Subject: [PATCH 122/207] logstash conf file fix --- docs/src/main/asciidoc/centralized-log-management.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/centralized-log-management.adoc b/docs/src/main/asciidoc/centralized-log-management.adoc index 4fbb13b06388c..f0127b3d339ce 100644 --- a/docs/src/main/asciidoc/centralized-log-management.adoc +++ b/docs/src/main/asciidoc/centralized-log-management.adoc @@ -250,7 +250,7 @@ For this you can use the same `docker-compose.yml` file as above but with a diff input { tcp { port => 4560 - coded => json + codec => json } } From b9371a88b78636cdedd3aed80a514c010a522263 Mon Sep 17 00:00:00 2001 From: "Gurubase.io" Date: Fri, 13 Dec 2024 16:36:57 +0300 Subject: [PATCH 123/207] Introducing Quarkus Guru Signed-off-by: Gurubase.io --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bd2037b525683..663a5c0283b13 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,9 @@ [![Project Chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg?style=for-the-badge&logo=zulip)](https://quarkusio.zulipchat.com/) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?style=for-the-badge&logo=gitpod&logoColor=white)](https://gitpod.io/#https://github.com/quarkusio/quarkus/-/tree/main/) [![Supported JVM Versions](https://img.shields.io/badge/JVM-17--21-brightgreen.svg?style=for-the-badge&logo=openjdk)](https://github.com/quarkusio/quarkus/actions/runs/113853915/) -[![Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?style=for-the-badge&logo=gradle)](https://ge.quarkus.io/scans) +[![Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-007EC5?style=for-the-badge&logo=gradle)](https://ge.quarkus.io/scans) [![GitHub Repo stars](https://img.shields.io/github/stars/quarkusio/quarkus?style=for-the-badge)](https://github.com/quarkusio/quarkus/stargazers) +[![Gurubase](https://img.shields.io/badge/Gurubase-Ask%20Quarkus%20Guru-007EC5?style=for-the-badge)](https://gurubase.io/g/quarkus) # Quarkus - Supersonic Subatomic Java From 9e501b21f828b37c792ae0b076f4752b426c6053 Mon Sep 17 00:00:00 2001 From: rghara Date: Fri, 13 Dec 2024 09:20:40 -0500 Subject: [PATCH 124/207] Replace oidc auth apple screenshots with generic ones --- .../src/main/asciidoc/images/oidc-apple-1.png | Bin 36237 -> 33232 bytes .../main/asciidoc/images/oidc-apple-10.png | Bin 37334 -> 34324 bytes .../main/asciidoc/images/oidc-apple-11.png | Bin 40350 -> 37719 bytes .../main/asciidoc/images/oidc-apple-12.png | Bin 51475 -> 48879 bytes .../main/asciidoc/images/oidc-apple-13.png | Bin 92587 -> 76343 bytes .../main/asciidoc/images/oidc-apple-14.png | Bin 35125 -> 31880 bytes .../main/asciidoc/images/oidc-apple-15.png | Bin 50736 -> 47930 bytes .../main/asciidoc/images/oidc-apple-16.png | Bin 75869 -> 74143 bytes .../main/asciidoc/images/oidc-apple-17.png | Bin 34545 -> 31210 bytes .../main/asciidoc/images/oidc-apple-18.png | Bin 119532 -> 121661 bytes .../main/asciidoc/images/oidc-apple-19.png | Bin 74425 -> 72999 bytes .../src/main/asciidoc/images/oidc-apple-2.png | Bin 61767 -> 59069 bytes .../main/asciidoc/images/oidc-apple-20.png | Bin 117374 -> 119342 bytes .../main/asciidoc/images/oidc-apple-21.png | Bin 77577 -> 76164 bytes .../main/asciidoc/images/oidc-apple-22.png | Bin 66637 -> 64785 bytes .../src/main/asciidoc/images/oidc-apple-3.png | Bin 41094 -> 38063 bytes .../src/main/asciidoc/images/oidc-apple-4.png | Bin 72614 -> 71358 bytes .../src/main/asciidoc/images/oidc-apple-5.png | Bin 41786 -> 41749 bytes .../src/main/asciidoc/images/oidc-apple-6.png | Bin 71520 -> 72148 bytes .../src/main/asciidoc/images/oidc-apple-7.png | Bin 38720 -> 37306 bytes .../src/main/asciidoc/images/oidc-apple-8.png | Bin 62072 -> 59204 bytes .../src/main/asciidoc/images/oidc-apple-9.png | Bin 49110 -> 48410 bytes .../security-openid-connect-providers.adoc | 4 ++-- 23 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/images/oidc-apple-1.png b/docs/src/main/asciidoc/images/oidc-apple-1.png index 984e71462b51bbe9dccd6b5e829fcca0a761e512..3424675d54cc437bd0b494186e170bbf7c820cfb 100644 GIT binary patch delta 24814 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 delta 27842 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 T7y*Ac3rk5sO}^r}X~=&7j~Gf` diff --git a/docs/src/main/asciidoc/images/oidc-apple-10.png b/docs/src/main/asciidoc/images/oidc-apple-10.png index 96c897799905faefc16b20525c7101fdfe4bf30e..72c002b5cc2e2023da22051ac08bf266d86c61f2 100644 GIT binary patch delta 28399 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

    *JRY+akkK58YMC0Gz*(&Fqv?@)U+* zj#72cFVl!{@Cp*Y(cy<$dN7-}Fw(mNhV8fSz3Od66;AJ@-g1H+e48il>)tf$(3!6i zLM<&V1y^sa>L)LnnUje0L2)zsUf5_yBW&88jHoIIwPEhv6Es5)E}rJ-panHCE{LYQ zqAP17T@0iOBn=2NUV3CF!F_%gEpRWrON@WcOxp2tiIPlsvT&u=u1`!@Q9n4<7VB$W z=RYg!TuZWnYVXWUL{Bv)1`S7gu7r6tbp)mcF|A!z2!lkc%jYADZ5*+vYPZL?)PbFd z2eEP%uLR+5dX4QE^O!VBB<**<0lH1wo;}4UUTJfXgMeN-Dt<20Zkd=8L5->?K%r5n z`s~YLJgCmWLgk%aCr*xG&WG*_@D z;OTSWh_tI4PhB+LHuSG=bE-8gTxg=fb$F~SV)i-msEPPb+Z+lpP{m`Y|8xiF(~MSF$i|#X4`fg< zIDM(}XejQf7m>8#6*r88HmLCmZytoA_QSq@P14^ji4%SB;K6dBVz!c#S3mnw`R`_i zNnR7k!;j^UyH~k3c4ho@*+2~D_dX<$v;$lU&Cu#L)MO z8bMR!ZaAYY84Y!Z;WtJFk zTHj5HqtJ?LioE0*TsD2aE)UR%N!hZ`V8;Z&Q>pyOJkNG?Q52rKZTW)WRqktU@X{-dc5kK$w$k!g(IX;XFJK{>9U?kd#jet1EAHf^0KV*Svf`ZzWm#Kn{#q)a!pi zp3Td$XT+ISv*75FFg>N;;9*H|N4fyseyFtmEjI5fbVUI$Uth5)@EJogZ`1C?G71YE zV?C?9NEsHCCn4%fc$;XSU277bE+whHDL*v>40jBNAZqSoduyR-ScguhT@^Sb?{S*{ zZpn4ht^C)CC1R-UPs+Mia(@Na8GLjja^!8NV^^iu0*1v1!9}j8c=-i8{QKTcX$k@< zB>PF%=*ZS9HIm(?Dn$T5TRU?84O4d>+&p)9Jd6~nOIUfDtiNgSZ_o@V>)~bpBa%LW zredOh3<5Ho{kV7p{O~{AhZp!iQ~NkQBoLFiu^18ZY#j2>jBXj3->ALr_UL~BY3Ik# delta 31432 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 diff --git a/docs/src/main/asciidoc/images/oidc-apple-11.png b/docs/src/main/asciidoc/images/oidc-apple-11.png index 2182c11e558d634becdafe6c598520af1f51b9a3..5b7d0bac597923986eb71407cde05f70964efa92 100644 GIT binary patch delta 28777 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 XdONhZo*-{eekCR>EmS0^?e)I^JN5%& diff --git a/docs/src/main/asciidoc/images/oidc-apple-12.png b/docs/src/main/asciidoc/images/oidc-apple-12.png index d7cfb8717ff71d0d95cc2d6d71251241828f3692..fb0d88e1597f0a4aa3915592e49c0b72125ef585 100644 GIT binary patch delta 42811 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

    T?4w3Ki*WCe1ONj_DoKhI@9wDN){(#cL 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 delta 45427 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

    Se}b+*8_NGaZX4K8zJYR1%)w2ci*K9%&9Td# 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 J7h7Do@h|T~QD^`F literal 92587 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 diff --git a/docs/src/main/asciidoc/images/oidc-apple-14.png b/docs/src/main/asciidoc/images/oidc-apple-14.png index 526ae9cf232c8e0ee9bf9b5d3594b03668ee90b2..55a31882c92c36386b85e751a1e61f266cb36220 100644 GIT binary patch delta 24208 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 L`=Bes#b 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 diff --git a/docs/src/main/asciidoc/images/oidc-apple-15.png b/docs/src/main/asciidoc/images/oidc-apple-15.png index 3188d816ee4c06424b09ed89e5e3ec790a449029..65a1b662e0859bad7fd6d89758c3e700541deae4 100644 GIT binary patch delta 41890 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


    ;2Pu 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

    B;LOQehvTW9Ea=>++j~wXJ_h#Ey?y8S&+5Pib_> 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 delta 112177 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 YMOV diff --git a/docs/src/main/asciidoc/images/oidc-apple-19.png b/docs/src/main/asciidoc/images/oidc-apple-19.png index 35f68417682d9de70bffdcdd09a62f8254dd139c..b60337825088aa5beed490880993800d01f05877 100644 GIT binary patch delta 66206 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¥ku;F+;lj$j=7xyN~Q_wShqcA zy$kQ({w_4Ke1UUJUb5louz-?x}@eAXq;>J?`3-kQA%JWw$R}NBk^-ItrQ#_mO4=5<>OA!1a z;xaNkEN~Gf(kSDbnaBYsD5YR?H~$Ldu{}%hSDvM+d89YCj55UhH4HoPJ*=AVal3ky zHw;Uq6kRq}(ws9dfvcUXKI~&=HZfk_kIQw9^4$hOwjJ&(D1%}#9n6V6MY&;F=fkqG zM44ZDFJb>2bFZww{6oF8_4Z0S&$8o;kFe~Fkr7I-%EpxDW2o4_vWfi_O~L%rihJ^5 zs*`?8grye>L7*XtM)uZAXN0tVFr$Sx~7L6*PX z+?VyCmOPmcejIRKE372>`$0eG+MaFqCzP(Av@^DUa~UyKUjMIx{lD|i|1Hn1{~|muYkRUk<9`Z3_8*`BfB$&=`Kwzzc^_}O3=j=p-M|bbIW^hRr)EL_3o{BGBLDyZ delta 67627 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 Ak^lez diff --git a/docs/src/main/asciidoc/images/oidc-apple-2.png b/docs/src/main/asciidoc/images/oidc-apple-2.png index 045ec05eeb1f1a24a923a1d4526bc8a8c39d3377..1ad292aad731527a2e268cbf173578948e376bb6 100644 GIT binary patch delta 50098 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

    RB_*face4*v` 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 Cc&s0?By$(=F;c-Uw^`_S`otdv08OHuG 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

    `rRIDio@Z;83E##kHcA+%6=FjtM4j)z@K+PE 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%0DvmDGm}S33lk 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 U=TG+68|X_~TtTct#K8Z50Q1;5!~g&Q delta 70455 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 I-k1daUo@pAk^lez diff --git a/docs/src/main/asciidoc/images/oidc-apple-22.png b/docs/src/main/asciidoc/images/oidc-apple-22.png index 33380e8d4ff4e9268740640c9449e71b83e72836..3684318f015b0a089f9413b4d50981fd639fb9d4 100644 GIT binary patch delta 58149 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%0D8;Y%P}SnflxFjv9UYa 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 ijdMT$+vy;aZDzKJ3HD(SM@!+!#mwb8@? delta 60012 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

    vB{1(@8Ox)0ig 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

    HO@X#%897Rj3UGIYfyT)0)# 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 z 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

    K0 zojRG)LCN3fQxs1jiMf;H< zk#`S$07mFAG?vxm?>H2t0;~N)m8c2kLgaj_-~;8T`(0Em#MFTbGsc2bZET0gZ(=wT ziWn)$BCe+&0>M*eomFA`bsu>O=L(iN*6t)A{Nr5fTIJ2{l;lN4B!8|@lH$+)EdDs6 z2p)bkH|~5iAX}HyA5~Ucp%Klt*x%XU86F1326)=sT3WIckbXY|tDK}ZMwwMAEQaGt z_~K}$-F(9@mltuOKWUp@(CaxieRwtj9;}P`w zOn|U3RjBx6rZ8d^3DRP7MmsF4-wl#!zpfa=dB4}=2PTj6eePq8DtFrNlW9-+fytwN z0C_DZZ5kAhr9Eonm??b_hcYYASy}K#1!svD`(gxpP>AFhBT$@P(_poWh&_FWxd<&* z1glta@(%t+10kUJ>uk<|G7pPqjBL`xOeWB8JMo$Db9;(+LZQ@Z9rK~DkYOz;=r*SI zGi{5ng!t|L5=gMq-sK03)A5tkNnG3f?qd7V*!@bZnj%MC7{@oB_V!w>ZL5jJ#3m8j zDzn${Tqat_+GFcimxGNZk;$$n>8TXQR}Z3W9|j1o8S#MQ)vad#v@Fv3G&6S^WI%8{ zo2$V_J#Y0Z8JcgF>Avg!mPVZz?ek&}&wUl9!lvy|)G9wVF4vA8zf{cZ%?nG2zoOTS z==WOhHx7<`hLJ>HB&5DZ`&#Cbuo~&{(UPmJJq;FPsog;I;+N&V*%@0K_SbzbJ?{FV zlwid+FZQ*ZhXOx&Zf!=|lH62}qY~{*3w!ZHAV7KPsu9VT{5^B@VG$_iQeemHhuV?Y-%Kn0_|C+7; zB%aAucdhxzODjIHJoFdtK0RpswDVl7K7P{r*^A%yBYC%ar7D5hn!V7VV53lX89j`N4rV;~20EU{eN8eFe&L=pyVJWAS<>{+S= zA&--gph$(ZBIiJPaIc_bP2{_H7V#Bq+3-2sw#mBNqQd$2EL}zBs36Y^Q$Bo6gCXYU z*GB6M@4i^p3c2~LaqP*x4vY=oc*F26pfjvx22D@PZjCw#L6VI31RgaV?tHW0b)j8L zgCkxOK#ji7xMy9ByzqtznD4!+&+Iukpt$g|*7W;&w6#k??8k|Y>*Ed6Ti<&WS+I4z zd3d; zvkC~NwP|4a3~(x!|E>vrFkm1+AFK)YLK!C^uCjHZ?&;@4Mdn9IWe^BLv!&*5^(5cQ zs&siann|{5gO zrVnp>b@uP;(P3lag6fZ*R=BvhsSARJAYmMowSU?RXyLA3#p=7f$%pah=-n)sRBd&Q zLBF7|?mY;v0xmj|V`Yu(7BTuqT5i{(D735t0HgiP@S=zPh>I65clL~Rt3cuVi{*>T z^l@VAdcvTI$IwZyv=*%K`T3sh?pR6t#qcVd%kLHeKejsi>}~IFw|5(DPhBGPiL2?f zWXX?Qndr1aM<)!t2zJLdme4MY%#h&9+R-UEc4l2|uMD|vian7-!?DhK2M>zwulJIJ z0BDNFw^o-AuptAt<`)-=LDP{Hy-uGfNyhW{GAEj_^SaP3+*oMeb>_OfZYsjqQm+XF z2Yr6-{S7+Vtm+5xrRw%R@7~6aT86(3Gm^Bk<|RFNGc}@uBb9{JbIm4n+xGNzEsDXK z+qj7niDh4qFf;VmU|s)%37tbma z*xdi*5{8XXfgolZxNa~IsW2=0L2w#3a~|e5{v}7b!#mGv`8p{?$SsLSHo20k_iozw{{|qUrgBzuOD`fGjBPrns@;{Usp; zOBOA^8ubZ>Kp&sU8h$o3ouwX;J>oWULrt>#I-;+G5cG@IjW%rU3<$~9bu$!;;r%E$ zk4ha|P{FON)927&?YiErXIr$+4=38`Asg3Jt_cqHP@uF)o zR*@?ERhRJpsO>s~qH4D7zz9fGBnv}UkSq#}NEpH(AVHLzh9n?i$XPgKkgS3zNE{^$ zIVTB927y6xa>yCUaR?7TzkA<(uj*CZANTd&Q(e2Ot9zf-Ypw1bWBUk2!C0j6bKMq`>yo>BJ-&H8iimqH3R09AMb++eW~S!Ojm!j4La>(XUX)wB z%Md|#+ox5PvE~RS##*9M&aVYol-D{PRkZQ=Fk&MMLyQx?{TSK9J^?%Ej5^KM{e_@% z#r3|uvo9~5@8(;@eyG_5S9+{+qeb=>5id1+1@^qk#WjBUvf|6F#~Adn@v z*sDw~^yAJEmkVa`o`mZ0j4o>x0wRWB%kIr*&(GY5G;iLLea8ts1Mb=-x(H37Cbi4% zbH3%7yun(d#rgJTe%IjXoY-~e*ci$*EZ9@-suw5d#+OyejwnACIRlmcngHs=BMa3r+&KX|Cd4>OfMUE4O@i;6R0U^k$ZhI|VhvA;@k&nz zG!1SkHm?ap<2);{EonW7?cIyii#31;BL8gZ7C6zi)`hwnF!X;O-PgrL@?}7<8_8W7 zk{U9mR?4@RPbl2DJfK6>BuUz=F`}X;)8t@U^+K);D>E!g>B^L$@6dbz$?y@pns%iL znHk@M+Ci3+n}8TIoF2N`E%L8ZmmRrv2b#k}7!Z$C+>C4EHpV0efq@d~fl`niXlL^7 zdZzKHY>7KSW(z%k`B=sRT{o5bp((KYR&#^r@PjIHT0YVzlU;+n0@d+wlBG(n4^srV|t}eHHvmUO!n*RcE##U8o z`K_@m64ii*s1FUO#B01#UMtF(=(4y=9ZS{R%Xu4cSmA0PtYmUDfyPwei4%F*(Zpho zC1Tutt`><4Xfybo8b6T54mxT+Y^!&q5cXGV|F(p}mY^@BhTJaSvOh>L7wo)Y!mq7d zRx4_e=wpdBVy4?dzPwWb!x|>)6x3{_LX4DD%^w=W?q2Xl7&UEN<4BE>bHP&M=rS#g zrD}l8_gTYF~(zowz1s>5R^ znG&Bw^)m>DXR`uQVl6Bxy zJX76c%o+5DX+k8IHJrcYWmD#DpfIcWtJv+m?h`D4(+zgOd zi9v(gnQ0C=SsaVPY*57A4Pi%BNBi+e@}Y)TRt`UwupJ)C;h%Y}Klfe~jI7Ok5#!tQ z_RqWn5^uuD)`<;yxYNBWFoEM)_6E`rMDPaNiGVM9o=Y6z^Nxz6=Q?h(#<@4IU|2WA z`spiY`iCEJRkiZDzi!zD`|fRT-~->W>$z(v?oxFW$gVuk!1MiBU|v#~lrP27<$xu^ zCHXnrTm3y2%bhW!GL>1ZI#T{TV3bwzyj9(0v7`sSd)}fJX=Ky8f%e6wcl?Jc{L9+k z9VieqhHyWjZd!HE{)vT;+?3UbXFS+i)3s*0{kg-FSX}~sdcqylRrbxA2KcI4GIx*i zri5(8Oj8{alA*Ve}pBQiXPMJK^ zgI9A*WS*tIx!%ghb2R}(<``ESs|3*_38w7WoXweo)z5|9B~k1^GDs85dcGbhtPYnv zFBNd=E>1QYg(B+5*7huofwU1ZF?-yJJL1Il=sOvSC1G)04&BoZ3+nZRC`L12SoL_m za07B*cw~t0$f>ez92tY*7wi+ z-nTK*uDTaWB+pwF!P|;zl1h?PTlXWXoDVS2U^ReT`V*{nPLGg8@A6?a-7+usF^tps z>Cj^DVvB{RW3%qE2s7o0y-4FCI>mFCcMVb-I^){7Lq) zpTpQ&|3wxCiSLkfV5q`$!l?Y(4!3Cg7KcK~FX)(2a@x`rfE|%&)Og ze$i=?BR0J1Y;O$DJIwYA-5SeBw;s`LNN*n0t*3NJ@imJ2_+)Z{q*rrNC9ivg&rL~m z6`bd!Kj}2DVuV2*-Mhl{8~iN+A@6FthTvgk>#Rkw+8h!NfU{AyWbmeu->AK&@LdbE z4)%x}C*qj|kLPDOP1X1+Ae57?n@G9!FuV7T^xUpVdHpI&#bvq>fBq?xLGvLPBuu@) z1!Xmo`tT0_s;#IyDNXrCf2&GayaJyNVvDONtat;@UrK*r>T%;!>!Ap45gdJ!!qT)y z{J0c7-XZ@uz{+u*B7OG}bHagj1w79X_IyVC$MRYIlmt4ZANO!b!rf=U+;bPtZ3$}N z%5=LR0SJ6HAunK&u~qCpZ1Q?^`L)1?)Tfzn0n73WVJc!mfTmnd|B~HT&tX0FvBHqT{#(!47`#Xqr6;?8*pV zue98KPr004S`ldu(7(;t4_5KS(v%F)SM>d2Vog+x2JH8`+oq^U%s*?%o~H-l5iX07 zayOLr3G5(OlWP{@4a(~fsvJoIv6p};l>M=z;teK`@H5-pPP(eYBnh@-%3=RiHDVOC z&(JC0;`Y+x+D?a75sPA#Ws{zuS+)QNQ!Sd^9F-c$e)s(K6(x;y#W^kKswe`Y7!9xZ zHk2~eR0DY(R;K<*OWs$>E84&4!$w;6S{v`m!S?MaRx=wCV6J(@xX?*I-$}#myQNof zeZ5DbXA`Xn2KT0IX-eEM48F*`;IIo-^QwnHue~y))r{&4PiR?8gKs$Fz3I`fIJVGc z@rYybTCfSm-oz>!@0P2VfmlpfGhUcmRE#ff&grjZUcF5}_-#wYp-vCBJ#-xLscvC* zZRv3AeRU?#*yZOJef*miCdgfQt7RuO<==Qn#9a8Z-B&UKd%pa&ahsYE?fT*ypffO` z`}T1AiB1N*%$fj&Vd{1`h*%7na*>6kSu38iPD+yU2H2+BvK^b=Br*Q{3vupN&RFpz z*I>)`P=KyYb6U%7Cm&3N|N6T4!$w&xH_k4(;9W)xmk3+CB>n9t%F9nS+lvRDz3wsE zCoiMR-5}3rdR~G?KZzz=RVGuK1Cll~Q~a*PGfNezkXSNbc`0|gvehi@7wKRRUMvnC z^`+6bBT9i?<$de4OCKH;L3$W2?gEtF06-InBuyE}4PSJG)9*ACtpl5yT01I9hF$7K9 zs@4bNEcWyl-{(th;naLes5t~fv$IvENU}6DuH8Ufw<3*gwgZlSJoq$EA{@KAEO`AP zvucnTuTa#k8>==dRKMVO->-I(E^xJY=C0h*_J-&-)S*e>JOYP~82Zjz{f6LEyB64r zJ32l)2I~q5{qT*Yl<>j`aE@e>^=^*z_<%@9H%^=O1Yy2MP!jubfbzzIu`YZVWKoCcEM>@@~c%)yJl7UPJ`ivo_{7dp$Ewp%P1sgis#U5#*y$ z2+cYzHMiu^-bX^f5eJ@;R!LHBbHaCym6Y$1dPgxXy7fh~=Qb4W4Sbd69tJly979aK z(TXcP=Y6Xj<=Q_w5EWlevbJ^antJPZERQei93b!c?H(LHcK#Oa(gS5#KvfsnD8@gR zxLOpYtuVz#hrQp3hj#a&n%XzGOasR8T+ zPK(~-I865I42(CaZwBv5~mo;^QI&Ka!LB@UT(QTCrwIG%CHAxO(;2?`Dm z2bLXHul9;Pz?13$E$VXbpI27P{|I-rIzukfI@{d~s|6C-w{J>8``Y&pdw6+Y|$Uk=p^JS-%qU$cC z#Cd5r8B(sSNYA4=S8IP^d(MArixelx!V%rH{acDU;q@IMxRa;R zhODoeMm*kH)mS!Od6y>KWMz9bv5$1+F{6YvN_(>Xp^p+|Z|s{@D^bzzBgTK}T}6;< z*$evz`+Z5wcJj)(^61IC(Vzhv)^|nbdvBs`l;LRcLc%fr%il145~0?;xDLql&Pg)u z&LYpwW~gUEe>$Ah8VtKM6mp)q^(r3s?Fw36iGIhN+X6`;IJB34*m)E`Ok3c)-x zRQ&1`O?VHBkAXkPVjFmW(xE`>T^>vUDt8vj)T1s%xo2G?Y)TITYy|M+p7l-mwnp&Q zC55J<&&`Pd*s8EBsS907(E_mDm;L&2e%4gT@DX`5>w@KzZhmVT=U zB615?s*r;m;5VNiN~kqt(juHwe%sdwuB@6Nt`%;(q)J~y3rc?$@lBB~PMsc8ensG? zk>|c{tdzt3-kZR0dE)%o=Ont{FGo7|aMz@?UtCxp|Ja%Kl6BAepqOZ2t@Y@l$X48} zM(O+C#>IZ4msJFJfUJn@*B4DR0_lEF{O{@!Sg>Ralbhn;V4?+RygqH?h@g(0ek)%D zm`eTHs` zPzJna9@Zvx<4wsy*;lVccDx(+pJ*ANOTH?8s<=6%p@gFy@0;1C6mKApUvryxOaGv5 znoTEPI1WQ4$xZiRU-MK7)~k!|K)Hj{^IJ5~EUZP{u&Tg|$ z@Mj0q=CN$*95DIG&;BMTe8}GWr4Q7+%u56}HLa!(l--T14_|!TVZGBc;jn?Sd7;>P z=7=9BdHbm;!~WTALeQiF^TJ2sA~M(k>nE@NwLQm?c7+FqY%MB+79fEBzJ~7t49XCq zPRRO)*m5`KOv-+im%b6nQQ*TW7dSxI?A;Nd|JiF;3gDy|^4jlt^#&UpDsICMDt6Me z{bn9I9T1H=4QI1$7Nrv;qtpbx$|VvQu5MhcV>if4UTwA}Bq0pq8nj?K zS0mpS0CmQ?uG|5BBr)FLgla*ga>LARf8;U;t4Ldb-n0{?Wi~nFprqVSGQ9b8r|`;% z{z_Mr{g5+U*o65CSI4t`>P|L1ok968of4w%B-~kKOxLEih&U9p$S04&?{v%d*|6?L zO6|vjr&B}NK;^ui|$d6bieE}v4=XlPRDP->GIix-dgWmWmH|YO<1Qf3~|rH9-^&v9Kj^UI6C^gYL%- z?M7Xe0R7!EZygt29-l0T57JV2nHBt~821gSU&&I5f_~#<)W%c?or0oYh*_?P_g2M} z!YwMftnpUsg`Vp{GaxxokQ(Ik+1v`PoU?2Hxyw`Mr_+EtxZorQLhpK67jAm|X*4xV zx2(hXo_`_CZM8`-SJ!rYAYjli--Qt7}!8T99w(b>DkYaw+ z9N=X7Sb>!Z<{%bp(@toDde&oJMF)ejf=h{*KL?%6=gyspyT|4W(y#R|xph5+E|Y=C zFa=Aml>usuc-|tp=>!<$Ti#U%t(_BOJV?GZuS_mA|M8D4VwtvKEinF3WD}O(L@VVy zp&s6WF>}iQ(rv0Wkbd??wkM&@vZbuar(V(C!DN9uQcEku#^Q;Nnc__(2uZ)f8E=DM zi#B!3BSv%p4JV2_&G)IlC{KmGw#AQ2zXga*OZ#1s6Eiv2_utUTFvN}B7>u^(T;O58 z$uo$%fHy42NEDi8WDC})O7t=oM>ftjpv^>fNeV6SUR>BCbzNjh3!2=on4p(7T~_rZ zUMb~#BFjMsXu@Uf9+FNGgQW89gSWh_XlhN_PjX)Q;Puf(S3K)8n_!xaZSl=P#{h^( zTKrD>mp54dH)gJzinkK6$r(y2e*gH-M1<2G{AFRmj10g<_IcgU)HNEqeS`j9%X?Ee z7I!>fktvcJ`qc1z{_3R5*XaLhe)5KF|AH_6)uF-%{DC3=J_`98xBRC%{JH=CKY`AF yIK*Fx>;H-X{F~tG|7%P(|3rkE|FIDJ7kJ9nuc$WDm2QA8n-W}2zEIXA@V@}Oe-i}& diff --git a/docs/src/main/asciidoc/images/oidc-apple-3.png b/docs/src/main/asciidoc/images/oidc-apple-3.png index 868440a5a676057a2c8f528caa21aefe8115cb66..1649628657976933926fa35b9e1fd1ddd0cf57a8 100644 GIT binary patch delta 30165 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�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 D423t_ diff --git a/docs/src/main/asciidoc/images/oidc-apple-4.png b/docs/src/main/asciidoc/images/oidc-apple-4.png index 95c8e1125a7a6c95589fddca236e0e54a4f79e8b..adeeaec171b5ad40a18929b40e08d195258e9f3b 100644 GIT binary patch delta 63145 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 ^mRVb__hz3A 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 WHLiWkpa?rdT=!HTs^s4>^Z#GtM50{) delta 64410 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

    )hr3Z}LWHMl1e?&mMtsC$l0b$zTE3fEmjk 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 Un0{}$MEbdors3T(_4`l%55u5fsQ>@~ diff --git a/docs/src/main/asciidoc/images/oidc-apple-5.png b/docs/src/main/asciidoc/images/oidc-apple-5.png index 5fd241e2d4bdb783ab89d885fc64c56d40149514..87e081d2647268d3f3f3991adf1aec982b9bc060 100644 GIT binary patch delta 35364 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 llN6c*(3)shv#_a%a&i;aNcV;4w+}D6*nc*4` z-IzM)JJn^3Kh85B*{yVMNxuK!aO(}Y|4MoxImzMhn2E8P|FXzCJi~s&z2S?CMPSpuKfds@+@@{*!2ljq zB5Eh4;8e;d7mMnv?VOb70)JvtK1Gcj^F5#5Id$@^xEUB+BM9Q$I@NwO{Wx*+dC+*4EEb1Adi(wi8{!rJ$CbE Z@MI{Fbn@y;X%XgP>i4wo;#D5L_#dR=as&VX delta 35383 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

    Ol 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�_vEbs=O^4F1M?{09b z7=J{9KyutQJ71VbNjK`U9m>?v^hFFVA|PN-PPL$}vR2PG*44Uw9p=+=9> zs-?BaZS+*DY)~Zy%8!WJiDZ<4(p#fnQmgWRFtjwwjm@#pN}Ala%5jK&Bd$`y$zs1R zkYx`4!2

    ^`WbAL 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 delta 63240 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

    Kx2bzUy{~a6>K!WgvAeZ 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 diff --git a/docs/src/main/asciidoc/images/oidc-apple-9.png b/docs/src/main/asciidoc/images/oidc-apple-9.png index 972daafd664437b86f82a925b5d3a0575019bbd8..db2a537fa8c1a70daab700a8b42d9272e3f5a333 100644 GIT binary patch delta 41878 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 F{|jgRoB#j- delta 42585 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 diff --git a/docs/src/main/asciidoc/security-openid-connect-providers.adoc b/docs/src/main/asciidoc/security-openid-connect-providers.adoc index 6f43935a6c57a..240922f2a9249 100644 --- a/docs/src/main/asciidoc/security-openid-connect-providers.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-providers.adoc @@ -32,7 +32,7 @@ This property can be used in `application.properties`, in xref:security-openid-c [[apple]] === Apple -In order to set up OIDC for Apple you need to create a developer account, and sign up for the 99€/year program, but you cannot test your application on `localhost` like most other OIDC providers: +In order to set up OIDC for Apple you need to create a developer account, and sign up for the 99$/year program, but you cannot test your application on `localhost` like most other OIDC providers: you will need to run it over HTTPS and make it publicly accessible, so for development purposes you may want to use a service such as https://ngrok.com. @@ -84,7 +84,7 @@ Enable `Sign in with Apple` and press `Configure`: image::oidc-apple-12.png[role="thumb"] -Add your domain and return URL (set to `/_renarde/security/oidc-success`) and press `Next`: +Add your domain and return URL (set to `/apple`) and press `Next`: image::oidc-apple-13.png[role="thumb"] From 6985f0114767b4d579766285d3f591159a06c5f1 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Fri, 13 Dec 2024 17:32:12 +0100 Subject: [PATCH 125/207] Fix an endless loop resolving conditional dependencies on regular artifacts --- ...onditionalDevModeDependenciesTestCase.java | 67 +++++++++++++++++++ .../ApplicationDependencyTreeResolver.java | 18 ++--- 2 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/DevUiStyleConditionalDevModeDependenciesTestCase.java diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/DevUiStyleConditionalDevModeDependenciesTestCase.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/DevUiStyleConditionalDevModeDependenciesTestCase.java new file mode 100644 index 0000000000000..bc4a0d7341b3f --- /dev/null +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/DevUiStyleConditionalDevModeDependenciesTestCase.java @@ -0,0 +1,67 @@ +package io.quarkus.bootstrap.resolver.test; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; + +import io.quarkus.bootstrap.app.QuarkusBootstrap; +import io.quarkus.bootstrap.resolver.CollectDependenciesBase; +import io.quarkus.bootstrap.resolver.TsArtifact; +import io.quarkus.bootstrap.resolver.TsQuarkusExt; +import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; +import io.quarkus.maven.dependency.ArtifactCoords; +import io.quarkus.maven.dependency.DependencyFlags; +import io.quarkus.maven.dependency.ResolvedDependency; + +public class DevUiStyleConditionalDevModeDependenciesTestCase extends CollectDependenciesBase { + + @Override + protected QuarkusBootstrap.Mode getBootstrapMode() { + return QuarkusBootstrap.Mode.DEV; + } + + @Override + protected void setupDependencies() { + + final TsArtifact extLibDev = TsArtifact.jar("ext-lib-dev"); + + final TsQuarkusExt extA = new TsQuarkusExt("ext-a"); + extA.setConditionalDevDeps(extLibDev); + extLibDev.addDependency(extA.getRuntime()); + + install(extA, false); + installAsDep(extA.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + install(extLibDev, true); + addCollectedDeploymentDep(extA.getDeployment()); + } + + @Override + protected void assertBuildDependencies(Collection buildDeps) { + if (!IncubatingApplicationModelResolver.isIncubatingEnabled(null)) { + return; + } + for (var d : buildDeps) { + switch (d.getArtifactId()) { + case "ext-a": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-lib-dev", TsArtifact.DEFAULT_VERSION)); + break; + case "ext-a-deployment": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, + d.getArtifactId().substring(0, d.getArtifactId().length() - "-deployment".length()), + TsArtifact.DEFAULT_VERSION)); + break; + case "ext-lib-dev": + assertThat(d.getDependencies()).containsExactlyInAnyOrder( + ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-a", TsArtifact.DEFAULT_VERSION)); + break; + default: + throw new RuntimeException("unexpected dependency " + d.toCompactCoords()); + } + } + } +} diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java index 252745b2202e6..641c6c5913565 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java @@ -234,12 +234,10 @@ private void enableConditionalDeps() { final Iterator i = unsatisfiedConditionalDeps.iterator(); while (i.hasNext()) { final ConditionalDependency cd = i.next(); - final boolean satisfied = cd.isSatisfied(); - if (!satisfied) { - continue; + if (cd.isSatisfied()) { + i.remove(); + cd.activate(); } - i.remove(); - cd.activate(); } if (totalConditionsToProcess == unsatisfiedConditionalDeps.size()) { // none of the dependencies was satisfied @@ -465,6 +463,8 @@ private void visitRuntimeDependency(DependencyNode node) { if (isWalkingFlagOn(COLLECT_TOP_EXTENSION_RUNTIME_NODES)) { dep.setFlags(DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); } + managedDeps.add(new Dependency(extDep.info.deploymentArtifact, JavaScopes.COMPILE)); + collectConditionalDependencies(extDep); } if (isWalkingFlagOn(COLLECT_RELOADABLE_MODULES)) { if (module != null) { @@ -519,13 +519,7 @@ private ExtensionDependency getExtensionDependencyOrNull(DependencyNode node, Ar return null; } - private void visitExtensionDependency(ExtensionDependency extDep) - throws BootstrapDependencyProcessingException { - - managedDeps.add(new Dependency(extDep.info.deploymentArtifact, JavaScopes.COMPILE)); - - collectConditionalDependencies(extDep); - + private void visitExtensionDependency(ExtensionDependency extDep) { if (clearWalkingFlag(COLLECT_TOP_EXTENSION_RUNTIME_NODES)) { currentTopLevelExtension = extDep; } else if (currentTopLevelExtension != null) { From 9291cd97b0414c3f1a2fe70d9f6dc4a11a992793 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 22:39:57 +0000 Subject: [PATCH 126/207] Bump org.apache.logging.log4j:log4j-api from 2.24.2 to 2.24.3 Bumps org.apache.logging.log4j:log4j-api from 2.24.2 to 2.24.3. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 2e2ca4637bcb8..6f92eeae4571c 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -190,7 +190,7 @@ 1.12.0 2.11.0 2.0.1.Final - 2.24.2 + 2.24.3 1.3.1.Final 1.12.0 2.6.6.Final From 90737d678c0af37833d9dd50ce93fea9a8cc77df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 22:41:30 +0000 Subject: [PATCH 127/207] Bump kafka3.version from 3.7.1 to 3.7.2 Bumps `kafka3.version` from 3.7.1 to 3.7.2. Updates `org.apache.kafka:kafka-clients` from 3.7.1 to 3.7.2 Updates `org.apache.kafka:kafka-streams` from 3.7.1 to 3.7.2 Updates `org.apache.kafka:kafka-streams-test-utils` from 3.7.1 to 3.7.2 Updates `org.apache.kafka:kafka_2.13` from 3.7.1 to 3.7.2 --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.kafka:kafka-streams dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.kafka:kafka-streams-test-utils dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.kafka:kafka_2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 2e2ca4637bcb8..21b0bd740aaac 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -138,7 +138,7 @@ 3.6.1.Final 2.7.0 4.0.5 - 3.7.1 + 3.7.2 1.8.0 1.1.10.5 0.107.0 From 6e039fb10a913c6e1288aea44244ba1f11c93f99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 22:43:14 +0000 Subject: [PATCH 128/207] Bump org.hibernate.validator:hibernate-validator Bumps [org.hibernate.validator:hibernate-validator](https://github.com/hibernate/hibernate-validator) from 8.0.1.Final to 8.0.2.Final. - [Changelog](https://github.com/hibernate/hibernate-validator/blob/8.0.2.Final/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-validator/compare/8.0.1.Final...8.0.2.Final) --- updated-dependencies: - dependency-name: org.hibernate.validator:hibernate-validator dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3101339049d40..f4198885401f4 100644 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,7 @@ 1.14.18 7.0.3.Final 2.4.2.Final - 8.0.1.Final + 8.0.2.Final 7.2.2.Final From cec48c0a31d5f38627313bfba422370986854ff1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 22:43:59 +0000 Subject: [PATCH 129/207] Bump org.apache.commons:commons-text from 1.12.0 to 1.13.0 Bumps org.apache.commons:commons-text from 1.12.0 to 1.13.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-text dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 2e2ca4637bcb8..f4be7342962ca 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -187,7 +187,7 @@ 4.7.6 1.1.4 1.27.1 - 1.12.0 + 1.13.0 2.11.0 2.0.1.Final 2.24.2 From 4f8602d8ede4df4195ffc1dd9a0150b735b3c730 Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Fri, 13 Dec 2024 15:02:26 +0100 Subject: [PATCH 130/207] TLS - Enable Policy Configuration for Expired or Not Yet Valid Certificates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces the ability to configure a policy for handling expired or not-yet-valid certificates presented during TLS handshakes (anywhere in the certificate chain). Previously, the trust store could not be configured to reject or warn about such certificates. While surprising, this behavior aligns with RFC 3280 and related specifications. With this change, users can now define the desired behavior using the following options: * IGNORE – Matches the previous behavior, allowing expired or not-yet-valid certificates without any warning. * WARN – Logs a warning message when such certificates are detected in the chain (new default). * REJECT – Rejects the handshake entirely if an expired or not-yet-valid certificate is encountered. --- .../pulsar/PulsarClientConfigCustomizer.java | 5 + .../quarkus/tls/ExpiredJKSTrustStoreTest.java | 100 ++++++++++++ .../quarkus/tls/ExpiredP12TrustStoreTest.java | 100 ++++++++++++ .../quarkus/tls/ExpiredPemTrustStoreTest.java | 98 ++++++++++++ ...stStoreWithMTLSAndServerRejectionTest.java | 87 ++++++++++ .../tls/ExpiredTrustStoreWithMTLSTest.java | 124 ++++++++++++++ .../tls/runtime/config/TrustStoreConfig.java | 27 ++++ .../runtime/keystores/ExpiryTrustOptions.java | 151 ++++++++++++++++++ .../tls/runtime/keystores/JKSKeyStores.java | 8 +- .../tls/runtime/keystores/P12KeyStores.java | 7 +- .../tls/runtime/keystores/PemKeyStores.java | 9 +- 11 files changed, 712 insertions(+), 4 deletions(-) create mode 100644 extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredJKSTrustStoreTest.java create mode 100644 extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredP12TrustStoreTest.java create mode 100644 extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredPemTrustStoreTest.java create mode 100644 extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredTrustStoreWithMTLSAndServerRejectionTest.java create mode 100644 extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredTrustStoreWithMTLSTest.java create mode 100644 extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/ExpiryTrustOptions.java diff --git a/extensions/smallrye-reactive-messaging-pulsar/runtime/src/main/java/io/quarkus/pulsar/PulsarClientConfigCustomizer.java b/extensions/smallrye-reactive-messaging-pulsar/runtime/src/main/java/io/quarkus/pulsar/PulsarClientConfigCustomizer.java index 07e04f1cb9e74..da69afed37ebb 100644 --- a/extensions/smallrye-reactive-messaging-pulsar/runtime/src/main/java/io/quarkus/pulsar/PulsarClientConfigCustomizer.java +++ b/extensions/smallrye-reactive-messaging-pulsar/runtime/src/main/java/io/quarkus/pulsar/PulsarClientConfigCustomizer.java @@ -13,6 +13,7 @@ import io.quarkus.tls.TlsConfiguration; import io.quarkus.tls.TlsConfigurationRegistry; +import io.quarkus.tls.runtime.keystores.ExpiryTrustOptions; import io.smallrye.reactive.messaging.ClientCustomizer; import io.vertx.core.buffer.Buffer; import io.vertx.core.net.KeyCertOptions; @@ -46,6 +47,10 @@ public ClientBuilder customize(String channel, Config channelConfig, ClientBuild KeyCertOptions keyStoreOptions = configuration.getKeyStoreOptions(); TrustOptions trustStoreOptions = configuration.getTrustStoreOptions(); + if (trustStoreOptions instanceof ExpiryTrustOptions) { + trustStoreOptions = ((ExpiryTrustOptions) trustStoreOptions).unwrap(); + } + if (keyStoreOptions instanceof PemKeyCertOptions keyCertOptions && trustStoreOptions instanceof PemTrustOptions trustCertOptions) { Buffer trust = trustCertOptions.getCertValues().stream() diff --git a/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredJKSTrustStoreTest.java b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredJKSTrustStoreTest.java new file mode 100644 index 0000000000000..b421a4cec129c --- /dev/null +++ b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredJKSTrustStoreTest.java @@ -0,0 +1,100 @@ +package io.quarkus.tls; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CountDownLatch; + +import javax.net.ssl.SSLHandshakeException; + +import jakarta.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; + +@Certificates(baseDir = "target/certs", certificates = { + @Certificate(name = "expired-test-formats", password = "password", formats = { Format.JKS, Format.PEM, + Format.PKCS12 }, duration = -5) +}) +public class ExpiredJKSTrustStoreTest { + + private static final String configuration = """ + # Server + quarkus.tls.key-store.jks.path=target/certs/expired-test-formats-keystore.jks + quarkus.tls.key-store.jks.password=password + + # Clients + quarkus.tls.warn.trust-store.jks.path=target/certs/expired-test-formats-truststore.jks + quarkus.tls.warn.trust-store.jks.password=password + quarkus.tls.warn.trust-store.certificate-expiration-policy=warn + + quarkus.tls.reject.trust-store.jks.path=target/certs/expired-test-formats-truststore.jks + quarkus.tls.reject.trust-store.jks.password=password + quarkus.tls.reject.trust-store.certificate-expiration-policy=reject + """; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest().setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .add(new StringAsset(configuration), "application.properties")); + + @Inject + TlsConfigurationRegistry certificates; + + @Inject + Vertx vertx; + + @Test + void testWarn() throws InterruptedException { + TlsConfiguration cf = certificates.get("warn").orElseThrow(); + assertThat(cf.getTrustStoreOptions()).isNotNull(); + + WebClient client = WebClient.create(vertx, new WebClientOptions() + .setSsl(true) + .setTrustOptions(cf.getTrustStoreOptions())); + + vertx.createHttpServer(new HttpServerOptions() + .setSsl(true) + .setKeyCertOptions(certificates.getDefault().orElseThrow().getKeyStoreOptions())) + .requestHandler(rc -> rc.response().end("Hello")).listen(8081).toCompletionStage().toCompletableFuture().join(); + + CountDownLatch latch = new CountDownLatch(1); + client.get(8081, "localhost", "/").send(ar -> { + assertThat(ar.succeeded()).isTrue(); + assertThat(ar.result().bodyAsString()).isEqualTo("Hello"); + latch.countDown(); + }); + + assertThat(latch.await(10, java.util.concurrent.TimeUnit.SECONDS)).isTrue(); + } + + @Test + void testReject() { + TlsConfiguration cf = certificates.get("reject").orElseThrow(); + assertThat(cf.getTrustStoreOptions()).isNotNull(); + + WebClient client = WebClient.create(vertx, new WebClientOptions() + .setSsl(true) + .setTrustOptions(cf.getTrustStoreOptions())); + + vertx.createHttpServer(new HttpServerOptions() + .setSsl(true) + .setKeyCertOptions(certificates.getDefault().orElseThrow().getKeyStoreOptions())) + .requestHandler(rc -> rc.response().end("Hello")).listen(8081).toCompletionStage().toCompletableFuture().join(); + + assertThatThrownBy(() -> client.get(8081, "localhost", "/") + .send().toCompletionStage().toCompletableFuture().join()).hasCauseInstanceOf(SSLHandshakeException.class); + } +} diff --git a/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredP12TrustStoreTest.java b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredP12TrustStoreTest.java new file mode 100644 index 0000000000000..dafb2dce66bd5 --- /dev/null +++ b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredP12TrustStoreTest.java @@ -0,0 +1,100 @@ +package io.quarkus.tls; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CountDownLatch; + +import javax.net.ssl.SSLHandshakeException; + +import jakarta.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; + +@Certificates(baseDir = "target/certs", certificates = { + @Certificate(name = "expired-test-formats", password = "password", formats = { Format.JKS, Format.PEM, + Format.PKCS12 }, duration = -5) +}) +public class ExpiredP12TrustStoreTest { + + private static final String configuration = """ + # Server + quarkus.tls.key-store.p12.path=target/certs/expired-test-formats-keystore.p12 + quarkus.tls.key-store.p12.password=password + + # Clients + quarkus.tls.warn.trust-store.p12.path=target/certs/expired-test-formats-truststore.p12 + quarkus.tls.warn.trust-store.p12.password=password + quarkus.tls.warn.trust-store.certificate-expiration-policy=warn + + quarkus.tls.reject.trust-store.p12.path=target/certs/expired-test-formats-truststore.p12 + quarkus.tls.reject.trust-store.p12.password=password + quarkus.tls.reject.trust-store.certificate-expiration-policy=reject + """; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest().setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .add(new StringAsset(configuration), "application.properties")); + + @Inject + TlsConfigurationRegistry certificates; + + @Inject + Vertx vertx; + + @Test + void testWarn() throws InterruptedException { + TlsConfiguration cf = certificates.get("warn").orElseThrow(); + assertThat(cf.getTrustStoreOptions()).isNotNull(); + + WebClient client = WebClient.create(vertx, new WebClientOptions() + .setSsl(true) + .setTrustOptions(cf.getTrustStoreOptions())); + + vertx.createHttpServer(new HttpServerOptions() + .setSsl(true) + .setKeyCertOptions(certificates.getDefault().orElseThrow().getKeyStoreOptions())) + .requestHandler(rc -> rc.response().end("Hello")).listen(8081).toCompletionStage().toCompletableFuture().join(); + + CountDownLatch latch = new CountDownLatch(1); + client.get(8081, "localhost", "/").send(ar -> { + assertThat(ar.succeeded()).isTrue(); + assertThat(ar.result().bodyAsString()).isEqualTo("Hello"); + latch.countDown(); + }); + + assertThat(latch.await(10, java.util.concurrent.TimeUnit.SECONDS)).isTrue(); + } + + @Test + void testReject() { + TlsConfiguration cf = certificates.get("reject").orElseThrow(); + assertThat(cf.getTrustStoreOptions()).isNotNull(); + + WebClient client = WebClient.create(vertx, new WebClientOptions() + .setSsl(true) + .setTrustOptions(cf.getTrustStoreOptions())); + + vertx.createHttpServer(new HttpServerOptions() + .setSsl(true) + .setKeyCertOptions(certificates.getDefault().orElseThrow().getKeyStoreOptions())) + .requestHandler(rc -> rc.response().end("Hello")).listen(8081).toCompletionStage().toCompletableFuture().join(); + + assertThatThrownBy(() -> client.get(8081, "localhost", "/") + .send().toCompletionStage().toCompletableFuture().join()).hasCauseInstanceOf(SSLHandshakeException.class); + } +} diff --git a/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredPemTrustStoreTest.java b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredPemTrustStoreTest.java new file mode 100644 index 0000000000000..7324667f18623 --- /dev/null +++ b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredPemTrustStoreTest.java @@ -0,0 +1,98 @@ +package io.quarkus.tls; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CountDownLatch; + +import javax.net.ssl.SSLHandshakeException; + +import jakarta.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; + +@Certificates(baseDir = "target/certs", certificates = { + @Certificate(name = "expired-test-formats", password = "password", formats = { Format.JKS, Format.PEM, + Format.PKCS12 }, duration = -5) +}) +public class ExpiredPemTrustStoreTest { + + private static final String configuration = """ + # Server + quarkus.tls.key-store.p12.path=target/certs/expired-test-formats-keystore.p12 + quarkus.tls.key-store.p12.password=password + + # Clients + quarkus.tls.warn.trust-store.pem.certs=target/certs/expired-test-formats.crt + quarkus.tls.warn.trust-store.certificate-expiration-policy=warn + + quarkus.tls.reject.trust-store.pem.certs=target/certs/expired-test-formats.crt + quarkus.tls.reject.trust-store.certificate-expiration-policy=reject + """; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest().setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .add(new StringAsset(configuration), "application.properties")); + + @Inject + TlsConfigurationRegistry certificates; + + @Inject + Vertx vertx; + + @Test + void testWarn() throws InterruptedException { + TlsConfiguration cf = certificates.get("warn").orElseThrow(); + assertThat(cf.getTrustStoreOptions()).isNotNull(); + + WebClient client = WebClient.create(vertx, new WebClientOptions() + .setSsl(true) + .setTrustOptions(cf.getTrustStoreOptions())); + + vertx.createHttpServer(new HttpServerOptions() + .setSsl(true) + .setKeyCertOptions(certificates.getDefault().orElseThrow().getKeyStoreOptions())) + .requestHandler(rc -> rc.response().end("Hello")).listen(8081).toCompletionStage().toCompletableFuture().join(); + + CountDownLatch latch = new CountDownLatch(1); + client.get(8081, "localhost", "/").send(ar -> { + assertThat(ar.succeeded()).isTrue(); + assertThat(ar.result().bodyAsString()).isEqualTo("Hello"); + latch.countDown(); + }); + + assertThat(latch.await(10, java.util.concurrent.TimeUnit.SECONDS)).isTrue(); + } + + @Test + void testReject() { + TlsConfiguration cf = certificates.get("reject").orElseThrow(); + assertThat(cf.getTrustStoreOptions()).isNotNull(); + + WebClient client = WebClient.create(vertx, new WebClientOptions() + .setSsl(true) + .setTrustOptions(cf.getTrustStoreOptions())); + + vertx.createHttpServer(new HttpServerOptions() + .setSsl(true) + .setKeyCertOptions(certificates.getDefault().orElseThrow().getKeyStoreOptions())) + .requestHandler(rc -> rc.response().end("Hello")).listen(8081).toCompletionStage().toCompletableFuture().join(); + + assertThatThrownBy(() -> client.get(8081, "localhost", "/") + .send().toCompletionStage().toCompletableFuture().join()).hasCauseInstanceOf(SSLHandshakeException.class); + } +} diff --git a/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredTrustStoreWithMTLSAndServerRejectionTest.java b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredTrustStoreWithMTLSAndServerRejectionTest.java new file mode 100644 index 0000000000000..5cbd873342efc --- /dev/null +++ b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredTrustStoreWithMTLSAndServerRejectionTest.java @@ -0,0 +1,87 @@ +package io.quarkus.tls; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import jakarta.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.vertx.core.Vertx; +import io.vertx.core.http.ClientAuth; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; + +@Certificates(baseDir = "target/certs", certificates = { + @Certificate(name = "expired-mtls", password = "password", formats = { Format.PKCS12 }, duration = -5, client = true) +}) +public class ExpiredTrustStoreWithMTLSAndServerRejectionTest { + + private static final String configuration = """ + # Server + quarkus.tls.key-store.p12.path=target/certs/expired-mtls-keystore.p12 + quarkus.tls.key-store.p12.password=password + quarkus.tls.trust-store.p12.path=target/certs/expired-mtls-server-truststore.p12 + quarkus.tls.trust-store.p12.password=password + quarkus.tls.trust-store.certificate-expiration-policy=reject + + # Client + quarkus.tls.warn.trust-store.p12.path=target/certs/expired-mtls-client-truststore.p12 + quarkus.tls.warn.trust-store.p12.password=password + quarkus.tls.warn.trust-store.certificate-expiration-policy=ignore + quarkus.tls.warn.key-store.p12.path=target/certs/expired-mtls-client-keystore.p12 + quarkus.tls.warn.key-store.p12.password=password + """; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest().setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .add(new StringAsset(configuration), "application.properties")); + + @Inject + TlsConfigurationRegistry certificates; + + @Inject + Vertx vertx; + + private HttpServer server; + + @AfterEach + void cleanup() { + if (server != null) { + server.close().toCompletionStage().toCompletableFuture().join(); + } + } + + @Test + void testServerRejection() throws InterruptedException { + TlsConfiguration cf = certificates.get("warn").orElseThrow(); + assertThat(cf.getTrustStoreOptions()).isNotNull(); + + WebClient client = WebClient.create(vertx, new WebClientOptions() + .setSsl(true) + .setKeyCertOptions(cf.getKeyStoreOptions()) + .setTrustOptions(cf.getTrustStoreOptions())); + + server = vertx.createHttpServer(new HttpServerOptions() + .setSsl(true) + .setClientAuth(ClientAuth.REQUIRED) + .setTrustOptions(certificates.getDefault().orElseThrow().getTrustStoreOptions()) + .setKeyCertOptions(certificates.getDefault().orElseThrow().getKeyStoreOptions())) + .requestHandler(rc -> rc.response().end("Hello")).listen(8081).toCompletionStage().toCompletableFuture().join(); + + assertThatThrownBy(() -> client.get(8081, "localhost", "/").send().toCompletionStage().toCompletableFuture().join()) + .hasMessageContaining("SSLHandshakeException"); + } +} diff --git a/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredTrustStoreWithMTLSTest.java b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredTrustStoreWithMTLSTest.java new file mode 100644 index 0000000000000..a56fd7af49093 --- /dev/null +++ b/extensions/tls-registry/deployment/src/test/java/io/quarkus/tls/ExpiredTrustStoreWithMTLSTest.java @@ -0,0 +1,124 @@ +package io.quarkus.tls; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CountDownLatch; + +import javax.net.ssl.SSLHandshakeException; + +import jakarta.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.certs.Format; +import io.smallrye.certs.junit5.Certificate; +import io.smallrye.certs.junit5.Certificates; +import io.vertx.core.Vertx; +import io.vertx.core.http.ClientAuth; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; + +@Certificates(baseDir = "target/certs", certificates = { + @Certificate(name = "expired-mtls", password = "password", formats = { Format.PKCS12 }, duration = -5, client = true) +}) +public class ExpiredTrustStoreWithMTLSTest { + + private static final String configuration = """ + # Server + quarkus.tls.key-store.p12.path=target/certs/expired-mtls-keystore.p12 + quarkus.tls.key-store.p12.password=password + quarkus.tls.trust-store.p12.path=target/certs/expired-mtls-server-truststore.p12 + quarkus.tls.trust-store.p12.password=password + # The server will ignore the expired client certificates + + # Clients + quarkus.tls.warn.trust-store.p12.path=target/certs/expired-mtls-client-truststore.p12 + quarkus.tls.warn.trust-store.p12.password=password + quarkus.tls.warn.trust-store.certificate-expiration-policy=warn + quarkus.tls.warn.key-store.p12.path=target/certs/expired-mtls-client-keystore.p12 + quarkus.tls.warn.key-store.p12.password=password + + quarkus.tls.reject.trust-store.p12.path=target/certs/expired-mtls-client-truststore.p12 + quarkus.tls.reject.trust-store.p12.password=password + quarkus.tls.reject.trust-store.certificate-expiration-policy=reject + quarkus.tls.reject.key-store.p12.path=target/certs/expired-mtls-client-keystore.p12 + quarkus.tls.reject.key-store.p12.password=password + """; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest().setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class) + .add(new StringAsset(configuration), "application.properties")); + + @Inject + TlsConfigurationRegistry certificates; + + @Inject + Vertx vertx; + + private HttpServer server; + + @AfterEach + void cleanup() { + if (server != null) { + server.close().toCompletionStage().toCompletableFuture().join(); + } + } + + @Test + void testWarn() throws InterruptedException { + TlsConfiguration cf = certificates.get("warn").orElseThrow(); + assertThat(cf.getTrustStoreOptions()).isNotNull(); + + WebClient client = WebClient.create(vertx, new WebClientOptions() + .setSsl(true) + .setKeyCertOptions(cf.getKeyStoreOptions()) + .setTrustOptions(cf.getTrustStoreOptions())); + + server = vertx.createHttpServer(new HttpServerOptions() + .setSsl(true) + .setClientAuth(ClientAuth.REQUIRED) + .setTrustOptions(certificates.getDefault().orElseThrow().getTrustStoreOptions()) + .setKeyCertOptions(certificates.getDefault().orElseThrow().getKeyStoreOptions())) + .requestHandler(rc -> rc.response().end("Hello")).listen(8081).toCompletionStage().toCompletableFuture().join(); + + CountDownLatch latch = new CountDownLatch(1); + client.get(8081, "localhost", "/").send(ar -> { + assertThat(ar.succeeded()).isTrue(); + assertThat(ar.result().bodyAsString()).isEqualTo("Hello"); + latch.countDown(); + }); + + assertThat(latch.await(10, java.util.concurrent.TimeUnit.SECONDS)).isTrue(); + } + + @Test + void testReject() { + TlsConfiguration cf = certificates.get("reject").orElseThrow(); + assertThat(cf.getTrustStoreOptions()).isNotNull(); + + WebClient client = WebClient.create(vertx, new WebClientOptions() + .setSsl(true) + .setKeyCertOptions(cf.getKeyStoreOptions()) + .setTrustOptions(cf.getTrustStoreOptions())); + + server = vertx.createHttpServer(new HttpServerOptions() + .setSsl(true) + .setClientAuth(ClientAuth.REQUIRED) + .setTrustOptions(certificates.getDefault().orElseThrow().getTrustStoreOptions()) + .setKeyCertOptions(certificates.getDefault().orElseThrow().getKeyStoreOptions())) + .requestHandler(rc -> rc.response().end("Hello")).listen(8081).toCompletionStage().toCompletableFuture().join(); + + assertThatThrownBy(() -> client.get(8081, "localhost", "/") + .send().toCompletionStage().toCompletableFuture().join()).hasCauseInstanceOf(SSLHandshakeException.class); + } +} diff --git a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/config/TrustStoreConfig.java b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/config/TrustStoreConfig.java index 7d7d75df0ffc0..319237618f92e 100644 --- a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/config/TrustStoreConfig.java +++ b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/config/TrustStoreConfig.java @@ -3,6 +3,7 @@ import java.util.Optional; import io.quarkus.runtime.annotations.ConfigGroup; +import io.smallrye.config.WithDefault; @ConfigGroup public interface TrustStoreConfig { @@ -22,6 +23,32 @@ public interface TrustStoreConfig { */ Optional jks(); + /** + * Enforce certificate expiration. + * When enabled, the certificate expiration date is verified and the certificate (or any certificate in the chain) + * is rejected if it is expired. + */ + @WithDefault("WARN") + CertificateExpiryPolicy certificateExpirationPolicy(); + + /** + * The policy to apply when a certificate is expired. + */ + enum CertificateExpiryPolicy { + /** + * Ignore the expiration date. + */ + IGNORE, + /** + * Log a warning when the certificate is expired. + */ + WARN, + /** + * Reject the certificate if it is expired. + */ + REJECT + } + /** * The credential provider configuration for the trust store. * A credential provider offers a way to retrieve the trust store password. diff --git a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/ExpiryTrustOptions.java b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/ExpiryTrustOptions.java new file mode 100644 index 0000000000000..ea57db4c22f33 --- /dev/null +++ b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/ExpiryTrustOptions.java @@ -0,0 +1,151 @@ +package io.quarkus.tls.runtime.keystores; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.util.function.Function; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.TrustManagerFactorySpi; +import javax.net.ssl.X509TrustManager; + +import org.jboss.logging.Logger; + +import io.quarkus.tls.runtime.config.TrustStoreConfig; +import io.smallrye.mutiny.unchecked.Unchecked; +import io.smallrye.mutiny.unchecked.UncheckedFunction; +import io.vertx.core.Vertx; +import io.vertx.core.net.TrustOptions; + +/** + * A trust options that verify for the certificate expiration date and reject the certificate if it is expired. + */ +public class ExpiryTrustOptions implements TrustOptions { + + private final TrustOptions delegate; + private final TrustStoreConfig.CertificateExpiryPolicy policy; + + private static final Logger LOGGER = Logger.getLogger(ExpiryTrustOptions.class); + + public ExpiryTrustOptions(TrustOptions delegate, TrustStoreConfig.CertificateExpiryPolicy certificateExpiryPolicy) { + this.delegate = delegate; + this.policy = certificateExpiryPolicy; + } + + public TrustOptions unwrap() { + return delegate; + } + + @Override + public TrustOptions copy() { + return this; + } + + @Override + public TrustManagerFactory getTrustManagerFactory(Vertx vertx) throws Exception { + var tmf = delegate.getTrustManagerFactory(vertx); + return new TrustManagerFactory(new TrustManagerFactorySpi() { + @Override + protected void engineInit(KeyStore ks) throws KeyStoreException { + tmf.init(ks); + } + + @Override + protected void engineInit(ManagerFactoryParameters spec) throws InvalidAlgorithmParameterException { + tmf.init(spec); + } + + @Override + protected TrustManager[] engineGetTrustManagers() { + var managers = tmf.getTrustManagers(); + return getWrappedTrustManagers(managers); + } + }, tmf.getProvider(), tmf.getAlgorithm()) { + // Empty - we use this pattern to have access to the protected constructor + }; + } + + @Override + public Function trustManagerMapper(Vertx vertx) { + return Unchecked.function(new UncheckedFunction() { + @Override + public TrustManager[] apply(String s) throws Exception { + TrustManager[] tms = delegate.trustManagerMapper(vertx).apply(s); + return ExpiryTrustOptions.this.getWrappedTrustManagers(tms); + } + }); + } + + private TrustManager[] getWrappedTrustManagers(TrustManager[] tms) { + var wrapped = new TrustManager[tms.length]; + for (int i = 0; i < tms.length; i++) { + var manager = tms[i]; + if (!(manager instanceof X509TrustManager)) { + wrapped[i] = manager; + } else { + wrapped[i] = new ExpiryAwareX509TrustManager((X509TrustManager) manager); + } + } + return wrapped; + } + + private class ExpiryAwareX509TrustManager implements X509TrustManager { + + final X509TrustManager tm; + + private ExpiryAwareX509TrustManager(X509TrustManager tm) { + this.tm = tm; + } + + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) + throws CertificateException { + verifyExpiration(chain); + tm.checkClientTrusted(chain, authType); + } + + private void verifyExpiration(X509Certificate[] chain) + throws CertificateExpiredException, CertificateNotYetValidException { + // Verify if there is any expired certificate in the chain - if so, throw an exception + for (X509Certificate cert : chain) { + try { + cert.checkValidity(); + } catch (CertificateExpiredException e) { + // Ignore has been handled before, so, no need to check for this value. + if (policy == TrustStoreConfig.CertificateExpiryPolicy.REJECT) { + LOGGER.error("A certificate has expired - rejecting", e); + throw e; + } else { // WARN + LOGGER.warn("A certificate has expired", e); + } + } catch (CertificateNotYetValidException e) { + // Ignore has been handled before, so, no need to check for this value. + if (policy == TrustStoreConfig.CertificateExpiryPolicy.REJECT) { + LOGGER.error("A certificate is not yet valid - rejecting", e); + throw e; + } else { // WARN + LOGGER.warn("A certificate is not yet valid", e); + } + } + } + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) + throws CertificateException { + verifyExpiration(chain); + tm.checkServerTrusted(chain, authType); + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return tm.getAcceptedIssuers(); + } + } +} diff --git a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/JKSKeyStores.java b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/JKSKeyStores.java index 347127541b1f9..2fc073b2e0eaa 100644 --- a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/JKSKeyStores.java +++ b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/JKSKeyStores.java @@ -43,7 +43,13 @@ public static TrustStoreAndTrustOptions verifyJKSTrustStoreStore(TrustStoreConfi JksOptions options = toOptions(jksConfig, config.credentialsProvider(), name); KeyStore ks = loadKeyStore(vertx, name, options, "trust"); verifyTrustStoreAlias(options, name, ks); - return new TrustStoreAndTrustOptions(ks, options); + if (config.certificateExpirationPolicy() == TrustStoreConfig.CertificateExpiryPolicy.IGNORE) { + return new TrustStoreAndTrustOptions(ks, options); + } else { + var wrapped = new ExpiryTrustOptions(options, config.certificateExpirationPolicy()); + return new TrustStoreAndTrustOptions(ks, wrapped); + } + } private static JksOptions toOptions(JKSKeyStoreConfig config, diff --git a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/P12KeyStores.java b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/P12KeyStores.java index 70f875be2568d..3d205261c836d 100644 --- a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/P12KeyStores.java +++ b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/P12KeyStores.java @@ -43,7 +43,12 @@ public static TrustStoreAndTrustOptions verifyP12TrustStoreStore(TrustStoreConfi PfxOptions options = toOptions(p12Config, config.credentialsProvider(), name); KeyStore ks = loadKeyStore(vertx, name, options, "trust"); verifyTrustStoreAlias(p12Config.alias(), name, ks); - return new TrustStoreAndTrustOptions(ks, options); + if (config.certificateExpirationPolicy() == TrustStoreConfig.CertificateExpiryPolicy.IGNORE) { + return new TrustStoreAndTrustOptions(ks, options); + } else { + var wrapped = new ExpiryTrustOptions(options, config.certificateExpirationPolicy()); + return new TrustStoreAndTrustOptions(ks, wrapped); + } } private static PfxOptions toOptions(P12KeyStoreConfig config, KeyStoreCredentialProviderConfig pc, String name) { diff --git a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/PemKeyStores.java b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/PemKeyStores.java index 47a3e104e357c..e0a21c360b6df 100644 --- a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/PemKeyStores.java +++ b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/keystores/PemKeyStores.java @@ -43,8 +43,13 @@ public static TrustStoreAndTrustOptions verifyPEMTrustStoreStore(TrustStoreConfi } try { var options = config.toOptions(); - KeyStore keyStore = options.loadKeyStore(vertx); - return new TrustStoreAndTrustOptions(keyStore, options); + KeyStore ks = options.loadKeyStore(vertx); + if (tsc.certificateExpirationPolicy() == TrustStoreConfig.CertificateExpiryPolicy.IGNORE) { + return new TrustStoreAndTrustOptions(ks, options); + } else { + var wrapped = new ExpiryTrustOptions(options, tsc.certificateExpirationPolicy()); + return new TrustStoreAndTrustOptions(ks, wrapped); + } } catch (UncheckedIOException e) { throw new IllegalStateException("Invalid PEM trusted certificates configuration for certificate '" + name + "' - cannot read the PEM certificate files", e); From 869c7ba1e25f580ee28e1c7945ea71b41ad00845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Sun, 15 Dec 2024 15:44:51 +0100 Subject: [PATCH 131/207] feat(oidc): Support JWT bearer client authentication --- ...ecurity-oidc-code-flow-authentication.adoc | 12 ++ ...urity-openid-connect-client-reference.adoc | 12 +- .../NamedOidcClientInjectionTestCase.java | 4 +- .../OidcClientKeycloakDevServiceTest.java | 4 +- .../oidc/client/runtime/OidcClientImpl.java | 29 +++- .../client/runtime/OidcClientRecorder.java | 7 +- .../client/OidcClientConfigBuilderTest.java | 6 + .../oidc/client/OidcClientConfigImpl.java | 9 +- .../runtime/ClientAssertionProvider.java | 109 +++++++++++++ .../runtime/OidcClientCommonConfig.java | 9 ++ .../oidc/common/runtime/OidcCommonUtils.java | 46 ++++++ .../config/OidcClientCommonConfig.java | 18 ++- .../config/OidcClientCommonConfigBuilder.java | 19 ++- .../runtime/ClientAssertionProviderTest.java | 59 ++++++++ .../runtime/CodeAuthenticationMechanism.java | 10 +- .../oidc/runtime/OidcIdentityProvider.java | 10 +- .../io/quarkus/oidc/runtime/OidcProvider.java | 2 +- .../oidc/runtime/OidcProviderClient.java | 43 +++++- .../io/quarkus/oidc/runtime/OidcUtils.java | 59 +------- .../oidc/runtime/StaticTenantResolver.java | 3 +- .../runtime/OidcTenantConfigBuilderTest.java | 5 + .../oidc/runtime/OidcTenantConfigImpl.java | 9 +- .../quarkus/oidc/runtime/OidcUtilsTest.java | 11 +- .../ClientAuthWithSignedJwtCreator.java | 143 ++++++++++++++++++ .../keycloak/CustomTenantConfigResolver.java | 23 +++ .../it/keycloak/ProtectedResource.java | 6 + .../keycloak/OidcClientRegistrationTest.java | 18 +++ .../quarkus/it/keycloak/FrontendResource.java | 10 ++ ...JwtBearerFileAuthenticationOidcClient.java | 17 +++ .../src/main/resources/application.properties | 8 + .../KeycloakRealmResourceManager.java | 26 ++++ .../quarkus/it/keycloak/OidcClientTest.java | 10 +- .../SessionExpiredOidcRedirectFilter.java | 3 +- .../it/keycloak/UnprotectedResource.java | 3 +- .../io/quarkus/it/keycloak/CodeFlowTest.java | 11 +- .../keycloak/CodeFlowAuthorizationTest.java | 4 +- 36 files changed, 667 insertions(+), 110 deletions(-) create mode 100644 extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/ClientAssertionProvider.java create mode 100644 extensions/oidc-common/runtime/src/test/java/io/quarkus/oidc/common/runtime/ClientAssertionProviderTest.java create mode 100644 integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/ClientAuthWithSignedJwtCreator.java create mode 100644 integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/JwtBearerFileAuthenticationOidcClient.java diff --git a/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc b/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc index b20907196ff14..a44bf9899fa6d 100644 --- a/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc +++ b/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc @@ -207,6 +207,18 @@ quarkus.oidc.credentials.jwt.key-id=mykeyAlias Using `client_secret_jwt` or `private_key_jwt` authentication methods ensures that a client secret does not get sent to the OIDC provider, therefore avoiding the risk of a secret being intercepted by a 'man-in-the-middle' attack. +.Example how JWT Bearer token can be used to authenticate client + +[source,properties] +---- +quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus/ +quarkus.oidc.client-id=quarkus-app +quarkus.oidc.credentials.jwt.source=bearer <1> +quarkus.oidc.credentials.jwt.token-path=/var/run/secrets/tokens <2> +---- +<1> Use JWT bearer token to authenticate OIDC provider client, see the link:https://www.rfc-editor.org/rfc/rfc7523#section-2.2[Using JWTs for Client Authentication] section for more information. +<2> Path to a JWT bearer token. Quarkus loads a new token from a filesystem and reloads it when the token has expired. + ==== Additional JWT authentication options If `client_secret_jwt`, `private_key_jwt`, or an Apple `post_jwt` authentication methods are used, then you can customize the JWT signature algorithm, key identifier, audience, subject and issuer. diff --git a/docs/src/main/asciidoc/security-openid-connect-client-reference.adoc b/docs/src/main/asciidoc/security-openid-connect-client-reference.adoc index 1f82509661f6b..41387d39bc78e 100644 --- a/docs/src/main/asciidoc/security-openid-connect-client-reference.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-client-reference.adoc @@ -878,7 +878,17 @@ quarkus.oidc-client.credentials.jwt.source=bearer Next, the JWT bearer token must be provided as a `client_assertion` parameter to the OIDC client. -You can use `OidcClient` methods for acquiring or refreshing tokens which accept additional grant parameters, for example, `oidcClient.getTokens(Map.of("client_assertion", "ey..."))`. +Quarkus can load the JWT bearer token from a file system. +For example, in Kubernetes, a service account token projection can be mounted to a `/var/run/secrets/tokens` path. +Then all you need to do is configure a JWT bearer token path as follows: + +[source,properties] +---- +quarkus.oidc-client.credentials.jwt.token-path=/var/run/secrets/tokens <1> +---- +<1> Path to a JWT bearer token. Quarkus loads a new token from a filesystem and reload it when the token has expired. + +Your other option is to use `OidcClient` methods for acquiring or refreshing tokens which accept additional grant parameters, for example, `oidcClient.getTokens(Map.of("client_assertion", "ey..."))`. If you work work with the OIDC client filters then you must register a custom filter which will provide this assertion. diff --git a/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/NamedOidcClientInjectionTestCase.java b/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/NamedOidcClientInjectionTestCase.java index e06687718effd..a164f65178c57 100644 --- a/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/NamedOidcClientInjectionTestCase.java +++ b/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/NamedOidcClientInjectionTestCase.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import io.quarkus.oidc.runtime.OidcUtils; +import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.quarkus.test.QuarkusUnitTest; import io.quarkus.test.common.QuarkusTestResource; import io.restassured.RestAssured; @@ -48,7 +48,7 @@ private void validateTokens(String token1, String token2) { } private String preferredUserOf(String token) { - return OidcUtils.decodeJwtContent(token).getString("preferred_username"); + return OidcCommonUtils.decodeJwtContent(token).getString("preferred_username"); } private String doTestGetTokenByNamedClient(String clientId) { diff --git a/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/OidcClientKeycloakDevServiceTest.java b/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/OidcClientKeycloakDevServiceTest.java index 8a2e94cb42caa..16895e0e833e2 100644 --- a/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/OidcClientKeycloakDevServiceTest.java +++ b/extensions/oidc-client/deployment/src/test/java/io/quarkus/oidc/client/OidcClientKeycloakDevServiceTest.java @@ -13,7 +13,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.oidc.client.runtime.OidcClientsConfig; -import io.quarkus.oidc.runtime.OidcUtils; +import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; @@ -67,7 +67,7 @@ private void validateTokens(String token1, String token2) { } private String upn(String token) { - return OidcUtils.decodeJwtContent(token).getString("upn"); + return OidcCommonUtils.decodeJwtContent(token).getString("upn"); } private String doTestGetTokenByNamedClient(String clientId) { diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java index 3b820603f7d3d..04f0bc32c11cc 100644 --- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java +++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java @@ -22,11 +22,13 @@ import io.quarkus.oidc.common.OidcRequestFilter; import io.quarkus.oidc.common.OidcRequestFilter.OidcRequestContext; import io.quarkus.oidc.common.OidcResponseFilter; +import io.quarkus.oidc.common.runtime.ClientAssertionProvider; import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.quarkus.oidc.common.runtime.OidcConstants; import io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig.Credentials.Jwt.Source; import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.groups.UniOnItem; +import io.vertx.core.Vertx; import io.vertx.core.http.HttpHeaders; import io.vertx.core.json.DecodeException; import io.vertx.core.json.JsonObject; @@ -55,12 +57,13 @@ public class OidcClientImpl implements OidcClient { private final OidcClientConfig oidcConfig; private final Map> requestFilters; private final Map> responseFilters; + private final ClientAssertionProvider clientAssertionProvider; private volatile boolean closed; - public OidcClientImpl(WebClient client, String tokenRequestUri, String tokenRevokeUri, String grantType, + OidcClientImpl(WebClient client, String tokenRequestUri, String tokenRevokeUri, String grantType, MultiMap tokenGrantParams, MultiMap commonRefreshGrantParams, OidcClientConfig oidcClientConfig, Map> requestFilters, - Map> responseFilters) { + Map> responseFilters, Vertx vertx) { this.client = client; this.tokenRequestUri = tokenRequestUri; this.tokenRevokeUri = tokenRevokeUri; @@ -73,6 +76,16 @@ public OidcClientImpl(WebClient client, String tokenRequestUri, String tokenRevo this.clientSecretBasicAuthScheme = OidcCommonUtils.initClientSecretBasicAuth(oidcClientConfig); this.jwtBearerAuthentication = oidcClientConfig.credentials().jwt().source() == Source.BEARER; this.clientJwtKey = jwtBearerAuthentication ? null : OidcCommonUtils.initClientJwtKey(oidcClientConfig, false); + if (jwtBearerAuthentication && oidcClientConfig.credentials().jwt().tokenPath().isPresent()) { + this.clientAssertionProvider = new ClientAssertionProvider(vertx, + oidcClientConfig.credentials().jwt().tokenPath().get()); + if (this.clientAssertionProvider.getClientAssertion() == null) { + throw new OidcClientException("Cannot find a valid JWT bearer token at path: " + + oidcClientConfig.credentials().jwt().tokenPath().get()); + } + } else { + this.clientAssertionProvider = null; + } } @Override @@ -177,7 +190,14 @@ private UniOnItem> postRequest( if (clientSecretBasicAuthScheme != null) { request.putHeader(AUTHORIZATION_HEADER, clientSecretBasicAuthScheme); } else if (jwtBearerAuthentication) { - if (!additionalGrantParameters.containsKey(OidcConstants.CLIENT_ASSERTION)) { + String clientAssertion = additionalGrantParameters.get(OidcConstants.CLIENT_ASSERTION); + if (clientAssertion == null && clientAssertionProvider != null) { + clientAssertion = clientAssertionProvider.getClientAssertion(); + if (clientAssertion != null) { + body.add(OidcConstants.CLIENT_ASSERTION, clientAssertion); + } + } + if (clientAssertion == null) { String errorMessage = String.format( "%s OidcClient can not complete the %s grant request because a JWT bearer client_assertion is missing", oidcConfig.id().get(), (refresh ? OidcConstants.REFRESH_TOKEN_GRANT : grantType)); @@ -319,6 +339,9 @@ private static MultiMap copyMultiMap(MultiMap oldMap) { public void close() throws IOException { if (!closed) { client.close(); + if (clientAssertionProvider != null) { + clientAssertionProvider.close(); + } closed = true; } } diff --git a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java index 5b9c1e6f64faf..86603aeba0015 100644 --- a/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java +++ b/extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientRecorder.java @@ -218,11 +218,8 @@ public OidcClient apply(OidcConfigurationMetadata metadata, Throwable t) { setGrantClientParams(oidcConfig, commonRefreshGrantParams, OidcConstants.REFRESH_TOKEN_GRANT); return new OidcClientImpl(client, metadata.tokenRequestUri, metadata.tokenRevokeUri, grantType, - tokenGrantParams, - commonRefreshGrantParams, - oidcConfig, - oidcRequestFilters, - oidcResponseFilters); + tokenGrantParams, commonRefreshGrantParams, oidcConfig, oidcRequestFilters, + oidcResponseFilters, vertx.get()); } }); diff --git a/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigBuilderTest.java b/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigBuilderTest.java index e32ffb2873c44..5de44331d95f8 100644 --- a/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigBuilderTest.java +++ b/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigBuilderTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.nio.file.Path; import java.time.Duration; import java.util.List; import java.util.Map; @@ -84,6 +85,7 @@ public void testDefaultValues() { assertTrue(jwt.signatureAlgorithm().isEmpty()); assertEquals(10, jwt.lifespan()); assertFalse(jwt.assertion()); + assertFalse(jwt.tokenPath().isPresent()); // OidcCommonConfig methods assertTrue(config.authServerUrl().isEmpty()); @@ -154,6 +156,7 @@ public void testSetEveryProperty() { .end() .jwt() .source(Source.BEARER) + .tokenPath(Path.of("janitor")) .secretProvider() .keyringName("jwt-keyring-name-yep") .key("jwt-key-yep") @@ -249,6 +252,7 @@ public void testSetEveryProperty() { assertNotNull(jwt); assertEquals(Source.BEARER, jwt.source()); assertEquals("jwt-secret-yep", jwt.secret().orElse(null)); + assertEquals("janitor", jwt.tokenPath().map(Path::toString).orElse(null)); provider = jwt.secretProvider(); assertNotNull(provider); assertEquals("jwt-keyring-name-yep", provider.keyringName().orElse(null)); @@ -460,6 +464,7 @@ public void testCopyOidcClientCommonConfigProperties() { .end() .jwt() .source(Source.BEARER) + .tokenPath(Path.of("robot")) .secretProvider() .keyringName("jwt-keyring-name-yep") .key("jwt-key-yep") @@ -507,6 +512,7 @@ public void testCopyOidcClientCommonConfigProperties() { assertNotNull(jwt); assertEquals(Source.BEARER, jwt.source()); assertEquals("jwt-secret-yep", jwt.secret().orElse(null)); + assertEquals("robot", jwt.tokenPath().map(Path::toString).orElse(null)); provider = jwt.secretProvider(); assertNotNull(provider); assertEquals("jwt-keyring-name-yep", provider.keyringName().orElse(null)); diff --git a/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigImpl.java b/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigImpl.java index b786c83e4237a..895e1478a1053 100644 --- a/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigImpl.java +++ b/extensions/oidc-client/runtime/src/test/java/io/quarkus/oidc/client/OidcClientConfigImpl.java @@ -89,7 +89,8 @@ enum ConfigMappingMethods { CREDENTIALS_JWT_LIFESPAN, CREDENTIALS_JWT_ASSERTION, CREDENTIALS_JWT_AUDIENCE, - CREDENTIALS_JWT_TOKEN_ID + CREDENTIALS_JWT_TOKEN_ID, + JWT_BEARER_TOKEN_PATH } final Map invocationsRecorder = new EnumMap<>(ConfigMappingMethods.class); @@ -182,6 +183,12 @@ public Source source() { return Source.BEARER; } + @Override + public Optional tokenPath() { + invocationsRecorder.put(ConfigMappingMethods.JWT_BEARER_TOKEN_PATH, true); + return Optional.empty(); + } + @Override public Optional secret() { invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SECRET, true); diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/ClientAssertionProvider.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/ClientAssertionProvider.java new file mode 100644 index 0000000000000..f5b8cd0a29d63 --- /dev/null +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/ClientAssertionProvider.java @@ -0,0 +1,109 @@ +package io.quarkus.oidc.common.runtime; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.eclipse.microprofile.jwt.Claims; +import org.jboss.logging.Logger; + +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.json.JsonObject; + +public final class ClientAssertionProvider implements Closeable { + + private record ClientAssertion(String bearerToken, long expiresAt, long timerId) { + private boolean isInvalid() { + final long nowSecs = System.currentTimeMillis() / 1000; + return nowSecs > expiresAt; + } + } + + private static final Logger LOG = Logger.getLogger(ClientAssertionProvider.class); + private final Vertx vertx; + private final Path bearerTokenPath; + private volatile ClientAssertion clientAssertion; + + public ClientAssertionProvider(Vertx vertx, Path bearerTokenPath) { + this.vertx = vertx; + this.bearerTokenPath = bearerTokenPath; + this.clientAssertion = loadFromFileSystem(); + } + + public String getClientAssertion() { + ClientAssertion clientAssertion = this.clientAssertion; + if (isInvalid(clientAssertion)) { + clientAssertion = loadClientAssertion(); + } + return clientAssertion == null ? null : clientAssertion.bearerToken; + } + + @Override + public void close() { + cancelRefresh(); + clientAssertion = null; + } + + private synchronized ClientAssertion loadClientAssertion() { + if (isInvalid(clientAssertion)) { + cancelRefresh(); + clientAssertion = loadFromFileSystem(); + } + return clientAssertion; + } + + private long scheduleRefresh(long expiresAt) { + // in K8 and OCP, tokens are proactively rotated at 80 % of their TTL + long delay = (long) (expiresAt * 0.85); + return vertx.setTimer(delay, new Handler() { + @Override + public void handle(Long ignored) { + ClientAssertionProvider.this.clientAssertion = loadFromFileSystem(); + } + }); + } + + private void cancelRefresh() { + if (clientAssertion != null) { + vertx.cancelTimer(clientAssertion.timerId); + } + } + + private ClientAssertion loadFromFileSystem() { + if (Files.exists(bearerTokenPath)) { + try { + String bearerToken = Files.readString(bearerTokenPath).trim(); + Long expiresAt = getExpiresAtFromExpClaim(bearerToken); + if (expiresAt != null) { + return new ClientAssertion(bearerToken, expiresAt, scheduleRefresh(expiresAt)); + } else { + LOG.error("Bearer token or its expiry claim is invalid"); + } + } catch (IOException e) { + LOG.error("Failed to read file with a bearer token at path: " + bearerTokenPath, e); + } + } else { + LOG.warn("Cannot find a file with a bearer token at path: " + bearerTokenPath); + } + return null; + } + + private static boolean isInvalid(ClientAssertion clientAssertion) { + return clientAssertion == null || clientAssertion.isInvalid(); + } + + private static Long getExpiresAtFromExpClaim(String bearerToken) { + JsonObject claims = OidcCommonUtils.decodeJwtContent(bearerToken); + if (claims == null || !claims.containsKey(Claims.exp.name())) { + return null; + } + try { + return claims.getLong(Claims.exp.name()); + } catch (IllegalArgumentException ex) { + LOG.debug("Bearer token expiry claim can not be converted to Long"); + return null; + } + } +} diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java index c7fa4e77f4882..6ed5eeb3ba782 100644 --- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java @@ -1,5 +1,6 @@ package io.quarkus.oidc.common.runtime; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -283,6 +284,11 @@ public io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig.Credentials. .valueOf(source.toString()); } + @Override + public Optional tokenPath() { + return tokenPath; + } + @Override public Optional secret() { return secret; @@ -363,6 +369,8 @@ public boolean assertion() { return assertion; } + private Optional tokenPath = Optional.empty(); + public static enum Source { // JWT token is generated by the OIDC provider client to support // `client_secret_jwt` and `private_key_jwt` authentication methods @@ -578,6 +586,7 @@ private void addConfigMappingValues( signatureAlgorithm = mapping.signatureAlgorithm(); lifespan = mapping.lifespan(); assertion = mapping.assertion(); + tokenPath = mapping.tokenPath(); } } diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonUtils.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonUtils.java index 3be6c684f063d..224ad6af5ab78 100644 --- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonUtils.java +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonUtils.java @@ -24,6 +24,7 @@ import java.util.Optional; import java.util.OptionalInt; import java.util.Set; +import java.util.StringTokenizer; import java.util.concurrent.Callable; import java.util.function.Function; import java.util.function.Predicate; @@ -121,6 +122,14 @@ public static void verifyCommonConfiguration(OidcClientCommonConfig oidcConfig, "Use only '%1$scredentials.secret' or '%1$scredentials.client-secret' or '%1$scredentials.jwt.secret' property", configPrefix)); } + Credentials.Jwt jwt = creds.jwt(); + if (jwt.source() == Credentials.Jwt.Source.BEARER) { + if (isServerConfig && jwt.tokenPath().isEmpty()) { + throw new ConfigurationException("Bearer token path must be set when the JWT source is a bearer token"); + } + } else if (jwt.tokenPath().isPresent()) { + throw new ConfigurationException("Bearer token path can only be set when the JWT source is a bearer token"); + } } public static String prependSlash(String path) { @@ -743,4 +752,41 @@ public Uni> apply(Void unused) { return request.send(); } } + + public static JsonObject decodeJwtContent(String jwt) { + String encodedContent = getJwtContentPart(jwt); + if (encodedContent == null) { + return null; + } + return decodeAsJsonObject(encodedContent); + } + + public static String getJwtContentPart(String jwt) { + StringTokenizer tokens = new StringTokenizer(jwt, "."); + // part 1: skip the token headers + tokens.nextToken(); + if (!tokens.hasMoreTokens()) { + return null; + } + // part 2: token content + String encodedContent = tokens.nextToken(); + + // let's check only 1 more signature part is available + if (tokens.countTokens() != 1) { + return null; + } + return encodedContent; + } + + public static String base64UrlDecode(String encodedContent) { + return new String(Base64.getUrlDecoder().decode(encodedContent), StandardCharsets.UTF_8); + } + + public static JsonObject decodeAsJsonObject(String encodedContent) { + try { + return new JsonObject(base64UrlDecode(encodedContent)); + } catch (IllegalArgumentException ex) { + return null; + } + } } diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfig.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfig.java index 07318e9f4c18a..58b02bdf81ec0 100644 --- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfig.java +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfig.java @@ -1,5 +1,6 @@ package io.quarkus.oidc.common.runtime.config; +import java.nio.file.Path; import java.util.Map; import java.util.Optional; @@ -132,11 +133,14 @@ enum Method { interface Jwt { enum Source { - // JWT token is generated by the OIDC provider client to support - // `client_secret_jwt` and `private_key_jwt` authentication methods + /** + * JWT token is generated by the OIDC provider client to support + * `client_secret_jwt` and `private_key_jwt` authentication methods. + */ CLIENT, - // JWT bearer token as used as a client assertion: https://www.rfc-editor.org/rfc/rfc7523#section-2.2 - // This option is only supported by the OIDC client extension. + /** + * JWT bearer token is used as a client assertion: https://www.rfc-editor.org/rfc/rfc7523#section-2.2. + */ BEARER } @@ -146,6 +150,12 @@ enum Source { @WithDefault("client") Source source(); + /** + * Path to a file with a JWT bearer token that should be used as a client assertion. + * This path can only be set when JWT source ({@link #source()}) is set to {@link Source#BEARER}. + */ + Optional tokenPath(); + /** * If provided, indicates that JWT is signed using a secret key. * It is mutually exclusive with {@link #key}, {@link #keyFile} and {@link #keyStore} properties. diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfigBuilder.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfigBuilder.java index 3e3112d0bd858..643fa456cae2e 100644 --- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfigBuilder.java +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/config/OidcClientCommonConfigBuilder.java @@ -1,5 +1,6 @@ package io.quarkus.oidc.common.runtime.config; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -472,7 +473,8 @@ private record JwtImpl(Source source, Optional secret, Provider secretPr Optional keyFile, Optional keyStoreFile, Optional keyStorePassword, Optional keyId, Optional keyPassword, Optional audience, Optional tokenKeyId, Optional issuer, Optional subject, Map claims, - Optional signatureAlgorithm, int lifespan, boolean assertion) implements Jwt { + Optional signatureAlgorithm, int lifespan, boolean assertion, + Optional tokenPath) implements Jwt { } @@ -492,6 +494,7 @@ private record JwtImpl(Source source, Optional secret, Provider secretPr private Optional issuer; private Optional subject; private Optional signatureAlgorithm; + private Optional tokenPath; private int lifespan; private boolean assertion; @@ -513,6 +516,7 @@ public JwtBuilder() { this.signatureAlgorithm = Optional.empty(); this.lifespan = 10; this.assertion = false; + this.tokenPath = Optional.empty(); } public JwtBuilder(CredentialsBuilder builder) { @@ -538,6 +542,16 @@ private JwtBuilder(CredentialsBuilder builder, Jwt jwt) { this.signatureAlgorithm = jwt.signatureAlgorithm(); this.lifespan = jwt.lifespan(); this.assertion = jwt.assertion(); + this.tokenPath = jwt.tokenPath(); + } + + /** + * @param tokenPath {@link Jwt#tokenPath()} + * @return this builder + */ + public JwtBuilder tokenPath(Path tokenPath) { + this.tokenPath = Optional.ofNullable(tokenPath); + return this; } /** @@ -741,7 +755,8 @@ public T endCredentials() { */ public Jwt build() { return new JwtImpl(source, secret, secretProvider, key, keyFile, keyStoreFile, keyStorePassword, keyId, keyPassword, - audience, tokenKeyId, issuer, subject, Map.copyOf(claims), signatureAlgorithm, lifespan, assertion); + audience, tokenKeyId, issuer, subject, Map.copyOf(claims), signatureAlgorithm, lifespan, assertion, + tokenPath); } } } diff --git a/extensions/oidc-common/runtime/src/test/java/io/quarkus/oidc/common/runtime/ClientAssertionProviderTest.java b/extensions/oidc-common/runtime/src/test/java/io/quarkus/oidc/common/runtime/ClientAssertionProviderTest.java new file mode 100644 index 0000000000000..6c340226da6e0 --- /dev/null +++ b/extensions/oidc-common/runtime/src/test/java/io/quarkus/oidc/common/runtime/ClientAssertionProviderTest.java @@ -0,0 +1,59 @@ +package io.quarkus.oidc.common.runtime; + +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import static java.nio.file.StandardOpenOption.WRITE; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; + +import io.smallrye.jwt.build.Jwt; +import io.vertx.core.Vertx; + +public class ClientAssertionProviderTest { + + @Test + public void testJwtBearerTokenRefresh() { + // if this test ever gets flaky, we will need longer expires in and waiting between storing / refresh + Vertx vertx = Vertx.vertx(); + Path jwtBearerTokenPath = Path.of("target").resolve("jwt-bearer-token.json"); + String jwtBearerToken = createJwtBearerToken(); + storeNewJwtBearerToken(jwtBearerTokenPath, jwtBearerToken); + try (var clientAssertionProvider = new ClientAssertionProvider(vertx, jwtBearerTokenPath)) { + // assert first token is loaded + assertEquals(jwtBearerToken, clientAssertionProvider.getClientAssertion()); + + // create a new token + String secondJwtBearerToken = createJwtBearerToken(); + storeNewJwtBearerToken(jwtBearerTokenPath, secondJwtBearerToken); + + Awaitility.await().atMost(Duration.ofSeconds(10)) + .untilAsserted(() -> assertEquals(secondJwtBearerToken, clientAssertionProvider.getClientAssertion())); + } finally { + vertx.close().toCompletionStage().toCompletableFuture().join(); + } + } + + private static void storeNewJwtBearerToken(Path jwtBearerTokenPath, String jwtBearerToken) { + try { + Files.writeString(jwtBearerTokenPath, jwtBearerToken, TRUNCATE_EXISTING, CREATE, WRITE); + } catch (IOException e) { + throw new RuntimeException("Failed to write JWT bearer token", e); + } + } + + private static String createJwtBearerToken() { + return Jwt.preferredUserName("Arnold") + .issuer("https://server.example.com") + .audience("https://service.example.com") + .expiresIn(Duration.ofSeconds(4)) + .signWithSecret("43".repeat(20)); + } + +} diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java index b6d7a0d6d3cfe..32491900bcb36 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java @@ -513,7 +513,7 @@ private boolean isBackChannelLogoutPending(TenantConfigContext configContext, Se BackChannelLogoutTokenCache tokens = resolver.getBackChannelLogoutTokens() .get(configContext.oidcConfig().tenantId().get()); if (tokens != null) { - JsonObject idTokenJson = OidcUtils.decodeJwtContent(((JsonWebToken) (identity.getPrincipal())).getRawToken()); + JsonObject idTokenJson = OidcCommonUtils.decodeJwtContent(((JsonWebToken) (identity.getPrincipal())).getRawToken()); String logoutTokenKeyValue = idTokenJson .getString(configContext.oidcConfig().logout().backchannel().logoutTokenKey()); @@ -530,7 +530,7 @@ private boolean isBackChannelLogoutPendingAndValid(TenantConfigContext configCon BackChannelLogoutTokenCache tokens = resolver.getBackChannelLogoutTokens() .get(configContext.oidcConfig().tenantId().get()); if (tokens != null) { - JsonObject idTokenJson = OidcUtils.decodeJwtContent(((JsonWebToken) (identity.getPrincipal())).getRawToken()); + JsonObject idTokenJson = OidcCommonUtils.decodeJwtContent(((JsonWebToken) (identity.getPrincipal())).getRawToken()); String logoutTokenKeyValue = idTokenJson .getString(configContext.oidcConfig().logout().backchannel().logoutTokenKey()); @@ -572,7 +572,7 @@ private boolean isBackChannelLogoutPendingAndValid(TenantConfigContext configCon private boolean isFrontChannelLogoutValid(RoutingContext context, TenantConfigContext configContext, SecurityIdentity identity) { if (isEqualToRequestPath(configContext.oidcConfig().logout().frontchannel().path(), context, configContext)) { - JsonObject idTokenJson = OidcUtils.decodeJwtContent(((JsonWebToken) (identity.getPrincipal())).getRawToken()); + JsonObject idTokenJson = OidcCommonUtils.decodeJwtContent(((JsonWebToken) (identity.getPrincipal())).getRawToken()); String idTokenIss = idTokenJson.getString(Claims.iss.name()); List frontChannelIss = context.queryParam(Claims.iss.name()); @@ -975,7 +975,7 @@ private CodeAuthenticationStateBean getCodeAuthenticationBean(String[] parsedSta boolean pkceRequired = authentication.pkceRequired().orElse(false); if (!pkceRequired && !authentication.nonceRequired()) { - JsonObject json = new JsonObject(OidcUtils.base64UrlDecode(parsedStateCookieValue[1])); + JsonObject json = new JsonObject(OidcCommonUtils.base64UrlDecode(parsedStateCookieValue[1])); bean.setRestorePath(json.getString(OidcUtils.STATE_COOKIE_RESTORE_PATH)); return bean; } @@ -1048,7 +1048,7 @@ private Uni processSuccessfulAuthentication(RoutingContext context, @Override public Uni apply(Void t) { - JsonObject idTokenJson = OidcUtils.decodeJwtContent(idToken); + JsonObject idTokenJson = OidcCommonUtils.decodeJwtContent(idToken); if (!idTokenJson.containsKey("exp") || !idTokenJson.containsKey("iat")) { final String error = "ID Token is required to contain 'exp' and 'iat' claims"; diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java index 717fa6b0cff89..673757cbd291d 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java @@ -24,6 +24,7 @@ import io.quarkus.oidc.TokenIntrospectionCache; import io.quarkus.oidc.UserInfo; import io.quarkus.oidc.UserInfoCache; +import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.quarkus.oidc.common.runtime.OidcConstants; import io.quarkus.oidc.runtime.OidcTenantConfig.Roles.Source; import io.quarkus.security.AuthenticationCompletionException; @@ -190,7 +191,8 @@ private Uni verifyPrimaryTokenUni(Map r if (requestData.get(NEW_AUTHENTICATION) == Boolean.TRUE) { // No need to verify it in this case as 'CodeAuthenticationMechanism' has just created it return Uni.createFrom() - .item(new TokenVerificationResult(OidcUtils.decodeJwtContent(request.getToken().getToken()), null)); + .item(new TokenVerificationResult(OidcCommonUtils.decodeJwtContent(request.getToken().getToken()), + null)); } else { return verifySelfSignedTokenUni(resolvedContext, request.getToken().getToken()); } @@ -286,7 +288,7 @@ private Uni createSecurityIdentityWithOidcServer(TokenVerifica // JSON token representation may be null not only if it is an opaque access token // but also if it is JWT and no JWK with a matching kid is available, asynchronous // JWK refresh has not finished yet, but the fallback introspection request has succeeded. - tokenJson = OidcUtils.decodeJwtContent(tokenCred.getToken()); + tokenJson = OidcCommonUtils.decodeJwtContent(tokenCred.getToken()); } if (tokenJson != null) { try { @@ -422,7 +424,7 @@ private static JsonObject getRolesJson(Map requestData, TenantCo // JSON token representation may be null not only if it is an opaque access token // but also if it is JWT and no JWK with a matching kid is available, asynchronous // JWK refresh has not finished yet, but the fallback introspection request has succeeded. - rolesJson = OidcUtils.decodeJwtContent((String) requestData.get(OidcConstants.ACCESS_TOKEN_VALUE)); + rolesJson = OidcCommonUtils.decodeJwtContent((String) requestData.get(OidcConstants.ACCESS_TOKEN_VALUE)); } } } @@ -589,7 +591,7 @@ private static Uni validateTokenWithoutOidcServer(TokenAuthent private Uni getUserInfoUni(Map requestData, TokenAuthenticationRequest request, TenantConfigContext resolvedContext) { if (isInternalIdToken(request) && OidcUtils.cacheUserInfoInIdToken(tenantResolver, resolvedContext.oidcConfig())) { - JsonObject userInfo = OidcUtils.decodeJwtContent(request.getToken().getToken()) + JsonObject userInfo = OidcCommonUtils.decodeJwtContent(request.getToken().getToken()) .getJsonObject(OidcUtils.USER_INFO_ATTRIBUTE); if (userInfo != null) { return Uni.createFrom().item(new UserInfo(userInfo.encode())); diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java index a7f24b28a1740..c50748cf8e936 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java @@ -270,7 +270,7 @@ private TokenVerificationResult verifyJwtTokenInternal(String token, } throw ex; } - TokenVerificationResult result = new TokenVerificationResult(OidcUtils.decodeJwtContent(token), null); + TokenVerificationResult result = new TokenVerificationResult(OidcCommonUtils.decodeJwtContent(token), null); verifyTokenAge(result.localVerificationResult.getLong(Claims.iat.name())); return result; diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java index d1edf36eb1e72..39a696bf8d27e 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java @@ -13,16 +13,17 @@ import io.quarkus.oidc.AuthorizationCodeTokens; import io.quarkus.oidc.OIDCException; import io.quarkus.oidc.OidcConfigurationMetadata; -import io.quarkus.oidc.OidcTenantConfig; import io.quarkus.oidc.TokenIntrospection; import io.quarkus.oidc.common.OidcEndpoint; import io.quarkus.oidc.common.OidcRequestContextProperties; import io.quarkus.oidc.common.OidcRequestFilter; import io.quarkus.oidc.common.OidcRequestFilter.OidcRequestContext; import io.quarkus.oidc.common.OidcResponseFilter; +import io.quarkus.oidc.common.runtime.ClientAssertionProvider; import io.quarkus.oidc.common.runtime.OidcClientRedirectException; import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.quarkus.oidc.common.runtime.OidcConstants; +import io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig; import io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig.Credentials.Secret.Method; import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.groups.UniOnItem; @@ -41,8 +42,7 @@ public class OidcProviderClient implements Closeable { private static final String AUTHORIZATION_HEADER = String.valueOf(HttpHeaders.AUTHORIZATION); private static final String CONTENT_TYPE_HEADER = String.valueOf(HttpHeaders.CONTENT_TYPE); private static final String ACCEPT_HEADER = String.valueOf(HttpHeaders.ACCEPT); - private static final String APPLICATION_X_WWW_FORM_URLENCODED = String - .valueOf(HttpHeaders.APPLICATION_X_WWW_FORM_URLENCODED.toString()); + private static final String APPLICATION_X_WWW_FORM_URLENCODED = HttpHeaders.APPLICATION_X_WWW_FORM_URLENCODED.toString(); private static final String APPLICATION_JSON = "application/json"; private final WebClient client; @@ -52,6 +52,8 @@ public class OidcProviderClient implements Closeable { private final String clientSecretBasicAuthScheme; private final String introspectionBasicAuthScheme; private final Key clientJwtKey; + private final boolean jwtBearerAuthentication; + private final ClientAssertionProvider clientAssertionProvider; private final Map> requestFilters; private final Map> responseFilters; private final boolean clientSecretQueryAuthentication; @@ -67,13 +69,26 @@ public OidcProviderClient(WebClient client, this.metadata = metadata; this.oidcConfig = oidcConfig; this.clientSecretBasicAuthScheme = OidcCommonUtils.initClientSecretBasicAuth(oidcConfig); - this.clientJwtKey = OidcCommonUtils.initClientJwtKey(oidcConfig, true); + this.jwtBearerAuthentication = oidcConfig.credentials().jwt() + .source() == OidcClientCommonConfig.Credentials.Jwt.Source.BEARER; + this.clientAssertionProvider = this.jwtBearerAuthentication ? createClientAssertionProvider(vertx, oidcConfig) : null; + this.clientJwtKey = jwtBearerAuthentication ? null : OidcCommonUtils.initClientJwtKey(oidcConfig, true); this.introspectionBasicAuthScheme = initIntrospectionBasicAuthScheme(oidcConfig); this.requestFilters = requestFilters; this.responseFilters = responseFilters; this.clientSecretQueryAuthentication = oidcConfig.credentials().clientSecret().method().orElse(null) == Method.QUERY; } + private static ClientAssertionProvider createClientAssertionProvider(Vertx vertx, OidcTenantConfig oidcConfig) { + var clientAssertionProvider = new ClientAssertionProvider(vertx, + oidcConfig.credentials().jwt().tokenPath().get()); + if (clientAssertionProvider.getClientAssertion() == null) { + throw new OIDCException("Cannot find a valid JWT bearer token at path: " + + oidcConfig.credentials().jwt().tokenPath().get()); + } + return clientAssertionProvider; + } + private static String initIntrospectionBasicAuthScheme(OidcTenantConfig oidcConfig) { if (oidcConfig.introspectionCredentials().name().isPresent() && oidcConfig.introspectionCredentials().secret().isPresent()) { @@ -111,7 +126,7 @@ private Uni doGetJsonWebKeySet(OidcRequestContextProperties reque return OidcCommonUtils .sendRequest(vertx, filterHttpRequest(requestProps, OidcEndpoint.Type.JWKS, request, null), - oidcConfig.useBlockingDnsLookup) + oidcConfig.useBlockingDnsLookup()) .onItem() .transform(resp -> getJsonWebKeySet(requestProps, resp)); } @@ -143,7 +158,7 @@ private Uni doGetUserInfo(OidcRequestContextProperties request .sendRequest(vertx, filterHttpRequest(requestProps, OidcEndpoint.Type.USERINFO, request, null) .putHeader(AUTHORIZATION_HEADER, OidcConstants.BEARER_SCHEME + " " + token), - oidcConfig.useBlockingDnsLookup) + oidcConfig.useBlockingDnsLookup()) .onItem().transform(resp -> getUserInfo(requestProps, resp)); } @@ -206,6 +221,15 @@ private UniOnItem> getHttpResponse(OidcRequestContextProper } } else if (clientSecretBasicAuthScheme != null) { request.putHeader(AUTHORIZATION_HEADER, clientSecretBasicAuthScheme); + } else if (jwtBearerAuthentication) { + final String clientAssertion = clientAssertionProvider.getClientAssertion(); + if (clientAssertion == null) { + throw new OIDCException(String.format( + "Cannot get token for tenant '%s' because a JWT bearer client_assertion is not available", + oidcConfig.tenantId().get())); + } + formBody.add(OidcConstants.CLIENT_ASSERTION, clientAssertion); + formBody.add(OidcConstants.CLIENT_ASSERTION_TYPE, OidcConstants.JWT_BEARER_CLIENT_ASSERTION_TYPE); } else if (clientJwtKey != null) { String jwt = OidcCommonUtils.signJwtWithKey(oidcConfig, metadata.getTokenUri(), clientJwtKey); if (OidcCommonUtils.isClientSecretPostJwtAuthRequired(oidcConfig.credentials())) { @@ -318,6 +342,9 @@ private static OIDCException responseException(String requestUri, HttpResponse T getAttribute(SecurityIdentity identity, String name) { public static boolean isJwtTokenExpired(String token) { if (!isOpaqueToken(token)) { - JsonObject claims = decodeJwtContent(token); + JsonObject claims = OidcCommonUtils.decodeJwtContent(token); Long expiresAt = getJwtExpiresAtClaim(claims); if (expiresAt == null) { return false; @@ -830,7 +781,7 @@ public static boolean isJwtTokenExpired(String token) { return false; } - private static Long getJwtExpiresAtClaim(JsonObject claims) { + static Long getJwtExpiresAtClaim(JsonObject claims) { if (claims == null || !claims.containsKey(Claims.exp.name())) { return null; } diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/StaticTenantResolver.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/StaticTenantResolver.java index 3a968768e54bd..1cc0128faf13b 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/StaticTenantResolver.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/StaticTenantResolver.java @@ -16,6 +16,7 @@ import io.quarkus.oidc.OidcTenantConfig; import io.quarkus.oidc.TenantResolver; +import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.quarkus.vertx.http.runtime.security.ImmutablePathMatcher; import io.smallrye.mutiny.Uni; import io.vertx.ext.web.RoutingContext; @@ -220,7 +221,7 @@ private boolean tryToInitialize(TenantConfigContext context) { private static String getTenantId(RoutingContext context, TenantConfigContext tenantContext) { final String token = OidcUtils.extractBearerToken(context, tenantContext.oidcConfig()); if (token != null && !OidcUtils.isOpaqueToken(token)) { - final var tokenJson = OidcUtils.decodeJwtContent(token); + final var tokenJson = OidcCommonUtils.decodeJwtContent(token); if (tokenJson != null) { final String iss = tokenJson.getString(Claims.iss.name()); diff --git a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigBuilderTest.java b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigBuilderTest.java index b1b3383f589e2..50fa9f66815eb 100644 --- a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigBuilderTest.java +++ b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigBuilderTest.java @@ -222,6 +222,7 @@ public void testDefaultValues() { assertTrue(jwt.signatureAlgorithm().isEmpty()); assertEquals(10, jwt.lifespan()); assertFalse(jwt.assertion()); + assertTrue(jwt.tokenPath().isEmpty()); // OidcCommonConfig methods assertTrue(config.authServerUrl().isEmpty()); @@ -352,6 +353,7 @@ public void testSetEveryProperty() { .end() .jwt() .source(Source.BEARER) + .tokenPath(Path.of("my-super-bearer-path")) .secretProvider() .keyringName("jwt-keyring-name-yep") .key("jwt-key-yep") @@ -618,6 +620,7 @@ public void testSetEveryProperty() { assertEquals("jwt-token-key-id-yep", jwt.tokenKeyId().orElse(null)); assertEquals("jwt-issuer", jwt.issuer().orElse(null)); assertEquals("jwt-subject", jwt.subject().orElse(null)); + assertEquals("my-super-bearer-path", jwt.tokenPath().orElseThrow().toString()); var claims = jwt.claims(); assertNotNull(claims); assertEquals(2, claims.size()); @@ -761,6 +764,7 @@ public void testCopyOidcClientCommonConfigProperties() { .end() .jwt() .source(Source.BEARER) + .tokenPath(Path.of("jwt-bearer-token-path-test-1")) .secretProvider() .keyringName("jwt-keyring-name-yep") .key("jwt-key-yep") @@ -895,6 +899,7 @@ public void testCopyOidcClientCommonConfigProperties() { assertEquals("jwt-token-key-id-yep", jwt.tokenKeyId().orElse(null)); assertEquals("jwt-issuer-CHANGED", jwt.issuer().orElse(null)); assertEquals("jwt-subject", jwt.subject().orElse(null)); + assertEquals("jwt-bearer-token-path-test-1", jwt.tokenPath().orElseThrow().toString()); claims = jwt.claims(); assertNotNull(claims); assertEquals(3, claims.size()); diff --git a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java index b71efbcb8f78c..73bc8ddf0671b 100644 --- a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java +++ b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java @@ -195,7 +195,8 @@ enum ConfigMappingMethods { INTROSPECTION_CREDENTIALS_NAME, INTROSPECTION_CREDENTIALS_SECRET, INTROSPECTION_CREDENTIALS_INCLUDE_CLIENT_ID, - TENANT_ID + TENANT_ID, + JWT_BEARER_TOKEN_PATH } final Map invocationsRecorder = new EnumMap<>(ConfigMappingMethods.class); @@ -949,6 +950,12 @@ public Source source() { return Source.BEARER; } + @Override + public Optional tokenPath() { + invocationsRecorder.put(ConfigMappingMethods.JWT_BEARER_TOKEN_PATH, true); + return Optional.empty(); + } + @Override public Optional secret() { invocationsRecorder.put(ConfigMappingMethods.CREDENTIALS_JWT_SECRET, true); diff --git a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcUtilsTest.java b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcUtilsTest.java index 15f03705d2936..abcf91f4150ee 100644 --- a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcUtilsTest.java +++ b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcUtilsTest.java @@ -25,6 +25,7 @@ import io.quarkus.oidc.OIDCException; import io.quarkus.oidc.OidcTenantConfig; +import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.smallrye.jwt.build.Jwt; import io.vertx.core.http.Cookie; import io.vertx.core.http.impl.CookieImpl; @@ -245,9 +246,9 @@ public void testTokenIsOpaque() throws Exception { @Test public void testDecodeOpaqueTokenAsJwt() throws Exception { - assertNull(OidcUtils.decodeJwtContent("123")); - assertNull(OidcUtils.decodeJwtContent("1.23")); - assertNull(OidcUtils.decodeJwtContent("1.2.3")); + assertNull(OidcCommonUtils.decodeJwtContent("123")); + assertNull(OidcCommonUtils.decodeJwtContent("1.23")); + assertNull(OidcCommonUtils.decodeJwtContent("1.2.3")); } @Test @@ -256,8 +257,8 @@ public void testDecodeJwt() throws Exception { .getBytes(StandardCharsets.UTF_8); SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "HMACSHA256"); String jwt = Jwt.claims().sign(key); - assertNull(OidcUtils.decodeJwtContent(jwt + ".4")); - JsonObject json = OidcUtils.decodeJwtContent(jwt); + assertNull(OidcCommonUtils.decodeJwtContent(jwt + ".4")); + JsonObject json = OidcCommonUtils.decodeJwtContent(jwt); assertTrue(json.containsKey("iat")); assertTrue(json.containsKey("exp")); assertTrue(json.containsKey("jti")); diff --git a/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/ClientAuthWithSignedJwtCreator.java b/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/ClientAuthWithSignedJwtCreator.java new file mode 100644 index 0000000000000..a8a710e0ab220 --- /dev/null +++ b/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/ClientAuthWithSignedJwtCreator.java @@ -0,0 +1,143 @@ +package io.quarkus.it.keycloak; + +import java.io.IOException; +import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; + +import jakarta.enterprise.event.Observes; +import jakarta.inject.Singleton; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.jose4j.base64url.Base64Url; + +import io.quarkus.logging.Log; +import io.quarkus.oidc.client.registration.ClientMetadata; +import io.quarkus.oidc.client.registration.OidcClientRegistration; +import io.quarkus.runtime.StartupEvent; +import io.smallrye.jwt.build.Jwt; + +@Singleton +public class ClientAuthWithSignedJwtCreator { + + private final KeyPair keyPair; + private final Path signedJwtTokenPath; + private volatile ClientMetadata createdClientMetadata = null; + + ClientAuthWithSignedJwtCreator() { + this.keyPair = generateRsaKeyPair(); + this.signedJwtTokenPath = Path.of("target").resolve("signed-jwt-token"); + } + + /** + * This observer creates client that use authentication with signed JWT, signs a JWT token and stores it as a file. + * This token is valid for 5 minutes and can be used for: https://datatracker.ietf.org/doc/html/rfc7523#section-2.2 + * Quarkus will get the token from the file and use it to get tokens from the token endpoint. + */ + void observe(@Observes StartupEvent event, OidcClientRegistration clientRegistration, + @ConfigProperty(name = "keycloak.url") String keycloakUrl) { + generateRsaKeyPair(); + var requestClientMetadata = new ClientMetadata(createClientMetadataJson(keycloakUrl)); + var registeredClient = clientRegistration.registerClient(requestClientMetadata).await().indefinitely(); + this.createdClientMetadata = registeredClient.metadata(); + var signedJwt = createSignedJwt(keycloakUrl, this.createdClientMetadata.getClientId()); + Log.debugf("Client 'signed-jwt-test' has signed JWT token %s", signedJwt); + storeSignedJwtToken(signedJwt); + } + + ClientMetadata getCreatedClientMetadata() { + return createdClientMetadata; + } + + Path getSignedJwtTokenPath() { + return signedJwtTokenPath; + } + + private void storeSignedJwtToken(String signedJwt) { + try { + Files.writeString(signedJwtTokenPath, signedJwt); + } catch (IOException e) { + throw new RuntimeException("Failed to create signed JWT token", e); + } + } + + private String createSignedJwt(String keycloakUrl, String clientId) { + return Jwt.preferredUserName("alice") + .groups("Contributor") + .issuer(clientId) + .audience(keycloakUrl + "/realms/quarkus/protocol/openid-connect/token") + .subject(clientId) + .sign(keyPair.getPrivate()); + } + + private String createClientMetadataJson(String keycloakUrl) { + RSAPublicKey rsaKey = (RSAPublicKey) keyPair.getPublic(); + String modulus = Base64Url.encode(toIntegerBytes(rsaKey.getModulus())); + String publicExponent = Base64Url.encode(toIntegerBytes(rsaKey.getPublicExponent())); + return """ + { + "redirect_uris" : [ "http://localhost:8081/protected/jwt-bearer-token-file" ], + "token_endpoint_auth_method" : "private_key_jwt", + "grant_types" : [ "client_credentials" ], + "client_name" : "signed-jwt-test", + "client_uri" : "%1$s/auth/realms/quarkus/app", + "jwks" : { + "keys" : [ { + "kid" : "%4$s", + "kty" : "RSA", + "alg" : "RS256", + "use" : "sig", + "e" : "%3$s", + "n" : "%2$s" + } ] + } + } + """ + .formatted(keycloakUrl, modulus, publicExponent, createKeyId()); + } + + private String createKeyId() { + try { + return Base64Url.encode(MessageDigest.getInstance("SHA-256").digest(keyPair.getPrivate().getEncoded())); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Failed to generate key id", e); + } + } + + private static KeyPair generateRsaKeyPair() { + try { + KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); + generator.initialize(2048); + return generator.generateKeyPair(); + } catch (Exception e) { + throw new RuntimeException("Failed to generate RSA key pair", e); + } + } + + private static byte[] toIntegerBytes(final BigInteger bigInt) { + final int bitlen = bigInt.bitLength(); + // following code comes from the Keycloak project + + final int bytelen = (bitlen + 7) / 8; + final byte[] array = bigInt.toByteArray(); + if (array.length == bytelen) { + // expected number of bytes, return them + return array; + } else if (bytelen < array.length) { + // if array is greater is because the sign bit (it can be only 1 byte more), remove it + return Arrays.copyOfRange(array, array.length - bytelen, array.length); + } else { + // if array is smaller fill it with zeros + final byte[] resizedBytes = new byte[bytelen]; + System.arraycopy(array, 0, resizedBytes, bytelen - array.length, array.length); + return resizedBytes; + } + } + +} diff --git a/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/CustomTenantConfigResolver.java b/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/CustomTenantConfigResolver.java index 9d8075d50e34d..1e281f0057658 100644 --- a/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/CustomTenantConfigResolver.java +++ b/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/CustomTenantConfigResolver.java @@ -1,5 +1,8 @@ package io.quarkus.it.keycloak; +import static io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig.Credentials.Jwt.Source.BEARER; +import static io.quarkus.oidc.runtime.OidcTenantConfig.ApplicationType.WEB_APP; + import java.net.URI; import java.util.List; import java.util.Map; @@ -34,6 +37,9 @@ public class CustomTenantConfigResolver implements TenantConfigResolver { @Inject OidcClientRegistrations clientRegs; + @Inject + ClientAuthWithSignedJwtCreator clientAuthWithSignedJwtCreator; + @Inject @ConfigProperty(name = "quarkus.oidc.auth-server-url") String authServerUrl; @@ -122,6 +128,23 @@ public Uni resolve(RoutingContext routingContext, } else if (routingContext.request().path().endsWith("/protected/multi2")) { return Uni.createFrom().item(createTenantConfig("registered-client-multi2", regClientsMulti.get("/protected/multi2").metadata())); + } else if (routingContext.normalizedPath().endsWith("/jwt-bearer-token-file")) { + var clientMetadata = clientAuthWithSignedJwtCreator.getCreatedClientMetadata(); + var redirectPath = URI.create(clientMetadata.getRedirectUris().get(0)).getPath(); + var tenantConfig = OidcTenantConfig + .authServerUrl(authServerUrl) + .applicationType(WEB_APP) + .tenantId("registered-client-jwt-bearer-token-file") + .clientName(clientMetadata.getClientName()) + .clientId(clientMetadata.getClientId()) + .authentication().redirectPath(redirectPath).end() + .credentials() + .jwt() + .source(BEARER) + .tokenPath(clientAuthWithSignedJwtCreator.getSignedJwtTokenPath()) + .endCredentials() + .build(); + return Uni.createFrom().item(tenantConfig); } return null; diff --git a/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java b/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java index 81ace6de744cb..63610105b20db 100644 --- a/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java +++ b/integration-tests/oidc-client-registration/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java @@ -61,6 +61,12 @@ public String principalNameMulti2() { return session.getTenantId() + ":" + getClientName() + ":" + principal.getName(); } + @GET + @Path("/jwt-bearer-token-file") + public String jwtBearerTokenFile() { + return session.getTenantId() + ":" + getClientName() + ":" + principal.getName(); + } + private String getClientName() { OidcTenantConfig oidcConfig = tenantConfigBean.getDynamicTenant(session.getTenantId()) .getOidcTenantConfig(); diff --git a/integration-tests/oidc-client-registration/src/test/java/io/quarkus/it/keycloak/OidcClientRegistrationTest.java b/integration-tests/oidc-client-registration/src/test/java/io/quarkus/it/keycloak/OidcClientRegistrationTest.java index 197aace36bd85..c1972cc05cc2a 100644 --- a/integration-tests/oidc-client-registration/src/test/java/io/quarkus/it/keycloak/OidcClientRegistrationTest.java +++ b/integration-tests/oidc-client-registration/src/test/java/io/quarkus/it/keycloak/OidcClientRegistrationTest.java @@ -137,6 +137,24 @@ public void testRegisteredClientMulti2() throws IOException { } } + @Test + public void testRegisteredClientJwtBearerTokenFromFile() throws IOException { + try (final WebClient webClient = createWebClient()) { + HtmlPage page = webClient.getPage("http://localhost:8081/protected/jwt-bearer-token-file"); + + assertEquals("Sign in to quarkus", page.getTitleText()); + + HtmlForm loginForm = page.getForms().get(0); + + loginForm.getInputByName("username").setValueAttribute("alice"); + loginForm.getInputByName("password").setValueAttribute("alice"); + + TextPage textPage = loginForm.getInputByName("login").click(); + + assertEquals("registered-client-jwt-bearer-token-file:signed-jwt-test:alice", textPage.getContent()); + } + } + private WebClient createWebClient() { WebClient webClient = new WebClient(); webClient.setCssErrorHandler(new SilentCssErrorHandler()); diff --git a/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/FrontendResource.java b/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/FrontendResource.java index 76564a6e68857..04af1e24b3954 100644 --- a/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/FrontendResource.java +++ b/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/FrontendResource.java @@ -33,6 +33,10 @@ public class FrontendResource { @RestClient JwtBearerAuthenticationOidcClient jwtBearerAuthenticationOidcClient; + @Inject + @RestClient + JwtBearerFileAuthenticationOidcClient jwtBearerFileAuthenticationOidcClient; + @Inject @NamedOidcClient("non-standard-response") Tokens tokens; @@ -76,6 +80,12 @@ public String echoTokenJwtBearerAuthentication() { return jwtBearerAuthenticationOidcClient.echoToken(); } + @GET + @Path("echoTokenJwtBearerAuthenticationFromFile") + public String echoTokenJwtBearerAuthenticationFromFile() { + return jwtBearerFileAuthenticationOidcClient.echoToken(); + } + @GET @Path("echoTokenNonStandardResponse") public String echoTokenNonStandardResponse() { diff --git a/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/JwtBearerFileAuthenticationOidcClient.java b/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/JwtBearerFileAuthenticationOidcClient.java new file mode 100644 index 0000000000000..9ee473d775533 --- /dev/null +++ b/integration-tests/oidc-client-wiremock/src/main/java/io/quarkus/it/keycloak/JwtBearerFileAuthenticationOidcClient.java @@ -0,0 +1,17 @@ +package io.quarkus.it.keycloak; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +import io.quarkus.oidc.client.filter.OidcClientFilter; + +@RegisterRestClient +@OidcClientFilter("jwtbearer-file") +@Path("/") +public interface JwtBearerFileAuthenticationOidcClient { + + @GET + String echoToken(); +} diff --git a/integration-tests/oidc-client-wiremock/src/main/resources/application.properties b/integration-tests/oidc-client-wiremock/src/main/resources/application.properties index 9285f92bbb684..79316e6568243 100644 --- a/integration-tests/oidc-client-wiremock/src/main/resources/application.properties +++ b/integration-tests/oidc-client-wiremock/src/main/resources/application.properties @@ -19,6 +19,13 @@ quarkus.oidc-client.jwtbearer.token-path=/tokens-jwtbearer quarkus.oidc-client.jwtbearer.client-id=quarkus-app quarkus.oidc-client.jwtbearer.credentials.jwt.source=bearer +quarkus.oidc-client.jwtbearer-file.auth-server-url=${keycloak.url} +quarkus.oidc-client.jwtbearer-file.discovery-enabled=false +quarkus.oidc-client.jwtbearer-file.token-path=/tokens-jwtbearer-file +quarkus.oidc-client.jwtbearer-file.client-id=quarkus-app +quarkus.oidc-client.jwtbearer-file.credentials.jwt.source=bearer +quarkus.oidc-client.jwtbearer-file.credentials.jwt.token-path=${token-path:} + quarkus.oidc-client.jwtbearer-grant.auth-server-url=${keycloak.url} quarkus.oidc-client.jwtbearer-grant.discovery-enabled=false quarkus.oidc-client.jwtbearer-grant.token-path=/tokens-jwtbearer-grant @@ -88,6 +95,7 @@ quarkus.oidc-client.crash-test.early-tokens-acquisition=false io.quarkus.it.keycloak.ProtectedResourceServiceOidcClient/mp-rest/url=http://localhost:8081/protected io.quarkus.it.keycloak.JwtBearerAuthenticationOidcClient/mp-rest/url=http://localhost:8081/protected +io.quarkus.it.keycloak.JwtBearerFileAuthenticationOidcClient/mp-rest/url=http://localhost:8081/protected io.quarkus.it.keycloak.ProtectedResourceServiceCrashTestClient/mp-rest/url=http://localhost:8081/protected quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".min-level=TRACE diff --git a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java index ea3ba7842ea0c..f2f7c2cbb50d9 100644 --- a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java +++ b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/KeycloakRealmResourceManager.java @@ -4,6 +4,10 @@ import static com.github.tomakehurst.wiremock.client.WireMock.matching; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; import java.util.HashMap; import java.util.Map; @@ -16,6 +20,7 @@ import com.github.tomakehurst.wiremock.core.Options.ChunkedEncodingPolicy; import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import io.smallrye.jwt.build.Jwt; public class KeycloakRealmResourceManager implements QuarkusTestResourceLifecycleManager { @@ -53,6 +58,26 @@ public Map start() { .withHeader("Content-Type", MediaType.APPLICATION_JSON) .withBody( "{\"access_token\":\"access_token_jwt_bearer_grant\", \"expires_in\":4, \"refresh_token\":\"refresh_token_jwt_bearer\"}"))); + String jwtBearerToken = Jwt.preferredUserName("Arnold") + .issuer("https://server.example.com") + .audience("https://service.example.com") + .expiresIn(Duration.ofMinutes(30)) + .signWithSecret("43".repeat(20)); + var jwtBearerTokenPath = Path.of("target").resolve("bearer-token-client-assertion.json"); + try { + Files.writeString(jwtBearerTokenPath, jwtBearerToken); + } catch (IOException e) { + throw new RuntimeException("Failed to prepare file with a client assertion", e); + } + server.stubFor(WireMock.post("/tokens-jwtbearer-file") + .withRequestBody(matching("grant_type=client_credentials&" + + "client_assertion=" + jwtBearerToken + + "&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer")) + .willReturn(WireMock + .aResponse() + .withHeader("Content-Type", MediaType.APPLICATION_JSON) + .withBody( + "{\"access_token\":\"access_token_jwt_bearer\", \"expires_in\":4, \"refresh_token\":\"refresh_token_jwt_bearer\"}"))); server.stubFor(WireMock.post("/tokens_public_client") .withRequestBody(matching("grant_type=password&username=alice&password=alice&client_id=quarkus-app")) .willReturn(WireMock @@ -166,6 +191,7 @@ public Map start() { Map conf = new HashMap<>(); conf.put("keycloak.url", server.baseUrl()); + conf.put("token-path", jwtBearerTokenPath.toString()); return conf; } diff --git a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java index 890bce60e15a9..058836d482e33 100644 --- a/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java +++ b/integration-tests/oidc-client-wiremock/src/test/java/io/quarkus/it/keycloak/OidcClientTest.java @@ -39,13 +39,21 @@ public class OidcClientTest { WireMockServer server; @Test - public void testEchoTokensJwtBearerAuthentication() { + public void testEchoTokensJwtBearerAuthenticationFromAdditionalAttrs() { RestAssured.when().get("/frontend/echoTokenJwtBearerAuthentication") .then() .statusCode(200) .body(equalTo("access_token_jwt_bearer")); } + @Test + public void testEchoTokensJwtBearerAuthenticationFromFile() { + RestAssured.when().get("/frontend/echoTokenJwtBearerAuthenticationFromFile") + .then() + .statusCode(200) + .body(equalTo("access_token_jwt_bearer")); + } + @Test public void testGetAccessTokenWithConfiguredExpiresIn() { Response r = RestAssured.when().get("/frontend/echoTokenConfiguredExpiresIn"); diff --git a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/SessionExpiredOidcRedirectFilter.java b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/SessionExpiredOidcRedirectFilter.java index 709b516e758ff..bd26d840475c2 100644 --- a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/SessionExpiredOidcRedirectFilter.java +++ b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/SessionExpiredOidcRedirectFilter.java @@ -10,6 +10,7 @@ import io.quarkus.oidc.Redirect; import io.quarkus.oidc.Redirect.Location; import io.quarkus.oidc.TenantFeature; +import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.quarkus.oidc.runtime.OidcUtils; import io.smallrye.jwt.build.Jwt; @@ -31,7 +32,7 @@ public void filter(OidcRedirectContext context) { } AuthorizationCodeTokens tokens = context.routingContext().get(AuthorizationCodeTokens.class.getName()); - String userName = OidcUtils.decodeJwtContent(tokens.getIdToken()).getString(Claims.preferred_username.name()); + String userName = OidcCommonUtils.decodeJwtContent(tokens.getIdToken()).getString(Claims.preferred_username.name()); String jwe = Jwt.preferredUserName(userName).jwe() .encryptWithSecret(context.oidcTenantConfig().credentials.secret.get()); OidcUtils.createCookie(context.routingContext(), context.oidcTenantConfig(), "session_expired", diff --git a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/UnprotectedResource.java b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/UnprotectedResource.java index 46168c0154bc6..4543696184483 100644 --- a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/UnprotectedResource.java +++ b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/UnprotectedResource.java @@ -21,7 +21,6 @@ import io.quarkus.oidc.client.OidcClient; import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.quarkus.oidc.common.runtime.OidcConstants; -import io.quarkus.oidc.runtime.OidcUtils; @Path("/public-web-app") public class UnprotectedResource { @@ -54,7 +53,7 @@ public String callback(@QueryParam("code") String code) { grantParams.put(OidcConstants.CODE_FLOW_CODE, code); grantParams.put(OidcConstants.CODE_FLOW_REDIRECT_URI, redirectUriParam); String encodedIdToken = oidcClient.getTokens(grantParams).await().indefinitely().get(OidcConstants.ID_TOKEN_VALUE); - return OidcUtils.decodeJwtContent(encodedIdToken).getString("preferred_username"); + return OidcCommonUtils.decodeJwtContent(encodedIdToken).getString("preferred_username"); } @GET diff --git a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java index 86a2689a2db34..3f2a60b94d61f 100644 --- a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java +++ b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java @@ -34,6 +34,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.quarkus.oidc.runtime.OidcUtils; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; @@ -353,7 +354,7 @@ public void testCodeFlowForceHttpsRedirectUriWithQueryAndPkce() throws Exception String encodedIdToken = decryptedSessionCookieValue.split("\\|")[0]; - JsonObject idToken = OidcUtils.decodeJwtContent(encodedIdToken); + JsonObject idToken = OidcCommonUtils.decodeJwtContent(encodedIdToken); String expiresAt = idToken.getInteger("exp").toString(); page = webClient.getPage(endpointLocationWithoutQueryUri.toURL()); String response = page.getBody().asNormalizedText(); @@ -1211,9 +1212,9 @@ public void testDefaultSessionManagerIdRefreshTokens() throws Exception { String[] parts = sessionCookieValue.split("\\|"); assertEquals(3, parts.length); - assertEquals("ID", OidcUtils.decodeJwtContent(parts[0]).getString("typ")); + assertEquals("ID", OidcCommonUtils.decodeJwtContent(parts[0]).getString("typ")); assertEquals("", parts[1]); - assertEquals("Refresh", OidcUtils.decodeJwtContent(parts[2]).getString("typ")); + assertEquals("Refresh", OidcCommonUtils.decodeJwtContent(parts[2]).getString("typ")); assertNull(getSessionAtCookie(webClient, "tenant-id-refresh-token")); assertNull(getSessionRtCookie(webClient, "tenant-id-refresh-token")); @@ -1354,7 +1355,7 @@ private void checkSingleTokenCookie(Cookie tokenCookie, String type, String decr } } assertEquals(3, tokenParts.length); - JsonObject json = OidcUtils.decodeJwtContent(token); + JsonObject json = OidcCommonUtils.decodeJwtContent(token); assertEquals(type, json.getString("typ")); } @@ -1595,7 +1596,7 @@ private String getStateCookieSavedPath(Cookie stateCookie) { } private String getSavedPathFromJson(String value) { - JsonObject json = new JsonObject(OidcUtils.base64UrlDecode(value)); + JsonObject json = new JsonObject(OidcCommonUtils.base64UrlDecode(value)); return json.getString(OidcUtils.STATE_COOKIE_RESTORE_PATH); } diff --git a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java index 3feda8cc8e90f..ed6fce21ac10a 100644 --- a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java +++ b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java @@ -406,7 +406,7 @@ public void testCodeFlowUserInfoCachedInIdToken() throws Exception { Thread.sleep(3000); // Refresh token is available but it is expired, so no token endpoint call is expected - assertTrue((System.currentTimeMillis() / 1000) > OidcUtils.decodeJwtContent(refreshJwtToken) + assertTrue((System.currentTimeMillis() / 1000) > OidcCommonUtils.decodeJwtContent(refreshJwtToken) .getLong(Claims.exp.name())); webClient.getOptions().setRedirectEnabled(false); @@ -595,7 +595,7 @@ private JsonObject decryptIdToken(WebClient webClient, String tenantId) throws E String encodedIdToken = decryptedSessionCookie.split("\\|")[0]; - return OidcUtils.decodeJwtContent(encodedIdToken); + return OidcCommonUtils.decodeJwtContent(encodedIdToken); } private WebClient createWebClient() { From 327341c79a719650ba5a5eea1f14512ed506b21b Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 16 Dec 2024 09:11:38 +0200 Subject: [PATCH 132/207] Break build cycle between OTel, logging and Flyway Fixes: #45130 --- .../main/java/io/quarkus/flyway/deployment/FlywayProcessor.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/deployment/FlywayProcessor.java b/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/deployment/FlywayProcessor.java index bf5a400c5610d..76dc5882235b2 100644 --- a/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/deployment/FlywayProcessor.java +++ b/extensions/flyway/deployment/src/main/java/io/quarkus/flyway/deployment/FlywayProcessor.java @@ -61,7 +61,6 @@ import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem; -import io.quarkus.deployment.logging.LoggingSetupBuildItem; import io.quarkus.deployment.recording.RecorderContext; import io.quarkus.flyway.FlywayDataSource; import io.quarkus.flyway.runtime.FlywayBuildTimeConfig; @@ -184,7 +183,6 @@ private void addJavaMigrations(Collection candidates, RecorderContext @BuildStep @Produce(SyntheticBeansRuntimeInitBuildItem.class) - @Consume(LoggingSetupBuildItem.class) @Record(ExecutionTime.RUNTIME_INIT) void createBeans(FlywayRecorder recorder, List jdbcDataSourceBuildItems, From 796c92acec34cb3d6bcc2e4f58019bf967e18389 Mon Sep 17 00:00:00 2001 From: Antonio Musarra Date: Fri, 13 Dec 2024 21:58:54 +0100 Subject: [PATCH 133/207] Fixed the assign value to the latestCommitTime: Replaced the method Instant.ofEpochMilli() with the method Instant.ofEpochSecond() because RevCommit.getCommitTime() return the number of the seconds from epoch. --- .../src/main/java/io/quarkus/info/deployment/InfoProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java index 27e76b1996431..135751323adef 100644 --- a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java +++ b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java @@ -85,7 +85,7 @@ void gitInfo(InfoBuildTimeConfig config, Map commit = new LinkedHashMap<>(); String latestCommitId = latestCommit.getName(); commit.put("id", latestCommitId); - String latestCommitTime = formatDate(Instant.ofEpochMilli(latestCommit.getCommitTime()), ZoneId.systemDefault()); + String latestCommitTime = formatDate(Instant.ofEpochSecond(latestCommit.getCommitTime()), ZoneId.systemDefault()); commit.put("time", latestCommitTime); if (addFullInfo) { From 13b72c6706caae10c5b7b90e447c16a6c1faeb28 Mon Sep 17 00:00:00 2001 From: Antonio Musarra Date: Sat, 14 Dec 2024 15:20:59 +0100 Subject: [PATCH 134/207] Extension of the JavaInfo interface: - added the method vendor - added the method vendorVersion - review the InfoRecorder - review the UnitTest --- .../io/quarkus/info/deployment/EnabledInfoTest.java | 2 ++ .../src/main/java/io/quarkus/info/JavaInfo.java | 4 ++++ .../java/io/quarkus/info/runtime/InfoRecorder.java | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/EnabledInfoTest.java b/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/EnabledInfoTest.java index fbac5fd326911..af7ca758626b2 100644 --- a/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/EnabledInfoTest.java +++ b/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/EnabledInfoTest.java @@ -70,5 +70,7 @@ public void test() { assertNotNull(javaInfo); assertNotNull(javaInfo.version()); + assertNotNull(javaInfo.vendor()); + assertNotNull(javaInfo.vendorVersion()); } } diff --git a/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java b/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java index e7e4ed3c7fa90..be30d87e468b2 100644 --- a/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java +++ b/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java @@ -3,4 +3,8 @@ public interface JavaInfo { String version(); + + String vendor(); + + String vendorVersion(); } diff --git a/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/InfoRecorder.java b/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/InfoRecorder.java index c3380f685abca..0411426bf63ee 100644 --- a/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/InfoRecorder.java +++ b/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/InfoRecorder.java @@ -134,6 +134,16 @@ public JavaInfo get() { public String version() { return JavaInfoContributor.getVersion(); } + + @Override + public String vendor() { + return JavaInfoContributor.getVendor(); + } + + @Override + public String vendorVersion() { + return JavaInfoContributor.getVendorVersion(); + } }; } }; From d61589b07d24245ca19f892d9ffbdda74778252b Mon Sep 17 00:00:00 2001 From: Antonio Musarra Date: Sat, 14 Dec 2024 15:22:00 +0100 Subject: [PATCH 135/207] Extended the DevUI JavaInfo card with the new info. --- .../src/main/resources/dev-ui/qwc-info.js | 7 ++++++- .../main/java/io/quarkus/info/JavaInfo.java | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/extensions/info/deployment/src/main/resources/dev-ui/qwc-info.js b/extensions/info/deployment/src/main/resources/dev-ui/qwc-info.js index a89b011d4f67b..2590edb796c58 100644 --- a/extensions/info/deployment/src/main/resources/dev-ui/qwc-info.js +++ b/extensions/info/deployment/src/main/resources/dev-ui/qwc-info.js @@ -104,6 +104,8 @@ export class QwcInfo extends LitElement {

    -_$nQUv^2W2$S=u>@K`EXle)>&K^I=jz7ef)Qx><1>f!X{de$S z%@{AP2ej3H$g3g9MgveQ{XQc*Kd`^+#7GBZ!aJYP2zr*O#FdWcZQ&2d!YtlmT`%eT zc4585{RkLzDGv_|enFRp$iv5>y#Y?;?0#0Ox%Zp(yxhE3ia)qnl0FUe@g=$g1`h2N za36TJrijin*t9@~K((qtQtFYhv`U14ffgc=b_$a3|$K;7M7aEaGiWmxPSkkUk& zt>ECE4pawXQ`6?Lgz20ncd~l@%qfs(eGDyg-&kY6R96Gqf!WzC317y{RP8KOm4tP+ zg}a7u9e1KAvnK6o7NZh-7`e*NxiH_?)Bo1LFVTMxPn}ylrMvr%WWj@$Ve!PWienJp z=2Vt{FY(4tZpQVY4Q&muzP2*62aU3&^WbF zn~a9BN<9{IAjztkGoH-yJBkZ_w<>_EF|KEq%ydLR*Jnpud@?E}Q&CyPceL|CEM`|$ z_fM{k`*i~5zf6G*emu{SvAR`9W--bi{M%Y+)E7^d+{Nx|uSAF{c delta 44720 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 delta 68911 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 z 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 z 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≧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

    + +
    Version${java.version}
    Vendor${java.vendor}
    Vendor Version${java.vendorVersion}
    `; @@ -151,7 +153,8 @@ export class QwcInfo extends LitElement { _renderOptionalData(git){ if(typeof git.commit.id !== "string"){ return html`Commit User${git.commit.user.name} <${git.commit.user.email}> - Commit Message${unsafeHTML(this._replaceNewLine(git.commit.id.message.full))}` + Commit Message${unsafeHTML(this._replaceNewLine(git.commit.id.message.full))} + Remote URL${unsafeHTML(git.remote)}` } } @@ -165,6 +168,8 @@ export class QwcInfo extends LitElement { return html`
    + + diff --git a/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java b/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java index be30d87e468b2..aeacce219a2b2 100644 --- a/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java +++ b/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java @@ -1,10 +1,31 @@ package io.quarkus.info; +/** + * This interface provides information about the Java runtime. + * + * @see io.quarkus.info.runtime.InfoRecorder + * @see io.quarkus.info.runtime.JavaInfoContributor + */ public interface JavaInfo { + /** + * Return the Java version with which application compiled. + * + * @return string that represent the Java version + */ String version(); + /** + * Return the Java vendor with which application compiled. + * + * @return string that represent the Java vendor + */ String vendor(); + /** + * Return the Java vendor version with which application compiled. + * + * @return string that represent the Java vendor version + */ String vendorVersion(); } From b7ad29cedeec1ca0ef29a1eaa906b4947587b827 Mon Sep 17 00:00:00 2001 From: Antonio Musarra Date: Sat, 14 Dec 2024 23:45:07 +0100 Subject: [PATCH 136/207] Reviewed the JavaDoc of the JavaInfo interface. --- .../runtime/src/main/java/io/quarkus/info/JavaInfo.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java b/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java index aeacce219a2b2..35a76cf26c9ad 100644 --- a/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java +++ b/extensions/info/runtime/src/main/java/io/quarkus/info/JavaInfo.java @@ -9,21 +9,21 @@ public interface JavaInfo { /** - * Return the Java version with which application compiled. + * Return the Java runtime version. * * @return string that represent the Java version */ String version(); /** - * Return the Java vendor with which application compiled. + * Return the Java vendor. * * @return string that represent the Java vendor */ String vendor(); /** - * Return the Java vendor version with which application compiled. + * Return the Java vendor runtime version. * * @return string that represent the Java vendor version */ From 40c114de1e76350758b7146c44c140b03144396c Mon Sep 17 00:00:00 2001 From: mariofusco Date: Mon, 16 Dec 2024 12:14:20 +0100 Subject: [PATCH 137/207] Drools extension documentation --- docs/src/main/asciidoc/drools.adoc | 638 +++++++++++++++++++++++++++++ 1 file changed, 638 insertions(+) create mode 100644 docs/src/main/asciidoc/drools.adoc diff --git a/docs/src/main/asciidoc/drools.adoc b/docs/src/main/asciidoc/drools.adoc new file mode 100644 index 0000000000000..02a3f46bfcc68 --- /dev/null +++ b/docs/src/main/asciidoc/drools.adoc @@ -0,0 +1,638 @@ +//// +This guide is maintained in the main Quarkus repository +and pull requests should be submitted there: +https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc +//// += Defining and executing business rules with Drools +include::_attributes.adoc[] +:categories: rule engine +:summary: Drools is the most used rule engine implementation in the Java ecosystem. The purpose of this guide is to show how to use to define and execute business rules in Quarkus using Drools. +:topics: drools,rules,rule engine +:extensions: org.drools:drools-quarkus + +This guide demonstrates how your Quarkus application can use https://www.drools.org[Drools] to add intelligent automation +and power it up with the Drools rule engine. + +== Prerequisites + +include::{includes}/prerequisites.adoc[] + +== Introduction + +https://www.drools.org[Drools] is a set of projects focusing on intelligent automation and decision management, most notably providing a forward-chaining and backward-chaining inference-based rule engine, DMN decisions engine and other projects. A rule engine is a fundamental building block to create an expert system which, in artificial intelligence, is a computer system that emulates the decision-making ability of a human expert. You can read more information on the https://www.drools.org[Drools website]. + +Drools allows defining rules with 2 different programming styles: one more traditional based on the concepts of a KieBase acting as a repository of business rules and a KieSession storing and evaluating the runtime data against them, and the other using a Rule Unit as a single abstraction that encapsulates the definitions of both a set of rules and the facts against which those rules will be matched. + +Both these styles are fully supported in the Drools Quarkus extension and this document explains how to use both, outlining the pros and cons of each one. + +== Integrating the traditional Drools programming model with Quarkus + +This first example demonstrates how to define a set of rules using the traditional Drools style and how to expose their evaluation inside a REST endpoint through Quarkus. + +The domain model of this sample project is made only by two classes, a loan application + +[source,java] +---- +public class LoanApplication { + private String id; + private Applicant applicant; + private int amount; + private int deposit; + private boolean approved = false; + + public LoanApplication(String id, Applicant applicant, int amount, int deposit) { + this.id = id; + this.applicant = applicant; + this.amount = amount; + this.deposit = deposit; + } +} +---- + +and the applicant who requested it + +[source,java] +---- +public class Applicant { + private String name; + private int age; + + public Applicant(String name, int age) { + this.name = name; + this.age = age; + } +} +---- + +The rules set is made of business decisions to approve or reject an application plus one last rule collecting all the approved applications into a list. + +[source] +---- +global Integer maxAmount; +global java.util.List approvedApplications; + +rule LargeDepositApprove when + $l: LoanApplication( applicant.age >= 20, deposit >= 1000, amount <= maxAmount ) +then + modify($l) { setApproved(true) }; // loan is approved +end + +rule LargeDepositReject when + $l: LoanApplication( applicant.age >= 20, deposit >= 1000, amount > maxAmount ) +then + modify($l) { setApproved(false) }; // loan is rejected +end + +// ... more loans approval/rejections business rules ... + +rule CollectApprovedApplication when + $l: LoanApplication( approved ) +then + approvedApplications.add($l); // collect all approved loan applications +end +---- + +The goal that we want to achieve is putting the evaluation of these rules in a microservice, exposing them in a REST endpoint developed with Quarkus. To do so it is enough to add the Drools Quarkus extension among the dependencies of your project. + +[source,xml] +---- + + org.drools + drools-quarkus + +---- + +and at this point it is possible to obtain a reference to the KieSession evaluating the formerly defined rules and use it in a REST endpoint as it follows: + +[source,java] +---- +@Path("/find-approved") +public class FindApprovedLoansEndpoint { + + @Inject + KieRuntimeBuilder kieRuntimeBuilder; + + @POST() + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public List executeQuery(LoanAppDto loanAppDto) { + KieSession session = kieRuntimeBuilder.newKieSession(); + List approvedApplications = new ArrayList<>(); + + session.setGlobal("approvedApplications", approvedApplications); + session.setGlobal("maxAmount", loanAppDto.getMaxAmount()); + loanAppDto.getLoanApplications().forEach(session::insert); + + session.fireAllRules(); + session.dispose(); + return approvedApplications; + } +} +---- + +where an implementation of the `KieRuntimeBuilder` interface is automatically generated and made injectable for you by the Drools extension and allows to obtain with a single statement an instance of any KieBases and KieSessions defined in your Drools project. + +Here the `LoanAppDto` is a simple POJO used to submit multiple loan application to the same KieSession + +[source,java] +---- +public class LoanAppDto { + private int maxAmount; + private List loanApplications; + + public int getMaxAmount() { + return maxAmount; + } + + public void setMaxAmount(int maxAmount) { + this.maxAmount = maxAmount; + } + + public List getLoanApplications() { + return loanApplications; + } + + public void setLoanApplications(List loanApplications) { + this.loanApplications = loanApplications; + } +} +---- + +thus trying for example to invoke that endpoint with a set of loan applications + +[source] +---- +curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d +'{"maxAmount":5000,"loanApplications":[ + {"id":"ABC10001","amount":2000,"deposit":1000,"applicant":{"age":45,"name":"John"}}, + {"id":"ABC10002","amount":5000,"deposit":100,"applicant":{"age":25,"name":"Paul"}}, + {"id":"ABC10015","amount":1000,"deposit":100,"applicant":{"age":12,"name":"George"}} +]}' +http://localhost:8080/find-approved +---- + +the rule engine will evaluate them against the business rules we have configured before, returning the only one that in this case can be approved according to them + +[source] +---- +[{"id":"ABC10001","applicant":{"name":"John","age":45},"amount":2000,"deposit":1000,"approved":true}] +---- + +== Moving to the rule unit programming model + +A rule unit is a new concept introduced in Drools encapsulating both a set of rules and the facts against which those rules will be matched. It comes with a second abstraction called data source, defining the sources through which the facts are inserted, acting in practice as typed entry-points. There are two types of data sources: + +* DataStream: an append-only data source +** subscribers only receive new (and possibly past) messages +** cannot update/remove +** stream may also be hot/cold in “reactive streams” terminology +* DataStore: data source for modifiable data +** subscribers may act upon the data store, by acting upon the fact handle + +In order to use rule units in our quarkus application it is necessary to add a second dependency. + +[source,xml] +---- + + org.drools + drools-ruleunits-engine + +---- + +In essence a rule unit is made of 2 strictly related parts: the definition of the fact to be evaluated and the set of rules evaluating them. The first part is implemented with a POJO, that for the loan example could be something like the following: + +[source,java] +---- +package org.loans; + +import org.drools.ruleunits.api.DataSource; +import org.drools.ruleunits.api.DataStore; +import org.drools.ruleunits.api.RuleUnitData; + +public class LoanUnit implements RuleUnitData { + + private int maxAmount; + private DataStore loanApplications; + + public LoanUnit() { + this(DataSource.createStore(), 0); + } + + public LoanUnit(DataStore loanApplications, int maxAmount) { + this.loanApplications = loanApplications; + this.maxAmount = maxAmount; + } + + public DataStore getLoanApplications() { + return loanApplications; + } + + public void setLoanApplications(DataStore loanApplications) { + this.loanApplications = loanApplications; + } + + public int getMaxAmount() { + return maxAmount; + } + + public void setMaxAmount(int maxAmount) { + this.maxAmount = maxAmount; + } +} +---- + +Here instead of using the `LoanAppDto` that we introduced to marshall/unmarshall the JSON requests we are binding directly the class representing the rule unit. The two relevant differences are that it implements the `RuleUnitData` interface and uses a `DataStore` instead of a plain `List` containing the loan applications to be approved. The first is just a marker interface to notify the engine that this class is part of a rule unit definition. The use of a `DataStore` is necessary to let the rule engine to react accordingly to the changes by firing new rules and triggering other rules. In the example, the consequences of the rules modify the approved property of the loan applications. Conversely, the `maxAmount` value can be considered a configuration parameter of the rule unit and left as it is: it will automatically be processed during the rules evaluation with the same semantic of a global, and automatically set from the value passed by the JSON request as in the first example, so you will still be allowed to use it in your rules. + +The second part of the rule unit is the drl file containing the rules belonging to this unit. + +[source] +---- +package org.loans; + +unit LoanUnit; // no need to using globals, all variables and facts are stored in the rule unit + +rule LargeDepositApprove when + $l: /loanApplications[ applicant.age >= 20, deposit >= 1000, amount <= maxAmount ] // oopath style +then + modify($l) { setApproved(true) }; +end + +rule LargeDepositReject when + $l: /loanApplications[ applicant.age >= 20, deposit >= 1000, amount > maxAmount ] +then + modify($l) { setApproved(false) }; +end + +// ... more loans approval/rejections business rules ... + +// approved loan applications are now retrieved through a query +query FindApproved + $l: /loanApplications[ approved ] +end +---- + +This rules file must declare the same package and a unit with the same name of the Java class implementing the `RuleUnitData` interface in order to state that they belong to the same rule unit. + +This file has also been rewritten using the new OOPath notation: as anticipated, here the data source acts as a typed entry-point and the oopath expression has its name as root while the constraints are in square brackets, like in the following example. + +[source] +---- +$l: /loanApplications[ applicant.age >= 20, deposit >= 1000, amount <= maxAmount ] +---- + +Alternatively you can still use the old DRL syntax, specifying the name of the data source as an entry-point, with the drawback that in this case you need to specify again the type of the matched object, even if the engine can infer it from the type of the datasource, as it follows. + +[source] +---- +$l: LoanApplication( applicant.age >= 20, deposit >= 1000, amount <= maxAmount ) from entry-point loanApplications +---- + +Finally note that the last rule collecting all the approved loan applications into a global `List` has been replaced by a query simply retrieving them. One of the advantages in using a rule unit is that it clearly defines the context of computation, in other terms the facts to be passed in input to the rule evaluation. Similarly, the query defines what is the output expected by this evaluation. + +This clear definition of the computation boundaries allows Drools to also automatically generate a class executing the query and returning its results, together with a REST endpoint taking the rule unit as input, passing it to the former query executor and returning its as output. + +You can have as many query as you want and for each of them it will be generated a different REST endpoint with the same name of the query transformed from camel case (like `FindApproved`) to dash separated (like `find-approved`). + +== A more comprehensive example + +In this more comprehensive and complete example, we will augment a basic Quarkus application with a few simple rules to infer potential issues with the status of a home automation setup. + +We will define a Drools Rule Unit and the rules in the DRL format. + +We will wire the Rule Unit into a standard Quarkus CDI bean, for use in the Quarkus application (for instance, wiring MQTT messages from Kafka, etc.). + +=== Prerequisites + +To complete this guide, you need: + +* less than 15 minutes +* an IDE +* JDK 17+ installed with `JAVA_HOME` configured appropriately +* Apache Maven 3.9.3+ +* Docker +* link:{https://quarkus.io/guides/building-native-image}[GraalVM installed] if you want to run in native mode + +=== Creating the Maven Project + +First, we need a new Quarkus project. +To create a new Quarkus project, you can reference the link:{https://quarkus.io/guides/maven-tooling}[Quarkus and Maven Guide] + +When you have your Quarkus project configured, you can add the Drools Quarkus extensions to your project by adding the following dependencies to your `pom.xml`: + +[source,xml,subs=attributes+] +---- + + org.drools + drools-quarkus + + + org.drools + drools-ruleunits-engine + + + + org.assertj + assertj-core + test + +---- + +=== Writing the application + +Let's start from the application domain model. + +This application goal is to infer potential issues with the status of a home automation setup, so we create the necessary domain models to represent status of sensors, devices and other things inside the house. + +Light device domain model: + +[source,java] +---- +package org.drools.quarkus.quickstart.test.model; + +public class Light { + private final String name; + private Boolean powered; + + public Light(String name, Boolean powered) { + this.name = name; + this.powered = powered; + } + + // getters, setters, etc. +} +---- + +CCTV security camera domain model: + +[source,java] +---- +package org.drools.quarkus.quickstart.test.model; + +public class CCTV { + private final String name; + private Boolean powered; + + public CCTV(String name, Boolean powered) { + this.name = name; + this.powered = powered; + } + + // getters, setters, etc. +} +---- + +Smartphone detected in WiFi domain model: + +[source,java] +---- +package org.drools.quarkus.quickstart.test.model; + +public class Smartphone { + private final String name; + + public Smartphone(String name) { + this.name = name; + } + + // getters, setters, etc. +} +---- + +Alert class to hold information of the potential detected problems: + +[source,java] +---- +package org.drools.quarkus.quickstart.test.model; + +public class Alert { + private final String notification; + + public Alert(String notification) { + this.notification = notification; + } + + // getters, setters, etc. +} +---- + +Next, we create a rule file `rules.drl` inside the `src/main/resources/org/drools/quarkus/quickstart/test` folder of the Quarkus project. + +[source] +---- +package org.drools.quarkus.quickstart.test; + +unit HomeRuleUnitData; + +import org.drools.quarkus.quickstart.test.model.*; + +rule "No lights on while outside" +when + $l: /lights[ powered == true ]; + not( /smartphones ); +then + alerts.add(new Alert("You might have forgot one light powered on: " + $l.getName())); +end + +query "AllAlerts" + $a: /alerts; +end + +rule "No camera when present at home" +when + accumulate( $s: /smartphones ; $count : count($s) ; $count >= 1 ); + $l: /cctvs[ powered == true ]; +then + alerts.add(new Alert("One CCTV is still operating: " + $l.getName())); +end +---- + +In this file there are some example rules to decide whether the overall status of the house is deemed inappropriate, triggering the necessary `Alert` (s). + +Rule Unit a central paradigm introduced in Drools 8 that helps users to encapsulate the set of rules and the facts against which those rules will be matched; you can read more information in the https://www.drools.org/learn/documentation.html[Drools documentation]. + +The facts will be inserted into a `DataStore`, a type-safe entry point. To make everything work, we need to define both the RuleUnit and the DataStore. + +[source,java] +---- +package org.drools.quarkus.quickstart.test; + +import org.drools.quarkus.quickstart.test.model.Alert; +import org.drools.quarkus.quickstart.test.model.CCTV; +import org.drools.quarkus.quickstart.test.model.Light; +import org.drools.quarkus.quickstart.test.model.Smartphone; +import org.drools.ruleunits.api.DataSource; +import org.drools.ruleunits.api.DataStore; +import org.drools.ruleunits.api.RuleUnitData; + +public class HomeRuleUnitData implements RuleUnitData { + + private final DataStore lights; + private final DataStore cctvs; + private final DataStore smartphones; + + private final DataStore alerts = DataSource.createStore(); + + public HomeRuleUnitData() { + this(DataSource.createStore(), DataSource.createStore(), DataSource.createStore()); + } + + public HomeRuleUnitData(DataStore lights, DataStore cctvs, DataStore smartphones) { + this.lights = lights; + this.cctvs = cctvs; + this.smartphones = smartphones; + } + + public DataStore getLights() { + return lights; + } + + public DataStore getCctvs() { + return cctvs; + } + + public DataStore getSmartphones() { + return smartphones; + } + + public DataStore getAlerts() { + return alerts; + } +} +---- + +=== Testing the Application + +We can create a standard Quarkus and JUnit test to check the behaviour of the Rule Unit and the defined rules, accordingly to a certain set of scenarios. + +[source,java] +---- +package org.drools.quarkus.quickstart.test; + +@QuarkusTest +public class RuntimeIT { + + @Inject + RuleUnit ruleUnit; + + @Test + public void testRuleOutside() { + HomeRuleUnitData homeUnitData = new HomeRuleUnitData(); + homeUnitData.getLights().add(new Light("living room", true)); + homeUnitData.getLights().add(new Light("bedroom", false)); + homeUnitData.getLights().add(new Light("bathroom", false)); + + RuleUnitInstance unitInstance = ruleUnit.createInstance(homeUnitData); + List> queryResults = unitInstance.executeQuery("AllAlerts"); + assertThat(queryResults).isNotEmpty().anyMatch(kv -> kv.containsValue(new Alert("You might have forgot one light powered on: living room"))); + } + + @Test + public void testRuleInside() { + HomeRuleUnitData homeUnitData = new HomeRuleUnitData(); + homeUnitData.getLights().add(new Light("living room", true)); + homeUnitData.getLights().add(new Light("bedroom", false)); + homeUnitData.getLights().add(new Light("bathroom", false)); + homeUnitData.getCctvs().add(new CCTV("security camera 1", false)); + homeUnitData.getCctvs().add(new CCTV("security camera 2", true)); + homeUnitData.getSmartphones().add(new Smartphone("John Doe's phone")); + + RuleUnitInstance unitInstance = ruleUnit.createInstance(homeUnitData); + List> queryResults = unitInstance.executeQuery("AllAlerts"); + assertThat(queryResults).isNotEmpty().anyMatch(kv -> kv.containsValue(new Alert("One CCTV is still operating: security camera 2"))); + } + + @Test + public void testNoAlerts() { + HomeRuleUnitData homeUnitData = new HomeRuleUnitData(); + homeUnitData.getLights().add(new Light("living room", false)); + homeUnitData.getLights().add(new Light("bedroom", false)); + homeUnitData.getLights().add(new Light("bathroom", false)); + homeUnitData.getCctvs().add(new CCTV("security camera 1", true)); + homeUnitData.getCctvs().add(new CCTV("security camera 2", true)); + + RuleUnitInstance unitInstance = ruleUnit.createInstance(homeUnitData); + List> queryResults = unitInstance.executeQuery("AllAlerts"); + assertThat(queryResults).isEmpty(); + } +} +---- + +=== Wiring the Rule Unit with Quarkus CDI beans + +We can now wire the Rule Unit into a standard Quarkus CDI bean, for general use in the Quarkus application. + +For example, this might later be helpful to wire device status reporting through MQTT via Kafka, using the appropriate Quarkus extensions. + +We create a simple CDI bean to abstract away the Rule Unit API usage with: + +[source,java] +---- +package org.drools.quarkus.quickstart.test; + +@ApplicationScoped +public class HomeAlertsBean { + + @Inject + RuleUnit ruleUnit; + + public Collection computeAlerts(Collection lights, Collection cameras, Collection phones) { + HomeRuleUnitData homeUnitData = new HomeRuleUnitData(); + lights.forEach(homeUnitData.getLights()::add); + cameras.forEach(homeUnitData.getCctvs()::add); + phones.forEach(homeUnitData.getSmartphones()::add); + + RuleUnitInstance unitInstance = ruleUnit.createInstance(homeUnitData); + var queryResults = unitInstance.executeQuery("AllAlerts"); + List results = queryResults.stream() + .flatMap(m -> m.values().stream() + .filter(Alert.class::isInstance) + .map(Alert.class::cast)) + .collect(Collectors.toList()); + return results; + } +} +---- + +The same test scenarios can be refactored using this CDI bean accordingly. + +[source,java] +---- +package org.drools.quarkus.quickstart.test; + +@QuarkusTest +public class BeanTest { + + @Inject + HomeAlertsBean alerts; + + @Test + public void testRuleOutside() { + Collection computeAlerts = alerts.computeAlerts( + List.of(new Light("living room", true), new Light("bedroom", false), new Light("bathroom", false)), + Collections.emptyList(), + Collections.emptyList()); + + assertThat(computeAlerts).isNotEmpty().contains(new Alert("You might have forgot one light powered on: living room")); + } + + @Test + public void testRuleInside() { + Collection computeAlerts = alerts.computeAlerts( + List.of(new Light("living room", true), new Light("bedroom", false), new Light("bathroom", false)), + List.of(new CCTV("security camera 1", false), new CCTV("security camera 2", true)), + List.of(new Smartphone("John Doe's phone"))); + + assertThat(computeAlerts).isNotEmpty().contains(new Alert("One CCTV is still operating: security camera 2")); + } + + @Test + public void testNoAlerts() { + Collection computeAlerts = alerts.computeAlerts( + List.of(new Light("living room", false), new Light("bedroom", false), new Light("bathroom", false)), + List.of(new CCTV("security camera 1", true), new CCTV("security camera 2", true)), + Collections.emptyList()); + + assertThat(computeAlerts).isEmpty(); + } +} +---- From 7bd308a2a4477ff9218c9012344033bdb67fc7d5 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 16 Dec 2024 16:37:32 +0200 Subject: [PATCH 138/207] Introduce @Cancellable annotation for Quarkus REST This annotation can be placed on REST methods that return a single result async type and allows the user to configure whether the subscription should be cancelled if the connection is closed before the result is available Closes: #45141 --- .../server/test/CancelableUniTest.java | 53 ++++++++++++++++--- .../scanning/AsyncReturnTypeScanner.java | 35 +++++++++++- .../resteasy/reactive/server/Cancellable.java | 22 ++++++++ .../CompletionStageResponseHandler.java | 6 +-- .../server/handlers/UniResponseHandler.java | 6 +-- .../AbstractCancellableServerRestHandler.java | 15 ++++++ 6 files changed, 122 insertions(+), 15 deletions(-) create mode 100644 independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/Cancellable.java create mode 100644 independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/AbstractCancellableServerRestHandler.java diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/CancelableUniTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/CancelableUniTest.java index 3b1f003566ff7..ca673fba96569 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/CancelableUniTest.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/CancelableUniTest.java @@ -15,6 +15,7 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; +import org.jboss.resteasy.reactive.server.Cancellable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -44,17 +45,35 @@ void setUp() { @Test public void testNormal() { - when().get("test") + doTestNormal("1"); + } + + @Test + public void testDefaultCancellable() { + doTestCancel("1", Resource.COUNT, 1); + } + + @Test + public void testUnCancellable() { + doTestCancel("2", Resource.COUNT, 2); + } + + @Test + public void testCancellable() { + doTestCancel("3", Resource.COUNT, 1); + } + + private void doTestNormal(String path) { + when().get("test/" + path) .then() .statusCode(200) .body(equalTo("Hello, world")); } - @Test - public void testCancel() { + private void doTestCancel(String path, AtomicInteger count, int expected) { WebClient client = WebClient.create(vertx); - client.get(url.getPort(), url.getHost(), "/test").send(); + client.get(url.getPort(), url.getHost(), "/test/" + path).send(); try { // make sure we did make the proper request @@ -67,7 +86,7 @@ public void testCancel() { Thread.sleep(7_000); // if the count did not increase, it means that Uni was cancelled - assertEquals(1, Resource.COUNT.get()); + assertEquals(expected, count.get()); } catch (InterruptedException ignored) { } finally { @@ -77,7 +96,6 @@ public void testCancel() { } } - } @Path("test") @@ -87,7 +105,28 @@ public static class Resource { @GET @Produces(MediaType.TEXT_PLAIN) - public Uni hello() { + @Path("1") + public Uni defaultCancelableHello() { + COUNT.incrementAndGet(); + return Uni.createFrom().item("Hello, world").onItem().delayIt().by(Duration.ofSeconds(5)).onItem().invoke( + COUNT::incrementAndGet); + } + + @GET + @Produces(MediaType.TEXT_PLAIN) + @Cancellable(false) + @Path("2") + public Uni uncancellableHello() { + COUNT.incrementAndGet(); + return Uni.createFrom().item("Hello, world").onItem().delayIt().by(Duration.ofSeconds(5)).onItem().invoke( + COUNT::incrementAndGet); + } + + @GET + @Produces(MediaType.TEXT_PLAIN) + @Cancellable + @Path("3") + public Uni cancellableHello() { COUNT.incrementAndGet(); return Uni.createFrom().item("Hello, world").onItem().delayIt().by(Duration.ofSeconds(5)).onItem().invoke( COUNT::incrementAndGet); diff --git a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/AsyncReturnTypeScanner.java b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/AsyncReturnTypeScanner.java index 53393c76317b6..94ebbea67ecb5 100644 --- a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/AsyncReturnTypeScanner.java +++ b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/AsyncReturnTypeScanner.java @@ -12,9 +12,14 @@ import java.util.List; import java.util.Map; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; import org.jboss.jandex.MethodInfo; +import org.jboss.resteasy.reactive.common.processor.EndpointIndexer; +import org.jboss.resteasy.reactive.common.processor.transformation.AnnotationStore; +import org.jboss.resteasy.reactive.server.Cancellable; import org.jboss.resteasy.reactive.server.handlers.CompletionStageResponseHandler; import org.jboss.resteasy.reactive.server.handlers.PublisherResponseHandler; import org.jboss.resteasy.reactive.server.handlers.UniResponseHandler; @@ -23,15 +28,24 @@ public class AsyncReturnTypeScanner implements MethodScanner { + private static final DotName CANCELLABLE = DotName.createSimple(Cancellable.class.getName()); + @Override public List scan(MethodInfo method, ClassInfo actualEndpointClass, Map methodContext) { DotName returnTypeName = method.returnType().name(); + AnnotationStore annotationStore = (AnnotationStore) methodContext + .get(EndpointIndexer.METHOD_CONTEXT_ANNOTATION_STORE); + boolean isCancelable = determineCancelable(method, actualEndpointClass, annotationStore); if (returnTypeName.equals(COMPLETION_STAGE) || returnTypeName.equals(COMPLETABLE_FUTURE)) { - return Collections.singletonList(new FixedHandlerChainCustomizer(new CompletionStageResponseHandler(), + CompletionStageResponseHandler handler = new CompletionStageResponseHandler(); + handler.setCancellable(isCancelable); + return Collections.singletonList(new FixedHandlerChainCustomizer(handler, HandlerChainCustomizer.Phase.AFTER_METHOD_INVOKE)); } else if (returnTypeName.equals(UNI)) { - return Collections.singletonList(new FixedHandlerChainCustomizer(new UniResponseHandler(), + UniResponseHandler handler = new UniResponseHandler(); + handler.setCancellable(isCancelable); + return Collections.singletonList(new FixedHandlerChainCustomizer(handler, HandlerChainCustomizer.Phase.AFTER_METHOD_INVOKE)); } if (returnTypeName.equals(MULTI) || returnTypeName.equals(REST_MULTI) || returnTypeName.equals(PUBLISHER) @@ -42,6 +56,23 @@ public List scan(MethodInfo method, ClassInfo actualEndp return Collections.emptyList(); } + private boolean determineCancelable(MethodInfo method, ClassInfo clazz, AnnotationStore annotationStore) { + AnnotationInstance instance = annotationStore.getAnnotation(method, CANCELLABLE); + if (instance == null) { + instance = annotationStore.getAnnotation(method.declaringClass(), CANCELLABLE); + if ((instance == null) && !clazz.equals(method.declaringClass())) { + instance = annotationStore.getAnnotation(clazz, CANCELLABLE); + } + } + if (instance != null) { + AnnotationValue value = instance.value(); + if (value != null) { + return value.asBoolean(); + } + } + return true; + } + @Override public boolean isMethodSignatureAsync(MethodInfo method) { DotName returnTypeName = method.returnType().name(); diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/Cancellable.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/Cancellable.java new file mode 100644 index 0000000000000..c07c104c051fb --- /dev/null +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/Cancellable.java @@ -0,0 +1,22 @@ +package org.jboss.resteasy.reactive.server; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.CompletionStage; + +import io.smallrye.mutiny.Uni; + +/** + * Used on a method that returns a single item async return type (such as {@link Uni} or {@link CompletionStage or Kotlin + * suspend function}) + * to control whether to cancel the subscription to the result if the connection is closed before the result is ready. + * By default, Quarkus will cancel the subscription + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE }) +public @interface Cancellable { + + boolean value() default true; +} diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/CompletionStageResponseHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/CompletionStageResponseHandler.java index 6998220d74e02..1854676749c19 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/CompletionStageResponseHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/CompletionStageResponseHandler.java @@ -6,9 +6,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; -import org.jboss.resteasy.reactive.server.spi.ServerRestHandler; +import org.jboss.resteasy.reactive.server.spi.AbstractCancellableServerRestHandler; -public class CompletionStageResponseHandler implements ServerRestHandler { +public class CompletionStageResponseHandler extends AbstractCancellableServerRestHandler { @Override public void handle(ResteasyReactiveRequestContext requestContext) throws Exception { @@ -45,7 +45,7 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti requestContext.serverResponse().addCloseHandler(new Runnable() { @Override public void run() { - if (!done.get()) { + if (isCancellable() && !done.get()) { if (result instanceof CompletableFuture cf) { canceled.set(true); cf.cancel(true); diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/UniResponseHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/UniResponseHandler.java index dc89c7e4c6aae..11d283f7a032e 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/UniResponseHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/UniResponseHandler.java @@ -4,12 +4,12 @@ import java.util.function.Consumer; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; -import org.jboss.resteasy.reactive.server.spi.ServerRestHandler; +import org.jboss.resteasy.reactive.server.spi.AbstractCancellableServerRestHandler; import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.subscription.Cancellable; -public class UniResponseHandler implements ServerRestHandler { +public class UniResponseHandler extends AbstractCancellableServerRestHandler { @Override public void handle(ResteasyReactiveRequestContext requestContext) throws Exception { @@ -38,7 +38,7 @@ public void accept(Throwable t) { requestContext.serverResponse().addCloseHandler(new Runnable() { @Override public void run() { - if (done.compareAndSet(false, true)) { + if (isCancellable() && done.compareAndSet(false, true)) { cancellable.cancel(); try { // get rid of everything related to the request since the connection has already gone away diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/AbstractCancellableServerRestHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/AbstractCancellableServerRestHandler.java new file mode 100644 index 0000000000000..0e527dd3db951 --- /dev/null +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/AbstractCancellableServerRestHandler.java @@ -0,0 +1,15 @@ +package org.jboss.resteasy.reactive.server.spi; + +public abstract class AbstractCancellableServerRestHandler implements ServerRestHandler { + + // make mutable to allow for bytecode serialization + private boolean cancellable; + + public boolean isCancellable() { + return cancellable; + } + + public void setCancellable(boolean cancellable) { + this.cancellable = cancellable; + } +} From 7e19d997f4839eeac0ee81ec56af446634ec3166 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Mon, 16 Dec 2024 15:46:47 +0100 Subject: [PATCH 139/207] Introduce IsLocalDevelopment boolean supplier --- .../deployment/IsLocalDevelopment.java | 27 +++++++++++++++++++ .../devui/AgroalDevUIProcessor.java | 4 +-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/IsLocalDevelopment.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/IsLocalDevelopment.java b/core/deployment/src/main/java/io/quarkus/deployment/IsLocalDevelopment.java new file mode 100644 index 0000000000000..626b76a2af00a --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/IsLocalDevelopment.java @@ -0,0 +1,27 @@ +package io.quarkus.deployment; + +import java.util.function.BooleanSupplier; + +import io.quarkus.dev.spi.DevModeType; +import io.quarkus.runtime.LaunchMode; + +/** + * Similar to {@link IsDevelopment} except checks whether the application is being launched in dev mode but not from a + * {@code mutable-jar} package, + * in other words, not a remote server in a remote dev session. + */ +public class IsLocalDevelopment implements BooleanSupplier { + + private final LaunchMode launchMode; + private final DevModeType devModeType; + + public IsLocalDevelopment(LaunchMode launchMode, DevModeType devModeType) { + this.launchMode = launchMode; + this.devModeType = devModeType; + } + + @Override + public boolean getAsBoolean() { + return launchMode == LaunchMode.DEVELOPMENT && devModeType != DevModeType.REMOTE_SERVER_SIDE; + } +} diff --git a/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/devui/AgroalDevUIProcessor.java b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/devui/AgroalDevUIProcessor.java index aeb86eca3df92..93cc1da30dcbc 100644 --- a/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/devui/AgroalDevUIProcessor.java +++ b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/devui/AgroalDevUIProcessor.java @@ -2,7 +2,7 @@ import io.quarkus.agroal.runtime.DataSourcesJdbcBuildTimeConfig; import io.quarkus.agroal.runtime.dev.ui.DatabaseInspector; -import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.IsLocalDevelopment; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.BuildSteps; @@ -12,7 +12,7 @@ import io.quarkus.devui.spi.page.CardPageBuildItem; import io.quarkus.devui.spi.page.Page; -@BuildSteps(onlyIf = IsDevelopment.class) +@BuildSteps(onlyIf = IsLocalDevelopment.class) class AgroalDevUIProcessor { @BuildStep From e72472f28cee16b706849b1d97d4c2893a761023 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Mon, 16 Dec 2024 13:33:23 +0000 Subject: [PATCH 140/207] Update OIDC bearer doc with a section about response filters --- ...rity-oidc-bearer-token-authentication.adoc | 43 +++++++++++++++++++ ...ecurity-oidc-code-flow-authentication.adoc | 8 ++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc b/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc index a91d02726b3a3..bc2a4fcecd343 100644 --- a/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc +++ b/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc @@ -1346,6 +1346,49 @@ Authentication that requires a dynamic tenant will fail. You can filter OIDC requests made by Quarkus to the OIDC provider by registering one or more `OidcRequestFilter` implementations, which can update or add new request headers, and log requests. For more information, see xref:security-oidc-code-flow-authentication#code-flow-oidc-request-filters[OIDC request filters]. +[[bearer-token-oidc-response-filters]] +=== OIDC response filters + +You can filter responses from the OIDC providers by registering one or more `OidcResponseFilter` implementations, which can check the response status, headers and body in order to log them or perform other actions. + +You can have a single filter intercepting all the OIDC responses, or use an `@OidcEndpoint` annotation to apply this filter to the specific endpoint responses only. For example: + +[source,java] +---- +package io.quarkus.it.keycloak; + +import jakarta.enterprise.context.ApplicationScoped; + +import io.quarkus.arc.Unremovable; +import io.quarkus.logging.Log; +import io.quarkus.oidc.common.OidcEndpoint; +import io.quarkus.oidc.common.OidcEndpoint.Type; +import io.quarkus.oidc.common.OidcResponseFilter; +import io.quarkus.oidc.common.runtime.OidcConstants; +import io.quarkus.oidc.runtime.OidcUtils; + +@ApplicationScoped +@Unremovable +@OidcEndpoint(value = Type.DISCOVERY) <1> +public class DiscoveryEndpointResponseFilter implements OidcResponseFilter { + + @Override + public void filter(OidcResponseContext rc) { + String contentType = rc.responseHeaders().get("Content-Type"); <2> + if (contentType.equals("application/json") { + String tenantId = rc.requestProperties().get(OidcUtils.TENANT_ID_ATTRIBUTE); <3> + String metadata = rc.responseBody().toString(); <4> + Log.debugf("Tenant %s OIDC metadata: %s", tenantId, metadata); + } + } +} + +---- +<1> Restrict this filter to requests targeting the OIDC discovery endpoint only. +<2> Check the response `Content-Type` header. +<3> Use `OidcRequestContextProperties` request properties to get the tenant id. +<4> Get the response data as String. + == References * xref:security-oidc-configuration-properties-reference.adoc[OIDC configuration properties] diff --git a/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc b/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc index b20907196ff14..dc57ffe76c4af 100644 --- a/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc +++ b/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc @@ -392,9 +392,8 @@ package io.quarkus.it.keycloak; import jakarta.enterprise.context.ApplicationScoped; -import org.jboss.logging.Logger; - import io.quarkus.arc.Unremovable; +import io.quarkus.logging.Log; import io.quarkus.oidc.common.OidcEndpoint; import io.quarkus.oidc.common.OidcEndpoint.Type; import io.quarkus.oidc.common.OidcResponseFilter; @@ -405,8 +404,7 @@ import io.quarkus.oidc.runtime.OidcUtils; @Unremovable @OidcEndpoint(value = Type.TOKEN) <1> public class TokenEndpointResponseFilter implements OidcResponseFilter { - private static final Logger LOG = Logger.getLogger(TokenResponseFilter.class); - + @Override public void filter(OidcResponseContext rc) { String contentType = rc.responseHeaders().get("Content-Type"); <2> @@ -414,7 +412,7 @@ public class TokenEndpointResponseFilter implements OidcResponseFilter { && OidcConstants.AUTHORIZATION_CODE.equals(rc.requestProperties().get(OidcConstants.GRANT_TYPE)) <3> && "code-flow-user-info-cached-in-idtoken".equals(rc.requestProperties().get(OidcUtils.TENANT_ID_ATTRIBUTE)) <3> && rc.responseBody().toJsonObject().containsKey("id_token")) { <4> - LOG.debug("Authorization code completed for tenant 'code-flow-user-info-cached-in-idtoken'"); + Log.debug("Authorization code completed for tenant 'code-flow-user-info-cached-in-idtoken'"); } } } From e311e31e56d7491aba9a09ed0fefca50b589e533 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 20:20:24 +0000 Subject: [PATCH 141/207] Bump org.junit:junit-bom from 5.10.5 to 5.11.4 in /devtools/gradle Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.10.5 to 5.11.4. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.5...r5.11.4) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- devtools/gradle/gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/gradle/gradle/libs.versions.toml b/devtools/gradle/gradle/libs.versions.toml index e4b86cbd74791..2497c6e17b349 100644 --- a/devtools/gradle/gradle/libs.versions.toml +++ b/devtools/gradle/gradle/libs.versions.toml @@ -5,7 +5,7 @@ plugin-publish = "1.3.0" kotlin = "2.0.21" smallrye-config = "3.10.2" -junit5 = "5.10.5" +junit5 = "5.11.4" assertj = "3.26.3" [plugins] From 731ef3a916f390915a46058012de5e58a7787902 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Mon, 16 Dec 2024 18:36:29 -0300 Subject: [PATCH 142/207] Bump org.asynchttpclient:async-http-client from 2.12.3 to 2.12.4 Bumps [org.asynchttpclient:async-http-client](https://github.com/AsyncHttpClient/async-http-client) from 2.12.3 to 2.12.4. - [Release notes](https://github.com/AsyncHttpClient/async-http-client/releases) - [Changelog](https://github.com/AsyncHttpClient/async-http-client/blob/main/CHANGES.md) - [Commits](AsyncHttpClient/async-http-client@async-http-client-project-2.12.3...async-http-client-project-2.12.4) --- updated-dependencies: - dependency-name: org.asynchttpclient:async-http-client dependency-type: direct:production ... --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 6cb37c112c246..acf6fca4f6551 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -214,7 +214,7 @@ 0.8.11 1.1.0 3.3.0 - 2.12.3 + 2.12.4 0.16.0 From 6575abcd3093487646e1cefe9bf6121ceaadde00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 22:44:17 +0000 Subject: [PATCH 143/207] Bump com.github.javaparser:javaparser-core from 3.26.2 to 3.26.3 Bumps [com.github.javaparser:javaparser-core](https://github.com/javaparser/javaparser) from 3.26.2 to 3.26.3. - [Release notes](https://github.com/javaparser/javaparser/releases) - [Changelog](https://github.com/javaparser/javaparser/blob/master/changelog.md) - [Commits](https://github.com/javaparser/javaparser/compare/javaparser-parent-3.26.2...javaparser-parent-3.26.3) --- updated-dependencies: - dependency-name: com.github.javaparser:javaparser-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- build-parent/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 6cb37c112c246..54f0d31c5a490 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -167,7 +167,7 @@ 6.0.0 5.2.1 0.34.1 - 3.26.2 + 3.26.3 0.3.0 4.18.1 6.1.SP4 diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 887efb2b3105e..967c59206dee6 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -34,7 +34,7 @@ 2.5.13 4.7.0 - 3.26.2 + 3.26.3 2.0.3.Final 6.0.1 From fc714fb20665ee64943a3cb58547388b67748cdd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 22:45:18 +0000 Subject: [PATCH 144/207] Bump com.google.guava:guava from 33.3.1-jre to 33.4.0-jre Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.3.1-jre to 33.4.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- independent-projects/bootstrap/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml index 4a2b659937fbf..39d762f973fc0 100644 --- a/independent-projects/bootstrap/pom.xml +++ b/independent-projects/bootstrap/pom.xml @@ -57,7 +57,7 @@ 1.17.1 2.18.0 3.17.0 - 33.3.1-jre + 33.4.0-jre 1.0.1 2.8 1.2.6 From 4e57c52138993cfcccee39dc74b17544061fd7fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 22:47:03 +0000 Subject: [PATCH 145/207] Bump org.jetbrains.dokka:dokka-maven-plugin from 1.9.20 to 2.0.0 Bumps [org.jetbrains.dokka:dokka-maven-plugin](https://github.com/Kotlin/dokka) from 1.9.20 to 2.0.0. - [Release notes](https://github.com/Kotlin/dokka/releases) - [Commits](https://github.com/Kotlin/dokka/compare/v1.9.20...v2.0.0) --- updated-dependencies: - dependency-name: org.jetbrains.dokka:dokka-maven-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- build-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 887efb2b3105e..075373d145b6d 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -21,7 +21,7 @@ ${version.compiler.plugin} 2.0.21 - 1.9.20 + 2.0.0 2.13.12 4.9.2 From 57c250d70157074941a0fa5fe7fc99ffc8b8d324 Mon Sep 17 00:00:00 2001 From: Auri Munoz Date: Fri, 13 Dec 2024 12:23:23 +0100 Subject: [PATCH 146/207] Register for reflection Pageable class for not missing paged/unpaged attributes. Related to #41292 --- .../data/deployment/SpringDataJPAProcessor.java | 1 + .../it/spring/data/jpa/BookRepository.java | 9 +++++++++ .../quarkus/it/spring/data/jpa/BookResource.java | 10 ++++++++++ .../it/spring/data/jpa/BookResourceTest.java | 16 ++++++++++++++++ 4 files changed, 36 insertions(+) diff --git a/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/SpringDataJPAProcessor.java b/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/SpringDataJPAProcessor.java index 104d9167067b7..2b893982be4f0 100644 --- a/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/SpringDataJPAProcessor.java +++ b/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/SpringDataJPAProcessor.java @@ -103,6 +103,7 @@ void registerReflection(BuildProducer producer) { "org.springframework.data.domain.Page", "org.springframework.data.domain.Slice", "org.springframework.data.domain.PageImpl", + "org.springframework.data.domain.Pageable", "org.springframework.data.domain.SliceImpl", "org.springframework.data.domain.Sort", "org.springframework.data.domain.Chunk", diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BookRepository.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BookRepository.java index e68d9c856ff73..e6802086398c1 100644 --- a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BookRepository.java +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BookRepository.java @@ -3,6 +3,9 @@ import java.util.List; import java.util.Optional; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; import org.springframework.data.repository.query.Param; @@ -45,6 +48,12 @@ public interface BookRepository extends Repository { @Query(value = "SELECT b.publicationYear FROM Book b where b.bid = :bid") Integer customFindPublicationYearObject(@Param("bid") Integer bid); + // Related to issue 41292 + public default Page findPaged(Pageable pageable) { + List list = findAll(); + return new PageImpl<>(list, pageable, list.size()); + } + interface BookCountByYear { int getPublicationYear(); diff --git a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BookResource.java b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BookResource.java index 55e6342d340e3..2db6fcd4d5f73 100644 --- a/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BookResource.java +++ b/integration-tests/spring-data-jpa/src/main/java/io/quarkus/it/spring/data/jpa/BookResource.java @@ -8,8 +8,12 @@ import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Response; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; + @Path("/book") public class BookResource { @@ -115,4 +119,10 @@ public Integer customFindPublicationYearObject(@PathParam("bid") Integer bid) { return bookRepository.customFindPublicationYearObject(bid); } + @GET + @Path("/paged") + public Page getPaged(@QueryParam("size") int size, @QueryParam("page") int page) { + return bookRepository.findPaged(PageRequest.of(page, size)); + } + } diff --git a/integration-tests/spring-data-jpa/src/test/java/io/quarkus/it/spring/data/jpa/BookResourceTest.java b/integration-tests/spring-data-jpa/src/test/java/io/quarkus/it/spring/data/jpa/BookResourceTest.java index 3bd490e6594ee..318cd12659c13 100644 --- a/integration-tests/spring-data-jpa/src/test/java/io/quarkus/it/spring/data/jpa/BookResourceTest.java +++ b/integration-tests/spring-data-jpa/src/test/java/io/quarkus/it/spring/data/jpa/BookResourceTest.java @@ -1,13 +1,17 @@ package io.quarkus.it.spring.data.jpa; +import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.when; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.core.Is.is; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import io.quarkus.test.junit.QuarkusTest; +import io.restassured.response.Response; @QuarkusTest public class BookResourceTest { @@ -132,4 +136,16 @@ void testCustomFindPublicationYearObject() { .statusCode(200) .body(is("2011")); } + + @Test + void testEnsureFieldPageableIsSerialized() { + Response response = given() + .accept("application/json") + .queryParam("size", "2") + .queryParam("page", "1") + .when().get("/book/paged"); + Assertions.assertEquals(200, response.statusCode()); + assertThat(response.body().jsonPath().getString("pageable")).contains("paged:true"); + assertThat(response.body().jsonPath().getString("pageable")).contains("unpaged:false"); + } } From 695e44a9da4657325176f9bf9f5b42ce9713e101 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Tue, 17 Dec 2024 09:41:50 +0100 Subject: [PATCH 147/207] ArC: introduce CurrentManagedContext - share the logic used in RequestContext and WebSocketSessionContext --- .../next/runtime/ContextSupport.java | 6 +- .../websockets/next/runtime/Endpoints.java | 4 +- .../next/runtime/WebSocketSessionContext.java | 230 ++------------- .../arc/impl/CurrentManagedContext.java | 270 ++++++++++++++++++ .../io/quarkus/arc/impl/RequestContext.java | 245 +--------------- 5 files changed, 304 insertions(+), 451 deletions(-) create mode 100644 independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CurrentManagedContext.java diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/ContextSupport.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/ContextSupport.java index 2b60536dfc45b..0698723d361dd 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/ContextSupport.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/ContextSupport.java @@ -6,8 +6,8 @@ import io.quarkus.arc.InjectableContext.ContextState; import io.quarkus.arc.ManagedContext; +import io.quarkus.arc.impl.CurrentManagedContext.CurrentContextState; import io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle; -import io.quarkus.websockets.next.runtime.WebSocketSessionContext.SessionContextState; import io.smallrye.common.vertx.VertxContext; import io.vertx.core.Context; @@ -21,11 +21,11 @@ public class ContextSupport { static final String WEB_SOCKET_CONN_KEY = WebSocketConnectionBase.class.getName(); private final WebSocketConnectionBase connection; - private final SessionContextState sessionContextState; + private final CurrentContextState sessionContextState; private final WebSocketSessionContext sessionContext; private final ManagedContext requestContext; - ContextSupport(WebSocketConnectionBase connection, SessionContextState sessionContextState, + ContextSupport(WebSocketConnectionBase connection, CurrentContextState sessionContextState, WebSocketSessionContext sessionContext, ManagedContext requestContext) { this.connection = connection; diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/Endpoints.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/Endpoints.java index 349ccd7a75aff..95d7e2158d7bc 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/Endpoints.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/Endpoints.java @@ -11,13 +11,13 @@ import io.netty.handler.codec.http.websocketx.WebSocketCloseStatus; import io.quarkus.arc.ArcContainer; import io.quarkus.arc.InjectableContext; +import io.quarkus.arc.impl.CurrentManagedContext.CurrentContextState; import io.quarkus.runtime.LaunchMode; import io.quarkus.security.AuthenticationFailedException; import io.quarkus.security.ForbiddenException; import io.quarkus.security.UnauthorizedException; import io.quarkus.websockets.next.CloseReason; import io.quarkus.websockets.next.WebSocketException; -import io.quarkus.websockets.next.runtime.WebSocketSessionContext.SessionContextState; import io.quarkus.websockets.next.runtime.config.UnhandledFailureStrategy; import io.quarkus.websockets.next.runtime.telemetry.ErrorInterceptor; import io.quarkus.websockets.next.runtime.telemetry.TelemetrySupport; @@ -44,7 +44,7 @@ static void initialize(Vertx vertx, ArcContainer container, Codecs codecs, WebSo // Initialize and capture the session context state that will be activated // during message processing WebSocketSessionContext sessionContext = null; - SessionContextState sessionContextState = null; + CurrentContextState sessionContextState = null; if (activateSessionContext) { sessionContext = sessionContext(container); sessionContextState = sessionContext.initializeContextState(); diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketSessionContext.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketSessionContext.java index 3d6c488289c41..4d5a91b170a7d 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketSessionContext.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketSessionContext.java @@ -1,51 +1,31 @@ package io.quarkus.websockets.next.runtime; import java.lang.annotation.Annotation; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; -import java.util.Map; -import java.util.Objects; +import java.util.function.Consumer; import java.util.function.Supplier; -import java.util.stream.Collectors; import jakarta.enterprise.context.BeforeDestroyed; import jakarta.enterprise.context.ContextNotActiveException; import jakarta.enterprise.context.Destroyed; import jakarta.enterprise.context.Initialized; import jakarta.enterprise.context.SessionScoped; -import jakarta.enterprise.context.spi.Contextual; -import jakarta.enterprise.context.spi.CreationalContext; import jakarta.enterprise.event.Event; import jakarta.enterprise.inject.Any; -import org.jboss.logging.Logger; - import io.quarkus.arc.Arc; import io.quarkus.arc.ArcContainer; -import io.quarkus.arc.ContextInstanceHandle; -import io.quarkus.arc.CurrentContext; import io.quarkus.arc.CurrentContextFactory; -import io.quarkus.arc.InjectableBean; -import io.quarkus.arc.ManagedContext; import io.quarkus.arc.impl.ComputingCacheContextInstances; -import io.quarkus.arc.impl.ContextInstanceHandleImpl; -import io.quarkus.arc.impl.ContextInstances; +import io.quarkus.arc.impl.CurrentManagedContext; import io.quarkus.arc.impl.LazyValue; -public class WebSocketSessionContext implements ManagedContext { - - private static final Logger LOG = Logger.getLogger(WebSocketSessionContext.class); - - private final CurrentContext currentContext; - private final LazyValue> initializedEvent; - private final LazyValue> beforeDestroyEvent; - private final LazyValue> destroyEvent; +public class WebSocketSessionContext extends CurrentManagedContext { public WebSocketSessionContext(CurrentContextFactory currentContextFactory) { - this.currentContext = currentContextFactory.create(SessionScoped.class); - this.initializedEvent = newEvent(Initialized.Literal.SESSION, Any.Literal.INSTANCE); - this.beforeDestroyEvent = newEvent(BeforeDestroyed.Literal.SESSION, Any.Literal.INSTANCE); - this.destroyEvent = newEvent(Destroyed.Literal.SESSION, Any.Literal.INSTANCE); + super(currentContextFactory.create(SessionScoped.class), ComputingCacheContextInstances::new, + newEvent(Initialized.Literal.SESSION, Any.Literal.INSTANCE), + newEvent(BeforeDestroyed.Literal.SESSION, Any.Literal.INSTANCE), + newEvent(Destroyed.Literal.SESSION, Any.Literal.INSTANCE)); } @Override @@ -53,147 +33,12 @@ public Class getScope() { return SessionScoped.class; } - @Override - public ContextState getState() { - SessionContextState state = currentState(); - if (state == null) { - throw notActive(); - } - return state; - } - - @Override - public ContextState activate(ContextState initialState) { - if (initialState == null) { - SessionContextState state = initializeContextState(); - currentContext.set(state); - return state; - } else { - if (initialState instanceof SessionContextState) { - currentContext.set((SessionContextState) initialState); - return initialState; - } else { - throw new IllegalArgumentException("Invalid initial state: " + initialState.getClass().getName()); - } - } - } - - @Override - public void deactivate() { - currentContext.remove(); - } - - @SuppressWarnings("unchecked") - @Override - public T get(Contextual contextual, CreationalContext creationalContext) { - Objects.requireNonNull(contextual, "Contextual must not be null"); - Objects.requireNonNull(creationalContext, "CreationalContext must not be null"); - InjectableBean bean = (InjectableBean) contextual; - if (!SessionScoped.class.getName().equals(bean.getScope().getName())) { - throw invalidScope(); - } - SessionContextState state = currentState(); - if (state == null || !state.isValid()) { - throw notActive(); - } - return (T) state.contextInstances.computeIfAbsent(bean.getIdentifier(), new Supplier>() { - - @Override - public ContextInstanceHandle get() { - return new ContextInstanceHandleImpl<>(bean, contextual.create(creationalContext), creationalContext); - } - }).get(); - } - - @Override - public T get(Contextual contextual) { - Objects.requireNonNull(contextual, "Contextual must not be null"); - InjectableBean bean = (InjectableBean) contextual; - if (!SessionScoped.class.getName().equals(bean.getScope().getName())) { - throw invalidScope(); - } - SessionContextState state = currentState(); - if (state == null || !state.isValid()) { - throw notActive(); - } - @SuppressWarnings("unchecked") - ContextInstanceHandle instance = (ContextInstanceHandle) state.contextInstances - .getIfPresent(bean.getIdentifier()); - return instance == null ? null : instance.get(); - } - - @Override - public boolean isActive() { - SessionContextState contextState = currentState(); - return contextState == null ? false : contextState.isValid(); - } - - @Override - public void destroy() { - destroy(currentState()); - } - - @Override - public void destroy(Contextual contextual) { - SessionContextState state = currentState(); - if (state == null || !state.isValid()) { - throw notActive(); - } - InjectableBean bean = (InjectableBean) contextual; - ContextInstanceHandle instance = state.contextInstances.remove(bean.getIdentifier()); - if (instance != null) { - instance.destroy(); - } - } - - @Override - public void destroy(ContextState state) { - if (state == null) { - // nothing to destroy - return; - } - if (state instanceof SessionContextState) { - SessionContextState sessionState = ((SessionContextState) state); - if (sessionState.invalidate()) { - fireIfNotNull(beforeDestroyEvent.get()); - sessionState.contextInstances.removeEach(ContextInstanceHandle::destroy); - fireIfNotNull(destroyEvent.get()); - } - } else { - throw new IllegalArgumentException("Invalid state implementation: " + state.getClass().getName()); - } - } - - SessionContextState initializeContextState() { - SessionContextState state = new SessionContextState(new ComputingCacheContextInstances()); - fireIfNotNull(initializedEvent.get()); - return state; - } - - private SessionContextState currentState() { - return currentContext.get(); - } - - private IllegalArgumentException invalidScope() { - throw new IllegalArgumentException("The bean does not declare @SessionScoped"); - } - - private ContextNotActiveException notActive() { + protected ContextNotActiveException notActive() { return new ContextNotActiveException("Session context is not active"); } - private void fireIfNotNull(Event event) { - if (event != null) { - try { - event.fire(toString()); - } catch (Exception e) { - LOG.warn("An error occurred during delivery of the context lifecycle event for " + toString(), e); - } - } - } - - private static LazyValue> newEvent(Annotation... qualifiers) { - return new LazyValue<>(new Supplier>() { + private static Consumer newEvent(Annotation... qualifiers) { + LazyValue> event = new LazyValue<>(new Supplier>() { @Override public Event get() { ArcContainer container = Arc.container(); @@ -203,54 +48,15 @@ public Event get() { return container.beanManager().getEvent().select(qualifiers); } }); - } - - static class SessionContextState implements ContextState { + return new Consumer() { - // Using 0 as default value enable removing an initialization - // in the constructor, piggybacking on the default value. - // As per https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5 - // the default field values are set before 'this' is accessible, hence - // they should be the very first value observable even in presence of - // unsafe publication of this object. - private static final int VALID = 0; - private static final int INVALID = 1; - private static final VarHandle IS_VALID; - - static { - try { - IS_VALID = MethodHandles.lookup().findVarHandle(SessionContextState.class, "isValid", int.class); - } catch (ReflectiveOperationException e) { - throw new Error(e); + @Override + public void accept(Object t) { + Event e = event.get(); + if (e != null) { + e.fire(t); + } } - } - - private final ContextInstances contextInstances; - private volatile int isValid; - - SessionContextState(ContextInstances contextInstances) { - this.contextInstances = contextInstances; - } - - @Override - public Map, Object> getContextualInstances() { - return contextInstances.getAllPresent().stream() - .collect(Collectors.toUnmodifiableMap(ContextInstanceHandle::getBean, ContextInstanceHandle::get)); - } - - /** - * @return {@code true} if the state was successfully invalidated, {@code false} otherwise - */ - boolean invalidate() { - // Atomically sets the value just like AtomicBoolean.compareAndSet(boolean, boolean) - return IS_VALID.compareAndSet(this, VALID, INVALID); - } - - @Override - public boolean isValid() { - return isValid == VALID; - } - + }; } - } diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CurrentManagedContext.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CurrentManagedContext.java new file mode 100644 index 0000000000000..7d5da765a94fc --- /dev/null +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CurrentManagedContext.java @@ -0,0 +1,270 @@ +package io.quarkus.arc.impl; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import jakarta.enterprise.context.ContextNotActiveException; +import jakarta.enterprise.context.spi.Contextual; +import jakarta.enterprise.context.spi.CreationalContext; + +import org.jboss.logging.Logger; + +import io.quarkus.arc.ContextInstanceHandle; +import io.quarkus.arc.CurrentContext; +import io.quarkus.arc.InjectableBean; +import io.quarkus.arc.ManagedContext; + +/** + * A managed context backed by the {@link CurrentContext}. + */ +public abstract class CurrentManagedContext implements ManagedContext { + + private static final Logger LOG = Logger.getLogger(CurrentManagedContext.class); + + private final CurrentContext currentContext; + + private final Supplier contextInstances; + + private final Consumer initializedNotifier; + private final Consumer beforeDestroyedNotifier; + private final Consumer destroyedNotifier; + + protected CurrentManagedContext(CurrentContext currentContext, + Supplier contextInstances, Consumer initializedNotifier, + Consumer beforeDestroyedNotifier, Consumer destroyedNotifier) { + this.currentContext = currentContext; + this.contextInstances = contextInstances; + this.initializedNotifier = initializedNotifier; + this.beforeDestroyedNotifier = beforeDestroyedNotifier; + this.destroyedNotifier = destroyedNotifier; + } + + @Override + public ContextState getState() { + CurrentContextState state = currentState(); + if (state == null) { + throw notActive(); + } + return state; + } + + @Override + public ContextState activate(ContextState initialState) { + if (traceLog().isTraceEnabled()) { + traceActivate(initialState); + } + if (initialState == null) { + CurrentContextState state = initializeContextState(); + currentContext.set(state); + return state; + } else { + if (initialState instanceof CurrentContextState) { + currentContext.set((CurrentContextState) initialState); + return initialState; + } else { + throw new IllegalArgumentException("Invalid initial state: " + initialState.getClass().getName()); + } + } + } + + @Override + public void deactivate() { + if (traceLog().isTraceEnabled()) { + traceDeactivate(); + } + currentContext.remove(); + } + + @SuppressWarnings("unchecked") + @Override + public T getIfActive(Contextual contextual, Function, CreationalContext> creationalContextFun) { + Objects.requireNonNull(contextual, "Contextual must not be null"); + Objects.requireNonNull(creationalContextFun, "CreationalContext function must not be null"); + InjectableBean bean = (InjectableBean) contextual; + if (!Scopes.scopeMatches(this, bean)) { + throw Scopes.scopeDoesNotMatchException(this, bean); + } + CurrentContextState state = currentState(); + if (state == null || !state.isValid()) { + return null; + } + ContextInstances contextInstances = state.contextInstances; + ContextInstanceHandle instance = (ContextInstanceHandle) contextInstances.getIfPresent(bean.getIdentifier()); + if (instance == null) { + CreationalContext creationalContext = creationalContextFun.apply(contextual); + return (T) contextInstances.computeIfAbsent(bean.getIdentifier(), new Supplier>() { + + @Override + public ContextInstanceHandle get() { + return new ContextInstanceHandleImpl<>(bean, contextual.create(creationalContext), creationalContext); + } + }).get(); + } + return instance.get(); + } + + @Override + public T get(Contextual contextual, CreationalContext creationalContext) { + T result = getIfActive(contextual, + CreationalContextImpl.unwrap(Objects.requireNonNull(creationalContext, "CreationalContext must not be null"))); + if (result == null) { + throw notActive(); + } + return result; + } + + @Override + public T get(Contextual contextual) { + Objects.requireNonNull(contextual, "Contextual must not be null"); + InjectableBean bean = (InjectableBean) contextual; + if (!Scopes.scopeMatches(this, bean)) { + throw Scopes.scopeDoesNotMatchException(this, bean); + } + CurrentContextState state = currentState(); + if (state == null || !state.isValid()) { + throw notActive(); + } + @SuppressWarnings("unchecked") + ContextInstanceHandle instance = (ContextInstanceHandle) state.contextInstances + .getIfPresent(bean.getIdentifier()); + return instance == null ? null : instance.get(); + } + + @Override + public boolean isActive() { + CurrentContextState contextState = currentState(); + return contextState == null ? false : contextState.isValid(); + } + + @Override + public void destroy() { + destroy(currentState()); + } + + @Override + public void destroy(Contextual contextual) { + CurrentContextState state = currentState(); + if (state == null || !state.isValid()) { + throw notActive(); + } + InjectableBean bean = (InjectableBean) contextual; + ContextInstanceHandle instance = state.contextInstances.remove(bean.getIdentifier()); + if (instance != null) { + instance.destroy(); + } + } + + @Override + public void destroy(ContextState state) { + if (traceLog().isTraceEnabled()) { + traceDestroy(state); + } + if (state == null) { + // nothing to destroy + return; + } + if (state instanceof CurrentContextState) { + CurrentContextState currentState = ((CurrentContextState) state); + if (currentState.invalidate()) { + fireIfNotNull(beforeDestroyedNotifier); + currentState.contextInstances.removeEach(ContextInstanceHandle::destroy); + fireIfNotNull(destroyedNotifier); + } + } else { + throw new IllegalArgumentException("Invalid state implementation: " + state.getClass().getName()); + } + } + + public CurrentContextState initializeContextState() { + CurrentContextState state = new CurrentContextState(contextInstances.get()); + fireIfNotNull(initializedNotifier); + return state; + } + + protected Logger traceLog() { + return LOG; + } + + protected void traceActivate(ContextState initialState) { + // Noop + } + + protected void traceDeactivate() { + // Noop + } + + protected void traceDestroy(ContextState state) { + // Noop + } + + private CurrentContextState currentState() { + return currentContext.get(); + } + + protected abstract ContextNotActiveException notActive(); + + private void fireIfNotNull(Consumer notifier) { + if (notifier != null) { + try { + notifier.accept(toString()); + } catch (Exception e) { + LOG.warn("An error occurred during delivery of the context lifecycle event for " + toString(), e); + } + } + } + + public static class CurrentContextState implements ContextState { + + // Using 0 as default value enable removing an initialization + // in the constructor, piggybacking on the default value. + // As per https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5 + // the default field values are set before 'this' is accessible, hence + // they should be the very first value observable even in presence of + // unsafe publication of this object. + private static final int VALID = 0; + private static final int INVALID = 1; + private static final VarHandle IS_VALID; + + static { + try { + IS_VALID = MethodHandles.lookup().findVarHandle(CurrentContextState.class, "isValid", int.class); + } catch (ReflectiveOperationException e) { + throw new Error(e); + } + } + + private final ContextInstances contextInstances; + private volatile int isValid; + + CurrentContextState(ContextInstances contextInstances) { + this.contextInstances = Objects.requireNonNull(contextInstances); + } + + @Override + public Map, Object> getContextualInstances() { + return contextInstances.getAllPresent().stream() + .collect(Collectors.toUnmodifiableMap(ContextInstanceHandle::getBean, ContextInstanceHandle::get)); + } + + /** + * @return {@code true} if the state was successfully invalidated, {@code false} otherwise + */ + boolean invalidate() { + // Atomically sets the value just like AtomicBoolean.compareAndSet(boolean, boolean) + return IS_VALID.compareAndSet(this, VALID, INVALID); + } + + @Override + public boolean isValid() { + return isValid == VALID; + } + + } + +} diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/RequestContext.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/RequestContext.java index 5164d84c374f3..62a1ac4abf829 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/RequestContext.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/RequestContext.java @@ -1,26 +1,16 @@ package io.quarkus.arc.impl; import java.lang.annotation.Annotation; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; import java.util.Arrays; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import jakarta.enterprise.context.ContextNotActiveException; import jakarta.enterprise.context.RequestScoped; -import jakarta.enterprise.context.spi.Contextual; -import jakarta.enterprise.context.spi.CreationalContext; import org.jboss.logging.Logger; -import io.quarkus.arc.ContextInstanceHandle; import io.quarkus.arc.CurrentContext; -import io.quarkus.arc.InjectableBean; -import io.quarkus.arc.ManagedContext; import io.quarkus.arc.impl.EventImpl.Notifier; /** @@ -28,25 +18,16 @@ * * @author Martin Kouba */ -class RequestContext implements ManagedContext { +class RequestContext extends CurrentManagedContext { private static final Logger LOG = Logger.getLogger("io.quarkus.arc.requestContext"); - private final CurrentContext currentContext; - - private final Notifier initializedNotifier; - private final Notifier beforeDestroyedNotifier; - private final Notifier destroyedNotifier; - private final Supplier contextInstances; - - public RequestContext(CurrentContext currentContext, Notifier initializedNotifier, + public RequestContext(CurrentContext currentContext, Notifier initializedNotifier, Notifier beforeDestroyedNotifier, Notifier destroyedNotifier, Supplier contextInstances) { - this.currentContext = currentContext; - this.initializedNotifier = initializedNotifier; - this.beforeDestroyedNotifier = beforeDestroyedNotifier; - this.destroyedNotifier = destroyedNotifier; - this.contextInstances = contextInstances; + super(currentContext, contextInstances, initializedNotifier != null ? initializedNotifier::notify : null, + beforeDestroyedNotifier != null ? beforeDestroyedNotifier::notify : null, + destroyedNotifier != null ? destroyedNotifier::notify : null); } @Override @@ -54,107 +35,12 @@ public Class getScope() { return RequestScoped.class; } - @SuppressWarnings("unchecked") - @Override - public T getIfActive(Contextual contextual, Function, CreationalContext> creationalContextFun) { - Objects.requireNonNull(contextual, "Contextual must not be null"); - Objects.requireNonNull(creationalContextFun, "CreationalContext supplier must not be null"); - InjectableBean bean = (InjectableBean) contextual; - if (!Scopes.scopeMatches(this, bean)) { - throw Scopes.scopeDoesNotMatchException(this, bean); - } - RequestContextState ctxState = currentContext.get(); - if (!isActive(ctxState)) { - // Context is not active! - return null; - } - ContextInstances contextInstances = ctxState.contextInstances; - ContextInstanceHandle instance = (ContextInstanceHandle) contextInstances.getIfPresent(bean.getIdentifier()); - if (instance == null) { - CreationalContext creationalContext = creationalContextFun.apply(contextual); - return (T) contextInstances.computeIfAbsent(bean.getIdentifier(), new Supplier>() { - - @Override - public ContextInstanceHandle get() { - return new ContextInstanceHandleImpl<>(bean, contextual.create(creationalContext), creationalContext); - } - }).get(); - } - return instance.get(); - } - - @Override - public T get(Contextual contextual, CreationalContext creationalContext) { - T result = getIfActive(contextual, - CreationalContextImpl.unwrap(Objects.requireNonNull(creationalContext, "CreationalContext must not be null"))); - if (result == null) { - throw notActive(); - } - return result; - } - - @SuppressWarnings("unchecked") - @Override - public T get(Contextual contextual) { - Objects.requireNonNull(contextual, "Contextual must not be null"); - InjectableBean bean = (InjectableBean) contextual; - if (!Scopes.scopeMatches(this, bean)) { - throw Scopes.scopeDoesNotMatchException(this, bean); - } - RequestContextState state = currentContext.get(); - if (!isActive(state)) { - throw notActive(); - } - ContextInstanceHandle instance = (ContextInstanceHandle) state.contextInstances - .getIfPresent(bean.getIdentifier()); - return instance == null ? null : instance.get(); - } - @Override - public boolean isActive() { - return isActive(currentContext.get()); + protected Logger traceLog() { + return LOG; } - private boolean isActive(RequestContextState state) { - return state == null ? false : state.isValid(); - } - - @Override - public void destroy(Contextual contextual) { - RequestContextState state = currentContext.get(); - if (!isActive(state)) { - // Context is not active - throw notActive(); - } - InjectableBean bean = (InjectableBean) contextual; - ContextInstanceHandle instance = state.contextInstances.remove(bean.getIdentifier()); - if (instance != null) { - instance.destroy(); - } - } - - @Override - public ContextState activate(ContextState initialState) { - if (LOG.isTraceEnabled()) { - traceActivate(initialState); - } - if (initialState == null) { - RequestContextState state = new RequestContextState(contextInstances.get()); - currentContext.set(state); - // Fire an event with qualifier @Initialized(RequestScoped.class) if there are any observers for it - fireIfNotEmpty(initializedNotifier); - return state; - } else { - if (initialState instanceof RequestContextState) { - currentContext.set((RequestContextState) initialState); - return initialState; - } else { - throw new IllegalArgumentException("Invalid initial state: " + initialState.getClass().getName()); - } - } - } - - private void traceActivate(ContextState initialState) { + protected void traceActivate(ContextState initialState) { String stack = Arrays.stream(Thread.currentThread().getStackTrace()) .skip(2) .limit(7) @@ -164,29 +50,7 @@ private void traceActivate(ContextState initialState) { initialState != null ? Integer.toHexString(initialState.hashCode()) : "new", stack); } - @Override - public ContextState getState() { - RequestContextState state = currentContext.get(); - if (!isActive(state)) { - throw notActive(); - } - return state; - } - - public ContextState getStateIfActive() { - ContextState state = currentContext.get(); - return state != null && state.isValid() ? state : null; - } - - @Override - public void deactivate() { - if (LOG.isTraceEnabled()) { - traceDeactivate(); - } - currentContext.remove(); - } - - private static void traceDeactivate() { + protected void traceDeactivate() { String stack = Arrays.stream(Thread.currentThread().getStackTrace()) .skip(2) .limit(7) @@ -195,35 +59,7 @@ private static void traceDeactivate() { LOG.tracef("Deactivate%s\n\t...", stack); } - @Override - public void destroy() { - destroy(currentContext.get()); - } - - @Override - public void destroy(ContextState state) { - if (LOG.isTraceEnabled()) { - traceDestroy(state); - } - if (state == null) { - // nothing to destroy - return; - } - if (state instanceof RequestContextState) { - RequestContextState reqState = ((RequestContextState) state); - if (reqState.invalidate()) { - // Fire an event with qualifier @BeforeDestroyed(RequestScoped.class) if there are any observers for it - fireIfNotEmpty(beforeDestroyedNotifier); - reqState.contextInstances.removeEach(ContextInstanceHandle::destroy); - // Fire an event with qualifier @Destroyed(RequestScoped.class) if there are any observers for it - fireIfNotEmpty(destroyedNotifier); - } - } else { - throw new IllegalArgumentException("Invalid state implementation: " + state.getClass().getName()); - } - } - - private static void traceDestroy(ContextState state) { + protected void traceDestroy(ContextState state) { String stack = Arrays.stream(Thread.currentThread().getStackTrace()) .skip(2) .limit(7) @@ -232,68 +68,9 @@ private static void traceDestroy(ContextState state) { LOG.tracef("Destroy %s%s\n\t...", state != null ? Integer.toHexString(state.hashCode()) : "", stack); } - private void fireIfNotEmpty(Notifier notifier) { - if (notifier != null && !notifier.isEmpty()) { - try { - notifier.notify(toString()); - } catch (Exception e) { - LOG.warn("An error occurred during delivery of the container lifecycle event for qualifiers " - + notifier.eventMetadata.getQualifiers(), e); - } - } - } - - private ContextNotActiveException notActive() { + protected ContextNotActiveException notActive() { String msg = "Request context is not active - you can activate the request context for a specific method using the @ActivateRequestContext interceptor binding"; return new ContextNotActiveException(msg); } - static class RequestContextState implements ContextState { - - // Using 0 as default value enable removing an initialization - // in the constructor, piggybacking on the default value. - // As per https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5 - // the default field values are set before 'this' is accessible, hence - // they should be the very first value observable even in presence of - // unsafe publication of this object. - private static final int VALID = 0; - private static final int INVALID = 1; - private static final VarHandle IS_VALID; - - static { - try { - IS_VALID = MethodHandles.lookup().findVarHandle(RequestContextState.class, "isValid", int.class); - } catch (ReflectiveOperationException e) { - throw new Error(e); - } - } - - private final ContextInstances contextInstances; - private volatile int isValid; - - RequestContextState(ContextInstances contextInstances) { - this.contextInstances = Objects.requireNonNull(contextInstances); - } - - @Override - public Map, Object> getContextualInstances() { - return contextInstances.getAllPresent().stream() - .collect(Collectors.toUnmodifiableMap(ContextInstanceHandle::getBean, ContextInstanceHandle::get)); - } - - /** - * @return {@code true} if the state was successfully invalidated, {@code false} otherwise - */ - boolean invalidate() { - // Atomically sets the value just like AtomicBoolean.compareAndSet(boolean, boolean) - return IS_VALID.compareAndSet(this, VALID, INVALID); - } - - @Override - public boolean isValid() { - return isValid == VALID; - } - - } - } From fcb49dbb892ed2699c4db11d823bb18c29d75f32 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 16 Dec 2024 11:08:48 +0100 Subject: [PATCH 148/207] Update Surefire/Failsafe plugins to 3.5.2 --- docs/src/main/asciidoc/native-reference.adoc | 2 +- .../src/main/resources/archetype-resources/pom.xml | 2 +- .../src/main/resources/archetype-resources/pom.xml | 2 +- .../src/main/resources/archetype-resources/pom.xml | 2 +- .../src/main/resources/archetype-resources/pom.xml | 2 +- independent-projects/junit5-virtual-threads/pom.xml | 2 +- independent-projects/parent/pom.xml | 2 +- .../main/java/io/quarkus/devtools/commands/CreateExtension.java | 2 +- .../maven-invoker-way/src/it/container-build-docker/pom.xml | 2 +- .../maven-invoker-way/src/it/container-build-jib-appcds/pom.xml | 2 +- .../src/it/container-build-jib-inherit/pom.xml | 2 +- .../maven-invoker-way/src/it/container-build-jib/pom.xml | 2 +- .../src/it/container-build-multiple-tags-docker/pom.xml | 2 +- .../src/it/container-build-multiple-tags-jib/pom.xml | 2 +- .../maven-invoker-way/src/it/container-image-push/pom.xml | 2 +- .../hibernate-orm-compatibility-5.6/database-generator/pom.xml | 2 +- .../istio/maven-invoker-way/src/it/xds-grpc/pom.xml | 2 +- .../src/it/knative-jib-build-and-deploy/pom.xml | 2 +- .../it/kubernetes-docker-build-and-deploy-deployment/pom.xml | 2 +- .../it/kubernetes-docker-build-and-deploy-statefulset/pom.xml | 2 +- .../src/it/kubernetes-jib-build-and-deploy/pom.xml | 2 +- .../it/kubernetes-with-existing-selectorless-manifest/pom.xml | 2 +- .../src/it/kubernetes-with-grpc-same-server/pom.xml | 2 +- .../maven-invoker-way/src/it/kubernetes-with-grpc/pom.xml | 2 +- .../src/it/minikube-with-existing-manifest/pom.xml | 2 +- .../src/it/openshift-docker-build-and-deploy/pom.xml | 2 +- .../src/it/openshift-s2i-build-and-deploy/pom.xml | 2 +- .../testCreateStandaloneExtension/my-org-my-own-ext_pom.xml | 2 +- .../projects/project-using-test-callback-from-extension/pom.xml | 2 +- .../projects/project-using-test-parameter-injection/pom.xml | 2 +- .../pom.xml | 2 +- .../projects/project-using-test-template-from-extension/pom.xml | 2 +- 32 files changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/src/main/asciidoc/native-reference.adoc b/docs/src/main/asciidoc/native-reference.adoc index a9e8baa63417d..c5f8f2f83dcbb 100644 --- a/docs/src/main/asciidoc/native-reference.adoc +++ b/docs/src/main/asciidoc/native-reference.adoc @@ -602,7 +602,7 @@ For example: ---- $ ./mvnw verify -DskipITs=false -Dquarkus.test.integration-test-profile=test-with-native-agent ... -[INFO] --- failsafe:3.5.0:integration-test (default) @ new-project --- +[INFO] --- failsafe:3.5.2:integration-test (default) @ new-project --- ... [INFO] ------------------------------------------------------- [INFO] T E S T S diff --git a/extensions/amazon-lambda-http/maven-archetype/src/main/resources/archetype-resources/pom.xml b/extensions/amazon-lambda-http/maven-archetype/src/main/resources/archetype-resources/pom.xml index 4a7f0c66550b1..fc4a0adb4899e 100644 --- a/extensions/amazon-lambda-http/maven-archetype/src/main/resources/archetype-resources/pom.xml +++ b/extensions/amazon-lambda-http/maven-archetype/src/main/resources/archetype-resources/pom.xml @@ -18,7 +18,7 @@ quarkus-bom io.quarkus 999-SNAPSHOT - 3.5.0 + 3.5.2 diff --git a/extensions/amazon-lambda-rest/maven-archetype/src/main/resources/archetype-resources/pom.xml b/extensions/amazon-lambda-rest/maven-archetype/src/main/resources/archetype-resources/pom.xml index b2102594bf46d..4d72ebc7bf0b7 100644 --- a/extensions/amazon-lambda-rest/maven-archetype/src/main/resources/archetype-resources/pom.xml +++ b/extensions/amazon-lambda-rest/maven-archetype/src/main/resources/archetype-resources/pom.xml @@ -18,7 +18,7 @@ quarkus-bom io.quarkus 999-SNAPSHOT - 3.5.0 + 3.5.2 diff --git a/extensions/amazon-lambda/maven-archetype/src/main/resources/archetype-resources/pom.xml b/extensions/amazon-lambda/maven-archetype/src/main/resources/archetype-resources/pom.xml index 601a9675f432a..fe81817155cd8 100644 --- a/extensions/amazon-lambda/maven-archetype/src/main/resources/archetype-resources/pom.xml +++ b/extensions/amazon-lambda/maven-archetype/src/main/resources/archetype-resources/pom.xml @@ -17,7 +17,7 @@ quarkus-bom io.quarkus 999-SNAPSHOT - 3.5.0 + 3.5.2 diff --git a/extensions/funqy/funqy-amazon-lambda/maven-archetype/src/main/resources/archetype-resources/pom.xml b/extensions/funqy/funqy-amazon-lambda/maven-archetype/src/main/resources/archetype-resources/pom.xml index a8f4423f490e9..3f395b13a370c 100644 --- a/extensions/funqy/funqy-amazon-lambda/maven-archetype/src/main/resources/archetype-resources/pom.xml +++ b/extensions/funqy/funqy-amazon-lambda/maven-archetype/src/main/resources/archetype-resources/pom.xml @@ -17,7 +17,7 @@ quarkus-bom io.quarkus 999-SNAPSHOT - 3.5.0 + 3.5.2 diff --git a/independent-projects/junit5-virtual-threads/pom.xml b/independent-projects/junit5-virtual-threads/pom.xml index 20bff11cf2c34..49f61acb50aaa 100644 --- a/independent-projects/junit5-virtual-threads/pom.xml +++ b/independent-projects/junit5-virtual-threads/pom.xml @@ -40,7 +40,7 @@ 3.13.0 3.2.1 - 3.5.0 + 3.5.2 3.2.3 5.10.5 diff --git a/independent-projects/parent/pom.xml b/independent-projects/parent/pom.xml index 2010a46d2a30a..325037f379b0c 100644 --- a/independent-projects/parent/pom.xml +++ b/independent-projects/parent/pom.xml @@ -38,7 +38,7 @@ 3.3.1 3.2.1 3.2.1 - 3.5.0 + 3.5.2 ${version.surefire.plugin} 2.15.0 1.1.3 diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateExtension.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateExtension.java index 850175e64281d..54f7af27da886 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateExtension.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateExtension.java @@ -91,7 +91,7 @@ public enum LayoutType { public static final String DEFAULT_QUARKIVERSE_NAMESPACE_ID = "quarkus-"; public static final String DEFAULT_QUARKIVERSE_GUIDE_URL = "https://docs.quarkiverse.io/%s/dev/"; - private static final String DEFAULT_SUREFIRE_PLUGIN_VERSION = "3.5.0"; + private static final String DEFAULT_SUREFIRE_PLUGIN_VERSION = "3.5.2"; private static final String DEFAULT_COMPILER_PLUGIN_VERSION = "3.13.0"; private final QuarkusExtensionCodestartProjectInputBuilder builder = QuarkusExtensionCodestartProjectInput.builder(); diff --git a/integration-tests/container-image/maven-invoker-way/src/it/container-build-docker/pom.xml b/integration-tests/container-image/maven-invoker-way/src/it/container-build-docker/pom.xml index 6634fa060264c..3b83eb3a6f7d1 100644 --- a/integration-tests/container-image/maven-invoker-way/src/it/container-build-docker/pom.xml +++ b/integration-tests/container-image/maven-invoker-way/src/it/container-build-docker/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib-appcds/pom.xml b/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib-appcds/pom.xml index 59510e3af52ed..95ad7a9106bae 100644 --- a/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib-appcds/pom.xml +++ b/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib-appcds/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib-inherit/pom.xml b/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib-inherit/pom.xml index 9be34487d77a4..46c5dc85531d3 100644 --- a/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib-inherit/pom.xml +++ b/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib-inherit/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib/pom.xml b/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib/pom.xml index fc80512091681..7aa61521beaba 100644 --- a/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib/pom.xml +++ b/integration-tests/container-image/maven-invoker-way/src/it/container-build-jib/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/container-image/maven-invoker-way/src/it/container-build-multiple-tags-docker/pom.xml b/integration-tests/container-image/maven-invoker-way/src/it/container-build-multiple-tags-docker/pom.xml index 6224987c1d462..be38e3eec1f5f 100644 --- a/integration-tests/container-image/maven-invoker-way/src/it/container-build-multiple-tags-docker/pom.xml +++ b/integration-tests/container-image/maven-invoker-way/src/it/container-build-multiple-tags-docker/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/container-image/maven-invoker-way/src/it/container-build-multiple-tags-jib/pom.xml b/integration-tests/container-image/maven-invoker-way/src/it/container-build-multiple-tags-jib/pom.xml index a18ef6c4db78c..372b14d6dc9f4 100644 --- a/integration-tests/container-image/maven-invoker-way/src/it/container-build-multiple-tags-jib/pom.xml +++ b/integration-tests/container-image/maven-invoker-way/src/it/container-build-multiple-tags-jib/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/container-image/maven-invoker-way/src/it/container-image-push/pom.xml b/integration-tests/container-image/maven-invoker-way/src/it/container-image-push/pom.xml index 96e0b6696b1ef..42f36cb5c5ea9 100644 --- a/integration-tests/container-image/maven-invoker-way/src/it/container-image-push/pom.xml +++ b/integration-tests/container-image/maven-invoker-way/src/it/container-image-push/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/hibernate-orm-compatibility-5.6/database-generator/pom.xml b/integration-tests/hibernate-orm-compatibility-5.6/database-generator/pom.xml index a4310bc090b71..bfca054cdef80 100644 --- a/integration-tests/hibernate-orm-compatibility-5.6/database-generator/pom.xml +++ b/integration-tests/hibernate-orm-compatibility-5.6/database-generator/pom.xml @@ -15,7 +15,7 @@ io.quarkus.platform 2.16.3.Final true - 3.5.0 + 3.5.2 diff --git a/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/pom.xml b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/pom.xml index 6d250a376993a..645068923f8c2 100644 --- a/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/pom.xml +++ b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/knative-jib-build-and-deploy/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/knative-jib-build-and-deploy/pom.xml index d8e6d3de89042..b071362d8f4c1 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/knative-jib-build-and-deploy/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/knative-jib-build-and-deploy/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-docker-build-and-deploy-deployment/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-docker-build-and-deploy-deployment/pom.xml index 1b5260d425205..9b4f2b6050145 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-docker-build-and-deploy-deployment/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-docker-build-and-deploy-deployment/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-docker-build-and-deploy-statefulset/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-docker-build-and-deploy-statefulset/pom.xml index edb24abc8d1b8..be073f36896ce 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-docker-build-and-deploy-statefulset/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-docker-build-and-deploy-statefulset/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-jib-build-and-deploy/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-jib-build-and-deploy/pom.xml index 137f8c690949e..9d542d751349e 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-jib-build-and-deploy/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-jib-build-and-deploy/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-existing-selectorless-manifest/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-existing-selectorless-manifest/pom.xml index 51e88a55f3713..15f7d4cd029eb 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-existing-selectorless-manifest/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-existing-selectorless-manifest/pom.xml @@ -8,7 +8,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-grpc-same-server/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-grpc-same-server/pom.xml index 8b381c178dd9d..fa53fb2597e2a 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-grpc-same-server/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-grpc-same-server/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-grpc/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-grpc/pom.xml index 849d0b370e237..5238212c27937 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-grpc/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/kubernetes-with-grpc/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/minikube-with-existing-manifest/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/minikube-with-existing-manifest/pom.xml index ae2bca28a0809..88dd72673ef47 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/minikube-with-existing-manifest/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/minikube-with-existing-manifest/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/openshift-docker-build-and-deploy/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/openshift-docker-build-and-deploy/pom.xml index 9a1b383999bce..169f0414b97bf 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/openshift-docker-build-and-deploy/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/openshift-docker-build-and-deploy/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/kubernetes/maven-invoker-way/src/it/openshift-s2i-build-and-deploy/pom.xml b/integration-tests/kubernetes/maven-invoker-way/src/it/openshift-s2i-build-and-deploy/pom.xml index 6db87aad3a89a..ea700691d461a 100644 --- a/integration-tests/kubernetes/maven-invoker-way/src/it/openshift-s2i-build-and-deploy/pom.xml +++ b/integration-tests/kubernetes/maven-invoker-way/src/it/openshift-s2i-build-and-deploy/pom.xml @@ -7,7 +7,7 @@ 0.1-SNAPSHOT UTF-8 - 3.5.0 + 3.5.2 17 UTF-8 17 diff --git a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateStandaloneExtension/my-org-my-own-ext_pom.xml b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateStandaloneExtension/my-org-my-own-ext_pom.xml index 8f3eb160b8699..811917d801feb 100644 --- a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateStandaloneExtension/my-org-my-own-ext_pom.xml +++ b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateStandaloneExtension/my-org-my-own-ext_pom.xml @@ -19,7 +19,7 @@ UTF-8 UTF-8 3.14.0 - 3.5.0 + 3.5.2 diff --git a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-callback-from-extension/pom.xml b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-callback-from-extension/pom.xml index 1c7c3a0267d69..557c179842511 100644 --- a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-callback-from-extension/pom.xml +++ b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-callback-from-extension/pom.xml @@ -12,7 +12,7 @@ 17 UTF-8 UTF-8 - 3.5.0 + 3.5.2 @project.version@ diff --git a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-parameter-injection/pom.xml b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-parameter-injection/pom.xml index e3a571400982e..9cda97d707057 100644 --- a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-parameter-injection/pom.xml +++ b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-parameter-injection/pom.xml @@ -13,7 +13,7 @@ UTF-8 UTF-8 quarkus-bom - 3.5.0 + 3.5.2 @project.version@ diff --git a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension-with-bytecode-changes/pom.xml b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension-with-bytecode-changes/pom.xml index c0f6c1cf83887..b90cfe7e754cd 100644 --- a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension-with-bytecode-changes/pom.xml +++ b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension-with-bytecode-changes/pom.xml @@ -12,7 +12,7 @@ 17 UTF-8 UTF-8 - 3.5.0 + 3.5.2 @project.version@ diff --git a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension/pom.xml b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension/pom.xml index c0f6c1cf83887..b90cfe7e754cd 100644 --- a/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension/pom.xml +++ b/integration-tests/test-extension/tests/src/test/resources-filtered/projects/project-using-test-template-from-extension/pom.xml @@ -12,7 +12,7 @@ 17 UTF-8 UTF-8 - 3.5.0 + 3.5.2 @project.version@ From 64c5045117044538c88d0c2e235d272dd18d7bfd Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 17 Dec 2024 10:54:08 +0200 Subject: [PATCH 149/207] Fix local proxy handling in REST Client module With the previous implementation, Cloudfare was blocking requests coming from the local proxy --- ...vServicesRestClientHttpProxyProcessor.java | 8 +++--- ...oxyDevServicesRestClientProxyProvider.java | 27 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/devservices/DevServicesRestClientHttpProxyProcessor.java b/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/devservices/DevServicesRestClientHttpProxyProcessor.java index 6e2eb61e3f12c..8672ee205a985 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/devservices/DevServicesRestClientHttpProxyProcessor.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/devservices/DevServicesRestClientHttpProxyProcessor.java @@ -211,10 +211,12 @@ public void start(List restClientHttpProxyBuildIte var urlKeyName = String.format("quarkus.rest-client.\"%s\".override-uri", bi.getClassName()); var urlKeyValue = String.format("http://%s:%d", createResult.host(), createResult.port()); - if (baseUri.getPath() != null) { - if (!"/".equals(baseUri.getPath()) && !baseUri.getPath().isEmpty()) { - urlKeyValue = urlKeyValue + "/" + baseUri.getPath(); + String basePath = baseUri.getPath(); + if ((basePath != null) && !basePath.isEmpty()) { + if (basePath.startsWith("/")) { + basePath = basePath.substring(1); } + urlKeyValue = urlKeyValue + "/" + basePath; } devServicePropertiesProducer.produce( diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/devservices/VertxHttpProxyDevServicesRestClientProxyProvider.java b/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/devservices/VertxHttpProxyDevServicesRestClientProxyProvider.java index 4965a4d35c457..73d457ce4a3ca 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/devservices/VertxHttpProxyDevServicesRestClientProxyProvider.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/devservices/VertxHttpProxyDevServicesRestClientProxyProvider.java @@ -15,7 +15,6 @@ import io.quarkus.rest.client.reactive.spi.RestClientHttpProxyBuildItem; import io.quarkus.runtime.ResettableSystemProperties; import io.vertx.core.Future; -import io.vertx.core.MultiMap; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.file.FileSystemOptions; @@ -23,6 +22,7 @@ import io.vertx.core.http.HttpClientOptions; import io.vertx.core.http.HttpServer; import io.vertx.core.metrics.MetricsOptions; +import io.vertx.core.net.HostAndPort; import io.vertx.httpproxy.HttpProxy; import io.vertx.httpproxy.ProxyContext; import io.vertx.httpproxy.ProxyInterceptor; @@ -71,16 +71,18 @@ public CreateResult create(RestClientHttpProxyBuildItem buildItem) { } HttpClient proxyClient = vertx.get().createHttpClient(clientOptions); HttpProxy proxy = HttpProxy.reverseProxy(proxyClient); - proxy.origin(determineOriginPort(baseUri), baseUri.getHost()) - .addInterceptor(new HostSettingInterceptor(baseUri.getHost())); + int targetPort = determineOriginPort(baseUri); + String targetHost = baseUri.getHost(); + proxy.origin(targetPort, targetHost) + .addInterceptor(new AuthoritySettingInterceptor(targetPort, targetHost)); HttpServer proxyServer = vertx.get().createHttpServer(); - Integer port = findRandomPort(); - proxyServer.requestHandler(proxy).listen(port); + Integer proxyPort = findRandomPort(); + proxyServer.requestHandler(proxy).listen(proxyPort); - logStartup(buildItem.getClassName(), port); + logStartup(buildItem.getClassName(), proxyPort); - return new CreateResult("localhost", port, new HttpServerClosable(proxyServer)); + return new CreateResult("localhost", proxyPort, new HttpServerClosable(proxyServer)); } protected void logStartup(String className, Integer port) { @@ -124,19 +126,18 @@ private Integer findRandomPort() { * This class sets the Host HTTP Header in order to avoid having services being blocked * for presenting a wrong value */ - private static class HostSettingInterceptor implements ProxyInterceptor { + private static class AuthoritySettingInterceptor implements ProxyInterceptor { - private final String host; + private final HostAndPort authority; - private HostSettingInterceptor(String host) { - this.host = host; + private AuthoritySettingInterceptor(int targetPort, String host) { + this.authority = HostAndPort.authority(host, targetPort); } @Override public Future handleProxyRequest(ProxyContext context) { ProxyRequest request = context.request(); - MultiMap headers = request.headers(); - headers.set("Host", host); + request.setAuthority(authority); return context.sendRequest(); } From 036cc7fc1c1bc18222ded80865e8ea886d100aa6 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Tue, 17 Dec 2024 11:13:17 +0200 Subject: [PATCH 150/207] Improve documentation for handling proxies in native-mode Follow up to https://github.com/quarkusio/quarkus/pull/45004 --- .../writing-native-applications-tips.adoc | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/docs/src/main/asciidoc/writing-native-applications-tips.adoc b/docs/src/main/asciidoc/writing-native-applications-tips.adoc index e4e19d35f0d73..32a6917cc22e0 100644 --- a/docs/src/main/asciidoc/writing-native-applications-tips.adoc +++ b/docs/src/main/asciidoc/writing-native-applications-tips.adoc @@ -320,6 +320,23 @@ and in the case of using the Maven configuration instead of `application.propert ---- ==== +[[managing-proxy-classes-app]] +=== Managing Proxy Classes + +While writing native application you'll need to define proxy classes at image build time by specifying the list of interfaces that they implement. + +In such a situation, the error you might encounter is: + +[source] +---- +com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface org.apache.http.conn.HttpClientConnectionManager, interface org.apache.http.pool.ConnPoolControl, interface com.amazonaws.http.conn.Wrapped] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles= and -H:DynamicProxyConfigurationResources= options. +---- + +To solve the issue you can create a `proxy-config.json` file under the `src/main/resources/META-INF/native-image//` folder. +For more information about the format of the `proxy-config.json`, see the https://www.graalvm.org/{graalvm-docs-version}/reference-manual/native-image/metadata/#dynamic-proxy-metadata-in-json[Dynamic Proxy Metadata in JSON] documentation. + +Alternatively, you can create a quarkus extension and register the proxy classes as described in <>. + [[modularity-benefits]] === Modularity Benefits @@ -618,18 +635,10 @@ Using such a construct means that a `--initialize-at-run-time` option will autom For more information about the `--initialize-at-run-time` option, see the link:https://www.graalvm.org/{graalvm-docs-version}/reference-manual/native-image/optimizations-and-performance/ClassInitialization/[GraalVM Class Initialization in Native Image] guide. ==== +[[managing-proxy-classes-extension]] === Managing Proxy Classes -While writing native application you'll need to define proxy classes at image build time by specifying the list of interfaces that they implement. - -In such a situation, the error you might encounter is: - -[source] ----- -com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface org.apache.http.conn.HttpClientConnectionManager, interface org.apache.http.pool.ConnPoolControl, interface com.amazonaws.http.conn.Wrapped] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles= and -H:DynamicProxyConfigurationResources= options. ----- - -Quarkus allows extensions authors to register a `NativeImageProxyDefinitionBuildItem`. An example of doing so is: +Similarly, Quarkus allows extensions authors to register a `NativeImageProxyDefinitionBuildItem`. An example of doing so is: [source,java] ---- @@ -645,8 +654,8 @@ public class S3Processor { ---- This will allow Quarkus to generate the necessary configuration for handling the proxy class. -Alternatively, you may create a `proxy-config.json` file under the `src/main/resources/META-INF/native-image//` folder. -For more information about the format of this file, see the https://www.graalvm.org/{graalvm-docs-version}/reference-manual/native-image/metadata/#dynamic-proxy-metadata-in-json[Dynamic Proxy Metadata in JSON] documentation. + +Alternatively, you may create a `proxy-config.json` as described in <>. [NOTE] ==== From 1cd124ea0ce7571ec61d89b83b35b675c591625e Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Tue, 17 Dec 2024 11:05:33 +0100 Subject: [PATCH 151/207] ArC: introduce built-in session context --- .../quarkus/arc/processor/BuiltinScope.java | 4 +- .../java/io/quarkus/arc/ArcContainer.java | 7 ++ .../io/quarkus/arc/impl/ArcContainerImpl.java | 11 ++ .../java/io/quarkus/arc/impl/Contexts.java | 30 ++++-- .../io/quarkus/arc/impl/SessionContext.java | 35 ++++++ .../contexts/session/ContextObserver.java | 34 ++++++ .../arc/test/contexts/session/Controller.java | 30 ++++++ .../contexts/session/SessionContextTest.java | 100 ++++++++++++++++++ 8 files changed, 242 insertions(+), 9 deletions(-) create mode 100644 independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/SessionContext.java create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/ContextObserver.java create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/Controller.java create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/SessionContextTest.java diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BuiltinScope.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BuiltinScope.java index 29ade50172ec4..d543ac90be81f 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BuiltinScope.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BuiltinScope.java @@ -5,6 +5,7 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.Dependent; import jakarta.enterprise.context.RequestScoped; +import jakarta.enterprise.context.SessionScoped; import jakarta.inject.Singleton; import org.jboss.jandex.AnnotationInstance; @@ -16,7 +17,8 @@ public enum BuiltinScope { DEPENDENT(Dependent.class, false), SINGLETON(Singleton.class, false), APPLICATION(ApplicationScoped.class, true), - REQUEST(RequestScoped.class, true); + REQUEST(RequestScoped.class, true), + SESSION(SessionScoped.class, true); private ScopeInfo info; diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ArcContainer.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ArcContainer.java index 1ed13a4a95040..c4f3a4a3ea654 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ArcContainer.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ArcContainer.java @@ -204,6 +204,13 @@ public interface ArcContainer { */ ManagedContext requestContext(); + /** + * This method never throws {@link ContextNotActiveException}. + * + * @return the built-in context for {@link jakarta.enterprise.context.SessionScoped} + */ + ManagedContext sessionContext(); + /** * NOTE: Not all methods are supported! * diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java index c63710b5cbd86..d9843805156a6 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java @@ -36,6 +36,7 @@ import jakarta.enterprise.context.Initialized; import jakarta.enterprise.context.NormalScope; import jakarta.enterprise.context.RequestScoped; +import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.event.Event; import jakarta.enterprise.inject.AmbiguousResolutionException; import jakarta.enterprise.inject.Any; @@ -207,9 +208,14 @@ public List get() { notifierOrNull(Set.of(BeforeDestroyed.Literal.REQUEST, Any.Literal.INSTANCE)), notifierOrNull(Set.of(Destroyed.Literal.REQUEST, Any.Literal.INSTANCE)), requestContextInstances != null ? requestContextInstances : ComputingCacheContextInstances::new); + SessionContext sessionContext = new SessionContext(this.currentContextFactory.create(SessionScoped.class), + notifierOrNull(Set.of(Initialized.Literal.SESSION, Any.Literal.INSTANCE)), + notifierOrNull(Set.of(BeforeDestroyed.Literal.SESSION, Any.Literal.INSTANCE)), + notifierOrNull(Set.of(Destroyed.Literal.SESSION, Any.Literal.INSTANCE)), ComputingCacheContextInstances::new); Contexts.Builder contextsBuilder = new Contexts.Builder( requestContext, + sessionContext, applicationContext, new SingletonContext(), new DependentContext()); @@ -399,6 +405,11 @@ public ManagedContext requestContext() { return contexts.requestContext; } + @Override + public ManagedContext sessionContext() { + return contexts.sessionContext; + } + @Override public BeanManager beanManager() { return BeanManagerImpl.INSTANCE.get(); diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/Contexts.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/Contexts.java index 5858b982dcc87..b0ec74902fa0b 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/Contexts.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/Contexts.java @@ -12,6 +12,7 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.Dependent; import jakarta.enterprise.context.RequestScoped; +import jakarta.enterprise.context.SessionScoped; import jakarta.inject.Singleton; import io.quarkus.arc.InjectableContext; @@ -26,6 +27,7 @@ class Contexts { // Built-in contexts final ManagedContext requestContext; + final ManagedContext sessionContext; final InjectableContext applicationContext; final InjectableContext singletonContext; final InjectableContext dependentContext; @@ -35,6 +37,7 @@ class Contexts { private final List singletonContextSingleton; private final List dependentContextSingleton; private final List requestContextSingleton; + private final List sessionContextSingleton; // Lazily computed list of contexts for a scope private final ClassValue> unoptimizedContexts; @@ -42,18 +45,22 @@ class Contexts { // Precomputed values final Set> scopes; - Contexts(ManagedContext requestContext, InjectableContext applicationContext, InjectableContext singletonContext, + Contexts(ManagedContext requestContext, ManagedContext sessionContext, InjectableContext applicationContext, + InjectableContext singletonContext, InjectableContext dependentContext, Map, List> contexts) { this.requestContext = requestContext; + this.sessionContext = sessionContext; this.applicationContext = applicationContext; this.singletonContext = singletonContext; this.dependentContext = dependentContext; - this.applicationContextSingleton = Collections.singletonList(applicationContext); - this.singletonContextSingleton = Collections.singletonList(singletonContext); - this.dependentContextSingleton = Collections.singletonList(dependentContext); + this.applicationContextSingleton = List.of(applicationContext); + this.singletonContextSingleton = List.of(singletonContext); + this.dependentContextSingleton = List.of(dependentContext); List requestContexts = contexts.get(RequestScoped.class); - this.requestContextSingleton = requestContexts != null ? requestContexts : Collections.singletonList(requestContext); + this.requestContextSingleton = requestContexts != null ? requestContexts : List.of(requestContext); + List sessionContexts = contexts.get(SessionScoped.class); + this.sessionContextSingleton = sessionContexts != null ? sessionContexts : List.of(sessionContext); if (!contexts.isEmpty()) { // At least one custom context is registered @@ -84,11 +91,13 @@ protected List computeValue(Class type) { all.add(Singleton.class); all.add(Dependent.class); all.add(RequestScoped.class); + all.add(SessionScoped.class); this.scopes = Set.copyOf(all); } else { // No custom context is registered this.unoptimizedContexts = null; - this.scopes = Set.of(ApplicationScoped.class, Singleton.class, Dependent.class, RequestScoped.class); + this.scopes = Set.of(ApplicationScoped.class, Singleton.class, Dependent.class, RequestScoped.class, + SessionScoped.class); } } @@ -125,6 +134,8 @@ List getContexts(Class scopeType) { return singletonContextSingleton; } else if (Dependent.class.equals(scopeType)) { return dependentContextSingleton; + } else if (SessionScoped.class.equals(scopeType)) { + return sessionContextSingleton; } return unoptimizedContexts != null ? unoptimizedContexts.get(scopeType) : Collections.emptyList(); } @@ -132,14 +143,16 @@ List getContexts(Class scopeType) { static class Builder { private final ManagedContext requestContext; + private final ManagedContext sessionContext; private final InjectableContext applicationContext; private final InjectableContext singletonContext; private final InjectableContext dependentContext; private final Map, List> contexts = new HashMap<>(); - public Builder(ManagedContext requestContext, InjectableContext applicationContext, + public Builder(ManagedContext requestContext, ManagedContext sessionContext, InjectableContext applicationContext, InjectableContext singletonContext, InjectableContext dependentContext) { this.requestContext = requestContext; + this.sessionContext = sessionContext; this.applicationContext = applicationContext; this.singletonContext = singletonContext; this.dependentContext = dependentContext; @@ -163,7 +176,8 @@ Contexts build() { // If a custom request context is registered then add the built-in context as well putContext(requestContext); } - return new Contexts(requestContext, applicationContext, singletonContext, dependentContext, contexts); + return new Contexts(requestContext, sessionContext, applicationContext, singletonContext, dependentContext, + contexts); } } diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/SessionContext.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/SessionContext.java new file mode 100644 index 0000000000000..fb44039c68305 --- /dev/null +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/SessionContext.java @@ -0,0 +1,35 @@ +package io.quarkus.arc.impl; + +import java.lang.annotation.Annotation; +import java.util.function.Supplier; + +import jakarta.enterprise.context.ContextNotActiveException; +import jakarta.enterprise.context.SessionScoped; + +import io.quarkus.arc.CurrentContext; +import io.quarkus.arc.impl.EventImpl.Notifier; + +/** + * The built-in context for {@link SessionScoped}. + */ +public class SessionContext extends CurrentManagedContext { + + public SessionContext(CurrentContext currentContext, Notifier initializedNotifier, + Notifier beforeDestroyedNotifier, Notifier destroyedNotifier, + Supplier contextInstances) { + super(currentContext, contextInstances, initializedNotifier != null ? initializedNotifier::notify : null, + beforeDestroyedNotifier != null ? beforeDestroyedNotifier::notify : null, + destroyedNotifier != null ? destroyedNotifier::notify : null); + } + + @Override + public Class getScope() { + return SessionScoped.class; + } + + @Override + protected ContextNotActiveException notActive() { + return new ContextNotActiveException("Session context is not active"); + } + +} diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/ContextObserver.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/ContextObserver.java new file mode 100644 index 0000000000000..375d944058227 --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/ContextObserver.java @@ -0,0 +1,34 @@ +package io.quarkus.arc.test.contexts.session; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.BeforeDestroyed; +import jakarta.enterprise.context.Destroyed; +import jakarta.enterprise.context.Initialized; +import jakarta.enterprise.context.SessionScoped; +import jakarta.enterprise.event.Observes; + +@ApplicationScoped +public class ContextObserver { + + static volatile int initializedObserved = 0; + static volatile int beforeDestroyedObserved = 0; + static volatile int destroyedObserved = 0; + + static void reset() { + initializedObserved = 0; + beforeDestroyedObserved = 0; + destroyedObserved = 0; + } + + void observeContextInit(@Observes @Initialized(SessionScoped.class) Object event) { + initializedObserved++; + } + + void observeContextBeforeDestroyed(@Observes @BeforeDestroyed(SessionScoped.class) Object event) { + beforeDestroyedObserved++; + } + + void observeContextDestroyed(@Observes @Destroyed(SessionScoped.class) Object event) { + destroyedObserved++; + } +} diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/Controller.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/Controller.java new file mode 100644 index 0000000000000..5fabd0f130e50 --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/Controller.java @@ -0,0 +1,30 @@ +package io.quarkus.arc.test.contexts.session; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.context.SessionScoped; + +@SessionScoped +public class Controller { + + static final AtomicBoolean DESTROYED = new AtomicBoolean(); + + private String id; + + @PostConstruct + void init() { + id = UUID.randomUUID().toString(); + } + + @PreDestroy + void destroy() { + DESTROYED.set(true); + } + + String getId() { + return id; + } +} diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/SessionContextTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/SessionContextTest.java new file mode 100644 index 0000000000000..871deb5d45be3 --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/contexts/session/SessionContextTest.java @@ -0,0 +1,100 @@ +package io.quarkus.arc.test.contexts.session; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import jakarta.enterprise.context.ContextNotActiveException; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.ManagedContext; +import io.quarkus.arc.test.ArcTestContainer; + +public class SessionContextTest { + + @RegisterExtension + public ArcTestContainer container = new ArcTestContainer(Controller.class, ContextObserver.class); + + @Test + public void testSessionContext() { + Controller.DESTROYED.set(false); + ArcContainer arc = Arc.container(); + ManagedContext sessionContext = arc.sessionContext(); + + try { + arc.instance(Controller.class).get().getId(); + fail(); + } catch (ContextNotActiveException expected) { + } + + sessionContext.activate(); + assertFalse(Controller.DESTROYED.get()); + Controller controller1 = arc.instance(Controller.class).get(); + Controller controller2 = arc.instance(Controller.class).get(); + String controller2Id = controller2.getId(); + assertEquals(controller1.getId(), controller2Id); + sessionContext.terminate(); + assertTrue(Controller.DESTROYED.get()); + + try { + arc.instance(Controller.class).get().getId(); + fail(); + } catch (ContextNotActiveException expected) { + } + + // Id must be different in a different context + Controller.DESTROYED.set(false); + sessionContext.activate(); + assertNotEquals(controller2Id, arc.instance(Controller.class).get().getId()); + sessionContext.terminate(); + assertTrue(Controller.DESTROYED.get()); + + Controller.DESTROYED.set(false); + sessionContext.activate(); + assertNotEquals(controller2Id, arc.instance(Controller.class).get().getId()); + sessionContext.terminate(); + assertTrue(Controller.DESTROYED.get()); + } + + @Test + public void testSessionContextEvents() { + // reset counters since other tests might have triggered it already + ContextObserver.reset(); + + // firstly test manual activation + ArcContainer arc = Arc.container(); + ManagedContext sessionContext = arc.sessionContext(); + + try { + arc.instance(Controller.class).get().getId(); + fail(); + } catch (ContextNotActiveException expected) { + } + + sessionContext.activate(); + assertEquals(1, ContextObserver.initializedObserved); + assertEquals(0, ContextObserver.beforeDestroyedObserved); + assertEquals(0, ContextObserver.destroyedObserved); + + // dummy check that bean is available + arc.instance(Controller.class).get().getId(); + + sessionContext.terminate(); + assertEquals(1, ContextObserver.initializedObserved); + assertEquals(1, ContextObserver.beforeDestroyedObserved); + assertEquals(1, ContextObserver.destroyedObserved); + + try { + arc.instance(Controller.class).get().getId(); + fail(); + } catch (ContextNotActiveException expected) { + } + } + +} From a3f0d32b7ef52cdbd8d2ac4ee075f82225a799be Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Tue, 17 Dec 2024 11:24:36 +0100 Subject: [PATCH 152/207] WebSockets Next: replace WebSocketSessionContext with built-in context --- .../next/deployment/WebSocketProcessor.java | 17 ----- .../next/runtime/ContextSupport.java | 9 ++- .../websockets/next/runtime/Endpoints.java | 20 ++---- .../next/runtime/WebSocketSessionContext.java | 62 ------------------- .../java/io/quarkus/arc/ManagedContext.java | 6 ++ .../arc/impl/CurrentManagedContext.java | 5 +- 6 files changed, 18 insertions(+), 101 deletions(-) delete mode 100644 extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketSessionContext.java diff --git a/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java b/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java index 1c5ecbb6df7ce..9c8c02a2deadc 100644 --- a/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java +++ b/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java @@ -45,9 +45,6 @@ import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem; import io.quarkus.arc.deployment.BeanDefiningAnnotationBuildItem; import io.quarkus.arc.deployment.BeanDiscoveryFinishedBuildItem; -import io.quarkus.arc.deployment.ContextRegistrationPhaseBuildItem; -import io.quarkus.arc.deployment.ContextRegistrationPhaseBuildItem.ContextConfiguratorBuildItem; -import io.quarkus.arc.deployment.CustomScopeBuildItem; import io.quarkus.arc.deployment.InvokerFactoryBuildItem; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; import io.quarkus.arc.deployment.SyntheticBeansRuntimeInitBuildItem; @@ -126,7 +123,6 @@ import io.quarkus.websockets.next.runtime.WebSocketEndpointBase; import io.quarkus.websockets.next.runtime.WebSocketHttpServerOptionsCustomizer; import io.quarkus.websockets.next.runtime.WebSocketServerRecorder; -import io.quarkus.websockets.next.runtime.WebSocketSessionContext; import io.quarkus.websockets.next.runtime.kotlin.ApplicationCoroutineScope; import io.quarkus.websockets.next.runtime.kotlin.CoroutineInvoker; import io.quarkus.websockets.next.runtime.telemetry.ErrorInterceptor; @@ -229,19 +225,6 @@ void produceCoroutineScope(BuildProducer additionalBean .build()); } - @BuildStep - ContextConfiguratorBuildItem registerSessionContext(ContextRegistrationPhaseBuildItem phase) { - return new ContextConfiguratorBuildItem(phase.getContext() - .configure(SessionScoped.class) - .normal() - .contextClass(WebSocketSessionContext.class)); - } - - @BuildStep - CustomScopeBuildItem registerSessionScope() { - return new CustomScopeBuildItem(DotName.createSimple(SessionScoped.class)); - } - @BuildStep void builtinCallbackArguments(BuildProducer providers) { providers.produce(new CallbackArgumentBuildItem(new MessageCallbackArgument())); diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/ContextSupport.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/ContextSupport.java index 0698723d361dd..26823e8b9b5c7 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/ContextSupport.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/ContextSupport.java @@ -6,7 +6,6 @@ import io.quarkus.arc.InjectableContext.ContextState; import io.quarkus.arc.ManagedContext; -import io.quarkus.arc.impl.CurrentManagedContext.CurrentContextState; import io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle; import io.smallrye.common.vertx.VertxContext; import io.vertx.core.Context; @@ -21,12 +20,12 @@ public class ContextSupport { static final String WEB_SOCKET_CONN_KEY = WebSocketConnectionBase.class.getName(); private final WebSocketConnectionBase connection; - private final CurrentContextState sessionContextState; - private final WebSocketSessionContext sessionContext; + private final ContextState sessionContextState; + private final ManagedContext sessionContext; private final ManagedContext requestContext; - ContextSupport(WebSocketConnectionBase connection, CurrentContextState sessionContextState, - WebSocketSessionContext sessionContext, + ContextSupport(WebSocketConnectionBase connection, ContextState sessionContextState, + ManagedContext sessionContext, ManagedContext requestContext) { this.connection = connection; this.sessionContext = sessionContext; diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/Endpoints.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/Endpoints.java index 95d7e2158d7bc..64f43ee3a7377 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/Endpoints.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/Endpoints.java @@ -4,14 +4,12 @@ import java.util.Optional; import java.util.function.Consumer; -import jakarta.enterprise.context.SessionScoped; - import org.jboss.logging.Logger; import io.netty.handler.codec.http.websocketx.WebSocketCloseStatus; import io.quarkus.arc.ArcContainer; import io.quarkus.arc.InjectableContext; -import io.quarkus.arc.impl.CurrentManagedContext.CurrentContextState; +import io.quarkus.arc.ManagedContext; import io.quarkus.runtime.LaunchMode; import io.quarkus.security.AuthenticationFailedException; import io.quarkus.security.ForbiddenException; @@ -43,11 +41,11 @@ static void initialize(Vertx vertx, ArcContainer container, Codecs codecs, WebSo // Initialize and capture the session context state that will be activated // during message processing - WebSocketSessionContext sessionContext = null; - CurrentContextState sessionContextState = null; + ManagedContext sessionContext = null; + InjectableContext.ContextState sessionContextState = null; if (activateSessionContext) { - sessionContext = sessionContext(container); - sessionContextState = sessionContext.initializeContextState(); + sessionContext = container.sessionContext(); + sessionContextState = sessionContext.initializeState(); } ContextSupport contextSupport = new ContextSupport(connection, sessionContextState, sessionContext, activateRequestContext ? container.requestContext() : null); @@ -406,12 +404,4 @@ private static WebSocketEndpoint createEndpoint(String endpointClassName, Contex } } - private static WebSocketSessionContext sessionContext(ArcContainer container) { - for (InjectableContext injectableContext : container.getContexts(SessionScoped.class)) { - if (WebSocketSessionContext.class.equals(injectableContext.getClass())) { - return (WebSocketSessionContext) injectableContext; - } - } - throw new WebSocketException("CDI session context not registered"); - } } diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketSessionContext.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketSessionContext.java deleted file mode 100644 index 4d5a91b170a7d..0000000000000 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketSessionContext.java +++ /dev/null @@ -1,62 +0,0 @@ -package io.quarkus.websockets.next.runtime; - -import java.lang.annotation.Annotation; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import jakarta.enterprise.context.BeforeDestroyed; -import jakarta.enterprise.context.ContextNotActiveException; -import jakarta.enterprise.context.Destroyed; -import jakarta.enterprise.context.Initialized; -import jakarta.enterprise.context.SessionScoped; -import jakarta.enterprise.event.Event; -import jakarta.enterprise.inject.Any; - -import io.quarkus.arc.Arc; -import io.quarkus.arc.ArcContainer; -import io.quarkus.arc.CurrentContextFactory; -import io.quarkus.arc.impl.ComputingCacheContextInstances; -import io.quarkus.arc.impl.CurrentManagedContext; -import io.quarkus.arc.impl.LazyValue; - -public class WebSocketSessionContext extends CurrentManagedContext { - - public WebSocketSessionContext(CurrentContextFactory currentContextFactory) { - super(currentContextFactory.create(SessionScoped.class), ComputingCacheContextInstances::new, - newEvent(Initialized.Literal.SESSION, Any.Literal.INSTANCE), - newEvent(BeforeDestroyed.Literal.SESSION, Any.Literal.INSTANCE), - newEvent(Destroyed.Literal.SESSION, Any.Literal.INSTANCE)); - } - - @Override - public Class getScope() { - return SessionScoped.class; - } - - protected ContextNotActiveException notActive() { - return new ContextNotActiveException("Session context is not active"); - } - - private static Consumer newEvent(Annotation... qualifiers) { - LazyValue> event = new LazyValue<>(new Supplier>() { - @Override - public Event get() { - ArcContainer container = Arc.container(); - if (container.resolveObserverMethods(Object.class, qualifiers).isEmpty()) { - return null; - } - return container.beanManager().getEvent().select(qualifiers); - } - }); - return new Consumer() { - - @Override - public void accept(Object t) { - Event e = event.get(); - if (e != null) { - e.fire(t); - } - } - }; - } -} diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ManagedContext.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ManagedContext.java index 69e7d09cbc08c..2cfbf4913628f 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ManagedContext.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ManagedContext.java @@ -50,4 +50,10 @@ default void terminate() { destroy(); deactivate(); } + + /** + * + * @return a new initialized context state + */ + ContextState initializeState(); } diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CurrentManagedContext.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CurrentManagedContext.java index 7d5da765a94fc..266185912d5a1 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CurrentManagedContext.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CurrentManagedContext.java @@ -60,7 +60,7 @@ public ContextState activate(ContextState initialState) { traceActivate(initialState); } if (initialState == null) { - CurrentContextState state = initializeContextState(); + CurrentContextState state = initializeState(); currentContext.set(state); return state; } else { @@ -181,7 +181,8 @@ public void destroy(ContextState state) { } } - public CurrentContextState initializeContextState() { + @Override + public CurrentContextState initializeState() { CurrentContextState state = new CurrentContextState(contextInstances.get()); fireIfNotNull(initializedNotifier); return state; From be1fa4096d3b856f2080caee5c38439d87ace108 Mon Sep 17 00:00:00 2001 From: vkn Date: Tue, 17 Dec 2024 11:52:07 +0100 Subject: [PATCH 153/207] Avoid producing empty AdditionalIndexedClassesBuildItem Even if it doesn't complain right now, that's certainly something that could break later --- extensions/mongodb-client/deployment/pom.xml | 5 +++++ .../mongodb/deployment/MongoClientProcessor.java | 8 ++++---- .../deployment/MongoClientProcessorTest.java | 14 +++++++++++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/extensions/mongodb-client/deployment/pom.xml b/extensions/mongodb-client/deployment/pom.xml index e97646dc79fd8..36b104c57bf4b 100644 --- a/extensions/mongodb-client/deployment/pom.xml +++ b/extensions/mongodb-client/deployment/pom.xml @@ -91,6 +91,11 @@ awaitility test + + org.mockito + mockito-core + test + org.assertj assertj-core diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java index 2dd946cf874e2..68003f57ea613 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java @@ -126,18 +126,18 @@ AdditionalIndexedClassesBuildItem includeMongoCommandListener(MongoClientBuildTi } @BuildStep - AdditionalIndexedClassesBuildItem includeMongoCommandMetricListener( + void includeMongoCommandMetricListener( + BuildProducer additionalIndexedClasses, MongoClientBuildTimeConfig buildTimeConfig, Optional metricsCapability) { if (!buildTimeConfig.metricsEnabled) { - return new AdditionalIndexedClassesBuildItem(); + return; } boolean withMicrometer = metricsCapability.map(cap -> cap.metricsSupported(MetricsFactory.MICROMETER)) .orElse(false); if (withMicrometer) { - return new AdditionalIndexedClassesBuildItem(MicrometerCommandListener.class.getName()); + additionalIndexedClasses.produce(new AdditionalIndexedClassesBuildItem(MicrometerCommandListener.class.getName())); } - return new AdditionalIndexedClassesBuildItem(); } @BuildStep diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/deployment/MongoClientProcessorTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/deployment/MongoClientProcessorTest.java index 86dae2cdda77f..ad437dc2dc882 100644 --- a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/deployment/MongoClientProcessorTest.java +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/deployment/MongoClientProcessorTest.java @@ -1,12 +1,16 @@ package io.quarkus.mongodb.deployment; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; import java.util.Optional; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.ArgumentCaptor; +import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.builditem.AdditionalIndexedClassesBuildItem; import io.quarkus.deployment.metrics.MetricsCapabilityBuildItem; import io.quarkus.runtime.metrics.MetricsFactory; @@ -14,6 +18,7 @@ class MongoClientProcessorTest { private final MongoClientProcessor buildStep = new MongoClientProcessor(); + @SuppressWarnings("unchecked") @ParameterizedTest @CsvSource({ "true, true, true", // Metrics enabled and Micrometer supported @@ -25,13 +30,16 @@ void testIncludeMongoCommandMetricListener(boolean metricsEnabled, boolean micro MongoClientBuildTimeConfig config = config(metricsEnabled); Optional capability = capability(metricsEnabled, micrometerSupported); - AdditionalIndexedClassesBuildItem result = buildStep.includeMongoCommandMetricListener(config, capability); + BuildProducer buildProducer = mock(BuildProducer.class); + buildStep.includeMongoCommandMetricListener(buildProducer, config, capability); if (expectedResult) { - assertThat(result.getClassesToIndex()) + var captor = ArgumentCaptor.forClass(AdditionalIndexedClassesBuildItem.class); + verify(buildProducer, times(1)).produce(captor.capture()); + assertThat(captor.getAllValues().get(0).getClassesToIndex()) .containsExactly("io.quarkus.mongodb.metrics.MicrometerCommandListener"); } else { - assertThat(result.getClassesToIndex()).isEmpty(); + verify(buildProducer, never()).produce(any(AdditionalIndexedClassesBuildItem.class)); } } From 83e6e85786b3c0d8aad4007749587fd61f11cbd1 Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Tue, 17 Dec 2024 08:00:47 -0300 Subject: [PATCH 154/207] Convert jaxb to use @ConfigMapping --- extensions/jaxb/deployment/pom.xml | 3 --- .../io/quarkus/jaxb/deployment/JaxbProcessor.java | 6 +++--- extensions/jaxb/runtime/pom.xml | 3 --- .../java/io/quarkus/jaxb/runtime/JaxbConfig.java | 15 ++++++++------- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/extensions/jaxb/deployment/pom.xml b/extensions/jaxb/deployment/pom.xml index 15589c3c49e5b..53d532adc436b 100644 --- a/extensions/jaxb/deployment/pom.xml +++ b/extensions/jaxb/deployment/pom.xml @@ -56,9 +56,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java b/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java index b08e753e7b3fa..aaf0c32bc958f 100644 --- a/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java +++ b/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/JaxbProcessor.java @@ -342,8 +342,8 @@ FilteredJaxbClassesToBeBoundBuildItem filterBoundClasses( .forEach(builder::classNames); // remove classes that have been excluded by users - if (config.excludeClasses.isPresent()) { - builder.classNameExcludes(config.excludeClasses.get()); + if (config.excludeClasses().isPresent()) { + builder.classNameExcludes(config.excludeClasses().get()); } return builder.build(); } @@ -362,7 +362,7 @@ void bindClassesToJaxbContext( .resolveBeans(Type.create(DotName.createSimple(JAXBContext.class), org.jboss.jandex.Type.Kind.CLASS)); if (!beans.isEmpty()) { jaxbContextConfig.addClassesToBeBound(filteredClassesToBeBound.getClasses()); - if (config.validateJaxbContext) { + if (config.validateJaxbContext()) { validateJaxbContext(filteredClassesToBeBound, beanResolver, beans); } } diff --git a/extensions/jaxb/runtime/pom.xml b/extensions/jaxb/runtime/pom.xml index 3c6144fcbb637..17ad6ef0aede2 100644 --- a/extensions/jaxb/runtime/pom.xml +++ b/extensions/jaxb/runtime/pom.xml @@ -71,9 +71,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbConfig.java b/extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbConfig.java index 10aee70162135..dc456f329460b 100644 --- a/extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbConfig.java +++ b/extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbConfig.java @@ -3,24 +3,25 @@ import java.util.List; import java.util.Optional; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; -@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED, name = "jaxb") -public class JaxbConfig { +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +@ConfigMapping(prefix = "quarkus.jaxb") +public interface JaxbConfig { /** * If enabled, it will validate the default JAXB context at build time. */ - @ConfigItem(defaultValue = "false") - public boolean validateJaxbContext; + @WithDefault("false") + boolean validateJaxbContext(); /** * Exclude classes to automatically be bound to the default JAXB context. * Values with suffix {@code .*}, i.e. {@code org.acme.*}, are considered packages and exclude all classes that are members * of these packages */ - @ConfigItem - public Optional> excludeClasses; + Optional> excludeClasses(); } From 265fa38207f1ff5152860766331e6a18854b876c Mon Sep 17 00:00:00 2001 From: Ales Justin Date: Tue, 17 Dec 2024 12:27:38 +0100 Subject: [PATCH 155/207] Rename package from deployment to codegen --- .../io/quarkus/grpc/{deployment => codegen}/GrpcCodeGen.java | 2 +- .../grpc/{deployment => codegen}/GrpcPostProcessing.java | 2 +- .../META-INF/services/io.quarkus.deployment.CodeGenProvider | 2 +- extensions/grpc/stubs/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename extensions/grpc/codegen/src/main/java/io/quarkus/grpc/{deployment => codegen}/GrpcCodeGen.java (99%) rename extensions/grpc/codegen/src/main/java/io/quarkus/grpc/{deployment => codegen}/GrpcPostProcessing.java (99%) diff --git a/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcCodeGen.java b/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/codegen/GrpcCodeGen.java similarity index 99% rename from extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcCodeGen.java rename to extensions/grpc/codegen/src/main/java/io/quarkus/grpc/codegen/GrpcCodeGen.java index d4e67796e2420..f17358b1bf27c 100644 --- a/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcCodeGen.java +++ b/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/codegen/GrpcCodeGen.java @@ -1,4 +1,4 @@ -package io.quarkus.grpc.deployment; +package io.quarkus.grpc.codegen; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; diff --git a/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcPostProcessing.java b/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/codegen/GrpcPostProcessing.java similarity index 99% rename from extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcPostProcessing.java rename to extensions/grpc/codegen/src/main/java/io/quarkus/grpc/codegen/GrpcPostProcessing.java index abe19f5de0934..72406fd7c1565 100644 --- a/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcPostProcessing.java +++ b/extensions/grpc/codegen/src/main/java/io/quarkus/grpc/codegen/GrpcPostProcessing.java @@ -1,4 +1,4 @@ -package io.quarkus.grpc.deployment; +package io.quarkus.grpc.codegen; import java.io.File; import java.nio.file.Path; diff --git a/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider b/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider index 79d063f5e2df5..a2c6cd0c7d022 100644 --- a/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider +++ b/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider @@ -1 +1 @@ -io.quarkus.grpc.deployment.GrpcCodeGen \ No newline at end of file +io.quarkus.grpc.codegen.GrpcCodeGen \ No newline at end of file diff --git a/extensions/grpc/stubs/pom.xml b/extensions/grpc/stubs/pom.xml index d3a387d227220..83fd66307ca75 100644 --- a/extensions/grpc/stubs/pom.xml +++ b/extensions/grpc/stubs/pom.xml @@ -127,7 +127,7 @@ ${project.build.directory}/generated-sources/protobuf/grpc-java - io.quarkus.grpc.deployment.GrpcPostProcessing + io.quarkus.grpc.codegen.GrpcPostProcessing From 732833d6b7f3b66fcb5965d999c07d7ea7a3ade7 Mon Sep 17 00:00:00 2001 From: Maciej Lisowski Date: Tue, 17 Dec 2024 14:36:29 +0100 Subject: [PATCH 156/207] Docs: Correct word form in Native Applications Tips Signed-off-by: Maciej Lisowski --- docs/src/main/asciidoc/writing-native-applications-tips.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/writing-native-applications-tips.adoc b/docs/src/main/asciidoc/writing-native-applications-tips.adoc index 32a6917cc22e0..3a75185d2411b 100644 --- a/docs/src/main/asciidoc/writing-native-applications-tips.adoc +++ b/docs/src/main/asciidoc/writing-native-applications-tips.adoc @@ -197,7 +197,7 @@ public class MyReflectionConfiguration { } ---- -Note: By default the `@RegisterForReflection` annotation will also registered any potential nested classes for reflection. If you want to avoid this behavior, you can set the `ignoreNested` attribute to `true`. +Note: By default the `@RegisterForReflection` annotation will also register any potential nested classes for reflection. If you want to avoid this behavior, you can set the `ignoreNested` attribute to `true`. ==== Using a configuration file From 09706b9a85799b73d9c8cf16232702e4c5d01f6b Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Tue, 17 Dec 2024 12:53:52 +0100 Subject: [PATCH 157/207] ArC: introduce the ActivateSessionContext interceptor binding - it's only available in tests - fixes #45146 Co-authored-by: Matej Novotny --- .../asciidoc/getting-started-testing.adoc | 2 + .../quarkus/arc/deployment/ArcProcessor.java | 24 ------- .../quarkus/arc/deployment/ArcTestSteps.java | 71 +++++++++++++++++++ .../arc/test/context/session/Client.java | 32 +++++++++ .../context/session/SessionContextTest.java | 49 +++++++++++++ .../arc/test/context/session/SimpleBean.java | 30 ++++++++ .../ActivateSessionContextInterceptor.java | 30 ++++++++ .../quarkus/test/ActivateSessionContext.java | 30 ++++++++ 8 files changed, 244 insertions(+), 24 deletions(-) create mode 100644 extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcTestSteps.java create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/Client.java create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SessionContextTest.java create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SimpleBean.java create mode 100644 extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/test/ActivateSessionContextInterceptor.java create mode 100644 test-framework/common/src/main/java/io/quarkus/test/ActivateSessionContext.java diff --git a/docs/src/main/asciidoc/getting-started-testing.adoc b/docs/src/main/asciidoc/getting-started-testing.adoc index e2c0fac89ccbe..35c28cc97071a 100644 --- a/docs/src/main/asciidoc/getting-started-testing.adoc +++ b/docs/src/main/asciidoc/getting-started-testing.adoc @@ -369,6 +369,8 @@ public class GreetingServiceTest { ---- <1> The `GreetingService` bean will be injected into the test +TIP: If you want to inject/test a `@SessionScoped` bean then it's very likely that the session context is not active and you would receive the `ContextNotActiveException` when a method of the injected bean is invoked. However, it's possible to use the `@io.quarkus.test.ActivateSessionContext` interceptor binding to activate the session context for a specific business method. Please read the javadoc for futher limitations. + == Applying Interceptors to Tests As mentioned above Quarkus tests are actually full CDI beans, and as such you can apply CDI interceptors as you would diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java index ff175046a6960..a89b988cb9184 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java @@ -68,16 +68,13 @@ import io.quarkus.arc.runtime.LoggerProducer; import io.quarkus.arc.runtime.appcds.AppCDSRecorder; import io.quarkus.arc.runtime.context.ArcContextProvider; -import io.quarkus.arc.runtime.test.PreloadedTestApplicationClassPredicate; import io.quarkus.bootstrap.BootstrapDebug; import io.quarkus.deployment.Capabilities; import io.quarkus.deployment.Capability; import io.quarkus.deployment.Feature; -import io.quarkus.deployment.IsTest; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.Consume; -import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Produce; import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.AdditionalApplicationArchiveMarkerBuildItem; @@ -653,27 +650,6 @@ public void signalBeanContainerReady(AppCDSRecorder recorder, PreBeanContainerBu beanContainerProducer.produce(new BeanContainerBuildItem(bi.getValue())); } - @BuildStep(onlyIf = IsTest.class) - public AdditionalBeanBuildItem testApplicationClassPredicateBean() { - // We need to register the bean implementation for TestApplicationClassPredicate - // TestApplicationClassPredicate is used programmatically in the ArC recorder when StartupEvent is fired - return AdditionalBeanBuildItem.unremovableOf(PreloadedTestApplicationClassPredicate.class); - } - - @BuildStep(onlyIf = IsTest.class) - @Record(ExecutionTime.STATIC_INIT) - void initTestApplicationClassPredicateBean(ArcRecorder recorder, BeanContainerBuildItem beanContainer, - BeanDiscoveryFinishedBuildItem beanDiscoveryFinished, - CompletedApplicationClassPredicateBuildItem predicate) { - Set applicationBeanClasses = new HashSet<>(); - for (BeanInfo bean : beanDiscoveryFinished.beanStream().classBeans()) { - if (predicate.test(bean.getBeanClass())) { - applicationBeanClasses.add(bean.getBeanClass().toString()); - } - } - recorder.initTestApplicationClassPredicate(applicationBeanClasses); - } - @BuildStep List marker() { return Arrays.asList(new AdditionalApplicationArchiveMarkerBuildItem("META-INF/beans.xml"), diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcTestSteps.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcTestSteps.java new file mode 100644 index 0000000000000..66c86e0b055e5 --- /dev/null +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcTestSteps.java @@ -0,0 +1,71 @@ +package io.quarkus.arc.deployment; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Predicate; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTransformation; +import org.jboss.jandex.DotName; + +import io.quarkus.arc.processor.BeanInfo; +import io.quarkus.arc.runtime.ArcRecorder; +import io.quarkus.arc.runtime.test.ActivateSessionContextInterceptor; +import io.quarkus.arc.runtime.test.PreloadedTestApplicationClassPredicate; +import io.quarkus.deployment.IsTest; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.BuildSteps; +import io.quarkus.deployment.annotations.ExecutionTime; +import io.quarkus.deployment.annotations.Record; +import io.quarkus.deployment.builditem.ApplicationClassPredicateBuildItem; + +@BuildSteps(onlyIf = IsTest.class) +public class ArcTestSteps { + + @BuildStep + public void additionalBeans(BuildProducer additionalBeans) { + // We need to register the bean implementation for TestApplicationClassPredicate + // TestApplicationClassPredicate is used programmatically in the ArC recorder when StartupEvent is fired + additionalBeans.produce(AdditionalBeanBuildItem.unremovableOf(PreloadedTestApplicationClassPredicate.class)); + // In tests, register the ActivateSessionContextInterceptor and ActivateSessionContext interceptor binding + additionalBeans.produce(new AdditionalBeanBuildItem(ActivateSessionContextInterceptor.class)); + additionalBeans.produce(new AdditionalBeanBuildItem("io.quarkus.test.ActivateSessionContext")); + } + + @BuildStep + AnnotationsTransformerBuildItem addInterceptorBinding() { + return new AnnotationsTransformerBuildItem( + AnnotationTransformation.forClasses().whenClass(ActivateSessionContextInterceptor.class).transform(tc -> tc.add( + AnnotationInstance.builder(DotName.createSimple("io.quarkus.test.ActivateSessionContext")).build()))); + } + + // For some reason the annotation literal generated for io.quarkus.test.ActivateSessionContext lives in app class loader. + // This predicates ensures that the generated bean is considered an app class too. + // As a consequence, the type and all methods of ActivateSessionContextInterceptor must be public. + @BuildStep + ApplicationClassPredicateBuildItem appClassPredicate() { + return new ApplicationClassPredicateBuildItem(new Predicate() { + + @Override + public boolean test(String name) { + return name.startsWith(ActivateSessionContextInterceptor.class.getName()); + } + }); + } + + @BuildStep + @Record(ExecutionTime.STATIC_INIT) + void initTestApplicationClassPredicateBean(ArcRecorder recorder, BeanContainerBuildItem beanContainer, + BeanDiscoveryFinishedBuildItem beanDiscoveryFinished, + CompletedApplicationClassPredicateBuildItem predicate) { + Set applicationBeanClasses = new HashSet<>(); + for (BeanInfo bean : beanDiscoveryFinished.beanStream().classBeans()) { + if (predicate.test(bean.getBeanClass())) { + applicationBeanClasses.add(bean.getBeanClass().toString()); + } + } + recorder.initTestApplicationClassPredicate(applicationBeanClasses); + } + +} diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/Client.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/Client.java new file mode 100644 index 0000000000000..2be51f601a58f --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/Client.java @@ -0,0 +1,32 @@ +package io.quarkus.arc.test.context.session; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.context.SessionScoped; +import jakarta.inject.Inject; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ClientProxy; +import io.quarkus.test.ActivateSessionContext; + +@Dependent +class Client { + + @Inject + SimpleBean bean; + + @ActivateSessionContext + public String ping() { + assertTrue(Arc.container().sessionContext().isActive()); + if (bean instanceof ClientProxy proxy) { + assertEquals(SessionScoped.class, proxy.arc_bean().getScope()); + } else { + fail("Not a client proxy"); + } + return bean.ping(); + } + +} diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SessionContextTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SessionContextTest.java new file mode 100644 index 0000000000000..b45fbfa2979af --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SessionContextTest.java @@ -0,0 +1,49 @@ +package io.quarkus.arc.test.context.session; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ManagedContext; +import io.quarkus.test.QuarkusUnitTest; + +public class SessionContextTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot(root -> root + .addClasses(SimpleBean.class, Client.class)); + + @Inject + Client client; + + @Inject + SimpleBean simpleBean; + + @Test + public void testContexts() { + assertFalse(Arc.container().sessionContext().isActive()); + assertNotNull(client.ping()); + assertTrue(SimpleBean.DESTROYED.get()); + assertFalse(Arc.container().sessionContext().isActive()); + SimpleBean.DESTROYED.set(false); + + ManagedContext sessionContext = Arc.container().sessionContext(); + try { + sessionContext.activate(); + String id = simpleBean.ping(); + assertEquals(id, client.ping()); + assertFalse(SimpleBean.DESTROYED.get()); + } finally { + sessionContext.terminate(); + } + assertTrue(SimpleBean.DESTROYED.get()); + } +} diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SimpleBean.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SimpleBean.java new file mode 100644 index 0000000000000..77bb8f5f81483 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/session/SimpleBean.java @@ -0,0 +1,30 @@ +package io.quarkus.arc.test.context.session; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.context.SessionScoped; + +@SessionScoped +class SimpleBean { + + static final AtomicBoolean DESTROYED = new AtomicBoolean(); + + private String id; + + @PostConstruct + void init() { + id = UUID.randomUUID().toString(); + } + + public String ping() { + return id; + } + + @PreDestroy + void destroy() { + DESTROYED.set(true); + } +} \ No newline at end of file diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/test/ActivateSessionContextInterceptor.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/test/ActivateSessionContextInterceptor.java new file mode 100644 index 0000000000000..ea5452e2babc7 --- /dev/null +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/test/ActivateSessionContextInterceptor.java @@ -0,0 +1,30 @@ +package io.quarkus.arc.runtime.test; + +import jakarta.annotation.Priority; +import jakarta.interceptor.AroundInvoke; +import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InvocationContext; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ManagedContext; + +// The @ActivateSessionContext interceptor binding is added by the extension +@Interceptor +@Priority(Interceptor.Priority.PLATFORM_BEFORE + 100) +public class ActivateSessionContextInterceptor { + + @AroundInvoke + public Object aroundInvoke(InvocationContext ctx) throws Exception { + ManagedContext sessionContext = Arc.container().sessionContext(); + if (sessionContext.isActive()) { + return ctx.proceed(); + } + try { + sessionContext.activate(); + return ctx.proceed(); + } finally { + sessionContext.terminate(); + } + } + +} diff --git a/test-framework/common/src/main/java/io/quarkus/test/ActivateSessionContext.java b/test-framework/common/src/main/java/io/quarkus/test/ActivateSessionContext.java new file mode 100644 index 0000000000000..3acd8b00525af --- /dev/null +++ b/test-framework/common/src/main/java/io/quarkus/test/ActivateSessionContext.java @@ -0,0 +1,30 @@ +package io.quarkus.test; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.concurrent.CompletionStage; + +import jakarta.interceptor.InterceptorBinding; + +/** + * Activates the session context before the intercepted method is called, and terminates the context when the method invocation + * completes (regardless of any exceptions being thrown). + *

    + * If the context is already active, it's a noop - the context is neither activated nor deactivated. + *

    + * Keep in mind that if the method returns an asynchronous type (such as {@link CompletionStage} then the session context is + * still terminated when the invocation completes and not at the time the asynchronous type is completed. Also note that session + * context is not propagated by MicroProfile Context Propagation. + *

    + * This interceptor binding is only available in tests. + */ +@InterceptorBinding +@Target({ METHOD, TYPE }) +@Retention(RUNTIME) +public @interface ActivateSessionContext { + +} From d0bb1d12117b55a9ad94fc1d99992483bd0f8a54 Mon Sep 17 00:00:00 2001 From: Yoshikazu Nojima Date: Sun, 15 Dec 2024 00:02:28 +0900 Subject: [PATCH 158/207] Change from POST to GET method Change register-options-challenge endpoint and login-options-challenge endpoint from POST to GET Update webauthn.js regarding change from POST to GET Update security-webauthn.adoc --- docs/src/main/asciidoc/security-webauthn.adoc | 31 ++++++------------- .../webauthn/test/WebAuthnOriginsTest.java | 8 ++--- .../security/webauthn/test/WebAuthnTest.java | 29 +++++++---------- .../security/webauthn/WebAuthnController.java | 12 ++----- .../security/webauthn/WebAuthnRecorder.java | 4 +-- .../runtime/src/main/resources/webauthn.js | 18 +++++------ .../webauthn/WebAuthnEndpointHelper.java | 18 +++++------ 7 files changed, 45 insertions(+), 75 deletions(-) diff --git a/docs/src/main/asciidoc/security-webauthn.adoc b/docs/src/main/asciidoc/security-webauthn.adoc index 09ee4ce6b24e2..d3cbf05faa85c 100644 --- a/docs/src/main/asciidoc/security-webauthn.adoc +++ b/docs/src/main/asciidoc/security-webauthn.adoc @@ -621,21 +621,14 @@ The Quarkus WebAuthn extension comes out of the box with these REST endpoints pr === Obtain a registration challenge -`POST /q/webauthn/register-options-challenge`: Set up and obtain a registration challenge +`GET /q/webauthn/register-options-challenge?name=&displayName=`: Set up and obtain a registration challenge -This causes a cookie to be set for the challenge, it will be used by the registration step later. +Query parameters: -[source,json] -.Request ----- -{ - "name": "userName", <1> - "displayName": "Mr Nice Guy" <2> -} ----- +- `name` is a username. Required. +- `displayName` is a human-palatable name for the user account. Optional. -<1> Required -<2> Optional +This causes a cookie to be set for the challenge, it will be used by the registration step later. [source,json] .Response @@ -700,19 +693,13 @@ This returns a 204 with no body. === Obtain a login challenge -`POST /q/webauthn/login-options-challenge`: Set up and obtain a login challenge +`GET /q/webauthn/login-options-challenge?name=`: Set up and obtain a login challenge -This causes a cookie to be set for the challenge, it will be used by the login step later. +Query parameters: -[source,json] -.Request ----- -{ - "name": "userName" <1> -} ----- +- `name` is a username. Optional in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys). -<1> The name is optional, in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys) +This causes a cookie to be set for the challenge, it will be used by the login step later. [source,json] .Response diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java index 4acb80be4f140..30632fa6cefd2 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java @@ -9,7 +9,6 @@ import io.quarkus.test.security.webauthn.WebAuthnTestUserProvider; import io.restassured.RestAssured; import io.restassured.http.ContentType; -import io.vertx.core.json.JsonObject; public class WebAuthnOriginsTest { @@ -24,10 +23,9 @@ public class WebAuthnOriginsTest { public void testLoginRpFromFirstOrigin() { RestAssured .given() - .body(new JsonObject() - .put("name", "foo").encode()) - .contentType(ContentType.JSON) - .post("/q/webauthn/register-options-challenge") + .contentType(ContentType.URLENC) + .queryParam("name", "foo") + .get("/q/webauthn/register-options-challenge") .then() .log().all() .statusCode(200) diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java index f671a33f0cd1a..36dcb23982352 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java @@ -31,10 +31,9 @@ public void testJavaScriptFile() { public void testLoginRpFromFirstOrigin() { RestAssured .given() - .body(new JsonObject() - .put("name", "foo").encode()) .contentType(ContentType.JSON) - .post("/q/webauthn/register-options-challenge") + .queryParam("name", "foo") + .get("/q/webauthn/register-options-challenge") .then() .statusCode(200) .contentType(ContentType.JSON) @@ -48,19 +47,17 @@ public void testRegisterChallengeIsEqualAcrossCalls() { String challenge = RestAssured .given() .filter(cookieFilter) - .body(new JsonObject() - .put("name", "foo").encode()) - .contentType(ContentType.JSON) - .post("/q/webauthn/register-options-challenge") + .contentType(ContentType.URLENC) + .queryParam("name", "foo") + .get("/q/webauthn/register-options-challenge") .jsonPath().get("challenge"); RestAssured .given() .filter(cookieFilter) - .body(new JsonObject() - .put("name", "foo").encode()) - .contentType(ContentType.JSON) - .post("/q/webauthn/register-options-challenge") + .contentType(ContentType.URLENC) + .queryParam("name", "foo") + .get("/q/webauthn/register-options-challenge") .then() .statusCode(200) .contentType(ContentType.JSON) @@ -74,17 +71,15 @@ public void testLoginChallengeIsEqualAcrossCalls() { String challenge = RestAssured .given() .filter(cookieFilter) - .body(new JsonObject().encode()) - .contentType(ContentType.JSON) - .post("/q/webauthn/login-options-challenge") + .contentType(ContentType.URLENC) + .get("/q/webauthn/login-options-challenge") .jsonPath().get("challenge"); RestAssured .given() .filter(cookieFilter) - .body(new JsonObject().encode()) - .contentType(ContentType.JSON) - .post("/q/webauthn/login-options-challenge") + .contentType(ContentType.URLENC) + .get("/q/webauthn/login-options-challenge") .then() .statusCode(200) .contentType(ContentType.JSON) diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java index bbe16c5d3282c..96682d37cda30 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java @@ -47,11 +47,8 @@ public void wellKnown(RoutingContext ctx) { */ public void registerOptionsChallenge(RoutingContext ctx) { try { - // might throw runtime exception if there's no json or is bad formed - final JsonObject webauthnRegister = ctx.getBodyAsJson(); - - String name = webauthnRegister.getString("name"); - String displayName = webauthnRegister.getString("displayName"); + String name = ctx.queryParams().get("name"); + String displayName = ctx.queryParams().get("displayName"); withContext(() -> security.getRegisterChallenge(name, displayName, ctx)) .map(challenge -> security.toJsonString(challenge)) .subscribe().with(challenge -> ok(ctx, challenge), ctx::fail); @@ -77,10 +74,7 @@ private Uni withContext(Supplier> uni) { */ public void loginOptionsChallenge(RoutingContext ctx) { try { - // might throw runtime exception if there's no json or is bad formed - final JsonObject webauthnLogin = ctx.getBodyAsJson(); - - String name = webauthnLogin.getString("name"); + String name = ctx.queryParams().get("name"); withContext(() -> security.getLoginChallenge(name, ctx)) .map(challenge -> security.toJsonString(challenge)) .subscribe().with(challenge -> ok(ctx, challenge), ctx::fail); diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java index f23f509f74dd0..5fb56a234798e 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java @@ -38,9 +38,9 @@ public void setupRoutes(BeanContainer beanContainer, RuntimeValue router BodyHandler bodyHandler = BodyHandler.create(); // FIXME: paths configurable // prefix is the non-application root path, ends with a slash: defaults to /q/ - router.post(prefix + "webauthn/login-options-challenge").handler(bodyHandler) + router.get(prefix + "webauthn/login-options-challenge").handler(bodyHandler) .handler(controller::loginOptionsChallenge); - router.post(prefix + "webauthn/register-options-challenge").handler(bodyHandler) + router.get(prefix + "webauthn/register-options-challenge").handler(bodyHandler) .handler(controller::registerOptionsChallenge); if (config.getValue().enableLoginEndpoint().orElse(false)) { router.post(prefix + "webauthn/login").handler(bodyHandler).handler(controller::login); diff --git a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js index cc91864350831..d798424ede9f5 100644 --- a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js +++ b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js @@ -120,13 +120,12 @@ if (!self.registerOptionsChallengePath) { return Promise.reject('Register challenge path missing form the initial configuration!'); } - return self.fetchWithCsrf(self.registerOptionsChallengePath, { - method: 'POST', + return self.fetchWithCsrf(self.registerOptionsChallengePath + "?" + new URLSearchParams({name: user.name, displayName: user.displayName}).toString(), { + method: 'GET', headers: { 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(user || {}) + 'Content-Type': 'application/x-www-form-urlencoded' + } }) .then(res => { if (res.status === 200) { @@ -215,13 +214,12 @@ if (!self.loginOptionsChallengePath) { return Promise.reject('Login challenge path missing from the initial configuration!'); } - return self.fetchWithCsrf(self.loginOptionsChallengePath, { - method: 'POST', + return self.fetchWithCsrf(self.loginOptionsChallengePath + "?" + new URLSearchParams({name: user.name}).toString(), { + method: 'GET', headers: { 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(user || {}) + 'Content-Type': 'application/x-www-form-urlencoded' + } }) .then(res => { if (res.status === 200) { diff --git a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java index b33d01d876ec9..fb78f49c2816d 100644 --- a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java +++ b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java @@ -15,14 +15,13 @@ public class WebAuthnEndpointHelper { public static String obtainRegistrationChallenge(String userName, Filter cookieFilter) { - JsonObject registerJson = new JsonObject() - .put("name", userName); ExtractableResponse response = RestAssured - .given().body(registerJson.encode()) - .contentType(ContentType.JSON) + .given() + .contentType(ContentType.URLENC) .filter(cookieFilter) .log().ifValidationFails() - .post("/q/webauthn/register-options-challenge") + .queryParam("name", userName) + .get("/q/webauthn/register-options-challenge") .then() .log().ifValidationFails() .statusCode(200) @@ -65,14 +64,13 @@ public static void invokeRegistration(String username, JsonObject registration, } public static String obtainLoginChallenge(String userName, Filter cookieFilter) { - JsonObject loginJson = new JsonObject() - .put("name", userName); ExtractableResponse response = RestAssured - .given().body(loginJson.encode()) - .contentType(ContentType.JSON) + .given() + .contentType(ContentType.URLENC) .filter(cookieFilter) .log().ifValidationFails() - .post("/q/webauthn/login-options-challenge") + .queryParam("name", userName) + .get("/q/webauthn/login-options-challenge") .then() .log().ifValidationFails() .statusCode(200) From 1b6d48c899601051ca61f2394396bb100fc856e6 Mon Sep 17 00:00:00 2001 From: Yoshikazu Nojima Date: Sun, 15 Dec 2024 00:58:05 +0900 Subject: [PATCH 159/207] Keep userName for all endpoints for consistency --- docs/src/main/asciidoc/security-webauthn.adoc | 14 +++++++++----- .../webauthn/test/WebAuthnOriginsTest.java | 2 +- .../security/webauthn/test/WebAuthnTest.java | 7 +++---- .../security/webauthn/WebAuthnController.java | 12 ++++++------ .../security/webauthn/WebAuthnEndpointHelper.java | 2 +- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/docs/src/main/asciidoc/security-webauthn.adoc b/docs/src/main/asciidoc/security-webauthn.adoc index d3cbf05faa85c..7016ddee3e759 100644 --- a/docs/src/main/asciidoc/security-webauthn.adoc +++ b/docs/src/main/asciidoc/security-webauthn.adoc @@ -621,11 +621,11 @@ The Quarkus WebAuthn extension comes out of the box with these REST endpoints pr === Obtain a registration challenge -`GET /q/webauthn/register-options-challenge?name=&displayName=`: Set up and obtain a registration challenge +`GET /q/webauthn/register-options-challenge?userName=&displayName=`: Set up and obtain a registration challenge Query parameters: -- `name` is a username. Required. +- `userName` is a username. Required. - `displayName` is a human-palatable name for the user account. Optional. This causes a cookie to be set for the challenge, it will be used by the registration step later. @@ -667,7 +667,11 @@ This causes a cookie to be set for the challenge, it will be used by the registr === Trigger a registration -`POST /q/webauthn/register`: Trigger a registration +`POST /q/webauthn/register?userName=`: Trigger a registration + +Query parameters: + +- `userName` is a username. Required. This uses the challenge cookie set by the registration challenge and clears it. It also uses your link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`] to store the new credentials, and sets up @@ -693,11 +697,11 @@ This returns a 204 with no body. === Obtain a login challenge -`GET /q/webauthn/login-options-challenge?name=`: Set up and obtain a login challenge +`GET /q/webauthn/login-options-challenge?userName=`: Set up and obtain a login challenge Query parameters: -- `name` is a username. Optional in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys). +- `userName` is a username. Optional in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys). This causes a cookie to be set for the challenge, it will be used by the login step later. diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java index 30632fa6cefd2..9c8a3e65d99d0 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java @@ -24,7 +24,7 @@ public void testLoginRpFromFirstOrigin() { RestAssured .given() .contentType(ContentType.URLENC) - .queryParam("name", "foo") + .queryParam("userName", "foo") .get("/q/webauthn/register-options-challenge") .then() .log().all() diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java index 36dcb23982352..6b90fa05a002a 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java @@ -10,7 +10,6 @@ import io.restassured.RestAssured; import io.restassured.filter.cookie.CookieFilter; import io.restassured.http.ContentType; -import io.vertx.core.json.JsonObject; public class WebAuthnTest { @@ -32,7 +31,7 @@ public void testLoginRpFromFirstOrigin() { RestAssured .given() .contentType(ContentType.JSON) - .queryParam("name", "foo") + .queryParam("userName", "foo") .get("/q/webauthn/register-options-challenge") .then() .statusCode(200) @@ -48,7 +47,7 @@ public void testRegisterChallengeIsEqualAcrossCalls() { .given() .filter(cookieFilter) .contentType(ContentType.URLENC) - .queryParam("name", "foo") + .queryParam("userName", "foo") .get("/q/webauthn/register-options-challenge") .jsonPath().get("challenge"); @@ -56,7 +55,7 @@ public void testRegisterChallengeIsEqualAcrossCalls() { .given() .filter(cookieFilter) .contentType(ContentType.URLENC) - .queryParam("name", "foo") + .queryParam("userName", "foo") .get("/q/webauthn/register-options-challenge") .then() .statusCode(200) diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java index 96682d37cda30..32bce81fef053 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java @@ -47,9 +47,9 @@ public void wellKnown(RoutingContext ctx) { */ public void registerOptionsChallenge(RoutingContext ctx) { try { - String name = ctx.queryParams().get("name"); + String userName = ctx.queryParams().get("userName"); String displayName = ctx.queryParams().get("displayName"); - withContext(() -> security.getRegisterChallenge(name, displayName, ctx)) + withContext(() -> security.getRegisterChallenge(userName, displayName, ctx)) .map(challenge -> security.toJsonString(challenge)) .subscribe().with(challenge -> ok(ctx, challenge), ctx::fail); @@ -74,8 +74,8 @@ private Uni withContext(Supplier> uni) { */ public void loginOptionsChallenge(RoutingContext ctx) { try { - String name = ctx.queryParams().get("name"); - withContext(() -> security.getLoginChallenge(name, ctx)) + String userName = ctx.queryParams().get("userName"); + withContext(() -> security.getLoginChallenge(userName, ctx)) .map(challenge -> security.toJsonString(challenge)) .subscribe().with(challenge -> ok(ctx, challenge), ctx::fail); @@ -118,11 +118,11 @@ public void login(RoutingContext ctx) { */ public void register(RoutingContext ctx) { try { - final String username = ctx.queryParams().get("username"); + final String userName = ctx.queryParams().get("userName"); // might throw runtime exception if there's no json or is bad formed final JsonObject webauthnResp = ctx.getBodyAsJson(); - withContext(() -> security.register(username, webauthnResp, ctx)) + withContext(() -> security.register(userName, webauthnResp, ctx)) .onItem().call(record -> security.storage().create(record)) .subscribe().with(record -> { security.rememberUser(record.getUserName(), ctx); diff --git a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java index fb78f49c2816d..8146e33012c2a 100644 --- a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java +++ b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java @@ -20,7 +20,7 @@ public static String obtainRegistrationChallenge(String userName, Filter cookieF .contentType(ContentType.URLENC) .filter(cookieFilter) .log().ifValidationFails() - .queryParam("name", userName) + .queryParam("userName", userName) .get("/q/webauthn/register-options-challenge") .then() .log().ifValidationFails() From bf6139574d062961fa58b2e7b99d0673bf855f68 Mon Sep 17 00:00:00 2001 From: Yoshikazu Nojima Date: Tue, 17 Dec 2024 21:47:18 +0900 Subject: [PATCH 160/207] Make user parameter of loginCLientSteps optional Correct query parameter name from name to userName --- .../runtime/src/main/resources/webauthn.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js index d798424ede9f5..485d060f4cf02 100644 --- a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js +++ b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js @@ -120,7 +120,7 @@ if (!self.registerOptionsChallengePath) { return Promise.reject('Register challenge path missing form the initial configuration!'); } - return self.fetchWithCsrf(self.registerOptionsChallengePath + "?" + new URLSearchParams({name: user.name, displayName: user.displayName}).toString(), { + return self.fetchWithCsrf(self.registerOptionsChallengePath + "?" + new URLSearchParams({userName: user.name, displayName: user.displayName}).toString(), { method: 'GET', headers: { 'Accept': 'application/json', @@ -168,7 +168,7 @@ } return self.registerClientSteps(user) .then(body => { - return self.fetchWithCsrf(self.registerPath + "?" + new URLSearchParams({username: user.name}).toString(), { + return self.fetchWithCsrf(self.registerPath + "?" + new URLSearchParams({userName: user.name}).toString(), { method: 'POST', headers: { 'Accept': 'application/json', @@ -214,7 +214,11 @@ if (!self.loginOptionsChallengePath) { return Promise.reject('Login challenge path missing from the initial configuration!'); } - return self.fetchWithCsrf(self.loginOptionsChallengePath + "?" + new URLSearchParams({name: user.name}).toString(), { + let path = self.loginOptionsChallengePath + if (user != null && user.name != null) { + path = path + "?" + new URLSearchParams({userName: user.name}).toString() + } + return self.fetchWithCsrf(path, { method: 'GET', headers: { 'Accept': 'application/json', From fce5db47fd245a829f6c5b08f1eb57e95ff990fd Mon Sep 17 00:00:00 2001 From: Yoshikazu Nojima Date: Tue, 17 Dec 2024 22:28:18 +0900 Subject: [PATCH 161/207] Rename userName variable to username --- docs/src/main/asciidoc/security-webauthn.adoc | 106 +++++++++--------- .../webauthn/test/ManualResource.java | 4 +- .../security/webauthn/test/TestResource.java | 2 +- .../test/WebAuthnAndBasicAuthnTest.java | 6 +- .../webauthn/test/WebAuthnAutomaticTest.java | 14 +-- .../WebAuthnBlockingTestUserProvider.java | 4 +- .../test/WebAuthnManualCustomCookiesTest.java | 10 +- .../webauthn/test/WebAuthnManualTest.java | 18 +-- .../test/WebAuthnManualTestUserProvider.java | 4 +- .../WebAuthnNonBlockingTestUserProvider.java | 4 +- .../webauthn/test/WebAuthnOriginsTest.java | 2 +- .../security/webauthn/test/WebAuthnTest.java | 6 +- .../WebAuthnAuthenticatorStorage.java | 4 +- .../security/webauthn/WebAuthnController.java | 16 +-- .../webauthn/WebAuthnCredentialRecord.java | 20 ++-- .../security/webauthn/WebAuthnSecurity.java | 34 +++--- .../webauthn/WebAuthnUserProvider.java | 15 ++- .../runtime/src/main/resources/webauthn.js | 12 +- .../it/security/webauthn/LoginResource.java | 20 ++-- .../it/security/webauthn/MyWebAuthnSetup.java | 14 +-- .../io/quarkus/it/security/webauthn/User.java | 6 +- .../security/webauthn/WebAuthnCredential.java | 6 +- .../resources/META-INF/resources/index.html | 16 +-- .../webauthn/test/WebAuthnResourceTest.java | 22 ++-- ...WebAuthnVirtualThreadTestUserProvider.java | 4 +- .../webauthn/RunOnVirtualThreadTest.java | 10 +- .../webauthn/WebAuthnEndpointHelper.java | 8 +- .../webauthn/WebAuthnTestUserProvider.java | 6 +- 28 files changed, 196 insertions(+), 197 deletions(-) diff --git a/docs/src/main/asciidoc/security-webauthn.adoc b/docs/src/main/asciidoc/security-webauthn.adoc index 7016ddee3e759..ee8c82686c94c 100644 --- a/docs/src/main/asciidoc/security-webauthn.adoc +++ b/docs/src/main/asciidoc/security-webauthn.adoc @@ -274,13 +274,13 @@ public class WebAuthnCredential extends PanacheEntityBase { public WebAuthnCredentialRecord toWebAuthnCredentialRecord() { return WebAuthnCredentialRecord .fromRequiredPersistedData( - new RequiredPersistedData(user.userName, credentialId, + new RequiredPersistedData(user.username, credentialId, aaguid, publicKey, publicKeyAlgorithm, counter)); } - public static List findByUserName(String userName) { - return list("user.userName", userName); + public static List findByUsername(String username) { + return list("user.username", username); } public static WebAuthnCredential findByCredentialId(String credentialId) { @@ -306,14 +306,14 @@ import jakarta.persistence.Table; public class User extends PanacheEntity { @Column(unique = true) - public String userName; + public String username; // non-owning side, so we can add more credentials later @OneToOne(mappedBy = "user") public WebAuthnCredential webAuthnCredential; - public static User findByUserName(String userName) { - return User.find("userName", userName).firstResult(); + public static User findByUsername(String username) { + return User.find("username", username).firstResult(); } } ---- @@ -350,9 +350,9 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider { @Transactional @Override - public Uni> findByUserName(String userId) { + public Uni> findByUsername(String userId) { return Uni.createFrom().item( - WebAuthnCredential.findByUserName(userId) + WebAuthnCredential.findByUsername(userId) .stream() .map(WebAuthnCredential::toWebAuthnCredentialRecord) .toList()); @@ -372,9 +372,9 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider { @Override public Uni store(WebAuthnCredentialRecord credentialRecord) { User newUser = new User(); - // We can only store one credential per userName thanks to the unicity constraint - // which will cause this transaction to fail and throw if the userName already exists - newUser.userName = credentialRecord.getUserName(); + // We can only store one credential per username thanks to the unicity constraint + // which will cause this transaction to fail and throw if the username already exists + newUser.username = credentialRecord.getUsername(); WebAuthnCredential credential = new WebAuthnCredential(credentialRecord, newUser); credential.persist(); newUser.persist(); @@ -401,10 +401,10 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider { ---- Warning: When implementing your own `WebAuthnUserProvider.store` method, make sure that you never allow creating -new credentials for a `userName` that already exists. Otherwise you risk allowing third-parties to impersonate existing +new credentials for a `username` that already exists. Otherwise you risk allowing third-parties to impersonate existing users by letting them add their own credentials to existing accounts. If you want to allow existing users to register more than one WebAuthn credential, you must make sure in `WebAuthnUserProvider.store` that the user is currently logged -in under the same `userName` to which you want to add new credentials. In every other case, make sure to return a failed +in under the same `username` to which you want to add new credentials. In every other case, make sure to return a failed `Uni` from this method. In this particular example, this is checked using a unicity constraint on the user name, which will cause the transaction to fail if the user already exists. @@ -492,7 +492,7 @@ in `src/main/resources/META-INF/resources/index.html`:

    Register

    -
    +


    @@ -506,7 +506,7 @@ in `src/main/resources/META-INF/resources/index.html`: fetch('/api/public/me') .then(response => response.text()) - .then(name => result.append("User: "+name)); + .then(username => result.append("User: "+username)); const loginButton = document.getElementById('login'); @@ -515,8 +515,8 @@ in `src/main/resources/META-INF/resources/index.html`: webAuthn.login() .then(x => fetch('/api/public/me')) .then(response => response.text()) - .then(userName => { - result.append("User: "+userName); + .then(username => { + result.append("User: "+username); }) .catch(err => { result.append("Login failed: "+err); @@ -527,13 +527,13 @@ in `src/main/resources/META-INF/resources/index.html`: const registerButton = document.getElementById('register'); registerButton.addEventListener("click", (e) => { - var userName = document.getElementById('userNameRegister').value; + var username = document.getElementById('usernameRegister').value; var firstName = document.getElementById('firstName').value; var lastName = document.getElementById('lastName').value; result.replaceChildren(); - webAuthn.register({ name: userName, displayName: firstName + " " + lastName }) + webAuthn.register({ username: username, displayName: firstName + " " + lastName }) .then(body => { - result.append("User: "+userName); + result.append("User: "+username); }) .catch(err => { result.append("Registration failed: "+err); @@ -621,11 +621,11 @@ The Quarkus WebAuthn extension comes out of the box with these REST endpoints pr === Obtain a registration challenge -`GET /q/webauthn/register-options-challenge?userName=&displayName=`: Set up and obtain a registration challenge +`GET /q/webauthn/register-options-challenge?username=&displayName=`: Set up and obtain a registration challenge Query parameters: -- `userName` is a username. Required. +- `username` is a username. Required. - `displayName` is a human-palatable name for the user account. Optional. This causes a cookie to be set for the challenge, it will be used by the registration step later. @@ -667,11 +667,11 @@ This causes a cookie to be set for the challenge, it will be used by the registr === Trigger a registration -`POST /q/webauthn/register?userName=`: Trigger a registration +`POST /q/webauthn/register?username=`: Trigger a registration Query parameters: -- `userName` is a username. Required. +- `username` is a username. Required. This uses the challenge cookie set by the registration challenge and clears it. It also uses your link:{webauthn-api}/io/quarkus/security/webauthn/WebAuthnUserProvider.html[`WebAuthnUserProvider`] to store the new credentials, and sets up @@ -697,11 +697,11 @@ This returns a 204 with no body. === Obtain a login challenge -`GET /q/webauthn/login-options-challenge?userName=`: Set up and obtain a login challenge +`GET /q/webauthn/login-options-challenge?username=`: Set up and obtain a login challenge Query parameters: -- `userName` is a username. Optional in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys). +- `username` is a username. Optional in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys). This causes a cookie to be set for the challenge, it will be used by the login step later. @@ -846,7 +846,7 @@ for that registration, and returns a https://developer.mozilla.org/en-US/docs/We [source,javascript] ---- -webAuthn.register({ name: userName, displayName: firstName + " " + lastName }) +webAuthn.register({ username: username, displayName: firstName + " " + lastName }) .then(body => { // do something now that the user is registered }) @@ -862,7 +862,7 @@ for that login, and returns a https://developer.mozilla.org/en-US/docs/Web/JavaS [source,javascript] ---- -webAuthn.login({ name: userName }) <1> +webAuthn.login({ username: username }) <1> .then(body => { // do something now that the user is logged in }) @@ -871,7 +871,7 @@ webAuthn.login({ name: userName }) <1> }); ---- -<1> The name is optional, in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys) +<1> The username is optional, in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys) === Only invoke the registration challenge and authenticator @@ -882,7 +882,7 @@ in hidden form `input` elements, for example, and send it as part of a regular H [source,javascript] ---- -webAuthn.registerClientSteps({ name: userName, displayName: firstName + " " + lastName }) +webAuthn.registerClientSteps({ username: username, displayName: firstName + " " + lastName }) .then(body => { // store the registration JSON in form elements document.getElementById('webAuthnId').value = body.id; @@ -905,7 +905,7 @@ in hidden form `input` elements, for example, and send it as part of a regular H [source,javascript] ---- -webAuthn.loginClientSteps({ name: userName }) <1> +webAuthn.loginClientSteps({ username: username }) <1> .then(body => { // store the login JSON in form elements document.getElementById('webAuthnId').value = body.id; @@ -921,7 +921,7 @@ webAuthn.loginClientSteps({ name: userName }) <1> }); ---- -<1> The name is optional, in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys) +<1> The username is optional, in the case of https://www.w3.org/TR/webauthn-3/#discoverable-credential[Discoverable Credentials] (with PassKeys) == Handling login and registration endpoints yourself @@ -977,9 +977,9 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider { @Transactional @Override - public Uni> findByUserName(String userName) { + public Uni> findByUsername(String username) { return Uni.createFrom().item( - WebAuthnCredential.findByUserName(userName) + WebAuthnCredential.findByUsername(username) .stream() .map(WebAuthnCredential::toWebAuthnCredentialRecord) .toList()); @@ -1050,7 +1050,7 @@ public class LoginResource { try { WebAuthnCredentialRecord credentialRecord = this.webAuthnSecurity.login(webAuthnResponse, ctx).await().indefinitely(); - User user = User.findByUserName(credentialRecord.getUserName()); + User user = User.findByUsername(credentialRecord.getUsername()); if(user == null) { // Invalid user return Response.status(Status.BAD_REQUEST).build(); @@ -1058,7 +1058,7 @@ public class LoginResource { // bump the auth counter user.webAuthnCredential.counter = credentialRecord.getCounter(); // make a login cookie - this.webAuthnSecurity.rememberUser(credentialRecord.getUserName(), ctx); + this.webAuthnSecurity.rememberUser(credentialRecord.getUsername(), ctx); return Response.ok().build(); } catch (Exception exception) { // handle login failure - make a proper error response @@ -1070,16 +1070,16 @@ public class LoginResource { @Path("/register") @POST @Transactional - public Response register(@RestForm String userName, + public Response register(@RestForm String username, @BeanParam WebAuthnRegisterResponse webAuthnResponse, RoutingContext ctx) { // Input validation - if(userName == null || userName.isEmpty() + if(username == null || username.isEmpty() || !webAuthnResponse.isSet() || !webAuthnResponse.isValid()) { return Response.status(Status.BAD_REQUEST).build(); } - User user = User.findByUserName(userName); + User user = User.findByUsername(username); if(user != null) { // Duplicate user return Response.status(Status.BAD_REQUEST).build(); @@ -1087,15 +1087,15 @@ public class LoginResource { try { // store the user WebAuthnCredentialRecord credentialRecord = - webAuthnSecurity.register(userName, webAuthnResponse, ctx).await().indefinitely(); + webAuthnSecurity.register(username, webAuthnResponse, ctx).await().indefinitely(); User newUser = new User(); - newUser.userName = credentialRecord.getUserName(); + newUser.username = credentialRecord.getUsername(); WebAuthnCredential credential = new WebAuthnCredential(credentialRecord, newUser); credential.persist(); newUser.persist(); // make a login cookie - this.webAuthnSecurity.rememberUser(newUser.userName, ctx); + this.webAuthnSecurity.rememberUser(newUser.username, ctx); return Response.ok().build(); } catch (Exception ignored) { // handle login failure @@ -1205,26 +1205,26 @@ public class WebAuthnResourceTest { testWebAuthn("admin", User.ADMIN, Endpoint.DEFAULT); } - private void testWebAuthn(String userName, User user, Endpoint endpoint) { + private void testWebAuthn(String username, User user, Endpoint endpoint) { Filter cookieFilter = new RenardeCookieFilter(); WebAuthnHardware token = new WebAuthnHardware(url); verifyLoggedOut(cookieFilter); // two-step registration - String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge(userName, cookieFilter); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge(username, cookieFilter); JsonObject registrationJson = token.makeRegistrationJson(challenge); if(endpoint == Endpoint.DEFAULT) - WebAuthnEndpointHelper.invokeRegistration(userName, registrationJson, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration(username, registrationJson, cookieFilter); else { invokeCustomEndpoint("/register", cookieFilter, request -> { WebAuthnEndpointHelper.addWebAuthnRegistrationFormParameters(request, registrationJson); - request.formParam("userName", userName); + request.formParam("username", username); }); } // verify that we can access logged-in endpoints - verifyLoggedIn(cookieFilter, userName, user); + verifyLoggedIn(cookieFilter, username, user); // logout WebAuthnEndpointHelper.invokeLogout(cookieFilter); @@ -1243,7 +1243,7 @@ public class WebAuthnResourceTest { } // verify that we can access logged-in endpoints - verifyLoggedIn(cookieFilter, userName, user); + verifyLoggedIn(cookieFilter, username, user); // logout WebAuthnEndpointHelper.invokeLogout(cookieFilter); @@ -1267,7 +1267,7 @@ public class WebAuthnResourceTest { .cookie(WebAuthnEndpointHelper.getMainCookie(), Matchers.notNullValue()); } - private void verifyLoggedIn(Filter cookieFilter, String userName, User user) { + private void verifyLoggedIn(Filter cookieFilter, String username, User user) { // public API still good RestAssured.given().filter(cookieFilter) .when() @@ -1281,7 +1281,7 @@ public class WebAuthnResourceTest { .get("/api/public/me") .then() .statusCode(200) - .body(Matchers.is(userName)); + .body(Matchers.is(username)); // user API accessible RestAssured.given().filter(cookieFilter) @@ -1289,7 +1289,7 @@ public class WebAuthnResourceTest { .get("/api/users/me") .then() .statusCode(200) - .body(Matchers.is(userName)); + .body(Matchers.is(username)); // admin API? if(user == User.ADMIN) { @@ -1372,7 +1372,7 @@ public class TestUserProvider extends MyWebAuthnSetup { @Override public Uni store(WebAuthnCredentialRecord credentialRecord) { // this user is handled in the LoginResource endpoint manually - if (credentialRecord.getUserName().equals("scooby")) { + if (credentialRecord.getUsername().equals("scooby")) { return Uni.createFrom().voidItem(); } return super.store(credentialRecord); @@ -1383,7 +1383,7 @@ public class TestUserProvider extends MyWebAuthnSetup { public Uni update(String credentialId, long counter) { WebAuthnCredential credential = WebAuthnCredential.findByCredentialId(credentialId); // this user is handled in the LoginResource endpoint manually - if (credential.user.userName.equals("scooby")) { + if (credential.user.username.equals("scooby")) { return Uni.createFrom().voidItem(); } return super.update(credentialId, counter); diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java index 42fd2c508e285..0eb35dfe100d9 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/ManualResource.java @@ -29,7 +29,7 @@ public Uni register(@QueryParam("username") String username, @BeanParam return security.register(username, register, ctx).map(authenticator -> { // need to attach the authenticator to the user userProvider.reallyStore(authenticator); - security.rememberUser(authenticator.getUserName(), ctx); + security.rememberUser(authenticator.getUsername(), ctx); return "OK"; }); } @@ -40,7 +40,7 @@ public Uni login(@BeanParam WebAuthnLoginResponse login, RoutingContext return security.login(login, ctx).map(authenticator -> { // need to update the user's authenticator userProvider.reallyUpdate(authenticator.getCredentialID(), authenticator.getCounter()); - security.rememberUser(authenticator.getUserName(), ctx); + security.rememberUser(authenticator.getUsername(), ctx); return "OK"; }); } diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/TestResource.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/TestResource.java index f1415255f31c8..90160a8bb38fc 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/TestResource.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/TestResource.java @@ -16,7 +16,7 @@ public class TestResource { @Authenticated @Path("secure") @GET - public String getUserName() { + public String getUsername() { return identity.getPrincipal().getName() + ": " + identity.getRoles(); } diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java index efa77f85bb7cf..1e9bc68a63ef3 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAndBasicAuthnTest.java @@ -55,7 +55,7 @@ public static void setupUsers() { @Test public void test() throws Exception { - Assertions.assertTrue(userProvider.findByUserName("stev").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUsername("stev").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stev", cookieFilter); WebAuthnHardware hardwareKey = new WebAuthnHardware(url); @@ -79,9 +79,9 @@ public void test() throws Exception { .cookie("quarkus-credential", Matchers.notNullValue()); // make sure we stored the user - List users = userProvider.findByUserName("stev").await().indefinitely(); + List users = userProvider.findByUsername("stev").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stev")); + Assertions.assertTrue(users.get(0).getUsername().equals("stev")); Assertions.assertEquals(1, users.get(0).getCounter()); // make sure our login cookie works diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java index ce1074c868e2b..b64600f2649ca 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnAutomaticTest.java @@ -40,7 +40,7 @@ public void test() throws Exception { .given().redirects().follow(false) .get("/cheese").then().statusCode(302); - Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUsername("stef").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); WebAuthnHardware hardwareKey = new WebAuthnHardware(url); String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); @@ -50,9 +50,9 @@ public void test() throws Exception { WebAuthnEndpointHelper.invokeRegistration("stef", registration, cookieFilter); // make sure we stored the user - List users = userProvider.findByUserName("stef").await().indefinitely(); + List users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(1, users.get(0).getCounter()); // make sure our login cookie works @@ -68,9 +68,9 @@ public void test() throws Exception { WebAuthnEndpointHelper.invokeLogin(login, cookieFilter); // make sure we bumped the user - users = userProvider.findByUserName("stef").await().indefinitely(); + users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(2, users.get(0).getCounter()); // make sure our login cookie still works @@ -86,9 +86,9 @@ public void test() throws Exception { WebAuthnEndpointHelper.invokeLogin(login, cookieFilter); // make sure we bumped the user - users = userProvider.findByUserName("stef").await().indefinitely(); + users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(3, users.get(0).getCounter()); // make sure our login cookie still works diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnBlockingTestUserProvider.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnBlockingTestUserProvider.java index 9fd20f321a561..49786959dff82 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnBlockingTestUserProvider.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnBlockingTestUserProvider.java @@ -24,9 +24,9 @@ public Uni findByCredentialId(String credId) { } @Override - public Uni> findByUserName(String userId) { + public Uni> findByUsername(String userId) { assertBlockingAllowed(); - return super.findByUserName(userId); + return super.findByUsername(userId); } @Override diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java index c9c15baf3c6c8..d2b0ef0f4643d 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualCustomCookiesTest.java @@ -57,7 +57,7 @@ public void test() throws Exception { .given().redirects().follow(false) .get("/cheese").then().statusCode(302); - Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUsername("stef").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); WebAuthnHardware hardwareKey = new WebAuthnHardware(url); @@ -77,9 +77,9 @@ public void test() throws Exception { .cookie("main-cookie", Matchers.notNullValue()); // make sure we stored the user - List users = userProvider.findByUserName("stef").await().indefinitely(); + List users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(1, users.get(0).getCounter()); // make sure our login cookie works @@ -104,9 +104,9 @@ public void test() throws Exception { .cookie("main-cookie", Matchers.notNullValue()); // make sure we bumped the user - users = userProvider.findByUserName("stef").await().indefinitely(); + users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(2, users.get(0).getCounter()); // make sure our login cookie still works diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java index ef2a4c69886ca..e54ae25e2a92f 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTest.java @@ -56,7 +56,7 @@ public void test() throws Exception { .given().redirects().follow(false) .get("/cheese").then().statusCode(302); - Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUsername("stef").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); WebAuthnHardware hardwareKey = new WebAuthnHardware(url); @@ -78,9 +78,9 @@ public void test() throws Exception { .cookie("quarkus-credential", Matchers.notNullValue()); // make sure we stored the user - List users = userProvider.findByUserName("stef").await().indefinitely(); + List users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(1, users.get(0).getCounter()); // make sure our login cookie works @@ -107,9 +107,9 @@ public void test() throws Exception { .cookie("quarkus-credential", Matchers.notNullValue()); // make sure we bumped the user - users = userProvider.findByUserName("stef").await().indefinitely(); + users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(2, users.get(0).getCounter()); // make sure our login cookie still works @@ -127,15 +127,15 @@ public void test() throws Exception { () -> WebAuthnEndpointHelper.invokeLogin(defaultLogin, finalCookieFilter)); // make sure we did not bump the user - users = userProvider.findByUserName("stef").await().indefinitely(); + users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(2, users.get(0).getCounter()); } @Test public void checkDefaultRegistrationDisabled() { - Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUsername("stef").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); WebAuthnHardware hardwareKey = new WebAuthnHardware(url); String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); @@ -146,7 +146,7 @@ public void checkDefaultRegistrationDisabled() { () -> WebAuthnEndpointHelper.invokeRegistration("stef", registration, cookieFilter)); // make sure we did not create any user - Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUsername("stef").await().indefinitely().isEmpty()); } private void checkLoggedIn(CookieFilter cookieFilter) { diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTestUserProvider.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTestUserProvider.java index be5779656c498..86d561d3321d1 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTestUserProvider.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnManualTestUserProvider.java @@ -25,9 +25,9 @@ public Uni findByCredentialId(String credId) { } @Override - public Uni> findByUserName(String userId) { + public Uni> findByUsername(String userId) { assertRequestContext(); - return super.findByUserName(userId); + return super.findByUsername(userId); } private void assertRequestContext() { diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnNonBlockingTestUserProvider.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnNonBlockingTestUserProvider.java index 4cab358e2a838..7d88c1c620187 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnNonBlockingTestUserProvider.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnNonBlockingTestUserProvider.java @@ -22,9 +22,9 @@ public Uni findByCredentialId(String credId) { } @Override - public Uni> findByUserName(String userId) { + public Uni> findByUsername(String userId) { assertBlockingNotAllowed(); - return super.findByUserName(userId); + return super.findByUsername(userId); } @Override diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java index 9c8a3e65d99d0..faba447abe20a 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnOriginsTest.java @@ -24,7 +24,7 @@ public void testLoginRpFromFirstOrigin() { RestAssured .given() .contentType(ContentType.URLENC) - .queryParam("userName", "foo") + .queryParam("username", "foo") .get("/q/webauthn/register-options-challenge") .then() .log().all() diff --git a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java index 6b90fa05a002a..03cf9cec1850a 100644 --- a/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java +++ b/extensions/security-webauthn/deployment/src/test/java/io/quarkus/security/webauthn/test/WebAuthnTest.java @@ -31,7 +31,7 @@ public void testLoginRpFromFirstOrigin() { RestAssured .given() .contentType(ContentType.JSON) - .queryParam("userName", "foo") + .queryParam("username", "foo") .get("/q/webauthn/register-options-challenge") .then() .statusCode(200) @@ -47,7 +47,7 @@ public void testRegisterChallengeIsEqualAcrossCalls() { .given() .filter(cookieFilter) .contentType(ContentType.URLENC) - .queryParam("userName", "foo") + .queryParam("username", "foo") .get("/q/webauthn/register-options-challenge") .jsonPath().get("challenge"); @@ -55,7 +55,7 @@ public void testRegisterChallengeIsEqualAcrossCalls() { .given() .filter(cookieFilter) .contentType(ContentType.URLENC) - .queryParam("userName", "foo") + .queryParam("username", "foo") .get("/q/webauthn/register-options-challenge") .then() .statusCode(200) diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticatorStorage.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticatorStorage.java index bc67b739be83b..a1031100ddfc1 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticatorStorage.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnAuthenticatorStorage.java @@ -26,8 +26,8 @@ public class WebAuthnAuthenticatorStorage { @Inject Vertx vertx; - public Uni> findByUserName(String userName) { - return runPotentiallyBlocking(() -> userProvider.findByUserName(userName)); + public Uni> findByUsername(String username) { + return runPotentiallyBlocking(() -> userProvider.findByUsername(username)); } public Uni findByCredID(String credID) { diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java index 32bce81fef053..083a8b7cb5b26 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnController.java @@ -47,9 +47,9 @@ public void wellKnown(RoutingContext ctx) { */ public void registerOptionsChallenge(RoutingContext ctx) { try { - String userName = ctx.queryParams().get("userName"); + String username = ctx.queryParams().get("username"); String displayName = ctx.queryParams().get("displayName"); - withContext(() -> security.getRegisterChallenge(userName, displayName, ctx)) + withContext(() -> security.getRegisterChallenge(username, displayName, ctx)) .map(challenge -> security.toJsonString(challenge)) .subscribe().with(challenge -> ok(ctx, challenge), ctx::fail); @@ -74,8 +74,8 @@ private Uni withContext(Supplier> uni) { */ public void loginOptionsChallenge(RoutingContext ctx) { try { - String userName = ctx.queryParams().get("userName"); - withContext(() -> security.getLoginChallenge(userName, ctx)) + String username = ctx.queryParams().get("username"); + withContext(() -> security.getLoginChallenge(username, ctx)) .map(challenge -> security.toJsonString(challenge)) .subscribe().with(challenge -> ok(ctx, challenge), ctx::fail); @@ -100,7 +100,7 @@ public void login(RoutingContext ctx) { withContext(() -> security.login(webauthnResp, ctx)) .onItem().call(record -> security.storage().update(record.getCredentialID(), record.getCounter())) .subscribe().with(record -> { - security.rememberUser(record.getUserName(), ctx); + security.rememberUser(record.getUsername(), ctx); ok(ctx); }, x -> ctx.fail(400, x)); } catch (IllegalArgumentException e) { @@ -118,14 +118,14 @@ public void login(RoutingContext ctx) { */ public void register(RoutingContext ctx) { try { - final String userName = ctx.queryParams().get("userName"); + final String username = ctx.queryParams().get("username"); // might throw runtime exception if there's no json or is bad formed final JsonObject webauthnResp = ctx.getBodyAsJson(); - withContext(() -> security.register(userName, webauthnResp, ctx)) + withContext(() -> security.register(username, webauthnResp, ctx)) .onItem().call(record -> security.storage().create(record)) .subscribe().with(record -> { - security.rememberUser(record.getUserName(), ctx); + security.rememberUser(record.getUsername(), ctx); ok(ctx); }, x -> ctx.fail(400, x)); } catch (IllegalArgumentException e) { diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnCredentialRecord.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnCredentialRecord.java index 9deedc2ffa5cf..1739ac63adfbb 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnCredentialRecord.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnCredentialRecord.java @@ -35,28 +35,28 @@ */ public class WebAuthnCredentialRecord extends CredentialRecordImpl { - private String userName; + private String username; /* * This is used for registering */ - public WebAuthnCredentialRecord(String userName, + public WebAuthnCredentialRecord(String username, AttestationObject attestationObject, CollectedClientData clientData, AuthenticationExtensionsClientOutputs clientExtensions, Set transports) { super(attestationObject, clientData, clientExtensions, transports); - this.userName = userName; + this.username = username; } /* * This is used for login */ - private WebAuthnCredentialRecord(String userName, + private WebAuthnCredentialRecord(String username, long counter, AttestedCredentialData attestedCredentialData) { super(null, null, null, null, counter, attestedCredentialData, null, null, null, null); - this.userName = userName; + this.username = username; } /** @@ -76,8 +76,8 @@ public long getCounter() { * * @return the username for this credential record */ - public String getUserName() { - return userName; + public String getUsername() { + return username; } /** @@ -97,7 +97,7 @@ public String getCredentialID() { * @return the fields required to be persisted. */ public RequiredPersistedData getRequiredPersistedData() { - return new RequiredPersistedData(getUserName(), + return new RequiredPersistedData(getUsername(), getCredentialID(), getAttestedCredentialData().getAaguid().getValue(), getAttestedCredentialData().getCOSEKey().getPublicKey().getEncoded(), @@ -143,7 +143,7 @@ public static WebAuthnCredentialRecord fromRequiredPersistedData(RequiredPersist AAGUID aaguid = new AAGUID(persistedData.aaguid()); AttestedCredentialData attestedCredentialData = new AttestedCredentialData(aaguid, credentialId, coseKey); - return new WebAuthnCredentialRecord(persistedData.userName(), counter, attestedCredentialData); + return new WebAuthnCredentialRecord(persistedData.username(), counter, attestedCredentialData); } /** @@ -153,7 +153,7 @@ public record RequiredPersistedData( /** * The user name. A single user name may be associated with multiple WebAuthn credentials. */ - String userName, + String username, /** * The credential ID. This must be unique. See https://w3c.github.io/webauthn/#credential-id */ diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java index a489f5b892f92..7e2df1ea59900 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnSecurity.java @@ -312,30 +312,30 @@ private static byte[] uUIDBytes(UUID uuid) { } /** - * Obtains a registration challenge for the given required userName and displayName. This will also + * Obtains a registration challenge for the given required username and displayName. This will also * create and save a challenge in a session cookie. * - * @param userName the userName for the registration + * @param username the username for the registration * @param displayName the displayName for the registration * @param ctx the Vert.x context * @return the registration challenge. */ @SuppressWarnings("unused") - public Uni getRegisterChallenge(String userName, String displayName, + public Uni getRegisterChallenge(String username, String displayName, RoutingContext ctx) { - if (userName == null || userName.isEmpty()) { + if (username == null || username.isEmpty()) { return Uni.createFrom().failure(new IllegalArgumentException("Username is required")); } - // default displayName to userName, but it's required really + // default displayName to username, but it's required really if (displayName == null || displayName.isEmpty()) { - displayName = userName; + displayName = username; } String finalDisplayName = displayName; String challenge = getOrCreateChallenge(ctx); Origin origin = Origin.create(!this.origins.isEmpty() ? this.origins.get(0) : ctx.request().absoluteURI()); String rpId = this.rpId != null ? this.rpId : origin.getHost(); - return storage.findByUserName(userName) + return storage.findByUsername(username) .map(credentials -> { List excluded; // See https://github.com/quarkusio/quarkus/issues/44292 for why this is currently disabled @@ -355,7 +355,7 @@ public Uni getRegisterChallenge(String userN rpName), new PublicKeyCredentialUserEntity( uUIDBytes(UUID.randomUUID()), - userName, + username, finalDisplayName), new DefaultChallenge(challenge), pubKeyCredParams, @@ -379,30 +379,30 @@ public Uni getRegisterChallenge(String userN } /** - * Obtains a login challenge for the given optional userName. This will also + * Obtains a login challenge for the given optional username. This will also * create and save a challenge in a session cookie. * - * @param userName the optional userName for the login + * @param username the optional username for the login * @param ctx the Vert.x context * @return the login challenge. */ @SuppressWarnings("unused") - public Uni getLoginChallenge(String userName, RoutingContext ctx) { + public Uni getLoginChallenge(String username, RoutingContext ctx) { // Username is not required with passkeys - if (userName == null) { - userName = ""; + if (username == null) { + username = ""; } - String finalUserName = userName; + String finalUsername = username; String challenge = getOrCreateChallenge(ctx); Origin origin = Origin.create(!this.origins.isEmpty() ? this.origins.get(0) : ctx.request().absoluteURI()); String rpId = this.rpId != null ? this.rpId : origin.getHost(); // do not attempt to look users up if there's no user name Uni> credentialsUni; - if (userName.isEmpty()) { + if (username.isEmpty()) { credentialsUni = Uni.createFrom().item(Collections.emptyList()); } else { - credentialsUni = storage.findByUserName(userName); + credentialsUni = storage.findByUsername(username); } return credentialsUni .map(credentials -> { @@ -411,7 +411,7 @@ public Uni getLoginChallenge(String userName, if (false) { if (credentials.isEmpty()) { - throw new RuntimeException("No credentials found for " + finalUserName); + throw new RuntimeException("No credentials found for " + finalUsername); } allowedCredentials = new ArrayList<>(credentials.size()); for (WebAuthnCredentialRecord credential : credentials) { diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java index 03b58ce4924b3..d90f43e694767 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnUserProvider.java @@ -15,11 +15,11 @@ public interface WebAuthnUserProvider { /** * Look up a WebAuthn credential by username. This should return an empty list Uni if the user name is not found. * - * @param userName the username + * @param username the username * @return a list of credentials for this username, or an empty list if there are no credentials or if the user name is * not found. */ - public Uni> findByUserName(String userName); + public Uni> findByUsername(String username); /** * Look up a WebAuthn credential by credential ID, this should return an exception Uni rather than return a null-item Uni @@ -53,19 +53,18 @@ public default Uni update(String credentialId, long counter) { * {@link WebAuthnSecurity#register(WebAuthnRegisterResponse, io.vertx.ext.web.RoutingContext)} * * Make sure that you never allow creating - * new credentials for a `userName` that already exists. Otherwise you risk allowing third-parties to impersonate existing + * new credentials for a `username` that already exists. Otherwise you risk allowing third-parties to impersonate existing * users by letting them add their own credentials to existing accounts. If you want to allow existing users to register * more than one WebAuthn credential, you must make sure that the user is currently logged - * in under the same userName to which you want to add new credentials. In every other case, make sure to + * in under the same username to which you want to add new credentials. In every other case, make sure to * return a failed * {@link Uni} from this method. * * The default behaviour is to not do anything. * - * @param userName the userName's credentials * @param credentialRecord the new credentials to store * @return a uni completion object - * @throws Exception a failed {@link Uni} if the credentialId already exists, or the userName + * @throws Exception a failed {@link Uni} if the credentialId already exists, or the username * already * has a credential and you disallow having more, or if trying to add credentials to other users than the current * user. @@ -77,10 +76,10 @@ public default Uni store(WebAuthnCredentialRecord credentialRecord) { /** * Returns the set of roles for the given username * - * @param userName the username + * @param username the username * @return the set of roles (defaults to an empty set) */ - public default Set getRoles(String userName) { + public default Set getRoles(String username) { return Collections.emptySet(); } } diff --git a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js index 485d060f4cf02..c9a88f47be721 100644 --- a/extensions/security-webauthn/runtime/src/main/resources/webauthn.js +++ b/extensions/security-webauthn/runtime/src/main/resources/webauthn.js @@ -120,7 +120,7 @@ if (!self.registerOptionsChallengePath) { return Promise.reject('Register challenge path missing form the initial configuration!'); } - return self.fetchWithCsrf(self.registerOptionsChallengePath + "?" + new URLSearchParams({userName: user.name, displayName: user.displayName}).toString(), { + return self.fetchWithCsrf(self.registerOptionsChallengePath + "?" + new URLSearchParams({username: user.username, displayName: user.displayName}).toString(), { method: 'GET', headers: { 'Accept': 'application/json', @@ -163,12 +163,12 @@ if (!self.registerPath) { throw new Error('Register path is missing!'); } - if (!user || !user.name) { - return Promise.reject('User name (user.name) required'); + if (!user || !user.username) { + return Promise.reject('User name (user.username) required'); } return self.registerClientSteps(user) .then(body => { - return self.fetchWithCsrf(self.registerPath + "?" + new URLSearchParams({userName: user.name}).toString(), { + return self.fetchWithCsrf(self.registerPath + "?" + new URLSearchParams({username: user.username}).toString(), { method: 'POST', headers: { 'Accept': 'application/json', @@ -215,8 +215,8 @@ return Promise.reject('Login challenge path missing from the initial configuration!'); } let path = self.loginOptionsChallengePath - if (user != null && user.name != null) { - path = path + "?" + new URLSearchParams({userName: user.name}).toString() + if (user != null && user.username != null) { + path = path + "?" + new URLSearchParams({username: user.username}).toString() } return self.fetchWithCsrf(path, { method: 'GET', diff --git a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java index a34e51eb8e9b0..57314c65f97cc 100644 --- a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java +++ b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/LoginResource.java @@ -26,17 +26,17 @@ public class LoginResource { @Path("/login") @POST @WithTransaction - public Uni login(@RestForm String userName, + public Uni login(@RestForm String username, @BeanParam WebAuthnLoginResponse webAuthnResponse, RoutingContext ctx) { // Input validation - if (userName == null || userName.isEmpty() + if (username == null || username.isEmpty() || !webAuthnResponse.isSet() || !webAuthnResponse.isValid()) { return Uni.createFrom().item(Response.status(Status.BAD_REQUEST).build()); } - Uni userUni = User.findByUserName(userName); + Uni userUni = User.findByUsername(username); return userUni.flatMap(user -> { if (user == null) { // Invalid user @@ -49,7 +49,7 @@ public Uni login(@RestForm String userName, .invoke(auth -> user.webAuthnCredential.counter = auth.getCounter()) .map(auth -> { // make a login cookie - this.webAuthnSecurity.rememberUser(auth.getUserName(), ctx); + this.webAuthnSecurity.rememberUser(auth.getUsername(), ctx); return Response.ok().build(); }) // handle login failure @@ -65,29 +65,29 @@ public Uni login(@RestForm String userName, @Path("/register") @POST @WithTransaction - public Uni register(@RestForm String userName, + public Uni register(@RestForm String username, @BeanParam WebAuthnRegisterResponse webAuthnResponse, RoutingContext ctx) { // Input validation - if (userName == null || userName.isEmpty() + if (username == null || username.isEmpty() || !webAuthnResponse.isSet() || !webAuthnResponse.isValid()) { return Uni.createFrom().item(Response.status(Status.BAD_REQUEST).build()); } - Uni userUni = User.findByUserName(userName); + Uni userUni = User.findByUsername(username); return userUni.flatMap(user -> { if (user != null) { // Duplicate user return Uni.createFrom().item(Response.status(Status.BAD_REQUEST).build()); } - Uni authenticator = this.webAuthnSecurity.register(userName, webAuthnResponse, ctx); + Uni authenticator = this.webAuthnSecurity.register(username, webAuthnResponse, ctx); return authenticator // store the user .flatMap(auth -> { User newUser = new User(); - newUser.userName = auth.getUserName(); + newUser.username = auth.getUsername(); WebAuthnCredential credential = new WebAuthnCredential(auth, newUser); return credential.persist() .flatMap(c -> newUser. persist()); @@ -95,7 +95,7 @@ public Uni register(@RestForm String userName, }) .map(newUser -> { // make a login cookie - this.webAuthnSecurity.rememberUser(newUser.userName, ctx); + this.webAuthnSecurity.rememberUser(newUser.username, ctx); return Response.ok().build(); }) // handle login failure diff --git a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/MyWebAuthnSetup.java b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/MyWebAuthnSetup.java index 15423104b0f17..a3e52a38e0a6d 100644 --- a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/MyWebAuthnSetup.java +++ b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/MyWebAuthnSetup.java @@ -17,8 +17,8 @@ public class MyWebAuthnSetup implements WebAuthnUserProvider { @WithTransaction @Override - public Uni> findByUserName(String userName) { - return WebAuthnCredential.findByUserName(userName) + public Uni> findByUsername(String username) { + return WebAuthnCredential.findByUsername(username) .map(list -> list.stream().map(WebAuthnCredential::toWebAuthnCredentialRecord).toList()); } @@ -34,11 +34,11 @@ public Uni findByCredentialId(String credentialId) { @Override public Uni store(WebAuthnCredentialRecord credentialRecord) { // this user is handled in the LoginResource endpoint manually - if (credentialRecord.getUserName().equals("scooby")) { + if (credentialRecord.getUsername().equals("scooby")) { return Uni.createFrom().voidItem(); } User newUser = new User(); - newUser.userName = credentialRecord.getUserName(); + newUser.username = credentialRecord.getUsername(); WebAuthnCredential credential = new WebAuthnCredential(credentialRecord, newUser); return credential.persist() .flatMap(c -> newUser.persist()) @@ -51,7 +51,7 @@ public Uni update(String credentialId, long counter) { return WebAuthnCredential.findByCredentialId(credentialId) .invoke(credential -> { // this user is handled in the LoginResource endpoint manually - if (!credential.user.userName.equals("scooby")) { + if (!credential.user.username.equals("scooby")) { credential.counter = counter; } }) @@ -59,8 +59,8 @@ public Uni update(String credentialId, long counter) { } @Override - public Set getRoles(String userId) { - if (userId.equals("admin")) { + public Set getRoles(String username) { + if (username.equals("admin")) { Set ret = new HashSet<>(); ret.add("user"); ret.add("admin"); diff --git a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/User.java b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/User.java index dc4861726bca8..411027ea31820 100644 --- a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/User.java +++ b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/User.java @@ -13,13 +13,13 @@ public class User extends PanacheEntity { @Column(unique = true) - public String userName; + public String username; // non-owning side, so we can add more credentials later @OneToOne(mappedBy = "user") public WebAuthnCredential webAuthnCredential; - public static Uni findByUserName(String userName) { - return find("userName", userName).firstResult(); + public static Uni findByUsername(String username) { + return find("username", username).firstResult(); } } diff --git a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/WebAuthnCredential.java b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/WebAuthnCredential.java index ec0e526b9d9f0..6350f735ea63e 100644 --- a/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/WebAuthnCredential.java +++ b/integration-tests/security-webauthn/src/main/java/io/quarkus/it/security/webauthn/WebAuthnCredential.java @@ -56,11 +56,11 @@ public WebAuthnCredential(WebAuthnCredentialRecord credentialRecord, User user) public WebAuthnCredentialRecord toWebAuthnCredentialRecord() { return WebAuthnCredentialRecord .fromRequiredPersistedData( - new RequiredPersistedData(user.userName, credID, aaguid, publicKey, publicKeyAlgorithm, counter)); + new RequiredPersistedData(user.username, credID, aaguid, publicKey, publicKeyAlgorithm, counter)); } - public static Uni> findByUserName(String userName) { - return list("user.userName", userName); + public static Uni> findByUsername(String username) { + return list("user.username", username); } public static Uni findByCredentialId(String credID) { diff --git a/integration-tests/security-webauthn/src/main/resources/META-INF/resources/index.html b/integration-tests/security-webauthn/src/main/resources/META-INF/resources/index.html index 9446fd7df2d2f..293743f5c0257 100644 --- a/integration-tests/security-webauthn/src/main/resources/META-INF/resources/index.html +++ b/integration-tests/security-webauthn/src/main/resources/META-INF/resources/index.html @@ -57,14 +57,14 @@

    Status

    Login

    -
    +

    Register

    -
    +


    @@ -87,11 +87,11 @@

    Register

    const loginButton = document.getElementById('login'); loginButton.onclick = () => { - var userName = document.getElementById('userNameLogin').value; + var username = document.getElementById('usernameLogin').value; result.replaceChildren(); - webAuthn.login({ name: userName }) + webAuthn.login({ name: username }) .then(body => { - result.append("User: "+userName); + result.append("User: "+username); }) .catch(err => { result.append("Login failed: "+err); @@ -102,13 +102,13 @@

    Register

    const registerButton = document.getElementById('register'); registerButton.onclick = () => { - var userName = document.getElementById('userNameRegister').value; + var username = document.getElementById('usernameRegister').value; var firstName = document.getElementById('firstName').value; var lastName = document.getElementById('lastName').value; result.replaceChildren(); - webAuthn.register({ name: userName, displayName: firstName + " " + lastName }) + webAuthn.register({ name: username, displayName: firstName + " " + lastName }) .then(body => { - result.append("User: "+userName); + result.append("User: "+username); }) .catch(err => { result.append("Registration failed: "+err); diff --git a/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java b/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java index cefcdd3f22202..ad550bb3b4919 100644 --- a/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java +++ b/integration-tests/security-webauthn/src/test/java/io/quarkus/it/security/webauthn/test/WebAuthnResourceTest.java @@ -44,26 +44,26 @@ public void testWebAuthnAdmin() { testWebAuthn("admin", User.ADMIN, Endpoint.DEFAULT); } - private void testWebAuthn(String userName, User user, Endpoint endpoint) { + private void testWebAuthn(String username, User user, Endpoint endpoint) { Filter cookieFilter = new RenardeCookieFilter(); WebAuthnHardware token = new WebAuthnHardware(url); verifyLoggedOut(cookieFilter); // two-step registration - String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge(userName, cookieFilter); + String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge(username, cookieFilter); JsonObject registrationJson = token.makeRegistrationJson(challenge); if (endpoint == Endpoint.DEFAULT) - WebAuthnEndpointHelper.invokeRegistration(userName, registrationJson, cookieFilter); + WebAuthnEndpointHelper.invokeRegistration(username, registrationJson, cookieFilter); else { invokeCustomEndpoint("/register", cookieFilter, request -> { WebAuthnEndpointHelper.addWebAuthnRegistrationFormParameters(request, registrationJson); - request.formParam("userName", userName); + request.formParam("username", username); }); } // verify that we can access logged-in endpoints - verifyLoggedIn(cookieFilter, userName, user); + verifyLoggedIn(cookieFilter, username, user); // logout WebAuthnEndpointHelper.invokeLogout(cookieFilter); @@ -71,19 +71,19 @@ private void testWebAuthn(String userName, User user, Endpoint endpoint) { verifyLoggedOut(cookieFilter); // two-step login - challenge = WebAuthnEndpointHelper.obtainLoginChallenge(userName, cookieFilter); + challenge = WebAuthnEndpointHelper.obtainLoginChallenge(username, cookieFilter); JsonObject loginJson = token.makeLoginJson(challenge); if (endpoint == Endpoint.DEFAULT) WebAuthnEndpointHelper.invokeLogin(loginJson, cookieFilter); else { invokeCustomEndpoint("/login", cookieFilter, request -> { WebAuthnEndpointHelper.addWebAuthnLoginFormParameters(request, loginJson); - request.formParam("userName", userName); + request.formParam("username", username); }); } // verify that we can access logged-in endpoints - verifyLoggedIn(cookieFilter, userName, user); + verifyLoggedIn(cookieFilter, username, user); // logout WebAuthnEndpointHelper.invokeLogout(cookieFilter); @@ -107,7 +107,7 @@ private void invokeCustomEndpoint(String uri, Filter cookieFilter, Consumer findByCredentialId(String credId) { } @Override - public Uni> findByUserName(String userId) { + public Uni> findByUsername(String username) { assertVirtualThread(); - return super.findByUserName(userId); + return super.findByUsername(username); } @Override diff --git a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java index a8f7b84031a7d..145e64ad43d16 100644 --- a/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java +++ b/integration-tests/virtual-threads/security-webauthn-virtual-threads/src/test/java/io/quarkus/virtual/security/webauthn/RunOnVirtualThreadTest.java @@ -46,7 +46,7 @@ public void test() throws Exception { .given().redirects().follow(false) .get("/cheese").then().statusCode(302); - Assertions.assertTrue(userProvider.findByUserName("stef").await().indefinitely().isEmpty()); + Assertions.assertTrue(userProvider.findByUsername("stef").await().indefinitely().isEmpty()); CookieFilter cookieFilter = new CookieFilter(); WebAuthnHardware hardwareKey = new WebAuthnHardware(url); String challenge = WebAuthnEndpointHelper.obtainRegistrationChallenge("stef", cookieFilter); @@ -56,9 +56,9 @@ public void test() throws Exception { WebAuthnEndpointHelper.invokeRegistration("stef", registration, cookieFilter); // make sure we stored the user - List users = userProvider.findByUserName("stef").await().indefinitely(); + List users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(1, users.get(0).getCounter()); // make sure our login cookie works @@ -74,9 +74,9 @@ public void test() throws Exception { WebAuthnEndpointHelper.invokeLogin(login, cookieFilter); // make sure we bumped the user - users = userProvider.findByUserName("stef").await().indefinitely(); + users = userProvider.findByUsername("stef").await().indefinitely(); Assertions.assertEquals(1, users.size()); - Assertions.assertTrue(users.get(0).getUserName().equals("stef")); + Assertions.assertTrue(users.get(0).getUsername().equals("stef")); Assertions.assertEquals(2, users.get(0).getCounter()); // make sure our login cookie still works diff --git a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java index 8146e33012c2a..7eb20347e2d5c 100644 --- a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java +++ b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnEndpointHelper.java @@ -14,13 +14,13 @@ import io.vertx.core.json.JsonObject; public class WebAuthnEndpointHelper { - public static String obtainRegistrationChallenge(String userName, Filter cookieFilter) { + public static String obtainRegistrationChallenge(String username, Filter cookieFilter) { ExtractableResponse response = RestAssured .given() .contentType(ContentType.URLENC) .filter(cookieFilter) .log().ifValidationFails() - .queryParam("userName", userName) + .queryParam("username", username) .get("/q/webauthn/register-options-challenge") .then() .log().ifValidationFails() @@ -63,13 +63,13 @@ public static void invokeRegistration(String username, JsonObject registration, .cookie(getMainCookie(), Matchers.notNullValue()); } - public static String obtainLoginChallenge(String userName, Filter cookieFilter) { + public static String obtainLoginChallenge(String username, Filter cookieFilter) { ExtractableResponse response = RestAssured .given() .contentType(ContentType.URLENC) .filter(cookieFilter) .log().ifValidationFails() - .queryParam("name", userName) + .queryParam("username", username) .get("/q/webauthn/login-options-challenge") .then() .log().ifValidationFails() diff --git a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnTestUserProvider.java b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnTestUserProvider.java index e6a5ca5509e71..29976565a4a40 100644 --- a/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnTestUserProvider.java +++ b/test-framework/security-webauthn/src/main/java/io/quarkus/test/security/webauthn/WebAuthnTestUserProvider.java @@ -21,10 +21,10 @@ public class WebAuthnTestUserProvider implements WebAuthnUserProvider { private List auths = new ArrayList<>(); @Override - public Uni> findByUserName(String userId) { + public Uni> findByUsername(String userId) { List ret = new ArrayList<>(); for (WebAuthnCredentialRecord authenticator : auths) { - if (authenticator.getUserName().equals(userId)) { + if (authenticator.getUsername().equals(userId)) { ret.add(authenticator); } } @@ -55,7 +55,7 @@ public Uni store(WebAuthnCredentialRecord credentialRecord) { } @Override - public Set getRoles(String userId) { + public Set getRoles(String username) { return Collections.singleton("admin"); } From 2859983ab0c40de27c61173ec1ad7fb89fc38c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20=C3=89pardaud?= Date: Tue, 17 Dec 2024 16:52:36 +0100 Subject: [PATCH 162/207] WebAuthn docs: updated workflow diagrams --- docs/src/main/asciidoc/images/webauthn-custom-login.svg | 2 +- docs/src/main/asciidoc/images/webauthn-custom-register.svg | 2 +- docs/src/main/asciidoc/images/webauthn-login.svg | 2 +- docs/src/main/asciidoc/images/webauthn-register.svg | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/main/asciidoc/images/webauthn-custom-login.svg b/docs/src/main/asciidoc/images/webauthn-custom-login.svg index e08ba0cd89ee0..ed2d6dee9c081 100644 --- a/docs/src/main/asciidoc/images/webauthn-custom-login.svg +++ b/docs/src/main/asciidoc/images/webauthn-custom-login.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/src/main/asciidoc/images/webauthn-custom-register.svg b/docs/src/main/asciidoc/images/webauthn-custom-register.svg index 75b98727ac93b..04628daff7c18 100644 --- a/docs/src/main/asciidoc/images/webauthn-custom-register.svg +++ b/docs/src/main/asciidoc/images/webauthn-custom-register.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/src/main/asciidoc/images/webauthn-login.svg b/docs/src/main/asciidoc/images/webauthn-login.svg index 0055a442c28e9..eaff8b619a2d7 100644 --- a/docs/src/main/asciidoc/images/webauthn-login.svg +++ b/docs/src/main/asciidoc/images/webauthn-login.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/src/main/asciidoc/images/webauthn-register.svg b/docs/src/main/asciidoc/images/webauthn-register.svg index 5c60cdb486b8e..7b6405aa86da0 100644 --- a/docs/src/main/asciidoc/images/webauthn-register.svg +++ b/docs/src/main/asciidoc/images/webauthn-register.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From eecda81363908479b08631724dc0088fcf35d073 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Tue, 3 Dec 2024 16:36:01 +0000 Subject: [PATCH 163/207] Update OidcTenantConfigBuilder shortcuts --- .../io/quarkus/oidc/OidcTenantConfigBuilder.java | 13 ++----------- .../oidc/runtime/providers/KnownOidcProviders.java | 12 ++++++------ .../oidc/runtime/OidcTenantConfigBuilderTest.java | 4 ++-- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfigBuilder.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfigBuilder.java index a189f2aa7fa6f..2600affd4c7fa 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfigBuilder.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfigBuilder.java @@ -466,20 +466,11 @@ public OidcTenantConfigBuilder token(Token token) { } /** - * @param verifyAccessTokenWithUserInfo {@link Token#verifyAccessTokenWithUserInfo()} * @param principalClaim {@link Token#principalClaim()} * @return this builder */ - public OidcTenantConfigBuilder token(boolean verifyAccessTokenWithUserInfo, String principalClaim) { - return token().verifyAccessTokenWithUserInfo(verifyAccessTokenWithUserInfo).principalClaim(principalClaim).end(); - } - - /** - * @param verifyAccessTokenWithUserInfo {@link Token#verifyAccessTokenWithUserInfo()} - * @return this builder - */ - public OidcTenantConfigBuilder token(boolean verifyAccessTokenWithUserInfo) { - return token().verifyAccessTokenWithUserInfo(verifyAccessTokenWithUserInfo).end(); + public OidcTenantConfigBuilder token(String principalClaim) { + return token().principalClaim(principalClaim).end(); } /** diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/providers/KnownOidcProviders.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/providers/KnownOidcProviders.java index 8e1e6348e94e4..8912c22ad4065 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/providers/KnownOidcProviders.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/providers/KnownOidcProviders.java @@ -34,7 +34,7 @@ private static OidcTenantConfig slack() { return OidcTenantConfig .authServerUrl("https://slack.com") .applicationType(WEB_APP) - .token().principalClaim("name").end() + .token("name") .authentication() .forceRedirectHttpsScheme() .scopes("profile", "email") @@ -64,7 +64,7 @@ private static OidcTenantConfig github() { .authorizationPath("authorize") .tokenPath("access_token") .userInfoPath("https://api.github.com/user") - .token(true, "name") + .token().verifyAccessTokenWithUserInfo(true).principalClaim("name").end() .authentication(authBuilder.build()) .build(); } @@ -93,7 +93,7 @@ private static OidcTenantConfig google() { .authServerUrl("https://accounts.google.com") .applicationType(WEB_APP) .authentication().scopes("openid", "email", "profile").end() - .token(true, "name") + .token().verifyAccessTokenWithUserInfo(true).principalClaim("name").end() .build(); } @@ -171,7 +171,7 @@ private static OidcTenantConfig spotify() { .authorizationPath("authorize") .tokenPath("api/token") .userInfoPath("https://api.spotify.com/v1/me") - .token(true, "display_name") + .token().verifyAccessTokenWithUserInfo(true).principalClaim("display_name").end() .authentication(authentication) .build(); } @@ -183,7 +183,7 @@ private static OidcTenantConfig strava() { .discoveryEnabled(false) .authorizationPath("authorize") .tokenPath("token") - .token(true) + .token().verifyAccessTokenWithUserInfo(true).end() .userInfoPath("https://www.strava.com/api/v3/athlete"); builder.authentication() @@ -218,7 +218,7 @@ private static OidcTenantConfig discord() { .authorizationPath("authorize") .tokenPath("token") .jwksPath("keys") - .token(true) + .token().verifyAccessTokenWithUserInfo(true).end() .authentication().scopes("identify", "email").idTokenRequired(false).end() .userInfoPath("https://discord.com/api/users/@me") .build(); diff --git a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigBuilderTest.java b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigBuilderTest.java index 50fa9f66815eb..a3bb7b8b92798 100644 --- a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigBuilderTest.java +++ b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigBuilderTest.java @@ -1089,7 +1089,7 @@ public void testTokenBuilder() { .requiredClaims(Map.of("III", "IV")) .audience("extra"); var config2 = second.end() - .token(false, "prince") + .token().verifyAccessTokenWithUserInfo(false).principalClaim("prince").end() .build(); var builtSecond = config2.token(); assertFalse(builtSecond.verifyAccessTokenWithUserInfo().orElseThrow()); @@ -1107,7 +1107,7 @@ public void testTokenBuilder() { assertTrue(builtSecond.audience().orElseThrow().contains("extra")); assertEquals("prince", builtSecond.principalClaim().orElse(null)); - var config3 = OidcTenantConfig.builder(config2).token(true).build(); + var config3 = OidcTenantConfig.builder(config2).token().verifyAccessTokenWithUserInfo().end().build(); assertTrue(config3.token().verifyAccessTokenWithUserInfo().orElseThrow()); assertEquals("haha", config3.tenantId().orElse(null)); From 070bf60a795c0a393880168e71e7f3615543cb62 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Tue, 17 Dec 2024 22:53:41 +0000 Subject: [PATCH 164/207] Make abstract OIDC config classes undeprecated --- .../quarkus/oidc/common/runtime/OidcClientCommonConfig.java | 4 ---- .../java/io/quarkus/oidc/common/runtime/OidcCommonConfig.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java index c7fa4e77f4882..355a707658208 100644 --- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcClientCommonConfig.java @@ -4,10 +4,6 @@ import java.util.Map; import java.util.Optional; -/** - * @deprecated use the {@link io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig} interface instead - */ -@Deprecated(since = "3.18") public abstract class OidcClientCommonConfig extends OidcCommonConfig implements io.quarkus.oidc.common.runtime.config.OidcClientCommonConfig { diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonConfig.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonConfig.java index 978c116d80827..705f23329a0d2 100644 --- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonConfig.java +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonConfig.java @@ -5,10 +5,6 @@ import java.util.Optional; import java.util.OptionalInt; -/** - * @deprecated use the {@link io.quarkus.oidc.common.runtime.config.OidcCommonConfig} interface instead - */ -@Deprecated(since = "3.18") public abstract class OidcCommonConfig implements io.quarkus.oidc.common.runtime.config.OidcCommonConfig { public OidcCommonConfig() { From 349d540e8275e0cd0f1cb543387c9ebcf78ff973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Barto=C5=A1?= Date: Tue, 17 Dec 2024 15:22:15 +0100 Subject: [PATCH 165/207] Unable to use custom handlers for HTTP OPTIONS method in subresources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #45173 Signed-off-by: Martin Bartoš --- .../resource/basic/ResourceLocatorTest.java | 50 ++++++++++++++++++- .../basic/resource/CorsPreflightResource.java | 17 +++++++ .../resource/ResourceLocatorBaseResource.java | 7 +++ .../resource/ResourceLocatorSubresource.java | 17 +++++++ .../resource/ResourceLocatorSubresource2.java | 11 +++- .../handlers/ResourceLocatorHandler.java | 42 ++++++++-------- 6 files changed, 121 insertions(+), 23 deletions(-) create mode 100644 extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/CorsPreflightResource.java diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/ResourceLocatorTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/ResourceLocatorTest.java index 2f610a82cce42..ba94a8dd38463 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/ResourceLocatorTest.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/ResourceLocatorTest.java @@ -1,10 +1,15 @@ package io.quarkus.resteasy.reactive.server.test.resource.basic; import static io.restassured.RestAssured.given; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import java.util.Arrays; import java.util.function.Supplier; +import jakarta.ws.rs.HttpMethod; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.Entity; @@ -22,6 +27,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import io.quarkus.resteasy.reactive.server.test.resource.basic.resource.CorsPreflightResource; import io.quarkus.resteasy.reactive.server.test.resource.basic.resource.ResourceLocatorAbstractAnnotationFreeResource; import io.quarkus.resteasy.reactive.server.test.resource.basic.resource.ResourceLocatorAnnotationFreeSubResource; import io.quarkus.resteasy.reactive.server.test.resource.basic.resource.ResourceLocatorBaseResource; @@ -68,7 +74,7 @@ public JavaArchive get() { JavaArchive war = ShrinkWrap.create(JavaArchive.class); war.addClass(ResourceLocatorQueueReceiver.class).addClass(ResourceLocatorReceiver.class) .addClass(ResourceLocatorRootInterface.class).addClass(ResourceLocatorSubInterface.class) - .addClass(ResourceLocatorSubresource3Interface.class); + .addClass(ResourceLocatorSubresource3Interface.class).addClass(CorsPreflightResource.class); war.addClasses(PortProviderUtil.class, ResourceLocatorAbstractAnnotationFreeResource.class, ResourceLocatorAnnotationFreeSubResource.class, ResourceLocatorBaseResource.class, ResourceLocatorCollectionResource.class, ResourceLocatorDirectory.class, @@ -114,6 +120,48 @@ public void testSubresource() throws Exception { } } + /** + * @tpTestDetails Return custom handler for HTTP OPTIONS method in subresource redirection. The + * {@link CorsPreflightResource} instance should be returned + */ + @Test + @DisplayName("Test custom HTTP OPTIONS handler in subresource") + public void testOptionsMethodInSubresource() { + try (Response response = client.target(generateURL("/sub3/something/resources/test-options-method")).request() + .options()) { + assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode())); + + var customHeader = response.getHeaderString(CorsPreflightResource.TEST_PREFLIGHT_HEADER); + assertThat(customHeader, notNullValue()); + assertThat(customHeader, is("test")); + + var allowHeader = response.getHeaderString("Allow"); + assertThat(allowHeader, notNullValue()); + assertThat(Arrays.asList(allowHeader.split(", ")), + containsInAnyOrder(HttpMethod.GET, HttpMethod.POST, HttpMethod.OPTIONS, HttpMethod.HEAD)); + } + } + + /** + * @tpTestDetails Custom handler for HTTP OPTIONS method in subresource. + */ + @Test + @DisplayName("Test custom explicit HTTP OPTIONS handler in subresource") + public void testOptionsMethodExplicitInSubresource() { + try (Response response = client.target(generateURL("/sub3/something/resources/test-options-method-explicit")).request() + .options()) { + assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode())); + + var customHeader = response.getHeaderString(ResourceLocatorSubresource2.TEST_PREFLIGHT_HEADER); + assertThat(customHeader, notNullValue()); + assertThat(customHeader, is("test")); + + var allowHeader = response.getHeaderString("Allow"); + assertThat(allowHeader, notNullValue()); + assertThat(Arrays.asList(allowHeader.split(", ")), containsInAnyOrder(HttpMethod.GET)); + } + } + /** * @tpTestDetails Two matching methods, one a resource locator, the other a resource method. * @tpSince RESTEasy 3.0.20 diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/CorsPreflightResource.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/CorsPreflightResource.java new file mode 100644 index 0000000000000..d1b56b49d77fa --- /dev/null +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/CorsPreflightResource.java @@ -0,0 +1,17 @@ +package io.quarkus.resteasy.reactive.server.test.resource.basic.resource; + +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.OPTIONS; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; + +public class CorsPreflightResource { + public static final String TEST_PREFLIGHT_HEADER = "preflight-header-test"; + + @Path("{any:.*}") + @OPTIONS + public Response preflight() { + return Response.ok().allow(HttpMethod.GET, HttpMethod.POST, HttpMethod.OPTIONS, HttpMethod.HEAD) + .header(TEST_PREFLIGHT_HEADER, "test").build(); + } +} diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorBaseResource.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorBaseResource.java index 308a4a738be87..ab09e88f1643c 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorBaseResource.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorBaseResource.java @@ -6,6 +6,7 @@ import java.util.List; import jakarta.ws.rs.GET; +import jakarta.ws.rs.OPTIONS; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; @@ -61,4 +62,10 @@ public ResourceLocatorSubresource getSubresource() { return new ResourceLocatorSubresource(); } + @OPTIONS + @Path("{any:.*}") + public Object preflight() { + return "Here might be a custom handler for HTTP OPTIONS method"; + } + } diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorSubresource.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorSubresource.java index dfb0d717642ef..58261ac763c3b 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorSubresource.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorSubresource.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.BeanParam; import jakarta.ws.rs.GET; +import jakarta.ws.rs.HttpMethod; import jakarta.ws.rs.Path; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; @@ -13,6 +14,8 @@ import org.jboss.resteasy.reactive.RestPath; import org.junit.jupiter.api.Assertions; +import io.vertx.core.http.HttpServerRequest; + public class ResourceLocatorSubresource { private static final Logger LOG = Logger.getLogger(ResourceLocatorSubresource.class); @@ -62,6 +65,20 @@ public String getValueFromBeanParam(@BeanParam Params params) { return params.param + " and " + params.value; } + @Path("/test-options-method-explicit") + public Object testOptionsMethodExplicit() { + return new ResourceLocatorSubresource2(); + } + + @Path("/test-options-method") + public Object testOptionsMethod(@Context HttpServerRequest request) { + if (request.method().name().equals(HttpMethod.OPTIONS)) { + return new CorsPreflightResource(); + } + + return "Should be used only with HTTP @OPTIONS method"; + } + public static class Params { @RestPath String param; diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorSubresource2.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorSubresource2.java index da745c63579ec..677ba369a33ec 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorSubresource2.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/resource/basic/resource/ResourceLocatorSubresource2.java @@ -1,16 +1,19 @@ package io.quarkus.resteasy.reactive.server.test.resource.basic.resource; import jakarta.ws.rs.GET; +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.OPTIONS; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriInfo; import org.jboss.logging.Logger; import org.junit.jupiter.api.Assertions; public class ResourceLocatorSubresource2 { - + public static final String TEST_PREFLIGHT_HEADER = "test-preflight-header"; private static final Logger LOG = Logger.getLogger(ResourceLocatorSubresource2.class); @GET @@ -35,4 +38,10 @@ public String doGet(@PathParam("param") String param, @Context UriInfo uri) { Assertions.assertEquals("2", param); return this.getClass().getName() + "-" + param; } + + @OPTIONS + @Path("{any:.*}") + public Response preflight() { + return Response.ok().allow(HttpMethod.GET).header(TEST_PREFLIGHT_HEADER, "test").build(); + } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResourceLocatorHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResourceLocatorHandler.java index 83215887b91af..9dafe4e57b544 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResourceLocatorHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResourceLocatorHandler.java @@ -63,29 +63,29 @@ public void onComplete(Throwable throwable) { RequestMapper mapper = target.get(requestContext.getMethod()); boolean hadNullMethodMapper = false; if (mapper == null) { - String requestMethod = requestContext.getMethod(); - if (requestMethod.equals(HttpMethod.HEAD)) { - mapper = target.get(HttpMethod.GET); - } else if (requestMethod.equals(HttpMethod.OPTIONS)) { - Set allowedMethods = new HashSet<>(); - for (String method : target.keySet()) { - if (method == null) { - continue; - } - allowedMethods.add(method); - } - allowedMethods.add(HttpMethod.OPTIONS); - allowedMethods.add(HttpMethod.HEAD); - requestContext.abortWith(Response.ok().allow(allowedMethods).build()); - return; - } + mapper = target.get(null); //another layer of resource locators maybe + // we set this without checking if we matched, but we only use it after + // we check for a null mapper, so by the time we use it, it must have meant that + // we had a matcher for a null method + hadNullMethodMapper = true; if (mapper == null) { - mapper = target.get(null); //another layer of resource locators maybe - // we set this without checking if we matched, but we only use it after - // we check for a null mapper, so by the time we use it, it must have meant that - // we had a matcher for a null method - hadNullMethodMapper = true; + String requestMethod = requestContext.getMethod(); + if (requestMethod.equals(HttpMethod.HEAD)) { + mapper = target.get(HttpMethod.GET); + } else if (requestMethod.equals(HttpMethod.OPTIONS)) { + Set allowedMethods = new HashSet<>(); + for (String method : target.keySet()) { + if (method == null) { + continue; + } + allowedMethods.add(method); + } + allowedMethods.add(HttpMethod.OPTIONS); + allowedMethods.add(HttpMethod.HEAD); + requestContext.abortWith(Response.ok().allow(allowedMethods).build()); + return; + } } } if (mapper == null) { From 49ee0bc7c954d8b7a1f67b87a64fce5b2ed6ae61 Mon Sep 17 00:00:00 2001 From: Francesco Nigro Date: Wed, 18 Dec 2024 12:27:07 +0100 Subject: [PATCH 166/207] Sys prop configuration to leverage SSL heap buffer pooling --- .../options/HttpServerOptionsUtils.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/options/HttpServerOptionsUtils.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/options/HttpServerOptionsUtils.java index f270cc64b2bd6..dc441ca8d25c4 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/options/HttpServerOptionsUtils.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/options/HttpServerOptionsUtils.java @@ -39,12 +39,15 @@ import io.vertx.core.http.HttpVersion; import io.vertx.core.net.JdkSSLEngineOptions; import io.vertx.core.net.KeyCertOptions; +import io.vertx.core.net.TCPSSLOptions; import io.vertx.core.net.TrafficShapingOptions; import io.vertx.core.net.TrustOptions; @SuppressWarnings("OptionalIsPresent") public class HttpServerOptionsUtils { + private static final boolean JDK_SSL_BUFFER_POOLING = Boolean.getBoolean("quarkus.http.server.ssl.jdk.bufferPooling"); + /** * When the http port is set to 0, replace it by this value to let Vert.x choose a random port */ @@ -172,6 +175,7 @@ private static void applySslConfigToHttpServerOptions(ServerSslConfig httpConfig serverOptions.setEnabledSecureTransportProtocols(sslConfig.protocols); serverOptions.setSsl(true); serverOptions.setSni(sslConfig.sni); + setJdkHeapBufferPooling(serverOptions); } /** @@ -214,6 +218,7 @@ public static HttpServerOptions createSslOptionsForManagementInterface(Managemen public static void applyTlsConfigurationToHttpServerOptions(TlsConfiguration bucket, HttpServerOptions serverOptions) { serverOptions.setSsl(true); + setJdkHeapBufferPooling(serverOptions); KeyCertOptions keyStoreOptions = bucket.getKeyStoreOptions(); TrustOptions trustStoreOptions = bucket.getTrustStoreOptions(); @@ -240,6 +245,20 @@ public static void applyTlsConfigurationToHttpServerOptions(TlsConfiguration buc serverOptions.setEnabledSecureTransportProtocols(other.getEnabledSecureTransportProtocols()); } + private static void setJdkHeapBufferPooling(TCPSSLOptions tcpSslOptions) { + if (!JDK_SSL_BUFFER_POOLING) { + return; + } + var engineOption = tcpSslOptions.getSslEngineOptions(); + if (engineOption == null) { + var jdkEngineOptions = new JdkSSLEngineOptions(); + jdkEngineOptions.setPooledHeapBuffers(true); + tcpSslOptions.setSslEngineOptions(jdkEngineOptions); + } else if (engineOption instanceof JdkSSLEngineOptions jdkEngineOptions) { + jdkEngineOptions.setPooledHeapBuffers(true); + } + } + public static Optional getCredential(Optional password, Map credentials, Optional passwordKey) { if (password.isPresent()) { From 38f44a759e77ab8599788b0faa40f2668ff1a1e4 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Wed, 18 Dec 2024 17:37:49 +0100 Subject: [PATCH 167/207] Fix matrix computation for Ubuntu 24 --- .github/workflows/ci-actions-incremental.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index df2ab3edf07bd..ab05cfdb4c270 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -315,13 +315,13 @@ jobs: elif [ "${GIB_IMPACTED_MODULES}" != '_all_' ] then # Important: keep -pl ... in actual jobs in sync with the following grep commands! - if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -qPv 'integration-tests/(devtools|gradle|maven|devmode|kubernetes/.*)|tcks/.*'; then run_jvm=false; fi - if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/devtools'; then run_devtools=false; fi - if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/gradle'; then run_gradle=false; fi - if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -qP 'integration-tests/(maven|devmode)'; then run_maven=false; fi - if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -qP 'integration-tests/kubernetes/.*'; then run_kubernetes=false; fi - if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -qPv '(docs|integration-tests|tcks)/.*'; then run_quickstarts=false; fi - if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'tcks/.*'; then run_tcks=false; fi + if ! (echo -n "${GIB_IMPACTED_MODULES}" | grep -qPv 'integration-tests/(devtools|gradle|maven|devmode|kubernetes/.*)|tcks/.*'); then run_jvm=false; fi + if ! (echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/devtools'); then run_devtools=false; fi + if ! (echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/gradle'); then run_gradle=false; fi + if ! (echo -n "${GIB_IMPACTED_MODULES}" | grep -qP 'integration-tests/(maven|devmode)'); then run_maven=false; fi + if ! (echo -n "${GIB_IMPACTED_MODULES}" | grep -qP 'integration-tests/kubernetes/.*'); then run_kubernetes=false; fi + if ! (echo -n "${GIB_IMPACTED_MODULES}" | grep -qPv '(docs|integration-tests|tcks)/.*'); then run_quickstarts=false; fi + if ! (echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'tcks/.*'); then run_tcks=false; fi fi echo "run_jvm=${run_jvm}, run_devtools=${run_devtools}, run_gradle=${run_gradle}, run_maven=${run_maven}, run_kubernetes=${run_kubernetes}, run_quickstarts=${run_quickstarts}, run_tcks=${run_tcks}" echo "run_jvm=${run_jvm}" >> $GITHUB_OUTPUT From 92683ec9c1800ab45eed4c626dc323330ca66cd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:21:27 +0000 Subject: [PATCH 168/207] Bump smallrye-reactive-messaging.version from 4.25.0 to 4.26.0 Bumps `smallrye-reactive-messaging.version` from 4.25.0 to 4.26.0. Updates `io.smallrye.reactive:smallrye-reactive-messaging-bom` from 4.25.0 to 4.26.0 - [Release notes](https://github.com/smallrye/smallrye-reactive-messaging/releases) - [Commits](https://github.com/smallrye/smallrye-reactive-messaging/compare/4.25.0...4.26.0) Updates `io.smallrye.reactive:smallrye-reactive-messaging-kafka` from 4.25.0 to 4.26.0 - [Release notes](https://github.com/smallrye/smallrye-reactive-messaging/releases) - [Commits](https://github.com/smallrye/smallrye-reactive-messaging/compare/4.25.0...4.26.0) Updates `io.smallrye.reactive:smallrye-reactive-messaging-kafka-test-companion` from 4.25.0 to 4.26.0 - [Release notes](https://github.com/smallrye/smallrye-reactive-messaging/releases) - [Commits](https://github.com/smallrye/smallrye-reactive-messaging/compare/4.25.0...4.26.0) Updates `io.smallrye.reactive:smallrye-reactive-messaging-amqp` from 4.25.0 to 4.26.0 - [Release notes](https://github.com/smallrye/smallrye-reactive-messaging/releases) - [Commits](https://github.com/smallrye/smallrye-reactive-messaging/compare/4.25.0...4.26.0) --- updated-dependencies: - dependency-name: io.smallrye.reactive:smallrye-reactive-messaging-bom dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.smallrye.reactive:smallrye-reactive-messaging-kafka dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.smallrye.reactive:smallrye-reactive-messaging-kafka-test-companion dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.smallrye.reactive:smallrye-reactive-messaging-amqp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index ca79a8b267fb3..438a102c0249a 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -58,7 +58,7 @@ 1.0.13 3.0.1 3.17.1 - 4.25.0 + 4.26.0 2.7.0 2.1.3 3.0.0 From 7ea2da22fe9d3c01ec9409da64fadd80311e5e4d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 23:43:22 +0000 Subject: [PATCH 169/207] Bump gradle/develocity-actions from 1.2 to 1.3 Bumps [gradle/develocity-actions](https://github.com/gradle/develocity-actions) from 1.2 to 1.3. - [Release notes](https://github.com/gradle/develocity-actions/releases) - [Commits](https://github.com/gradle/develocity-actions/compare/v1.2...v1.3) --- updated-dependencies: - dependency-name: gradle/develocity-actions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-actions-incremental.yml | 20 +++++++++---------- .../develocity-publish-build-scans.yml | 4 ++-- .../workflows/native-it-selected-graalvm.yml | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index ab05cfdb4c270..463b858b3e82b 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -183,7 +183,7 @@ jobs: - name: Verify virtual-threads-tests.json run: ./.github/verify-tests-json.sh virtual-threads-tests.json integration-tests/virtual-threads/ - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Initial JDK 17 Build" @@ -420,7 +420,7 @@ jobs: restore-keys: | develocity-cache-JVM Tests - JDK ${{matrix.java.name}}-${{ github.event.pull_request.number }}- - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "JVM Tests - JDK ${{matrix.java.name}}" @@ -542,7 +542,7 @@ jobs: distribution: temurin java-version: ${{ matrix.java.java-version }} - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Maven Tests - JDK ${{matrix.java.name}}" @@ -649,7 +649,7 @@ jobs: if: "!startsWith(matrix.java.os-name, 'windows')" run: ./integration-tests/gradle/update-dependencies.sh $COMMON_MAVEN_ARGS -Dscan=false - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Gradle Tests - JDK ${{matrix.java.name}}" @@ -736,7 +736,7 @@ jobs: distribution: temurin java-version: ${{ matrix.java.java-version }} - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Devtools Tests - JDK ${{matrix.java.name}}" @@ -832,7 +832,7 @@ jobs: distribution: temurin java-version: ${{ matrix.java.java-version }} - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Kubernetes Tests - JDK ${{matrix.java.name}}" @@ -915,7 +915,7 @@ jobs: distribution: temurin java-version: ${{ matrix.java.java-version }} - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Quickstarts Compilation - JDK ${{matrix.java.name}}" @@ -1010,7 +1010,7 @@ jobs: cat <<< $(jq '.HttpHeaders += {"User-Agent": "Quarkus-CI-Docker-Client"}' ~/.docker/config.json) > ~/.docker/config.json fi - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Native Tests - Virtual Thread - ${{matrix.category}}" @@ -1083,7 +1083,7 @@ jobs: - name: Extract previously uploaded .m2 content run: tar -xzf m2-content.tgz -C ~ - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "MicroProfile TCKs Tests" @@ -1196,7 +1196,7 @@ jobs: - name: Extract previously uploaded .m2 content run: tar -xzf m2-content.tgz -C ~ - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Native Tests - ${{matrix.category}}" diff --git a/.github/workflows/develocity-publish-build-scans.yml b/.github/workflows/develocity-publish-build-scans.yml index b2397adda8fa4..5b622e3f161dd 100644 --- a/.github/workflows/develocity-publish-build-scans.yml +++ b/.github/workflows/develocity-publish-build-scans.yml @@ -20,13 +20,13 @@ jobs: steps: - name: Setup Build Scan link capture id: setup - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: add-pr-comment: false add-job-summary: true - name: Publish Maven Build Scans id: publish - uses: gradle/develocity-actions/maven-publish-build-scan@v1.2 + uses: gradle/develocity-actions/maven-publish-build-scan@v1.3 with: develocity-url: 'https://ge.quarkus.io' develocity-access-key: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} diff --git a/.github/workflows/native-it-selected-graalvm.yml b/.github/workflows/native-it-selected-graalvm.yml index 72f5db318beb2..38d77b3354ea9 100644 --- a/.github/workflows/native-it-selected-graalvm.yml +++ b/.github/workflows/native-it-selected-graalvm.yml @@ -103,7 +103,7 @@ jobs: - name: Verify virtual-threads-tests.json run: ./.github/verify-tests-json.sh virtual-threads-tests.json integration-tests/virtual-threads/ - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Initial JDK 17 Build" @@ -266,7 +266,7 @@ jobs: cat <<< $(jq '.HttpHeaders += {"User-Agent": "Quarkus-CI-Docker-Client"}' ~/.docker/config.json) > ~/.docker/config.json fi - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Native Tests - Virtual Thread - ${{matrix.category}}" @@ -353,7 +353,7 @@ jobs: - name: Extract .m2/repository/io/quarkus run: tar -xzf m2-io-quarkus.tgz -C ~ - name: Setup Develocity Build Scan capture - uses: gradle/develocity-actions/setup-maven@v1.2 + uses: gradle/develocity-actions/setup-maven@v1.3 with: capture-strategy: ON_DEMAND job-name: "Native Tests - ${{matrix.category}}" From b8f570cc6a96dd5bcb2126f3c4f9b978002c5d51 Mon Sep 17 00:00:00 2001 From: Akulov S V Date: Thu, 19 Dec 2024 00:12:30 +0300 Subject: [PATCH 170/207] Documenting Rest Client TLS Registry usage disabling SSL --- docs/src/main/asciidoc/rest-client.adoc | 31 ++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/src/main/asciidoc/rest-client.adoc b/docs/src/main/asciidoc/rest-client.adoc index 3c2c2a2be1d30..cec13b5a7bd6c 100644 --- a/docs/src/main/asciidoc/rest-client.adoc +++ b/docs/src/main/asciidoc/rest-client.adoc @@ -492,18 +492,33 @@ quarkus.rest-client.extensions-api.scope=jakarta.inject.Singleton Setting the base URL of the client is **mandatory**, however the REST Client supports per-invocation overrides of the base URL using the `@io.quarkus.rest.client.reactive.Url` annotation. ==== -=== Disabling Hostname Verification +=== Trusting all certificates and Disabling SSL hostname verification -To disable the SSL hostname verification for a specific REST client, add the following property to your configuration: +[WARNING] +==== +This properties set should not be used in production. +==== + +You can configure TLS connection of specific REST client to trust all certificates and disable the hostname verification using tls extension. +First of all, you should configure tls configuration bucket. +To trust all certificates: [source,properties] ---- -quarkus.rest-client.extensions-api.verify-host=false +quarkus.tls.tls-disabled.trust-all=true +---- + +To disable SSL hostname verification: +[source,properties] +---- +quarkus.tls.tls-disabled.hostname-verification-algorithm=NONE +---- + +Finally, lets configure our REST client with apropriate tls configuration name: +[source,properties] +---- +quarkus.rest-client.extensions-api.tls-configuration-name=tls-disabled ---- -[WARNING] -==== -This setting should not be used in production as it will disable the SSL hostname verification. -==== === HTTP/2 Support @@ -2086,7 +2101,7 @@ and limitations: - the default scope of the client for the new extension is `@ApplicationScoped` while the `quarkus-resteasy-client` defaults to `@Dependent` To change this behavior, set the `quarkus.rest-client.scope` property to the fully qualified scope name. -- it is not possible to set `HostnameVerifier` or `SSLContext` +- it is not possible to set `SSLContext` - a few things that don't make sense for a non-blocking implementations, such as setting the `ExecutorService`, don't work == Further reading From 7dd16de68c0f50340ccd2bd42cb1cf9beab4b689 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Thu, 19 Dec 2024 07:27:58 -0300 Subject: [PATCH 171/207] Revert "Bump org.junit:junit-bom from 5.10.5 to 5.11.4 in /devtools/gradle" --- devtools/gradle/gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/gradle/gradle/libs.versions.toml b/devtools/gradle/gradle/libs.versions.toml index 2497c6e17b349..e4b86cbd74791 100644 --- a/devtools/gradle/gradle/libs.versions.toml +++ b/devtools/gradle/gradle/libs.versions.toml @@ -5,7 +5,7 @@ plugin-publish = "1.3.0" kotlin = "2.0.21" smallrye-config = "3.10.2" -junit5 = "5.11.4" +junit5 = "5.10.5" assertj = "3.26.3" [plugins] From ecd59b49404e0cf8ea15ea779bd124f1b8e18f9c Mon Sep 17 00:00:00 2001 From: Roberto Balarezo Date: Thu, 19 Dec 2024 05:23:31 -0500 Subject: [PATCH 172/207] Fix NPE in ClientResponseFilterRestHandler. --- .../client/handlers/ClientResponseFilterRestHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientResponseFilterRestHandler.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientResponseFilterRestHandler.java index b5c8db5a7b1b9..f5593fe76d46d 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientResponseFilterRestHandler.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientResponseFilterRestHandler.java @@ -18,7 +18,8 @@ public ClientResponseFilterRestHandler(ClientResponseFilter filter) { @Override public void handle(RestClientRequestContext requestContext) throws Exception { try { - filter.filter(requestContext.getClientRequestContext(), requestContext.getOrCreateClientResponseContext()); + filter.filter(requestContext.getOrCreateClientRequestContext(), + requestContext.getOrCreateClientResponseContext()); } catch (WebApplicationException | ProcessingException x) { throw x; } catch (Exception x) { From a2fbed4bbfe4d52d8985cc9fdab2390859262541 Mon Sep 17 00:00:00 2001 From: Ozan Gunalp Date: Wed, 18 Dec 2024 23:40:06 +0100 Subject: [PATCH 173/207] Inject DevServicesContext in QuarkusTest --- .../devservices/DevServicesContextSpy.java | 32 ----------------- ...archDevServicesDisabledExplicitlyTest.java | 7 ---- ...archDevServicesDisabledImplicitlyTest.java | 7 ---- ...earchDevServicesEnabledImplicitlyTest.java | 8 ----- .../devservices/DevServicesContextSpy.java | 32 ----------------- ...chDevServicesConfiguredExplicitlyTest.java | 6 ---- ...archDevServicesDisabledExplicitlyTest.java | 7 ---- ...archDevServicesDisabledImplicitlyTest.java | 7 ---- ...earchDevServicesEnabledImplicitlyTest.java | 8 ----- .../devservices/DevServicesContextSpy.java | 32 ----------------- ...archDevServicesDisabledExplicitlyTest.java | 6 ---- ...archDevServicesDisabledImplicitlyTest.java | 6 ---- ...earchDevServicesEnabledImplicitlyTest.java | 7 ---- .../devservices/DevServicesContextSpy.java | 32 ----------------- ...archDevServicesDisabledExplicitlyTest.java | 7 ---- ...archDevServicesDisabledImplicitlyTest.java | 6 ---- ...earchDevServicesEnabledImplicitlyTest.java | 8 ----- .../RabbitMQDevServiceTopologyTest.java | 36 ++++++++++--------- .../test/common/TestResourceManager.java | 33 +++++++++++++++-- .../QuarkusIntegrationTestExtension.java | 36 ------------------- 20 files changed, 51 insertions(+), 272 deletions(-) delete mode 100644 integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/DevServicesContextSpy.java delete mode 100644 integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/DevServicesContextSpy.java delete mode 100644 integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/DevServicesContextSpy.java delete mode 100644 integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/DevServicesContextSpy.java diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/DevServicesContextSpy.java b/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/DevServicesContextSpy.java deleted file mode 100644 index c2c08bcff10be..0000000000000 --- a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/DevServicesContextSpy.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.quarkus.it.hibernate.search.orm.elasticsearch.devservices; - -import java.util.Collections; -import java.util.Map; - -import io.quarkus.test.common.DevServicesContext; -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; - -public class DevServicesContextSpy implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { - - DevServicesContext devServicesContext; - - @Override - public void setIntegrationTestContext(DevServicesContext context) { - this.devServicesContext = context; - } - - @Override - public Map start() { - return Collections.emptyMap(); - } - - @Override - public void inject(TestInjector testInjector) { - testInjector.injectIntoFields(devServicesContext, f -> f.getType().isAssignableFrom(DevServicesContext.class)); - } - - @Override - public void stop() { - - } -} diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledExplicitlyTest.java b/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledExplicitlyTest.java index 83f6c783fbbaa..8e2fd63e27479 100644 --- a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledExplicitlyTest.java +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledExplicitlyTest.java @@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.is; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -49,12 +48,6 @@ public String getConfigProfile() { // In this test, we do NOT set quarkus.hibernate-search-orm.elasticsearch.hosts. return "someotherprofile"; } - - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledImplicitlyTest.java b/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledImplicitlyTest.java index 768ead7d20475..efe94e41559fc 100644 --- a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledImplicitlyTest.java +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledImplicitlyTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -47,12 +46,6 @@ public String getConfigProfile() { // In this test, we DO set quarkus.hibernate-search-orm.elasticsearch.hosts (see above). return "someotherprofile"; } - - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesEnabledImplicitlyTest.java b/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesEnabledImplicitlyTest.java index 2667f733e5857..95d1826040cb8 100644 --- a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesEnabledImplicitlyTest.java +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesEnabledImplicitlyTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; -import java.util.List; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; @@ -27,12 +25,6 @@ public String getConfigProfile() { // In this test, we do NOT set quarkus.hibernate-search-orm.elasticsearch.hosts. return "someotherprofile"; } - - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/DevServicesContextSpy.java b/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/DevServicesContextSpy.java deleted file mode 100644 index c4d78dd73aaa4..0000000000000 --- a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/DevServicesContextSpy.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.quarkus.it.hibernate.search.orm.opensearch.devservices; - -import java.util.Collections; -import java.util.Map; - -import io.quarkus.test.common.DevServicesContext; -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; - -public class DevServicesContextSpy implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { - - DevServicesContext devServicesContext; - - @Override - public void setIntegrationTestContext(DevServicesContext context) { - this.devServicesContext = context; - } - - @Override - public Map start() { - return Collections.emptyMap(); - } - - @Override - public void inject(TestInjector testInjector) { - testInjector.injectIntoFields(devServicesContext, f -> f.getType().isAssignableFrom(DevServicesContext.class)); - } - - @Override - public void stop() { - - } -} diff --git a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesConfiguredExplicitlyTest.java b/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesConfiguredExplicitlyTest.java index 12b7385638b0e..7185a0f296cc2 100644 --- a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesConfiguredExplicitlyTest.java +++ b/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesConfiguredExplicitlyTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -40,11 +39,6 @@ public String getConfigProfile() { return "someotherprofile"; } - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledExplicitlyTest.java b/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledExplicitlyTest.java index 05e418748ab6c..2aadb26c771ad 100644 --- a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledExplicitlyTest.java +++ b/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledExplicitlyTest.java @@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.is; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -49,12 +48,6 @@ public String getConfigProfile() { // In this test, we do NOT set quarkus.hibernate-search-orm.elasticsearch.hosts. return "someotherprofile"; } - - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledImplicitlyTest.java b/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledImplicitlyTest.java index ac9a8b06bd270..80163bbff07e1 100644 --- a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledImplicitlyTest.java +++ b/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledImplicitlyTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -47,12 +46,6 @@ public String getConfigProfile() { // In this test, we DO set quarkus.hibernate-search-orm.elasticsearch.hosts (see above). return "someotherprofile"; } - - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesEnabledImplicitlyTest.java b/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesEnabledImplicitlyTest.java index 1287d5823c65f..4ec25d37e9a7f 100644 --- a/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesEnabledImplicitlyTest.java +++ b/integration-tests/hibernate-search-orm-opensearch/src/test/java/io/quarkus/it/hibernate/search/orm/opensearch/devservices/HibernateSearchOpenSearchDevServicesEnabledImplicitlyTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; -import java.util.List; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; @@ -28,12 +26,6 @@ public String getConfigProfile() { // In this test, we do NOT set quarkus.hibernate-search-orm.elasticsearch.hosts. return "someotherprofile"; } - - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/DevServicesContextSpy.java b/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/DevServicesContextSpy.java deleted file mode 100644 index 7ccf9233bdc44..0000000000000 --- a/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/DevServicesContextSpy.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.quarkus.it.hibernate.search.standalone.elasticsearch.devservices; - -import java.util.Collections; -import java.util.Map; - -import io.quarkus.test.common.DevServicesContext; -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; - -public class DevServicesContextSpy implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { - - DevServicesContext devServicesContext; - - @Override - public void setIntegrationTestContext(DevServicesContext context) { - this.devServicesContext = context; - } - - @Override - public Map start() { - return Collections.emptyMap(); - } - - @Override - public void inject(TestInjector testInjector) { - testInjector.injectIntoFields(devServicesContext, f -> f.getType().isAssignableFrom(DevServicesContext.class)); - } - - @Override - public void stop() { - - } -} diff --git a/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledExplicitlyTest.java b/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledExplicitlyTest.java index 5a32300a279d2..f824fc3f736fe 100644 --- a/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledExplicitlyTest.java +++ b/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledExplicitlyTest.java @@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.is; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -50,11 +49,6 @@ public String getConfigProfile() { return "someotherprofile"; } - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledImplicitlyTest.java b/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledImplicitlyTest.java index a5c43c6a6f9cf..6ef6ef2bd17e2 100644 --- a/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledImplicitlyTest.java +++ b/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesDisabledImplicitlyTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -48,11 +47,6 @@ public String getConfigProfile() { return "someotherprofile"; } - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesEnabledImplicitlyTest.java b/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesEnabledImplicitlyTest.java index e1bbaa08dcd27..bea2b0dbe4b1b 100644 --- a/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesEnabledImplicitlyTest.java +++ b/integration-tests/hibernate-search-standalone-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/standalone/elasticsearch/devservices/HibernateSearchElasticsearchDevServicesEnabledImplicitlyTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; -import java.util.List; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; @@ -28,11 +26,6 @@ public String getConfigProfile() { return "someotherprofile"; } - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/DevServicesContextSpy.java b/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/DevServicesContextSpy.java deleted file mode 100644 index 9f3ddf585fbb8..0000000000000 --- a/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/DevServicesContextSpy.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.quarkus.it.hibernate.search.standalone.opensearch.devservices; - -import java.util.Collections; -import java.util.Map; - -import io.quarkus.test.common.DevServicesContext; -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; - -public class DevServicesContextSpy implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { - - DevServicesContext devServicesContext; - - @Override - public void setIntegrationTestContext(DevServicesContext context) { - this.devServicesContext = context; - } - - @Override - public Map start() { - return Collections.emptyMap(); - } - - @Override - public void inject(TestInjector testInjector) { - testInjector.injectIntoFields(devServicesContext, f -> f.getType().isAssignableFrom(DevServicesContext.class)); - } - - @Override - public void stop() { - - } -} diff --git a/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledExplicitlyTest.java b/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledExplicitlyTest.java index 024a463b9b38c..a794bb91c0cdc 100644 --- a/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledExplicitlyTest.java +++ b/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledExplicitlyTest.java @@ -4,7 +4,6 @@ import static org.hamcrest.Matchers.is; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -49,12 +48,6 @@ public String getConfigProfile() { // In this test, we do NOT set quarkus.hibernate-search-standalone.elasticsearch.hosts. return "someotherprofile"; } - - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledImplicitlyTest.java b/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledImplicitlyTest.java index c91b2b245d6ad..246a745b10f86 100644 --- a/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledImplicitlyTest.java +++ b/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesDisabledImplicitlyTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -48,11 +47,6 @@ public String getConfigProfile() { return "someotherprofile"; } - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesEnabledImplicitlyTest.java b/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesEnabledImplicitlyTest.java index b3759a207d67e..0e7a317ba0206 100644 --- a/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesEnabledImplicitlyTest.java +++ b/integration-tests/hibernate-search-standalone-opensearch/src/test/java/io/quarkus/it/hibernate/search/standalone/opensearch/devservices/HibernateSearchOpenSearchDevServicesEnabledImplicitlyTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; -import java.util.List; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; @@ -27,12 +25,6 @@ public String getConfigProfile() { // In this test, we do NOT set quarkus.hibernate-search-standalone.elasticsearch.hosts. return "someotherprofile"; } - - @Override - public List testResources() { - // Enables injection of DevServicesContext - return List.of(new TestResourceEntry(DevServicesContextSpy.class)); - } } DevServicesContext context; diff --git a/integration-tests/reactive-messaging-rabbitmq-devservices/src/test/java/io/quarkus/it/rabbitmq/RabbitMQDevServiceTopologyTest.java b/integration-tests/reactive-messaging-rabbitmq-devservices/src/test/java/io/quarkus/it/rabbitmq/RabbitMQDevServiceTopologyTest.java index 64d0f0a4d1c9a..b845891c91efb 100644 --- a/integration-tests/reactive-messaging-rabbitmq-devservices/src/test/java/io/quarkus/it/rabbitmq/RabbitMQDevServiceTopologyTest.java +++ b/integration-tests/reactive-messaging-rabbitmq-devservices/src/test/java/io/quarkus/it/rabbitmq/RabbitMQDevServiceTopologyTest.java @@ -1,12 +1,11 @@ package io.quarkus.it.rabbitmq; -import static io.restassured.RestAssured.get; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; -import org.eclipse.microprofile.config.inject.ConfigProperty; import org.junit.jupiter.api.Test; +import io.quarkus.test.common.DevServicesContext; import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.restassured.http.ContentType; @@ -14,20 +13,25 @@ @QuarkusTest public class RabbitMQDevServiceTopologyTest { - @ConfigProperty(name = "rabbitmq-username") - String username; + DevServicesContext context; - @ConfigProperty(name = "rabbitmq-password") - String password; + public String getUsername() { + return context.devServicesProperties().get("rabbitmq-username"); + } + + public String getPassword() { + return context.devServicesProperties().get("rabbitmq-password"); + } - @ConfigProperty(name = "rabbitmq-http-port") - int rabbitMqHttpPort; + public int getRabbitMqHttpPort() { + return Integer.parseInt(context.devServicesProperties().get("rabbitmq-http-port")); + } @Test public void testVhosts() { RestAssured.given() - .port(rabbitMqHttpPort) - .auth().preemptive().basic(username, password) + .port(getRabbitMqHttpPort()) + .auth().preemptive().basic(getUsername(), getPassword()) .when().get("/api/vhosts") .then() .statusCode(200) @@ -38,8 +42,8 @@ public void testVhosts() { @Test public void testExchanges() { RestAssured.given() - .port(rabbitMqHttpPort) - .auth().preemptive().basic(username, password) + .port(getRabbitMqHttpPort()) + .auth().preemptive().basic(getUsername(), getPassword()) .when().get("/api/exchanges/my-vhost-1/my-exchange-1") .then() .statusCode(200) @@ -50,8 +54,8 @@ public void testExchanges() { @Test public void testQueues() { RestAssured.given() - .port(rabbitMqHttpPort) - .auth().preemptive().basic(username, password) + .port(getRabbitMqHttpPort()) + .auth().preemptive().basic(getUsername(), getPassword()) .when().get("/api/queues/my-vhost-1/my-queue-1") .then() .statusCode(200) @@ -62,8 +66,8 @@ public void testQueues() { @Test public void testBindings() { RestAssured.given() - .port(rabbitMqHttpPort) - .auth().preemptive().basic(username, password) + .port(getRabbitMqHttpPort()) + .auth().preemptive().basic(getUsername(), getPassword()) .when().get("/api/bindings/my-vhost-1/e/my-exchange-1/q/my-queue-1") .then() .statusCode(200) diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java b/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java index 176751c654bf4..b7dc8f2467de3 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java @@ -51,6 +51,7 @@ public class TestResourceManager implements Closeable { private final List allTestResources; private final Map configProperties = new ConcurrentHashMap<>(); private final Set testResourceComparisonInfo; + private final DevServicesContext devServicesContext; private boolean started = false; @@ -115,7 +116,7 @@ public TestResourceManager(Class testClass, this.allTestResources = new ArrayList<>(sequentialTestResources); this.allTestResources.addAll(parallelTestResources); - DevServicesContext context = new DevServicesContext() { + this.devServicesContext = new DevServicesContext() { @Override public Map devServicesProperties() { return devServicesProperties; @@ -128,7 +129,7 @@ public Optional containerNetworkId() { }; for (var i : allTestResources) { if (i.getTestResource() instanceof DevServicesContext.ContextAware) { - ((DevServicesContext.ContextAware) i.getTestResource()).setIntegrationTestContext(context); + ((DevServicesContext.ContextAware) i.getTestResource()).setIntegrationTestContext(devServicesContext); } } } @@ -193,6 +194,7 @@ public Map start() { } public void inject(Object testInstance) { + injectTestContext(testInstance, devServicesContext); for (TestResourceStartInfo entry : allTestResources) { QuarkusTestResourceLifecycleManager quarkusTestResourceLifecycleManager = entry.getTestResource(); quarkusTestResourceLifecycleManager.inject(testInstance); @@ -200,6 +202,33 @@ public void inject(Object testInstance) { } } + private static void injectTestContext(Object testInstance, DevServicesContext context) { + Class c = testInstance.getClass(); + while (c != Object.class) { + for (Field f : c.getDeclaredFields()) { + if (f.getType().equals(DevServicesContext.class)) { + try { + f.setAccessible(true); + f.set(testInstance, context); + return; + } catch (Exception e) { + throw new RuntimeException("Unable to set field '" + f.getName() + + "' with the proper test context", e); + } + } else if (DevServicesContext.ContextAware.class.isAssignableFrom(f.getType())) { + f.setAccessible(true); + try { + DevServicesContext.ContextAware val = (DevServicesContext.ContextAware) f.get(testInstance); + val.setIntegrationTestContext(context); + } catch (Exception e) { + throw new RuntimeException("Unable to inject context into field " + f.getName(), e); + } + } + } + c = c.getSuperclass(); + } + } + public void close() { if (!started) { return; diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java index 1c1b3c7429c00..3b81cdbc17ffd 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java @@ -17,7 +17,6 @@ import java.io.Closeable; import java.io.File; -import java.lang.reflect.Field; import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; @@ -327,44 +326,9 @@ public void postProcessTestInstance(Object testInstance, ExtensionContext contex ensureStarted(context); if (!failedBoot) { doProcessTestInstance(testInstance, context); - injectTestContext(testInstance); } } - private void injectTestContext(Object testInstance) { - Class c = testInstance.getClass(); - while (c != Object.class) { - for (Field f : c.getDeclaredFields()) { - if (f.getType().equals(DevServicesContext.class)) { - try { - f.setAccessible(true); - f.set(testInstance, createTestContext()); - return; - } catch (Exception e) { - throw new RuntimeException("Unable to set field '" + f.getName() - + "' with the proper test context", e); - } - } else if (DevServicesContext.ContextAware.class.isAssignableFrom(f.getType())) { - f.setAccessible(true); - try { - DevServicesContext.ContextAware val = (DevServicesContext.ContextAware) f.get(testInstance); - val.setIntegrationTestContext(createTestContext()); - } catch (Exception e) { - throw new RuntimeException("Unable to inject context into field " + f.getName(), e); - } - } - } - c = c.getSuperclass(); - } - } - - private DevServicesContext createTestContext() { - Map devServicesPropsCopy = devServicesProps.isEmpty() ? Collections.emptyMap() - : Collections.unmodifiableMap(devServicesProps); - return new DefaultQuarkusIntegrationTestContext(devServicesPropsCopy, - containerNetworkId == null ? Optional.empty() : Optional.of(containerNetworkId)); - } - private void throwBootFailureException() { if (firstException != null) { Throwable throwable = firstException; From 98ec83390d15627c0ae7ce8f799e905002dd3dae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:39:53 +0000 Subject: [PATCH 174/207] Bump org.assertj:assertj-core from 3.26.3 to 3.27.0 in /devtools/gradle Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.26.3 to 3.27.0. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.26.3...assertj-build-3.27.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- devtools/gradle/gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/gradle/gradle/libs.versions.toml b/devtools/gradle/gradle/libs.versions.toml index e4b86cbd74791..5508dac5d2176 100644 --- a/devtools/gradle/gradle/libs.versions.toml +++ b/devtools/gradle/gradle/libs.versions.toml @@ -6,7 +6,7 @@ kotlin = "2.0.21" smallrye-config = "3.10.2" junit5 = "5.10.5" -assertj = "3.26.3" +assertj = "3.27.0" [plugins] plugin-publish = { id = "com.gradle.plugin-publish", version.ref = "plugin-publish" } From 2048e465c3efffc5ab72c36058ae303ae66d2c12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:41:32 +0000 Subject: [PATCH 175/207] Bump org.assertj:assertj-core from 3.26.3 to 3.27.0 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.26.3 to 3.27.0. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.26.3...assertj-build-3.27.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build-parent/pom.xml | 2 +- independent-projects/arc/pom.xml | 2 +- independent-projects/bootstrap/pom.xml | 2 +- independent-projects/junit5-virtual-threads/pom.xml | 2 +- independent-projects/qute/pom.xml | 2 +- independent-projects/resteasy-reactive/pom.xml | 2 +- independent-projects/tools/pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 55d0c44c63f34..dfbc9cd07aa5c 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -103,7 +103,7 @@ 7.0.2 - 3.26.3 + 3.27.0 3.10.0 7.3.0 diff --git a/independent-projects/arc/pom.xml b/independent-projects/arc/pom.xml index 701e14d510271..58403e9f51699 100644 --- a/independent-projects/arc/pom.xml +++ b/independent-projects/arc/pom.xml @@ -50,7 +50,7 @@ 2.7.0 1.6.Final - 3.26.3 + 3.27.0 5.10.5 2.0.21 1.9.0 diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml index 39d762f973fc0..495a5a5d39e30 100644 --- a/independent-projects/bootstrap/pom.xml +++ b/independent-projects/bootstrap/pom.xml @@ -38,7 +38,7 @@ 1.37 - 3.26.3 + 3.27.0 0.9.5 3.6.1.Final 5.10.5 diff --git a/independent-projects/junit5-virtual-threads/pom.xml b/independent-projects/junit5-virtual-threads/pom.xml index 49f61acb50aaa..74f65bcd81eb2 100644 --- a/independent-projects/junit5-virtual-threads/pom.xml +++ b/independent-projects/junit5-virtual-threads/pom.xml @@ -45,7 +45,7 @@ 5.10.5 1.10.3 - 3.26.3 + 3.27.0 diff --git a/independent-projects/qute/pom.xml b/independent-projects/qute/pom.xml index 14b10676dc719..7c8000ae97624 100644 --- a/independent-projects/qute/pom.xml +++ b/independent-projects/qute/pom.xml @@ -39,7 +39,7 @@ UTF-8 5.10.5 - 3.26.3 + 3.27.0 3.2.3 1.8.0 3.6.1.Final diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index 8e20aa76a3415..24ab75f5b7195 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -49,7 +49,7 @@ 1.14.11 5.10.5 3.9.9 - 3.26.3 + 3.27.0 3.6.1.Final 3.1.1.Final 3.0.0 diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml index 67a4ffceffeed..37aeeb9664e78 100644 --- a/independent-projects/tools/pom.xml +++ b/independent-projects/tools/pom.xml @@ -48,7 +48,7 @@ 4.4.0 - 3.26.3 + 3.27.0 2.18.2 4.1.0 5.10.5 From 4506a5e9c8b1074b3d63dbd1c04f70f6536ad5b9 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 09:18:57 +0200 Subject: [PATCH 176/207] Add tip about startup profiling --- TROUBLESHOOTING.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index b1f09a9da9249..fa0dd3f42dde1 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -133,6 +133,31 @@ Stop the application with `CTRL+C` once you have gathered what you want (e.g. ju It will dump the profiling information. The name of the file is in the `file=` parameter. +> [!TIP] +> You can avoid needing to stop the application manually by writing a custom main that stops the application once it boots up +> +> ```java +> import io.quarkus.runtime.Quarkus; +> import io.quarkus.runtime.QuarkusApplication; +> import io.quarkus.runtime.annotations.QuarkusMain; +> +> @QuarkusMain +> public class Main { +> +> public static void main(String... args) { +> Quarkus.run(MyApp.class, args); +> } +> +> public static class MyApp implements QuarkusApplication { +> +> @Override +> public int run(String... args) throws Exception { +> return 0; +> } +> } +> } +``` + For the allocation case, you obtain a JFR file, you can convert it to your typical Async Profiler flamegraph HTML output with: ```shell script From ab710d6b101dbf73fa71dd3e9bbda1c1591d70a8 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 10:33:41 +0200 Subject: [PATCH 177/207] Get rid of unnecessary reflective calls at RESTEasy Reactive startup These calls were originally done to support REST Links, but the information they obtained has long been available at build time, meaning the reflective calls are totally unnecessary (and wasteful) --- .../startup/RuntimeResourceDeployment.java | 15 +--------- .../spi/ResteasyReactiveResourceInfo.java | 30 +------------------ 2 files changed, 2 insertions(+), 43 deletions(-) diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java index 2bc5999117537..2b655205434df 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java @@ -17,11 +17,9 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Supplier; @@ -177,19 +175,8 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, } } - Annotation[] resourceClassAnnotations = resourceClass.getAnnotations(); - Set classAnnotationNames; - if (resourceClassAnnotations.length == 0) { - classAnnotationNames = Collections.emptySet(); - } else { - classAnnotationNames = new HashSet<>(resourceClassAnnotations.length); - for (Annotation annotation : resourceClassAnnotations) { - classAnnotationNames.add(annotation.annotationType().getName()); - } - } - ResteasyReactiveResourceInfo lazyMethod = new ResteasyReactiveResourceInfo(method.getName(), resourceClass, - parameterDeclaredUnresolvedTypes, classAnnotationNames, method.getMethodAnnotationNames(), + parameterDeclaredUnresolvedTypes, !defaultBlocking && !method.isBlocking(), method.getActualDeclaringClassName()); RuntimeInterceptorDeployment.MethodInterceptorContext interceptorDeployment = runtimeInterceptorDeployment diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ResteasyReactiveResourceInfo.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ResteasyReactiveResourceInfo.java index b370a8cf5a309..143269aefa619 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ResteasyReactiveResourceInfo.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/spi/ResteasyReactiveResourceInfo.java @@ -3,7 +3,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Type; -import java.util.Set; import jakarta.ws.rs.container.ResourceInfo; @@ -20,8 +19,6 @@ public class ResteasyReactiveResourceInfo implements ResourceInfo { private final String name; private final Class declaringClass; private final Class[] parameterTypes; - private final Set classAnnotationNames; - private final Set methodAnnotationNames; /** * If it's non-blocking method within the runtime that won't always default to blocking */ @@ -30,27 +27,17 @@ public class ResteasyReactiveResourceInfo implements ResourceInfo { * This class name will only differ from {@link this#declaringClass} name when the {@link this#method} was inherited. */ private final String actualDeclaringClassName; - private volatile Annotation[] classAnnotations; private volatile Method method; private volatile Annotation[] annotations; private volatile Type returnType; private volatile String methodId; - @Deprecated - public ResteasyReactiveResourceInfo(String name, Class declaringClass, Class[] parameterTypes, - Set classAnnotationNames, Set methodAnnotationNames, boolean isNonBlocking) { - this(name, declaringClass, parameterTypes, classAnnotationNames, methodAnnotationNames, isNonBlocking, - declaringClass.getName()); - } - public ResteasyReactiveResourceInfo(String name, Class declaringClass, Class[] parameterTypes, - Set classAnnotationNames, Set methodAnnotationNames, boolean isNonBlocking, + boolean isNonBlocking, String actualDeclaringClassName) { this.name = name; this.declaringClass = declaringClass; this.parameterTypes = parameterTypes; - this.classAnnotationNames = classAnnotationNames; - this.methodAnnotationNames = methodAnnotationNames; this.isNonBlocking = isNonBlocking; this.actualDeclaringClassName = actualDeclaringClassName; } @@ -63,14 +50,6 @@ public Class[] getParameterTypes() { return parameterTypes; } - public Set getClassAnnotationNames() { - return classAnnotationNames; - } - - public Set getMethodAnnotationNames() { - return methodAnnotationNames; - } - public Method getMethod() { if (method == null) { synchronized (this) { @@ -89,13 +68,6 @@ public Method getMethod() { return method; } - public Annotation[] getClassAnnotations() { - if (classAnnotations == null) { - classAnnotations = declaringClass.getAnnotations(); - } - return classAnnotations; - } - public Annotation[] getAnnotations() { if (annotations == null) { getMethod(); From 718c582d096e8cc13c2b9923b07831174fc31d35 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 4 Dec 2024 09:50:05 +0200 Subject: [PATCH 178/207] Polish PublisherResponseHandler --- .../server/handlers/PublisherResponseHandler.java | 12 ++++++------ .../reactive/server/jaxrs/SseEventSinkImpl.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/PublisherResponseHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/PublisherResponseHandler.java index 20110476a41f8..9a82c247bca5f 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/PublisherResponseHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/PublisherResponseHandler.java @@ -312,21 +312,21 @@ private boolean requiresChunkedStream(MediaType mediaType) { || mediaType.isCompatible(RestMediaType.APPLICATION_STREAM_JSON_TYPE); } + @SuppressWarnings("rawtypes") private void handleChunkedStreaming(ResteasyReactiveRequestContext requestContext, Publisher result, boolean json) { long demand = 1L; - if (result instanceof RestMulti.SyncRestMulti) { - RestMulti.SyncRestMulti rest = (RestMulti.SyncRestMulti) result; + if (result instanceof RestMulti.SyncRestMulti rest) { demand = rest.getDemand(); } result.subscribe( new StreamingMultiSubscriber(requestContext, streamingResponseCustomizers, result, json, demand, false)); } + @SuppressWarnings("rawtypes") private void handleStreaming(ResteasyReactiveRequestContext requestContext, Publisher result, boolean json) { long demand = 1L; boolean encodeAsJsonArray = true; - if (result instanceof RestMulti.SyncRestMulti) { - RestMulti.SyncRestMulti rest = (RestMulti.SyncRestMulti) result; + if (result instanceof RestMulti.SyncRestMulti rest) { demand = rest.getDemand(); encodeAsJsonArray = rest.encodeAsJsonArray(); } @@ -334,10 +334,10 @@ private void handleStreaming(ResteasyReactiveRequestContext requestContext, Publ encodeAsJsonArray)); } + @SuppressWarnings("rawtypes") private void handleSse(ResteasyReactiveRequestContext requestContext, Publisher result) { long demand; - if (result instanceof RestMulti.SyncRestMulti) { - RestMulti.SyncRestMulti rest = (RestMulti.SyncRestMulti) result; + if (result instanceof RestMulti.SyncRestMulti rest) { demand = rest.getDemand(); } else { demand = 1L; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseEventSinkImpl.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseEventSinkImpl.java index bce377a34da90..c963813fe7e1e 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseEventSinkImpl.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseEventSinkImpl.java @@ -14,7 +14,7 @@ public class SseEventSinkImpl implements SseEventSink { public static final byte[] EMPTY_BUFFER = new byte[0]; - private ResteasyReactiveRequestContext context; + private final ResteasyReactiveRequestContext context; private SseBroadcasterImpl broadcaster; private boolean closed; From f0e1e4e9c926a26d188b372551dda55717871b3e Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 4 Dec 2024 09:57:21 +0200 Subject: [PATCH 179/207] Take RestMulti headers and status into account when using SSE resource method --- .../handlers/PublisherResponseHandler.java | 150 +++++++++++++----- 1 file changed, 110 insertions(+), 40 deletions(-) diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/PublisherResponseHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/PublisherResponseHandler.java index 9a82c247bca5f..bf20a89b8d648 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/PublisherResponseHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/PublisherResponseHandler.java @@ -10,6 +10,7 @@ import java.util.concurrent.Flow.Publisher; import java.util.concurrent.Flow.Subscriber; import java.util.concurrent.Flow.Subscription; +import java.util.function.Consumer; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.sse.OutboundSseEvent; @@ -46,32 +47,104 @@ public void setStreamingResponseCustomizers(List st this.streamingResponseCustomizers = streamingResponseCustomizers; } + @SuppressWarnings("rawtypes") private static class SseMultiSubscriber extends AbstractMultiSubscriber { + private final Publisher publisher; + // 0: no items have been pushed by the stream + // 1: the first item has been pushed by the stream, and we have yet to send the empty buffer (with the headers) + // 2: the empty buffer (with the headers) was sent, and we have received a response + // 3: all items pulled from upstream and successfully sent downstream + // 4: we got an error sending an item + private volatile int state = 0; + SseMultiSubscriber(ResteasyReactiveRequestContext requestContext, List staticCustomizers, - long demand) { + Publisher publisher, long demand) { super(requestContext, staticCustomizers, demand); + this.publisher = publisher; + } + + @Override + public void onSubscribe(Subscription s) { + this.subscription = s; + // we only request one item initially because we need to use that item to create the headers + // that will be sent in the first empty response + s.request(1); + } + + @Override + public void onComplete() { + // make sure we don't trigger cancel with our onCloseHandler + weClosed = true; + if (state == 1) { // stream only had one item that we have yet to send (we are waiting for the empty buffer to be sent) + // do nothing as we still need to send the first item + // the connection will be closed by doSend when the item is sent + } else if (state < 3) { + doClose(); + } else { + handleException(requestContext, new IllegalStateException("Unexpected state: " + state)); + } } @Override public void onNext(Object item) { - OutboundSseEvent event; - if (item instanceof OutboundSseEvent) { - event = (OutboundSseEvent) item; + if (state == 0) { // first item + state = 1; + SseUtil.setHeaders(requestContext, requestContext.serverResponse(), + determineCustomizers(publisher, true, staticCustomizers)); + + requestContext.serverResponse().write(EMPTY_BUFFER, new Consumer<>() { + @Override + public void accept(Throwable throwable) { + if (throwable == null) { + state = 2; + // now we can actually send the first item + doSend(item); + } else { + state = 4; + requestContext.resume(throwable); + } + } + }); + } else if (state == 2) { // the only should have got here is when the empty buffer was sent + doSend(item); } else { - event = new OutboundSseEventImpl.BuilderImpl().data(item).build(); + handleException(requestContext, new IllegalStateException("Unexpected state: " + state)); } - SseUtil.send(requestContext, event, staticCustomizers).whenComplete((v, t) -> { + } + + private void doSend(Object item) { + SseUtil.send(requestContext, fromItem(item), staticCustomizers).whenComplete((v, t) -> { if (t != null) { + state = 4; // need to cancel because the exception didn't come from the Multi subscription.cancel(); handleException(requestContext, t); + } else if (weClosed && !requestContext.serverResponse().closed()) { + // this is the case where the stream only had one item so we need to close the connection as onComplete could not do it at the time it was called + doClose(); } else { // send in the next item subscription.request(demand); } }); } + + private void doClose() { + state = 3; + requestContext.serverResponse().end(); + requestContext.close(); + } + + private OutboundSseEvent fromItem(Object item) { + OutboundSseEvent event; + if (item instanceof OutboundSseEvent) { + event = (OutboundSseEvent) item; + } else { + event = new OutboundSseEventImpl.BuilderImpl().data(item).build(); + } + return event; + } } @SuppressWarnings("rawtypes") @@ -103,7 +176,7 @@ private static class StreamingMultiSubscriber extends AbstractMultiSubscriber { @Override public void onNext(Object item) { - List customizers = determineCustomizers(!hadItem); + List customizers = determineCustomizers(publisher, !hadItem, staticCustomizers); hadItem = true; StreamingUtil.send(requestContext, customizers, item, messagePrefix(), messageSuffix()) .handle((v, t) -> { @@ -125,33 +198,12 @@ public void onNext(Object item) { }); } - private List determineCustomizers(boolean isFirst) { - // we only need to obtain the customizers from the Publisher if it's the first time we are sending data and the Publisher has customizable data - // at this point no matter the type of RestMulti we can safely obtain the headers and status - if (isFirst && (publisher instanceof RestMulti restMulti)) { - Map> headers = restMulti.getHeaders(); - Integer status = restMulti.getStatus(); - if (headers.isEmpty() && (status == null)) { - return staticCustomizers; - } - List result = new ArrayList<>(staticCustomizers.size() + 2); - result.addAll(staticCustomizers); // these are added first so that the result specific values will take precedence if there are conflicts - if (!headers.isEmpty()) { - result.add(new StreamingResponseCustomizer.AddHeadersCustomizer(headers)); - } - if (status != null) { - result.add(new StreamingResponseCustomizer.StatusCustomizer(status)); - } - return result; - } - - return staticCustomizers; - } - @Override public void onComplete() { if (!hadItem) { - StreamingUtil.setHeaders(requestContext, requestContext.serverResponse(), this.determineCustomizers(true)); + StreamingUtil.setHeaders(requestContext, requestContext.serverResponse(), determineCustomizers( + this.publisher, true, + this.staticCustomizers)); } if (json) { String postfix = onCompleteText(); @@ -202,7 +254,7 @@ static abstract class AbstractMultiSubscriber implements Subscriber { protected final long demand; protected volatile Subscription subscription; - private volatile boolean weClosed = false; + protected volatile boolean weClosed = false; AbstractMultiSubscriber(ResteasyReactiveRequestContext requestContext, List staticCustomizers, long demand) { @@ -218,6 +270,31 @@ static abstract class AbstractMultiSubscriber implements Subscriber { }); } + @SuppressWarnings("rawtypes") + protected static List determineCustomizers(Publisher publisher, boolean isFirst, + List staticCustomizers) { + // we only need to obtain the customizers from the Publisher if it's the first time we are sending data and the Publisher has customizable data + // at this point no matter the type of RestMulti we can safely obtain the headers and status + if (isFirst && (publisher instanceof RestMulti restMulti)) { + Map> headers = restMulti.getHeaders(); + Integer status = restMulti.getStatus(); + if (headers.isEmpty() && (status == null)) { + return staticCustomizers; + } + List result = new ArrayList<>(staticCustomizers.size() + 2); + result.addAll(staticCustomizers); // these are added first so that the result specific values will take precedence if there are conflicts + if (!headers.isEmpty()) { + result.add(new StreamingResponseCustomizer.AddHeadersCustomizer(headers)); + } + if (status != null) { + result.add(new StreamingResponseCustomizer.StatusCustomizer(status)); + } + return result; + } + + return staticCustomizers; + } + @Override public void onSubscribe(Subscription s) { this.subscription = s; @@ -343,15 +420,8 @@ private void handleSse(ResteasyReactiveRequestContext requestContext, Publisher< demand = 1L; } - SseUtil.setHeaders(requestContext, requestContext.serverResponse(), streamingResponseCustomizers); requestContext.suspend(); - requestContext.serverResponse().write(EMPTY_BUFFER, throwable -> { - if (throwable == null) { - result.subscribe(new SseMultiSubscriber(requestContext, streamingResponseCustomizers, demand)); - } else { - requestContext.resume(throwable); - } - }); + result.subscribe(new SseMultiSubscriber(requestContext, streamingResponseCustomizers, result, demand)); } public interface StreamingResponseCustomizer { From 0024c7f72a0012eaa7cdc09d3833f2231f85400e Mon Sep 17 00:00:00 2001 From: Daniel Strobusch <1847260+dastrobu@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:23:16 +0100 Subject: [PATCH 180/207] Add test for adding a custom response header for SSE resource method --- .../test/headers/ResponseHeaderTest.java | 152 +++++++++++++++++- 1 file changed, 147 insertions(+), 5 deletions(-) diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/headers/ResponseHeaderTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/headers/ResponseHeaderTest.java index 6c02c61cb12c1..2d50d4cf68341 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/headers/ResponseHeaderTest.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/headers/ResponseHeaderTest.java @@ -225,6 +225,105 @@ public void testReturnRestMulti5() { "header2", "h2")); } + @Test + public void testReturnRestSse() { + Map expectedHeaders = Map.of( + "Access-Control-Allow-Origin", "foo", + "Keep-Alive", "bar"); + RestAssured + .given() + .get("/test/rest-sse") + .then() + .statusCode(200) + .headers(expectedHeaders); + } + + @Test + public void testReturnRestSse2() { + RestAssured + .given() + .get("/test/rest-sse2") + .then() + .statusCode(200) + .headers(Map.of( + "Access-Control-Allow-Origin", "foo", + "Keep-Alive", "bar")); + + RestAssured + .given() + .get("/test/rest-sse2?keepAlive=dummy") + .then() + .statusCode(200) + .headers(Map.of( + "Access-Control-Allow-Origin", "foo", + "Keep-Alive", "dummy")); + } + + @Test + public void testReturnRestSse3() { + RestAssured + .given() + .get("/test/rest-sse3") + .then() + .statusCode(200) + .headers(Map.of( + "header1", "foo", + "header2", "bar")); + + RestAssured + .given() + .get("/test/rest-sse3?h1=h1&h2=h2") + .then() + .statusCode(200) + .headers(Map.of( + "header1", "h1", + "header2", "h2")); + } + + @Test + public void testReturnRestSse4() { + RestAssured + .given() + .get("/test/rest-sse2") + .then() + .statusCode(200) + .contentType(MediaType.SERVER_SENT_EVENTS) + .headers(Map.of( + "Access-Control-Allow-Origin", "foo", + "Keep-Alive", "bar")); + + RestAssured + .given() + .get("/test/rest-sse2?keepAlive=dummy") + .then() + .statusCode(200) + .contentType(MediaType.SERVER_SENT_EVENTS) + .headers(Map.of( + "Access-Control-Allow-Origin", "foo", + "Keep-Alive", "dummy")); + } + + @Test + public void testReturnRestSse5() { + RestAssured + .given() + .get("/test/rest-sse3") + .then() + .statusCode(200) + .headers(Map.of( + "header1", "foo", + "header2", "bar")); + + RestAssured + .given() + .get("/test/rest-sse3?h1=h1&h2=h2") + .then() + .statusCode(200) + .headers(Map.of( + "header1", "h1", + "header2", "h2")); + } + @Path("/test") public static class TestResource { @@ -301,14 +400,14 @@ public String throwExceptionPlain() { @ResponseHeader(name = "Keep-Alive", value = "timeout=5, max=997") @GET @Path("/rest-multi") - public RestMulti getTestRestMulti() { + public Multi getTestRestMulti() { return RestMulti.fromMultiData(Multi.createFrom().item("test")).header("Access-Control-Allow-Origin", "foo") .header("Keep-Alive", "bar").build(); } @GET @Path("/rest-multi2") - public RestMulti getTestRestMulti2(@DefaultValue("bar") @RestQuery String keepAlive) { + public Multi getTestRestMulti2(@DefaultValue("bar") @RestQuery String keepAlive) { return RestMulti.fromMultiData(Multi.createFrom().item("test")).header("Access-Control-Allow-Origin", "foo") .header("Keep-Alive", keepAlive).build(); } @@ -316,14 +415,14 @@ public RestMulti getTestRestMulti2(@DefaultValue("bar") @RestQuery Strin @GET @Path("/rest-multi3") @Produces("application/octet-stream") - public RestMulti getTestRestMulti3(@DefaultValue("foo") @RestQuery("h1") String header1, + public Multi getTestRestMulti3(@DefaultValue("foo") @RestQuery("h1") String header1, @DefaultValue("bar") @RestQuery("h2") String header2) { return RestMulti.fromUniResponse(getWrapper(header1, header2), Wrapper::getData, Wrapper::getHeaders); } @GET @Path("/rest-multi4") - public RestMulti getTestRestMulti4(@DefaultValue("bar") @RestQuery String keepAlive) { + public Multi getTestRestMulti4(@DefaultValue("bar") @RestQuery String keepAlive) { return RestMulti.fromMultiData(Multi.createFrom().item("test".getBytes(StandardCharsets.UTF_8))) .header("Access-Control-Allow-Origin", "foo") .header("Keep-Alive", keepAlive).header("Content-Type", MediaType.TEXT_PLAIN).build(); @@ -331,7 +430,50 @@ public RestMulti getTestRestMulti4(@DefaultValue("bar") @RestQuery Strin @GET @Path("/rest-multi5") - public RestMulti getTestRestMulti5(@DefaultValue("foo") @RestQuery("h1") String header1, + public Multi getTestRestMulti5(@DefaultValue("foo") @RestQuery("h1") String header1, + @DefaultValue("bar") @RestQuery("h2") String header2) { + return RestMulti.fromUniResponse(getWrapper(header1, header2), Wrapper::getData, Wrapper::getHeaders); + } + + @ResponseHeader(name = "Access-Control-Allow-Origin", value = "*") + @ResponseHeader(name = "Keep-Alive", value = "timeout=5, max=997") + @GET + @Path("/rest-sse") + @Produces(MediaType.SERVER_SENT_EVENTS) + public Multi getTestRestSse() { + return RestMulti.fromMultiData(Multi.createFrom().item("test")).header("Access-Control-Allow-Origin", "foo") + .header("Keep-Alive", "bar").build(); + } + + @GET + @Path("/rest-sse2") + @Produces(MediaType.SERVER_SENT_EVENTS) + public Multi getTestRestSse2(@DefaultValue("bar") @RestQuery String keepAlive) { + return RestMulti.fromMultiData(Multi.createFrom().item("test")).header("Access-Control-Allow-Origin", "foo") + .header("Keep-Alive", keepAlive).build(); + } + + @GET + @Path("/rest-sse3") + @Produces(MediaType.SERVER_SENT_EVENTS) + public Multi getTestRestSse3(@DefaultValue("foo") @RestQuery("h1") String header1, + @DefaultValue("bar") @RestQuery("h2") String header2) { + return RestMulti.fromUniResponse(getWrapper(header1, header2), Wrapper::getData, Wrapper::getHeaders); + } + + @GET + @Path("/rest-sse4") + @Produces(MediaType.SERVER_SENT_EVENTS) + public Multi getTestRestSse4(@DefaultValue("bar") @RestQuery String keepAlive) { + return RestMulti.fromMultiData(Multi.createFrom().item("test".getBytes(StandardCharsets.UTF_8))) + .header("Access-Control-Allow-Origin", "foo") + .header("Keep-Alive", keepAlive).header("Content-Type", MediaType.TEXT_PLAIN).build(); + } + + @GET + @Path("/rest-sse5") + @Produces(MediaType.SERVER_SENT_EVENTS) + public Multi getTestRestSse5(@DefaultValue("foo") @RestQuery("h1") String header1, @DefaultValue("bar") @RestQuery("h2") String header2) { return RestMulti.fromUniResponse(getWrapper(header1, header2), Wrapper::getData, Wrapper::getHeaders); } From 07ba5e6bcd1a0ac1b536002cdf459a8d8eb79d11 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 11:33:27 +0200 Subject: [PATCH 181/207] Lazily access ObjectMapper in Quarkus REST Jackson module This is done because the server MessageBodyReader and MessageBodyWriter classes are created at static init, which means two things: * The Jackson bean should not be accessed directly as it can still be configured by user provided code (via ObjectMapperCustomizer). * Accessing the Jackson bean directly imposes a rather large hit on startup time (on my machine, it's over 50ms), regardless if MessageBodyReader / MessageBodyWriter are ever used in the application --- .../test/MessageBodyReaderTests.java | 61 ++++++++++++++++++- ...bstractServerJacksonMessageBodyReader.java | 54 ++++++++++++++++ .../BasicServerJacksonMessageBodyWriter.java | 20 ++++-- ...eaturedServerJacksonMessageBodyReader.java | 14 ++--- .../ServerJacksonMessageBodyReader.java | 7 ++- 5 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/AbstractServerJacksonMessageBodyReader.java diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/MessageBodyReaderTests.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/MessageBodyReaderTests.java index 68bd47c204deb..1cdbc9c28c4a6 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/MessageBodyReaderTests.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/MessageBodyReaderTests.java @@ -7,12 +7,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.annotation.Annotation; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Objects; +import jakarta.enterprise.inject.Instance; +import jakarta.enterprise.util.TypeLiteral; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.container.CompletionCallback; import jakarta.ws.rs.container.ConnectionCallback; @@ -119,7 +123,8 @@ void shouldThrowInvalidDefinitionException() { @Nested @DisplayName("ServerJacksonMessageBodyReader") class ServerJacksonMessageBodyReaderTests { - private final CommonReaderTests tests = new CommonReaderTests(new ServerJacksonMessageBodyReader(new ObjectMapper())); + private final CommonReaderTests tests = new CommonReaderTests( + new ServerJacksonMessageBodyReader(new NewObjectMapperInstance())); @Test void shouldThrowWebExceptionWithStreamReadExceptionCause() { @@ -146,7 +151,7 @@ void shouldThrowInvalidDefinitionException() { @Test void shouldThrowWebExceptionWithValueInstantiationExceptionCauseUsingServerRequestContext() throws IOException { - var reader = new ServerJacksonMessageBodyReader(new ObjectMapper()); + var reader = new ServerJacksonMessageBodyReader(new NewObjectMapperInstance()); // missing non-nullable property var stream = new ByteArrayInputStream("{\"cost\": 2}".getBytes(StandardCharsets.UTF_8)); var context = new MockServerRequestContext(stream); @@ -279,4 +284,56 @@ public void abortWith(Response response) { } } + + private static class NewObjectMapperInstance implements Instance { + @Override + public Instance select(Annotation... qualifiers) { + throw new IllegalStateException("Should never be called"); + } + + @Override + public Instance select(Class subtype, Annotation... qualifiers) { + throw new IllegalStateException("Should never be called"); + } + + @Override + public Instance select(TypeLiteral subtype, Annotation... qualifiers) { + throw new IllegalStateException("Should never be called"); + } + + @Override + public boolean isUnsatisfied() { + throw new IllegalStateException("Should never be called"); + } + + @Override + public boolean isAmbiguous() { + throw new IllegalStateException("Should never be called"); + } + + @Override + public void destroy(ObjectMapper instance) { + throw new IllegalStateException("Should never be called"); + } + + @Override + public Handle getHandle() { + throw new IllegalStateException("Should never be called"); + } + + @Override + public Iterable> handles() { + throw new IllegalStateException("Should never be called"); + } + + @Override + public ObjectMapper get() { + return new ObjectMapper(); + } + + @Override + public Iterator iterator() { + throw new IllegalStateException("Should never be called"); + } + } } diff --git a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/AbstractServerJacksonMessageBodyReader.java b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/AbstractServerJacksonMessageBodyReader.java new file mode 100644 index 0000000000000..868053b40472b --- /dev/null +++ b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/AbstractServerJacksonMessageBodyReader.java @@ -0,0 +1,54 @@ +package io.quarkus.resteasy.reactive.jackson.runtime.serialisers; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.function.Supplier; + +import jakarta.enterprise.inject.Instance; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; + +import org.jboss.resteasy.reactive.common.providers.serialisers.AbstractJsonMessageBodyReader; +import org.jboss.resteasy.reactive.common.util.EmptyInputStream; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; + +import io.quarkus.arc.impl.LazyValue; + +public abstract class AbstractServerJacksonMessageBodyReader extends AbstractJsonMessageBodyReader { + + protected final LazyValue defaultReader; + + public AbstractServerJacksonMessageBodyReader(Instance mapper) { + this.defaultReader = new LazyValue<>(new Supplier<>() { + @Override + public ObjectReader get() { + return mapper.get().reader(); + } + }); + } + + @Override + public Object readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, + WebApplicationException { + return doReadFrom(type, genericType, entityStream); + } + + protected ObjectReader getEffectiveReader() { + return defaultReader.get(); + } + + private Object doReadFrom(Class type, Type genericType, InputStream entityStream) throws IOException { + if (entityStream instanceof EmptyInputStream) { + return null; + } + ObjectReader reader = getEffectiveReader(); + return reader.forType(reader.getTypeFactory().constructType(genericType != null ? genericType : type)) + .readValue(entityStream); + } +} diff --git a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/BasicServerJacksonMessageBodyWriter.java b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/BasicServerJacksonMessageBodyWriter.java index 2af17b6bc79f7..bf9bc6d2788a1 100644 --- a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/BasicServerJacksonMessageBodyWriter.java +++ b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/BasicServerJacksonMessageBodyWriter.java @@ -11,7 +11,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import java.util.function.Supplier; +import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; @@ -24,22 +26,28 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; +import io.quarkus.arc.impl.LazyValue; import io.quarkus.resteasy.reactive.jackson.runtime.mappers.JacksonMapperUtil; public class BasicServerJacksonMessageBodyWriter extends ServerMessageBodyWriter.AllWriteableMessageBodyWriter { - private final ObjectWriter defaultWriter; + private final LazyValue defaultWriter; private final Map genericWriters = new ConcurrentHashMap<>(); @Inject - public BasicServerJacksonMessageBodyWriter(ObjectMapper mapper) { - this.defaultWriter = createDefaultWriter(mapper); + public BasicServerJacksonMessageBodyWriter(Instance mapper) { + this.defaultWriter = new LazyValue<>(new Supplier<>() { + @Override + public ObjectWriter get() { + return createDefaultWriter(mapper.get()); + } + }); } private ObjectWriter getWriter(Type genericType, Object value) { // make sure we properly handle polymorphism in generic collections if (value != null && genericType != null) { - JavaType rootType = JacksonMapperUtil.getGenericRootType(genericType, defaultWriter); + JavaType rootType = JacksonMapperUtil.getGenericRootType(genericType, defaultWriter.get()); // Check that the determined root type is really assignable from the given entity. // A mismatch can happen, if a ServerResponseFilter replaces the response entity with another object // that does not match the original signature of the method (see HalServerResponseFilter for an example) @@ -50,7 +58,7 @@ private ObjectWriter getWriter(Type genericType, Object value) { writer = genericWriters.computeIfAbsent(rootType, new Function<>() { @Override public ObjectWriter apply(JavaType type) { - return defaultWriter.forType(type); + return defaultWriter.get().forType(type); } }); } @@ -59,7 +67,7 @@ public ObjectWriter apply(JavaType type) { } // no generic type given, or the generic type is just a class. Use the default writer. - return this.defaultWriter; + return this.defaultWriter.get(); } @Override diff --git a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/FullyFeaturedServerJacksonMessageBodyReader.java b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/FullyFeaturedServerJacksonMessageBodyReader.java index 863d2b396f877..1aa5fd93676d9 100644 --- a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/FullyFeaturedServerJacksonMessageBodyReader.java +++ b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/FullyFeaturedServerJacksonMessageBodyReader.java @@ -12,6 +12,7 @@ import java.util.function.BiFunction; import java.util.function.Function; +import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; @@ -22,7 +23,6 @@ import org.jboss.resteasy.reactive.common.util.StreamUtil; import org.jboss.resteasy.reactive.server.core.CurrentRequestManager; -import org.jboss.resteasy.reactive.server.jackson.JacksonBasicMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; @@ -36,10 +36,10 @@ import io.quarkus.resteasy.reactive.jackson.runtime.ResteasyReactiveServerJacksonRecorder; -public class FullyFeaturedServerJacksonMessageBodyReader extends JacksonBasicMessageBodyReader +public class FullyFeaturedServerJacksonMessageBodyReader extends AbstractServerJacksonMessageBodyReader implements ServerMessageBodyReader { - private final ObjectMapper originalMapper; + private final Instance originalMapper; private final Providers providers; private final ConcurrentMap perMethodReader = new ConcurrentHashMap<>(); private final ConcurrentMap perTypeReader = new ConcurrentHashMap<>(); @@ -47,7 +47,7 @@ public class FullyFeaturedServerJacksonMessageBodyReader extends JacksonBasicMes private final ConcurrentMap objectReaderMap = new ConcurrentHashMap<>(); @Inject - public FullyFeaturedServerJacksonMessageBodyReader(ObjectMapper mapper, Providers providers) { + public FullyFeaturedServerJacksonMessageBodyReader(Instance mapper, Providers providers) { super(mapper); this.originalMapper = mapper; this.providers = providers; @@ -152,7 +152,7 @@ private ObjectReader getObjectReaderFromAnnotations(ResteasyReactiveResourceInfo private ObjectReader getEffectiveReader(Class type, Type genericType, MediaType responseMediaType) { ObjectMapper effectiveMapper = getEffectiveMapper(type, responseMediaType); - ObjectReader effectiveReader = defaultReader; + ObjectReader effectiveReader = defaultReader.get(); if (effectiveMapper != originalMapper) { // Effective reader based on the context effectiveReader = objectReaderMap.computeIfAbsent(effectiveMapper, new Function<>() { @@ -192,7 +192,7 @@ public ObjectReader apply(ObjectMapper objectMapper) { private ObjectMapper getEffectiveMapper(Class type, MediaType responseMediaType) { if (providers == null) { - return originalMapper; + return originalMapper.get(); } ContextResolver contextResolver = providers.getContextResolver(ObjectMapper.class, @@ -214,7 +214,7 @@ public ObjectMapper apply(Class aClass) { } } - return originalMapper; + return originalMapper.get(); } private static class MethodObjectReaderFunction implements Function { diff --git a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/ServerJacksonMessageBodyReader.java b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/ServerJacksonMessageBodyReader.java index 1064ff509e28e..82e03c0356007 100644 --- a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/ServerJacksonMessageBodyReader.java +++ b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/ServerJacksonMessageBodyReader.java @@ -5,6 +5,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; @@ -12,7 +13,6 @@ import jakarta.ws.rs.core.Response; import org.jboss.resteasy.reactive.common.util.StreamUtil; -import org.jboss.resteasy.reactive.server.jackson.JacksonBasicMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; @@ -24,10 +24,11 @@ import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; import com.fasterxml.jackson.databind.exc.MismatchedInputException; -public class ServerJacksonMessageBodyReader extends JacksonBasicMessageBodyReader implements ServerMessageBodyReader { +public class ServerJacksonMessageBodyReader extends AbstractServerJacksonMessageBodyReader + implements ServerMessageBodyReader { @Inject - public ServerJacksonMessageBodyReader(ObjectMapper mapper) { + public ServerJacksonMessageBodyReader(Instance mapper) { super(mapper); } From cbad8d39e805938b3a6d3f4d6f5f9d600b4bb327 Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Fri, 20 Dec 2024 09:02:52 -0300 Subject: [PATCH 182/207] Convert web-dependency-locator to use @ConfigMapping --- .../web-dependency-locator/deployment/pom.xml | 3 --- .../WebDependencyLocatorConfig.java | 21 +++++++++--------- .../WebDependencyLocatorProcessor.java | 22 +++++++++---------- .../web-dependency-locator/runtime/pom.xml | 3 --- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/extensions/web-dependency-locator/deployment/pom.xml b/extensions/web-dependency-locator/deployment/pom.xml index 0a71bfa69a34c..8a3e74c33a61f 100644 --- a/extensions/web-dependency-locator/deployment/pom.xml +++ b/extensions/web-dependency-locator/deployment/pom.xml @@ -97,9 +97,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/web-dependency-locator/deployment/src/main/java/io/quarkus/webdependency/locator/deployment/WebDependencyLocatorConfig.java b/extensions/web-dependency-locator/deployment/src/main/java/io/quarkus/webdependency/locator/deployment/WebDependencyLocatorConfig.java index 6c3603da6b99e..97c41ccd052a1 100644 --- a/extensions/web-dependency-locator/deployment/src/main/java/io/quarkus/webdependency/locator/deployment/WebDependencyLocatorConfig.java +++ b/extensions/web-dependency-locator/deployment/src/main/java/io/quarkus/webdependency/locator/deployment/WebDependencyLocatorConfig.java @@ -3,37 +3,38 @@ import java.util.Map; import io.quarkus.runtime.annotations.ConfigDocMapKey; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; /** * Build time configuration for Web Dependency Locator. */ @ConfigRoot -public class WebDependencyLocatorConfig { +@ConfigMapping(prefix = "quarkus.web-dependency-locator") +public interface WebDependencyLocatorConfig { /** * If the version reroute is enabled. */ - @ConfigItem(defaultValue = "true") - public boolean versionReroute; + @WithDefault("true") + boolean versionReroute(); /** * User defined import mappings */ - @ConfigItem @ConfigDocMapKey("module-specifier") - public Map importMappings; + Map importMappings(); /** * The directory in the resources which serves as root for the web assets */ - @ConfigItem(defaultValue = "web") - public String webRoot; + @WithDefault("web") + String webRoot(); /** * The directory in the resources which serves as root for the app assets */ - @ConfigItem(defaultValue = "app") - public String appRoot; + @WithDefault("app") + String appRoot(); } diff --git a/extensions/web-dependency-locator/deployment/src/main/java/io/quarkus/webdependency/locator/deployment/WebDependencyLocatorProcessor.java b/extensions/web-dependency-locator/deployment/src/main/java/io/quarkus/webdependency/locator/deployment/WebDependencyLocatorProcessor.java index 6ee11770182c9..75862305ccfef 100644 --- a/extensions/web-dependency-locator/deployment/src/main/java/io/quarkus/webdependency/locator/deployment/WebDependencyLocatorProcessor.java +++ b/extensions/web-dependency-locator/deployment/src/main/java/io/quarkus/webdependency/locator/deployment/WebDependencyLocatorProcessor.java @@ -51,14 +51,14 @@ public void findRelevantFiles(BuildProducer ge BuildProducer hotDeploymentWatchedProducer, WebDependencyLocatorConfig config) throws IOException { - QuarkusClassLoader.visitRuntimeResources(config.webRoot, visit -> { + QuarkusClassLoader.visitRuntimeResources(config.webRoot(), visit -> { final Path web = visit.getPath(); if (Files.isDirectory(web)) { hotDeploymentWatchedProducer - .produce(new HotDeploymentWatchedFileBuildItem(config.webRoot + SLASH + STAR + STAR)); + .produce(new HotDeploymentWatchedFileBuildItem(config.webRoot() + SLASH + STAR + STAR)); // Find all css and js (under /app) Path app = web - .resolve(config.appRoot); + .resolve(config.appRoot()); List cssFiles = new ArrayList<>(); List jsFiles = new ArrayList<>(); @@ -66,7 +66,7 @@ public void findRelevantFiles(BuildProducer ge if (Files.exists(app)) { hotDeploymentWatchedProducer .produce(new HotDeploymentWatchedFileBuildItem( - config.webRoot + SLASH + config.appRoot + SLASH + STAR + STAR)); + config.webRoot() + SLASH + config.appRoot() + SLASH + STAR + STAR)); try (Stream appstream = Files.walk(app)) { appstream.forEach(path -> { if (Files.isRegularFile(path) && path.toString().endsWith(DOT_CSS)) { @@ -167,23 +167,23 @@ public void findWebDependenciesAndCreateHandler( if (webjarsLibInfo != null || mvnpmNameLibInfo != null) { if (webjarsLibInfo != null) { - if (config.versionReroute) { + if (config.versionReroute()) { routes.produce(createRouteBuildItem(recorder, httpConfig, WEBJARS_PATH, webjarsLibInfo.nameVersionMap)); } } if (mvnpmNameLibInfo != null) { - if (config.versionReroute) { + if (config.versionReroute()) { routes.produce(createRouteBuildItem(recorder, httpConfig, MVNPM_PATH, mvnpmNameLibInfo.nameVersionMap)); } // Also create a importmap endpoint Aggregator aggregator = new Aggregator(mvnpmNameLibInfo.jars); - Map importMappings = config.importMappings; - if (!importMappings.containsKey(config.appRoot + SLASH)) { + Map importMappings = config.importMappings(); + if (!importMappings.containsKey(config.appRoot() + SLASH)) { // Add default for app/ - importMappings.put(config.appRoot + SLASH, SLASH + config.appRoot + SLASH); + importMappings.put(config.appRoot() + SLASH, SLASH + config.appRoot() + SLASH); } - if (!config.importMappings.isEmpty()) { - aggregator.addMappings(config.importMappings); + if (!config.importMappings().isEmpty()) { + aggregator.addMappings(config.importMappings()); } String importMap = aggregator.aggregateAsJson(false); diff --git a/extensions/web-dependency-locator/runtime/pom.xml b/extensions/web-dependency-locator/runtime/pom.xml index 1bedaf80d0250..067029874533f 100644 --- a/extensions/web-dependency-locator/runtime/pom.xml +++ b/extensions/web-dependency-locator/runtime/pom.xml @@ -43,9 +43,6 @@ ${project.version} - - -AlegacyConfigRoot=true - From 279f5f5aafaac3f7a9f8d6813f4c36fc85fc1349 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 15:08:01 +0200 Subject: [PATCH 183/207] Remove unused IGNORE_RESPONSE handling This was essentially made obsolete by 5219229529bbff2ff8a2322d78edac7ae639e197 but the field was never removed --- .../server/core/RuntimeExceptionMapper.java | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/RuntimeExceptionMapper.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/RuntimeExceptionMapper.java index 444158beb2a63..74298a1e00cc7 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/RuntimeExceptionMapper.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/RuntimeExceptionMapper.java @@ -20,7 +20,6 @@ import org.jboss.logging.Logger; import org.jboss.resteasy.reactive.ResteasyReactiveClientProblem; import org.jboss.resteasy.reactive.common.model.ResourceExceptionMapper; -import org.jboss.resteasy.reactive.server.jaxrs.ResponseBuilderImpl; import org.jboss.resteasy.reactive.server.mapping.RuntimeResource; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveAsyncExceptionMapper; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveExceptionMapper; @@ -44,9 +43,6 @@ public class RuntimeExceptionMapper { private final List> nonBlockingProblemPredicate; private final Set> unwrappedExceptions; - public static final Response IGNORE_RESPONSE = new ResponseBuilderImpl().status(666).header( - "RR_EX_IGN", "true").build(); - public RuntimeExceptionMapper(ExceptionMapping mapping, ClassLoader classLoader) { try { mappers = new HashMap<>(); @@ -99,21 +95,9 @@ public void mapException(Throwable throwable, ResteasyReactiveRequestContext con } else { response = exceptionMapper.toResponse(mappedException); } - // this special case is used in order to ignore the mapping of built-in mappers and let the exception handling proceed to higher levels - if ((IGNORE_RESPONSE == response)) { - if (isWebApplicationException) { - context.setResult(((WebApplicationException) throwable).getResponse()); - logWebApplicationExceptions.debug("Application failed the request", throwable); - } else { - logBlockingErrorIfRequired(throwable, context); - logNonBlockingErrorIfRequired(throwable, context); - context.handleUnmappedException(throwable); - } - } else { - context.setResult(response); - logBlockingErrorIfRequired(mappedException, context); - logNonBlockingErrorIfRequired(mappedException, context); - } + context.setResult(response); + logBlockingErrorIfRequired(mappedException, context); + logNonBlockingErrorIfRequired(mappedException, context); return; } if (isWebApplicationException) { From 069c5a035c3671be9e9cd8faacc465c610c112b0 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 15:39:16 +0200 Subject: [PATCH 184/207] Avoid using the RuntimeDelegate indirection for MediaType This call happens a lot, so it makes sense to remove the indirection and just call the final target --- .../ResteasyReactiveCompressionHandler.java | 3 ++- .../reactive/common/headers/HeaderUtil.java | 6 +++--- .../common/model/ResourceContextResolver.java | 3 ++- .../reactive/common/model/ResourceReader.java | 2 +- .../reactive/common/model/ResourceWriter.java | 2 +- .../reactive/common/util/MediaTypeHelper.java | 14 ++++++++++++-- .../reactive/common/util/ServerMediaType.java | 4 +++- .../reactive/server/core/EncodedMediaType.java | 2 +- .../core/startup/RuntimeResourceDeployment.java | 6 +++--- .../server/handlers/ClassRoutingHandler.java | 2 +- .../reactive/server/handlers/MediaTypeMapper.java | 2 +- .../server/handlers/RequestDeserializeHandler.java | 2 +- .../reactive/server/jaxrs/HttpHeadersImpl.java | 3 ++- 13 files changed, 33 insertions(+), 18 deletions(-) diff --git a/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveCompressionHandler.java b/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveCompressionHandler.java index c6be2343ccdb3..13ae7da4bebf2 100644 --- a/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveCompressionHandler.java +++ b/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveCompressionHandler.java @@ -5,6 +5,7 @@ import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; +import org.jboss.resteasy.reactive.common.util.MediaTypeHelper; import org.jboss.resteasy.reactive.server.core.EncodedMediaType; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; import org.jboss.resteasy.reactive.server.spi.ServerHttpResponse; @@ -65,7 +66,7 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti if (encodedProduces == null) { synchronized (this) { if (encodedProduces == null) { - encodedProduces = new EncodedMediaType(MediaType.valueOf(produces)); + encodedProduces = new EncodedMediaType(MediaTypeHelper.valueOf(produces)); } } } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/headers/HeaderUtil.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/headers/HeaderUtil.java index 4aa5847e58c06..1ff0d9ae77ba0 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/headers/HeaderUtil.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/headers/HeaderUtil.java @@ -116,7 +116,7 @@ public static URI getLocation(MultivaluedMap headers) public static MediaType getMediaType(MultivaluedMap headers) { Object first = headers.getFirst(HttpHeaders.CONTENT_TYPE); if (first instanceof String contentType) { - return MediaType.valueOf(contentType); + return MediaTypeHelper.valueOf(contentType); } else { return (MediaType) first; } @@ -281,10 +281,10 @@ public static List getAcceptableMediaTypes(MultivaluedMap mediaTypes() { synchronized (this) { List ret = new ArrayList<>(); for (String i : mediaTypeStrings) { - ret.add(MediaType.valueOf(i)); + ret.add(MediaTypeHelper.valueOf(i)); } mediaTypes = Collections.unmodifiableList(ret); } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java index 23930a80f5858..a52e1080233bc 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceReader.java @@ -87,7 +87,7 @@ public List mediaTypes() { synchronized (this) { List mts = new ArrayList<>(mediaTypeStrings.size()); for (int i = 0; i < mediaTypeStrings.size(); i++) { - mts.add(MediaType.valueOf(mediaTypeStrings.get(i))); + mts.add(MediaTypeHelper.valueOf(mediaTypeStrings.get(i))); } mediaTypes = Collections.unmodifiableList(mts); } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java index 5de3a260ba4ed..f638840e8617f 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceWriter.java @@ -90,7 +90,7 @@ public List mediaTypes() { synchronized (this) { List mts = new ArrayList<>(mediaTypeStrings.size()); for (int i = 0; i < mediaTypeStrings.size(); i++) { - mts.add(MediaType.valueOf(mediaTypeStrings.get(i))); + mts.add(MediaTypeHelper.valueOf(mediaTypeStrings.get(i))); } mediaTypes = Collections.unmodifiableList(mts); } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java index ce799d31a24d6..491b0c54c387f 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/MediaTypeHelper.java @@ -12,6 +12,8 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import org.jboss.resteasy.reactive.common.headers.MediaTypeHeaderDelegate; + /** * @author Bill Burke */ @@ -21,6 +23,14 @@ public class MediaTypeHelper { public static final MediaTypeComparator QS_COMPARATOR = new MediaTypeComparator("qs"); private static final String MEDIA_TYPE_SUFFIX_DELIM = "+"; + public static MediaType valueOf(String value) { + return MediaTypeHeaderDelegate.INSTANCE.fromString(value); + } + + public static String toString(MediaType mediaType) { + return MediaTypeHeaderDelegate.INSTANCE.toString(mediaType); + } + private static float getQTypeWithParamInfo(MediaType type, String parameterName) { if (type.getParameters() != null) { String val = type.getParameters().get(parameterName); @@ -212,7 +222,7 @@ public static List parseHeader(String header) { ArrayList types = new ArrayList<>(); String[] medias = header.split(","); for (String media : medias) { - types.add(MediaType.valueOf(media.trim())); + types.add(valueOf(media.trim())); } return types; } @@ -289,7 +299,7 @@ public static List toListOfMediaType(String[] mediaTypes) { List list = new ArrayList<>(mediaTypes.length); for (String mediaType : mediaTypes) { - list.add(MediaType.valueOf(mediaType)); + list.add(valueOf(mediaType)); } return Collections.unmodifiableList(list); diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java index 9b34b68e1caaa..d385e9672428f 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/ServerMediaType.java @@ -10,6 +10,8 @@ import jakarta.ws.rs.core.MediaType; +import org.jboss.resteasy.reactive.common.headers.MediaTypeHeaderDelegate; + /** * A representation of a server side media type. * @@ -25,7 +27,7 @@ public class ServerMediaType { public static List mediaTypesFromArray(String[] mediaTypesStrs) { List mediaTypes = new ArrayList<>(mediaTypesStrs.length); for (String mediaTypesStr : mediaTypesStrs) { - mediaTypes.add(MediaType.valueOf(mediaTypesStr)); + mediaTypes.add(MediaTypeHeaderDelegate.INSTANCE.fromString(mediaTypesStr)); } return mediaTypes; } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/EncodedMediaType.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/EncodedMediaType.java index 1c3c4310be4c9..9039e57b90116 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/EncodedMediaType.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/EncodedMediaType.java @@ -53,7 +53,7 @@ public MediaType getMediaType() { @Override public String getEncoded() { if (encoded == null) { - return encoded = mediaType.toString(); + return encoded = MediaTypeHelper.toString(mediaType); } return encoded; } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java index 2b655205434df..e67c23eceab45 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java @@ -149,7 +149,7 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, Map pathParameterIndexes = buildParamIndexMap(classPathTemplate, methodPathTemplate); MediaType streamElementType = null; if (method.getStreamElementType() != null) { - streamElementType = MediaType.valueOf(method.getStreamElementType()); + streamElementType = MediaTypeHelper.valueOf(method.getStreamElementType()); } List consumesMediaTypes; if (method.getConsumes() == null) { @@ -157,7 +157,7 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, } else { consumesMediaTypes = new ArrayList<>(method.getConsumes().length); for (String s : method.getConsumes()) { - consumesMediaTypes.add(MediaType.valueOf(s)); + consumesMediaTypes.add(MediaTypeHelper.valueOf(s)); } } @@ -407,7 +407,7 @@ public RuntimeResource buildResourceMethod(ResourceClass clazz, if (method.getProduces() != null && method.getProduces().length > 0) { //the method can only produce a single content type, which is the most common case if (method.getProduces().length == 1) { - MediaType mediaType = MediaType.valueOf(method.getProduces()[0]); + MediaType mediaType = MediaTypeHelper.valueOf(method.getProduces()[0]); //its a wildcard type, makes it hard to determine statically if (mediaType.isWildcardType() || mediaType.isWildcardSubtype()) { handlers.add(new VariableProducesHandler(serverMediaType, serialisers)); diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ClassRoutingHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ClassRoutingHandler.java index efbd79da49c24..b9bf02d05af53 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ClassRoutingHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ClassRoutingHandler.java @@ -114,7 +114,7 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti try { if (MediaTypeHelper.getFirstMatch( target.value.getConsumes(), - Collections.singletonList(MediaType.valueOf(contentType))) == null) { + Collections.singletonList(MediaTypeHelper.valueOf(contentType))) == null) { throw new NotSupportedException("The content-type header value did not match the value in @Consumes"); } } catch (IllegalArgumentException e) { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java index 79780144bb854..e824f8deb3e16 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java @@ -100,7 +100,7 @@ private List contentTypeFromRequest(ResteasyReactiveRequestContext re } List result = new ArrayList<>(contentTypeList.size()); for (String s : contentTypeList) { - result.add(MediaType.valueOf(s)); + result.add(MediaTypeHelper.valueOf(s)); } return result; } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java index 88bd9824402c5..a9b09c19c00b7 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/RequestDeserializeHandler.java @@ -52,7 +52,7 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti Object requestType = requestContext.getHeader(HttpHeaders.CONTENT_TYPE, true); if (requestType != null) { try { - effectiveRequestType = MediaType.valueOf((String) requestType); + effectiveRequestType = MediaTypeHelper.valueOf((String) requestType); } catch (Exception e) { log.debugv("Incorrect media type", e); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).build()); diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/HttpHeadersImpl.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/HttpHeadersImpl.java index 35185cb1ed0d8..2c1ea75accd86 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/HttpHeadersImpl.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/HttpHeadersImpl.java @@ -13,6 +13,7 @@ import org.jboss.resteasy.reactive.common.headers.HeaderUtil; import org.jboss.resteasy.reactive.common.util.CaseInsensitiveMap; +import org.jboss.resteasy.reactive.common.util.MediaTypeHelper; import org.jboss.resteasy.reactive.common.util.UnmodifiableMultivaluedMap; /** @@ -85,7 +86,7 @@ public MediaType getMediaType() { if (obj == cachedMediaTypeString) return cachedMediaType; cachedMediaTypeString = obj; - cachedMediaType = MediaType.valueOf(obj); + cachedMediaType = MediaTypeHelper.valueOf(obj); return cachedMediaType; } From e430fbbe653878290ecbdce324612d3d8a89d584 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 12:01:58 +0200 Subject: [PATCH 185/207] Use MethodHandle to invoke the application's main class --- .../bootstrap/runner/QuarkusEntryPoint.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/QuarkusEntryPoint.java b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/QuarkusEntryPoint.java index 1460516db4c2d..a53e7d43b020d 100644 --- a/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/QuarkusEntryPoint.java +++ b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/QuarkusEntryPoint.java @@ -5,7 +5,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; @@ -31,14 +34,16 @@ public static void main(String... args) throws Throwable { try { doRun(args); - } catch (Exception e) { + } catch (RuntimeException | Error e) { InitialConfigurator.DELAYED_HANDLER.close(); throw e; + } catch (Throwable t) { + InitialConfigurator.DELAYED_HANDLER.close(); + throw new UndeclaredThrowableException(t); } } - private static void doRun(Object args) throws IOException, ClassNotFoundException, IllegalAccessException, - InvocationTargetException, NoSuchMethodException { + private static void doRun(String... args) throws Throwable { String path = QuarkusEntryPoint.class.getProtectionDomain().getCodeSource().getLocation().getPath(); String decodedPath = URLDecoder.decode(path, StandardCharsets.UTF_8); Path appRoot = new File(decodedPath).toPath().getParent().getParent().getParent(); @@ -59,7 +64,8 @@ private static void doRun(Object args) throws IOException, ClassNotFoundExceptio Thread.currentThread().setContextClassLoader(appRunnerClassLoader); QuarkusForkJoinWorkerThread.setQuarkusAppClassloader(appRunnerClassLoader); Class mainClass = appRunnerClassLoader.loadClass(app.getMainClass()); - mainClass.getMethod("main", String[].class).invoke(null, args); + MethodHandles.Lookup lookup = MethodHandles.lookup(); + lookup.findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)).invokeExact(args); } finally { QuarkusForkJoinWorkerThread.setQuarkusAppClassloader(null); appRunnerClassLoader.close(); From 38d776a2106094b62be42a46b375f6f4c591dae0 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 09:53:07 +0200 Subject: [PATCH 186/207] Use MethodHandle to invoke the generated Application class --- .../main/java/io/quarkus/runtime/Quarkus.java | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java b/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java index d58d2641dc2c2..dc54e1fdcf309 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java @@ -2,6 +2,10 @@ import java.io.Closeable; import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.UndeclaredThrowableException; import java.util.Locale; import java.util.function.BiConsumer; @@ -67,18 +71,17 @@ public static void run(Class quarkusApplication, B //we already have an application, run it directly Class appClass = (Class) Class.forName(Application.APP_CLASS_NAME, false, Thread.currentThread().getContextClassLoader()); - Application application = appClass.getDeclaredConstructor().newInstance(); + MethodHandle constructor = MethodHandles.lookup().findConstructor(appClass, MethodType.methodType(void.class)); + Application application = (Application) constructor.invoke(); ApplicationLifecycleManager.run(application, quarkusApplication, exitHandler, args); return; } catch (ClassNotFoundException e) { //ignore, this happens when running in dev mode - } catch (Exception e) { - if (exitHandler != null) { - exitHandler.accept(1, e); - } else { - Logger.getLogger(Quarkus.class).error("Error running Quarkus", e); - ApplicationLifecycleManager.getDefaultExitCodeHandler().accept(1, e); - } + } catch (RuntimeException | Error e) { + handleReflectiveInvocationIssue(exitHandler, e); + return; + } catch (Throwable t) { + handleReflectiveInvocationIssue(exitHandler, new UndeclaredThrowableException(t)); return; } @@ -89,6 +92,15 @@ public static void run(Class quarkusApplication, B } + private static void handleReflectiveInvocationIssue(BiConsumer exitHandler, Throwable t) { + if (exitHandler != null) { + exitHandler.accept(1, t); + } else { + Logger.getLogger(Quarkus.class).error("Error running Quarkus", t); + ApplicationLifecycleManager.getDefaultExitCodeHandler().accept(1, t); + } + } + private static void launchFromIDE(Class quarkusApplication, String... args) { //some trickery, get the class that has invoked us, and use this to figure out the //classes root From 27c3c7fcbb4fad653980e43057a0f06f580b7b7a Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 10:46:45 +0200 Subject: [PATCH 187/207] Polish Quarkus.java --- core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java b/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java index dc54e1fdcf309..f9c3725d73fac 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java @@ -60,6 +60,7 @@ public static void run(Class quarkusApplication, S * has finished * @param args The command line parameters */ + @SuppressWarnings("unchecked") public static void run(Class quarkusApplication, BiConsumer exitHandler, String... args) { try { From 6f82e71a91934bdcf0bbfb31e6dded2c4995ebaf Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 10:59:02 +0200 Subject: [PATCH 188/207] Make DefaultInstanceFactory a static inner class --- .../src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java index 51b2cf3627224..08e3750bcaaee 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java @@ -85,7 +85,7 @@ public ManagedContext requestContext() { * * @param represents the type that this factory can create */ - private final class DefaultInstanceFactory implements BeanContainer.Factory { + private static final class DefaultInstanceFactory implements BeanContainer.Factory { private final Class type; From a799237de90be77ecfdb6fa9b5cac5b740e4e308 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 20 Dec 2024 11:05:50 +0200 Subject: [PATCH 189/207] Replace reflection with MethodHandle in DefaultInstanceFactory This shouldn't really change anything in practice, but MethodHandles are supposed to perform slightly better than old school reflection --- .../quarkus/arc/runtime/BeanContainerImpl.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java index 08e3750bcaaee..e9a2256497b99 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java @@ -1,7 +1,9 @@ package io.quarkus.arc.runtime; import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.UndeclaredThrowableException; import java.util.Arrays; import java.util.function.Supplier; @@ -87,24 +89,30 @@ public ManagedContext requestContext() { */ private static final class DefaultInstanceFactory implements BeanContainer.Factory { + private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + private static final MethodType VOID_TYPE = MethodType.methodType(void.class); + private final Class type; DefaultInstanceFactory(Class type) { this.type = type; } + @SuppressWarnings("unchecked") @Override public BeanContainer.Instance create() { try { - T instance = type.getDeclaredConstructor().newInstance(); - return new BeanContainer.Instance() { + T instance = (T) LOOKUP.findConstructor(type, VOID_TYPE).invoke(); + return new BeanContainer.Instance<>() { @Override public T get() { return instance; } }; - } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { - throw new RuntimeException(e); + } catch (RuntimeException | Error e) { + throw e; + } catch (Throwable t) { + throw new UndeclaredThrowableException(t); } } } From 760c5c9d65aa67b8a01d4d5c5fc80e879629b92c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 22:19:28 +0000 Subject: [PATCH 190/207] Bump hibernate-orm.version from 6.6.3.Final to 6.6.4.Final Bumps `hibernate-orm.version` from 6.6.3.Final to 6.6.4.Final. Updates `org.hibernate.orm:hibernate-core` from 6.6.3.Final to 6.6.4.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.4/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.3...6.6.4) Updates `org.hibernate.orm:hibernate-graalvm` from 6.6.3.Final to 6.6.4.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.4/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.3...6.6.4) Updates `org.hibernate.orm:hibernate-envers` from 6.6.3.Final to 6.6.4.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.4/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.3...6.6.4) Updates `org.hibernate.orm:hibernate-jpamodelgen` from 6.6.3.Final to 6.6.4.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.4/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.3...6.6.4) Updates `org.hibernate:hibernate-jpamodelgen` from 6.6.3.Final to 6.6.4.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.4/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.3...6.6.4) Updates `org.hibernate.orm:hibernate-community-dialects` from 6.6.3.Final to 6.6.4.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.4/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.3...6.6.4) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.hibernate.orm:hibernate-graalvm dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.hibernate.orm:hibernate-envers dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.hibernate.orm:hibernate-jpamodelgen dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.hibernate:hibernate-jpamodelgen dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.hibernate.orm:hibernate-community-dialects dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f4198885401f4..051024017f7a3 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ 0.8.12 6.13.4 5.5.0 - 6.6.3.Final + 6.6.4.Final 4.13.0 1.14.18 7.0.3.Final From 128186c6eaeac08cc6db1092b4fbea042decefe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 20 Dec 2024 18:04:02 +0100 Subject: [PATCH 191/207] Upgrade to Hibernate Reactive 2.4.3.Final --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 051024017f7a3..f97057615cc69 100644 --- a/pom.xml +++ b/pom.xml @@ -75,7 +75,7 @@ 4.13.0 1.14.18 7.0.3.Final - 2.4.2.Final + 2.4.3.Final 8.0.2.Final 7.2.2.Final From f494fd519c7ec23013cb800396c587a582a92d8d Mon Sep 17 00:00:00 2001 From: Alex Martel <13215031+manofthepeace@users.noreply.github.com> Date: Fri, 20 Dec 2024 12:13:31 -0500 Subject: [PATCH 192/207] Lazily access ObjectMapper in Quarkus REST FullyFeaturedServerJacksonMessageBodyWriter --- ...eaturedServerJacksonMessageBodyWriter.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/FullyFeaturedServerJacksonMessageBodyWriter.java b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/FullyFeaturedServerJacksonMessageBodyWriter.java index 93d0b58600aae..6728c7f11553b 100644 --- a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/FullyFeaturedServerJacksonMessageBodyWriter.java +++ b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/serialisers/FullyFeaturedServerJacksonMessageBodyWriter.java @@ -14,7 +14,9 @@ import java.util.concurrent.ConcurrentMap; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Supplier; +import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; @@ -30,24 +32,30 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; +import io.quarkus.arc.impl.LazyValue; import io.quarkus.resteasy.reactive.jackson.runtime.ResteasyReactiveServerJacksonRecorder; import io.quarkus.resteasy.reactive.jackson.runtime.mappers.JacksonMapperUtil; public class FullyFeaturedServerJacksonMessageBodyWriter extends ServerMessageBodyWriter.AllWriteableMessageBodyWriter { - private final ObjectMapper originalMapper; + private final Instance originalMapper; private final Providers providers; - private final ObjectWriter defaultWriter; + private final LazyValue defaultWriter; private final ConcurrentMap perMethodWriter = new ConcurrentHashMap<>(); private final ConcurrentMap perTypeWriter = new ConcurrentHashMap<>(); private final ConcurrentMap, ObjectMapper> contextResolverMap = new ConcurrentHashMap<>(); private final ConcurrentMap objectWriterMap = new ConcurrentHashMap<>(); @Inject - public FullyFeaturedServerJacksonMessageBodyWriter(ObjectMapper mapper, Providers providers) { + public FullyFeaturedServerJacksonMessageBodyWriter(Instance mapper, Providers providers) { this.originalMapper = mapper; - this.defaultWriter = createDefaultWriter(mapper); this.providers = providers; + this.defaultWriter = new LazyValue<>(new Supplier<>() { + @Override + public ObjectWriter get() { + return createDefaultWriter(mapper.get()); + } + }); } @Override @@ -122,8 +130,8 @@ private ObjectWriter getObjectWriterFromAnnotations(ResteasyReactiveResourceInfo } private ObjectWriter getEffectiveWriter(ObjectMapper effectiveMapper) { - if (effectiveMapper == originalMapper) { - return defaultWriter; + if (effectiveMapper == originalMapper.get()) { + return defaultWriter.get(); } return objectWriterMap.computeIfAbsent(effectiveMapper, new Function<>() { @Override @@ -138,7 +146,7 @@ public ObjectWriter apply(ObjectMapper objectMapper) { * Otherwise, returns the default {@link ObjectMapper}. */ private ObjectMapper getEffectiveMapper(Object o, ServerRequestContext context) { - ObjectMapper effectiveMapper = originalMapper; + ObjectMapper effectiveMapper = originalMapper.get(); ContextResolver contextResolver = providers.getContextResolver(ObjectMapper.class, context.getResponseMediaType()); if (contextResolver == null) { @@ -163,7 +171,7 @@ public ObjectMapper apply(Class aClass) { @Override public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { - doLegacyWrite(o, annotations, httpHeaders, entityStream, defaultWriter); + doLegacyWrite(o, annotations, httpHeaders, entityStream, defaultWriter.get()); } private static class MethodObjectWriterFunction implements Function { From ed814fddc66c93ec961057a3b201cb80240cea65 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 20 Dec 2024 18:20:00 +0100 Subject: [PATCH 193/207] Update quarkus-project-develocity-extension to 1.1.8 --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 9c438a9c1d96d..2292cd139ef03 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -17,6 +17,6 @@ io.quarkus.develocity quarkus-project-develocity-extension - 1.1.7 + 1.1.8 From f7a8946e07288474540e2b554cac3abb45f2d2c3 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Tue, 17 Sep 2024 17:42:36 +0100 Subject: [PATCH 194/207] Support for OIDC MTLS binding --- ...rity-oidc-bearer-token-authentication.adoc | 75 + .../KeycloakDevServicesProcessor.java | 39 +- .../oidc/common/runtime/OidcConstants.java | 3 + .../io/quarkus/oidc/OidcTenantConfig.java | 39 + .../BearerAuthenticationMechanism.java | 32 + .../oidc/runtime/OidcIdentityProvider.java | 44 +- .../oidc/runtime/OidcTenantConfig.java | 18 + .../io/quarkus/oidc/runtime/OidcUtils.java | 2 + .../runtime/builders/TokenConfigBuilder.java | 87 +- .../oidc/runtime/OidcTenantConfigImpl.java | 14 + .../io/quarkus/it/oidc/OidcMtlsEndpoint.java | 47 +- .../src/main/resources/application.properties | 58 +- .../src/main/resources/quarkus-realm.json | 2530 +++++++++++++++++ .../KeycloakTestResourceLifecycleManager.java | 49 + .../java/io/quarkus/it/oidc/OidcMtlsTest.java | 86 +- 15 files changed, 3086 insertions(+), 37 deletions(-) create mode 100644 integration-tests/oidc-mtls/src/main/resources/quarkus-realm.json create mode 100644 integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/KeycloakTestResourceLifecycleManager.java diff --git a/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc b/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc index bc2a4fcecd343..aa7554a5a75db 100644 --- a/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc +++ b/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc @@ -1244,6 +1244,81 @@ If you set `quarkus.oidc.client-id`, but your endpoint does not require remote a Quarkus `web-app` applications always require the `quarkus.oidc.client-id` property. ==== +== Mutual TLS token binding + +https://datatracker.ietf.org/doc/html/rfc8705[RFC8705] describes a mechanism for binding access tokens to Mutual TLS (mTLS) client authentication certificates. +It requires that a client certificate's SHA256 thumbprint matches a JWT token or token introspection confirmation `x5t#S256` certificate thumbprint. + +For example, see https://datatracker.ietf.org/doc/html/rfc8705#section-3.1[JWT Certificate Thumbprint Confirmation Method] and https://datatracker.ietf.org/doc/html/rfc8705#section-3.2[Confirmation Method for Token Introspection] sections of https://datatracker.ietf.org/doc/html/rfc8705[RFC8705]. + +MTLS token binding supports a `holder of key` concept, and can be used to confirm that the current access token was issued to the current authenticated client who presents this token. + +When you use both mTLS and OIDC bearer authentication mechanisms, you can enforce that the access tokens must be certificate bound with a single property, after configuring your Quarkus endpoint and Quarkus OIDC to require the use of mTLS. + +For example: + +[source,properties] +---- +quarkus.oidc.auth-server-url=${your_oidc_provider_url} +quarkus.oidc.token.binding.certificate=true <1> +quarkus.oidc.tls.tls-configuration-name=oidc-client-tls <2> + +quarkus.tls.oidc-client-tls.key-store.p12.path=target/certificates/oidc-client-keystore.p12 <2> +quarkus.tls.oidc-client-tls.key-store.p12.password=password +quarkus.tls.oidc-client-tls.trust-store.p12.path=target/certificates/oidc-client-truststore.p12 +quarkus.tls.oidc-client-tls.trust-store.p12.password=password + +quarkus.http.tls-configuration-name=oidc-server-mtls <3> +quarkus.tls.oidc-server-mtls.key-store.p12.path=target/certificates/oidc-keystore.p12 +quarkus.tls.oidc-server-mtls.key-store.p12.password=password +quarkus.tls.oidc-server-mtls.trust-store.p12.path=target/certificates/oidc-server-truststore.p12 +quarkus.tls.oidc-server-mtls.trust-store.p12.password=password +---- +<1> Require that bearer access tokens must be bound to the client certificates. +<2> TLS registry configuration for Quarkus OIDC be able to communicate with the OIDC provider over MTLS +<3> TLS registry configuration requiring external clients to authenticate to the Quarkus endpoint over MTLS + +The above configuration is sufficient to require that OIDC bearer tokens are bound to the client certificates. + +Next, if you need to access both mTLS and OIDC bearer security identities, consider enabling xref:security-authentication-mechanisms#combining-authentication-mechanisms[Inclusive authentication] with `quarkus.http.auth.inclusive=true`. + +Now you can access both MTLS and OIDC security identities as follows: + +[source,java] +---- +package io.quarkus.it.oidc; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.eclipse.microprofile.jwt.JsonWebToken; +import io.quarkus.security.Authenticated; +import io.quarkus.security.credential.CertificateCredential; +import io.quarkus.security.identity.SecurityIdentity; + +@Path("/service") +@Authenticated +public class OidcMtlsEndpoint { + + @Inject + SecurityIdentity mtlsIdentity; <1> + + @Inject + JsonWebToken oidcAccessToken; <2> + + @GET + public String getIdentities() { + var cred = identity.getCredential(CertificateCredential.class).getCertificate(); + return "Identities: " + cred.getSubjectX500Principal().getName().split(",")[0] + + ", " + accessToken.getName(); + } +} +---- +<1> `SecurityIdentity` always represents the primary mTLS authentication when mTLS is used and an inclusive authentication is enabled. +<2> OIDC security identity is also available because enabling an inclusive authentication requires all registered mechanisms to produce the security identity. + + == Authentication after an HTTP request has completed Sometimes, `SecurityIdentity` for a given token must be created when there is no active HTTP request context. diff --git a/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesProcessor.java b/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesProcessor.java index c317f8fc6456d..6227b263b3125 100644 --- a/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesProcessor.java +++ b/extensions/devservices/keycloak/src/main/java/io/quarkus/devservices/keycloak/KeycloakDevServicesProcessor.java @@ -303,7 +303,7 @@ private static Map prepareConfiguration( BuildProducer keycloakBuildItemBuildProducer, String internalURL, String hostURL, List realmReps, List errors, KeycloakDevServicesConfigurator devServicesConfigurator, String internalBaseUrl) { - final String realmName = realmReps != null && !realmReps.isEmpty() ? realmReps.iterator().next().getRealm() + final String realmName = !realmReps.isEmpty() ? realmReps.iterator().next().getRealm() : getDefaultRealmName(); final String authServerInternalUrl = realmsURL(internalURL, realmName); @@ -320,29 +320,32 @@ private static Map prepareConfiguration( List realmNames = new LinkedList<>(); - // this needs to be only if we actually start the dev-service as it adds a shutdown hook - // whose TCCL is the Augmentation CL, which if not removed, causes a massive memory leaks - if (vertxInstance == null) { - vertxInstance = Vertx.vertx(); - } + if (createDefaultRealm || !realmReps.isEmpty()) { - WebClient client = createWebClient(vertxInstance); - try { - String adminToken = getAdminToken(client, clientAuthServerBaseUrl); - if (createDefaultRealm) { - createDefaultRealm(client, adminToken, clientAuthServerBaseUrl, users, oidcClientId, oidcClientSecret, errors, - devServicesConfigurator); - realmNames.add(realmName); - } else { - if (realmReps != null) { + // this needs to be only if we actually start the dev-service as it adds a shutdown hook + // whose TCCL is the Augmentation CL, which if not removed, causes a massive memory leaks + if (vertxInstance == null) { + vertxInstance = Vertx.vertx(); + } + + WebClient client = createWebClient(vertxInstance); + try { + String adminToken = getAdminToken(client, clientAuthServerBaseUrl); + if (createDefaultRealm) { + createDefaultRealm(client, adminToken, clientAuthServerBaseUrl, users, oidcClientId, oidcClientSecret, + errors, + devServicesConfigurator); + realmNames.add(realmName); + } else if (realmReps != null) { for (RealmRepresentation realmRep : realmReps) { createRealm(client, adminToken, clientAuthServerBaseUrl, realmRep, errors); realmNames.add(realmRep.getRealm()); } } + + } finally { + client.close(); } - } finally { - client.close(); } Map configProperties = new HashMap<>(); @@ -427,7 +430,7 @@ private static RunningDevService startContainer( // TODO: this probably needs to be addressed String sharedContainerUrl = getSharedContainerUrl(containerAddress); Map configs = prepareConfiguration(keycloakBuildItemBuildProducer, sharedContainerUrl, - sharedContainerUrl, null, errors, devServicesConfigurator, sharedContainerUrl); + sharedContainerUrl, List.of(), errors, devServicesConfigurator, sharedContainerUrl); return new RunningDevService(KEYCLOAK_CONTAINER_NAME, containerAddress.getId(), null, configs); }) .orElseGet(defaultKeycloakContainerSupplier); diff --git a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcConstants.java b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcConstants.java index 8dc67f4f41e11..5fb2e9f7f40c9 100644 --- a/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcConstants.java +++ b/extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcConstants.java @@ -85,4 +85,7 @@ public final class OidcConstants { public static final String CLIENT_METADATA_POST_LOGOUT_URIS = "post_logout_redirect_uris"; public static final String CLIENT_METADATA_SECRET_EXPIRES_AT = "client_secret_expires_at"; public static final String CLIENT_METADATA_ID_ISSUED_AT = "client_id_issued_at"; + + public static final String CONFIRMATION_CLAIM = "cnf"; + public static final String X509_SHA256_THUMBPRINT = "x5t#S256"; } diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java index 2111b756bb59e..d32ed85645deb 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java @@ -2340,6 +2340,11 @@ public static Token fromAudience(String... audience) { */ public Optional verifyAccessTokenWithUserInfo = Optional.empty(); + /** + * Token binding options + */ + Binding binding = new Binding(); + public Optional isVerifyAccessTokenWithUserInfo() { return verifyAccessTokenWithUserInfo; } @@ -2436,6 +2441,14 @@ public void setAllowOpaqueTokenIntrospection(boolean allowOpaqueTokenIntrospecti this.allowOpaqueTokenIntrospection = allowOpaqueTokenIntrospection; } + public Binding getBinding() { + return binding; + } + + public io.quarkus.oidc.runtime.OidcTenantConfig.Binding binding() { + return binding; + } + public Optional getAge() { return age; } @@ -2530,6 +2543,7 @@ private void addConfigMappingValues(io.quarkus.oidc.runtime.OidcTenantConfig.Tok allowOpaqueTokenIntrospection = mapping.allowOpaqueTokenIntrospection(); customizerName = mapping.customizerName(); verifyAccessTokenWithUserInfo = mapping.verifyAccessTokenWithUserInfo(); + binding.addConfigMappingValues(mapping.binding()); } @Override @@ -2639,6 +2653,31 @@ public Optional verifyAccessTokenWithUserInfo() { } } + /** + * @deprecated use the {@link TokenConfigBuilder.BindingConfigBuilder} builder + */ + @Deprecated(since = "3.18") + public static class Binding implements io.quarkus.oidc.runtime.OidcTenantConfig.Binding { + + /** + * If a bearer access token must be bound to the client mTLS certificate. + * It requires that JWT tokens must contain a confirmation `cnf` claim with a SHA256 certificate thumbprint + * matching the client mTLS certificate's SHA256 certificate thumbprint. + *

    + * For opaque tokens, SHA256 certificate thumbprint must be returned in their introspection response. + */ + public boolean certificate = false; + + @Override + public boolean certificate() { + return certificate; + } + + private void addConfigMappingValues(io.quarkus.oidc.runtime.OidcTenantConfig.Binding mapping) { + certificate = mapping.certificate(); + } + } + public static enum ApplicationType { /** * A {@code WEB_APP} is a client that serves pages, usually a front-end application. For this type of client the diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/BearerAuthenticationMechanism.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/BearerAuthenticationMechanism.java index f176785c8864a..8fabfca0601ba 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/BearerAuthenticationMechanism.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/BearerAuthenticationMechanism.java @@ -2,14 +2,20 @@ import static io.quarkus.oidc.runtime.OidcUtils.extractBearerToken; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; import java.util.function.Function; +import javax.net.ssl.SSLPeerUnverifiedException; + import org.jboss.logging.Logger; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpResponseStatus; import io.quarkus.oidc.AccessTokenCredential; import io.quarkus.oidc.OidcTenantConfig; +import io.quarkus.oidc.common.runtime.OidcConstants; +import io.quarkus.security.AuthenticationFailedException; import io.quarkus.security.identity.IdentityProviderManager; import io.quarkus.security.identity.SecurityIdentity; import io.quarkus.vertx.http.runtime.security.ChallengeData; @@ -25,12 +31,38 @@ public Uni authenticate(RoutingContext context, String token = extractBearerToken(context, oidcTenantConfig); // if a bearer token is provided try to authenticate if (token != null) { + try { + setCertificateThumbprint(context, oidcTenantConfig); + } catch (AuthenticationFailedException ex) { + return Uni.createFrom().failure(ex); + } return authenticate(identityProviderManager, context, new AccessTokenCredential(token)); } LOG.debug("Bearer access token is not available"); return Uni.createFrom().nullItem(); } + private static void setCertificateThumbprint(RoutingContext context, OidcTenantConfig oidcTenantConfig) { + if (oidcTenantConfig.token().binding().certificate()) { + Certificate cert = getCertificate(context); + if (!(cert instanceof X509Certificate)) { + LOG.warn("Access token must be bound to X509 client certiifcate"); + throw new AuthenticationFailedException(); + } + context.put(OidcConstants.X509_SHA256_THUMBPRINT, + TrustStoreUtils.calculateThumprint((X509Certificate) cert)); + } + } + + private static Certificate getCertificate(RoutingContext context) { + try { + return context.request().sslSession().getPeerCertificates()[0]; + } catch (SSLPeerUnverifiedException e) { + LOG.warn("Access token must be certificate bound but no client certificate is available"); + throw new AuthenticationFailedException(); + } + } + public Uni getChallenge(RoutingContext context) { Uni tenantContext = resolver.resolveContext(context); return tenantContext.onItem().transformToUni(new Function>() { diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java index 673757cbd291d..a850d77373dfc 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java @@ -197,9 +197,49 @@ private Uni verifyPrimaryTokenUni(Map r return verifySelfSignedTokenUni(resolvedContext, request.getToken().getToken()); } } else { - return verifyTokenUni(requestData, resolvedContext, request.getToken(), - isIdToken(request), userInfo); + final boolean idToken = isIdToken(request); + Uni result = verifyTokenUni(requestData, resolvedContext, request.getToken(), idToken, + userInfo); + if (!idToken && resolvedContext.oidcConfig().token().binding().certificate()) { + return result.onItem().transform(new Function() { + + @Override + public TokenVerificationResult apply(TokenVerificationResult t) { + String tokenCertificateThumbprint = getTokenCertThumbprint(requestData, t); + if (tokenCertificateThumbprint == null) { + LOG.warn( + "Access token does not contain a confirmation 'cnf' claim with the certificate thumbprint"); + throw new AuthenticationFailedException(); + } + String clientCertificateThumbprint = (String) requestData.get(OidcConstants.X509_SHA256_THUMBPRINT); + if (clientCertificateThumbprint == null) { + LOG.warn("Client certificate thumbprint is not available"); + throw new AuthenticationFailedException(); + } + if (!clientCertificateThumbprint.equals(tokenCertificateThumbprint)) { + LOG.warn("Client certificate thumbprint does not match the token certificate thumbprint"); + throw new AuthenticationFailedException(); + } + return t; + } + + }); + } else { + return result; + } + } + } + + private static String getTokenCertThumbprint(Map requestData, TokenVerificationResult t) { + JsonObject json = t.localVerificationResult != null ? t.localVerificationResult + : new JsonObject(t.introspectionResult.getIntrospectionString()); + JsonObject cnf = json.getJsonObject(OidcConstants.CONFIRMATION_CLAIM); + String thumbprint = cnf == null ? null : cnf.getString(OidcConstants.X509_SHA256_THUMBPRINT); + if (thumbprint != null) { + requestData.put((t.introspectionResult == null ? OidcUtils.JWT_THUMBPRINT : OidcUtils.INTROSPECTION_THUMBPRINT), + true); } + return thumbprint; } private Uni getUserInfoAndCreateIdentity(Uni tokenUni, diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcTenantConfig.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcTenantConfig.java index f3c9c1463458c..bdbeb99f785fd 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcTenantConfig.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcTenantConfig.java @@ -1106,6 +1106,24 @@ interface Token { @ConfigDocDefault("false") Optional verifyAccessTokenWithUserInfo(); + /** + * Token certificate binding options. + */ + Binding binding(); + + } + + interface Binding { + + /** + * If a bearer access token must be bound to the client mTLS certificate. + * It requires that JWT tokens must contain a confirmation `cnf` claim with a SHA256 certificate thumbprint + * matching the client mTLS certificate's SHA256 certificate thumbprint. + *

    + * For opaque tokens, SHA256 certificate thumbprint must be returned in their introspection response. + */ + @WithDefault("false") + boolean certificate(); } enum ApplicationType { diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java index 486ae0548e589..d7e4498ff9f9e 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java @@ -94,6 +94,8 @@ public final class OidcUtils { public static final String SESSION_AT_COOKIE_NAME = SESSION_COOKIE_NAME + ACCESS_TOKEN_COOKIE_SUFFIX; public static final String SESSION_RT_COOKIE_NAME = SESSION_COOKIE_NAME + REFRESH_TOKEN_COOKIE_SUFFIX; public static final String STATE_COOKIE_NAME = "q_auth"; + public static final String JWT_THUMBPRINT = "jwt_thumbprint"; + public static final String INTROSPECTION_THUMBPRINT = "introspection_thumbprint"; // Browsers enforce that the total Set-Cookie expression such as // `q_session_tenant-a=,Path=/somepath,Expires=...` does not exceed 4096 diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/builders/TokenConfigBuilder.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/builders/TokenConfigBuilder.java index cefe25f9dd82a..fed0552f6e248 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/builders/TokenConfigBuilder.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/builders/TokenConfigBuilder.java @@ -12,6 +12,7 @@ import io.quarkus.oidc.OidcTenantConfigBuilder; import io.quarkus.oidc.runtime.OidcTenantConfig; +import io.quarkus.oidc.runtime.OidcTenantConfig.Binding; /** * Builder for the {@link OidcTenantConfig.Token}. @@ -25,7 +26,7 @@ private record TokenImpl(Optional issuer, Optional> audienc String authorizationScheme, Optional signatureAlgorithm, Optional decryptionKeyLocation, boolean allowJwtIntrospection, boolean requireJwtIntrospectionOnly, boolean allowOpaqueTokenIntrospection, Optional customizerName, - Optional verifyAccessTokenWithUserInfo) implements OidcTenantConfig.Token { + Optional verifyAccessTokenWithUserInfo, Binding binding) implements OidcTenantConfig.Token { } private final OidcTenantConfigBuilder builder; @@ -50,6 +51,7 @@ private record TokenImpl(Optional issuer, Optional> audienc private boolean allowOpaqueTokenIntrospection; private Optional customizerName; private Optional verifyAccessTokenWithUserInfo; + private Binding binding; public TokenConfigBuilder() { this(new OidcTenantConfigBuilder()); @@ -83,6 +85,7 @@ public TokenConfigBuilder(OidcTenantConfigBuilder builder) { this.allowOpaqueTokenIntrospection = token.allowOpaqueTokenIntrospection(); this.customizerName = token.customizerName(); this.verifyAccessTokenWithUserInfo = token.verifyAccessTokenWithUserInfo(); + this.binding = token.binding(); } /** @@ -371,6 +374,31 @@ public TokenConfigBuilder verifyAccessTokenWithUserInfo(boolean verifyAccessToke return this; } + /** + * binding {@link OidcTenantConfig.Token#binding()} + * + * @return BindingConfigBuilder + */ + public BindingConfigBuilder binding() { + return new BindingConfigBuilder(this); + } + + /** + * @param binding {@link OidcTenantConfig#)} + * @return this builder + */ + public TokenConfigBuilder binding(Binding binding) { + this.binding = Objects.requireNonNull(binding); + return this; + } + + /** + * @return current {@link Binding} instance + */ + public Binding getBinding() { + return binding; + } + /** * @return built {@link OidcTenantConfig.Token} */ @@ -381,7 +409,62 @@ public OidcTenantConfig.Token build() { lifespanGrace, age, issuedAtRequired, principalClaim, refreshExpired, refreshTokenTimeSkew, forcedJwkRefreshInterval, header, authorizationScheme, signatureAlgorithm, decryptionKeyLocation, allowJwtIntrospection, requireJwtIntrospectionOnly, allowOpaqueTokenIntrospection, customizerName, - verifyAccessTokenWithUserInfo); + verifyAccessTokenWithUserInfo, binding); + } + + /** + * Builder for the {@link OidcTenantConfig.Token}. + */ + public static final class BindingConfigBuilder { + + private record BindingImpl(boolean certificate) implements OidcTenantConfig.Binding { + } + + private final TokenConfigBuilder builder; + private boolean certificate; + + public BindingConfigBuilder() { + this(new TokenConfigBuilder()); + } + + public BindingConfigBuilder(TokenConfigBuilder builder) { + this.builder = Objects.requireNonNull(builder); + var binding = builder.getBinding(); + this.certificate = binding.certificate(); + } + + /** + * @return TokenConfigBuilder builder + */ + public TokenConfigBuilder end() { + return builder.binding(build()); + } + + /** + * Sets {@link OidcTenantConfig.Binding#certificate()} to true. + * + * @return this builder + */ + public BindingConfigBuilder certificate() { + return certificate(true); + } + + /** + * @param certificate {@link OidcTenantConfig.Binding#certificate()} + * @return this builder + */ + public BindingConfigBuilder certificate(boolean certificate) { + this.certificate = certificate; + return this; + } + + /** + * @return built {@link OidcTenantConfig.Token} + */ + public OidcTenantConfig.Binding build() { + return new BindingImpl(certificate); + } + } } diff --git a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java index 73bc8ddf0671b..901016e517153 100644 --- a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java +++ b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java @@ -189,6 +189,8 @@ enum ConfigMappingMethods { TOKEN_ALLOW_OPAQUE_TOKEN_INTROSPECTION, TOKEN_CUSTOMIZER_NAME, TOKEN_VERIFY_ACCESS_TOKEN_WITH_USER_INFO, + TOKEN_BINDING, + TOKEN_BINDING_CERTIFICATE, ROLES_ROLE_CLAIM_PATH, ROLES_ROLE_CLAIM_SEPARATOR, ROLES_SOURCE, @@ -438,6 +440,18 @@ public Optional verifyAccessTokenWithUserInfo() { invocationsRecorder.put(ConfigMappingMethods.TOKEN_VERIFY_ACCESS_TOKEN_WITH_USER_INFO, true); return Optional.empty(); } + + @Override + public Binding binding() { + invocationsRecorder.put(ConfigMappingMethods.TOKEN_BINDING, true); + return new Binding() { + @Override + public boolean certificate() { + invocationsRecorder.put(ConfigMappingMethods.TOKEN_BINDING_CERTIFICATE, true); + return false; + } + }; + } }; } diff --git a/integration-tests/oidc-mtls/src/main/java/io/quarkus/it/oidc/OidcMtlsEndpoint.java b/integration-tests/oidc-mtls/src/main/java/io/quarkus/it/oidc/OidcMtlsEndpoint.java index 53319e396b3f8..1b9f0d5dcf0ba 100644 --- a/integration-tests/oidc-mtls/src/main/java/io/quarkus/it/oidc/OidcMtlsEndpoint.java +++ b/integration-tests/oidc-mtls/src/main/java/io/quarkus/it/oidc/OidcMtlsEndpoint.java @@ -6,10 +6,14 @@ import org.eclipse.microprofile.jwt.JsonWebToken; +import io.quarkus.oidc.runtime.OidcUtils; +import io.quarkus.security.Authenticated; import io.quarkus.security.credential.CertificateCredential; import io.quarkus.security.identity.SecurityIdentity; +import io.vertx.ext.web.RoutingContext; @Path("/service") +@Authenticated public class OidcMtlsEndpoint { @Inject @@ -18,11 +22,48 @@ public class OidcMtlsEndpoint { @Inject JsonWebToken accessToken; + @Inject + RoutingContext routingContext; + + @GET + @Path("mtls-jwt") + public String getNameJwt() { + var cred = identity.getCredential(CertificateCredential.class).getCertificate(); + return "Identities: " + cred.getSubjectX500Principal().getName().split(",")[0] + + ", " + accessToken.getName() + "; " + + "Client: " + accessToken.getClaim("azp") + "; " + + "JWT cert thumbprint: " + isJwtTokenThumbprintAvailable() + ", " + + "introspection cert thumbprint: " + isIntrospectionThumbprintAvailable(); + } + + @GET + @Path("mtls-introspection") + public String getNameIntrospection() { + var cred = identity.getCredential(CertificateCredential.class).getCertificate(); + return "Identities: " + cred.getSubjectX500Principal().getName().split(",")[0] + ", " + + accessToken.getName() + "; " + + "Client: " + accessToken.getClaim("azp") + "; " + + "JWT cert thumbprint: " + isJwtTokenThumbprintAvailable() + ", " + + "introspection cert thumbprint: " + isIntrospectionThumbprintAvailable(); + } + @GET - @Path("name") - public String getName() { + @Path("mtls-client-with-secret") + public String getNameMtlsClientWithSecret() { var cred = identity.getCredential(CertificateCredential.class).getCertificate(); return "Identities: " + cred.getSubjectX500Principal().getName().split(",")[0] + ", " - + accessToken.getName(); + + accessToken.getName() + "; " + + "Client: " + accessToken.getClaim("azp") + "; " + + "JWT cert thumbprint: " + isJwtTokenThumbprintAvailable() + ", " + + "introspection cert thumbprint: " + isIntrospectionThumbprintAvailable(); + } + + private boolean isJwtTokenThumbprintAvailable() { + return Boolean.TRUE.equals(routingContext.get(OidcUtils.JWT_THUMBPRINT)); + } + + private boolean isIntrospectionThumbprintAvailable() { + + return Boolean.TRUE.equals(routingContext.get(OidcUtils.INTROSPECTION_THUMBPRINT)); } } diff --git a/integration-tests/oidc-mtls/src/main/resources/application.properties b/integration-tests/oidc-mtls/src/main/resources/application.properties index 939e259a700ac..0c2e0521ca021 100644 --- a/integration-tests/oidc-mtls/src/main/resources/application.properties +++ b/integration-tests/oidc-mtls/src/main/resources/application.properties @@ -1,11 +1,57 @@ -quarkus.http.tls-configuration-name=oidc-mtls -quarkus.tls.oidc-mtls.key-store.p12.path=target/certificates/oidc-keystore.p12 -quarkus.tls.oidc-mtls.key-store.p12.password=password -quarkus.tls.oidc-mtls.trust-store.p12.path=target/certificates/oidc-server-truststore.p12 -quarkus.tls.oidc-mtls.trust-store.p12.password=password +# Disable default tenant +quarkus.oidc.tenant-enabled=false + +# Tenant which expects JWT token to contain a certificate thumbprint +quarkus.oidc.mtls-jwt.auth-server-url=${quarkus.oidc.auth-server-url} +quarkus.oidc.mtls-jwt.client-id=backend-service +# Certificate bound +quarkus.oidc.mtls-jwt.token.binding.certificate=true +quarkus.oidc.mtls-jwt.tls.tls-configuration-name=oidc-client-tls + +# Tenant which expects token introspection to contain a certificate thumbprint +quarkus.oidc.mtls-introspection.auth-server-url=${quarkus.oidc.auth-server-url} +quarkus.oidc.mtls-introspection.client-id=backend-service +# Certificate bound +quarkus.oidc.mtls-introspection.token.binding.certificate=true +quarkus.oidc.mtls-introspection.token.require-jwt-introspection-only=true +quarkus.oidc.mtls-introspection.tls.tls-configuration-name=oidc-client-tls + +# Tenant which accepts tokens not bound to certificates +quarkus.oidc.mtls-client-with-secret.auth-server-url=${quarkus.oidc.auth-server-url} +quarkus.oidc.mtls-client-with-secret.tls.tls-configuration-name=oidc-client-tls + +# MTLS TLS registry configuration for Quarkus OIDC to be able to communicate with Keycloak +quarkus.tls.oidc-client-tls.key-store.p12.path=target/certificates/oidc-client-keystore.p12 +quarkus.tls.oidc-client-tls.key-store.p12.password=password +quarkus.tls.oidc-client-tls.trust-store.p12.path=target/certificates/oidc-client-truststore.p12 +quarkus.tls.oidc-client-tls.trust-store.p12.password=password +quarkus.tls.oidc-client-tls.hostname-verification-algorithm=NONE + +# Quarkus endpoint MTLS TLS registry configuration requiring external clients to authenticate with MTLS +quarkus.http.tls-configuration-name=oidc-server-mtls +quarkus.tls.oidc-server-mtls.key-store.p12.path=target/certificates/oidc-keystore.p12 +quarkus.tls.oidc-server-mtls.key-store.p12.password=password +quarkus.tls.oidc-server-mtls.trust-store.p12.path=target/certificates/oidc-server-truststore.p12 +quarkus.tls.oidc-server-mtls.trust-store.p12.password=password + +# Have Keycloak devservice started even though the default tenant is disabled +quarkus.keycloak.devservices.start-with-disabled-tenant=true +# Do not create the default ream and client, since the test factory uploads the realm file +quarkus.keycloak.devservices.create-realm=false +quarkus.keycloak.devservices.create-client=false +# Make Keycloak require MTLS +quarkus.keycloak.devservices.start-command=start --https-client-auth=required --hostname-strict=false --https-key-store-file=/etc/server-keystore.p12 --https-trust-store-file=/etc/server-truststore.p12 --https-trust-store-password=password --spi-user-profile-declarative-user-profile-config-file=/opt/keycloak/upconfig.json +quarkus.keycloak.devservices.resource-aliases.keystore=target/certificates/oidc-keystore.p12 +quarkus.keycloak.devservices.resource-aliases.truststore=target/certificates/oidc-server-truststore.p12 +quarkus.keycloak.devservices.resource-mappings.keystore=/etc/server-keystore.p12 +quarkus.keycloak.devservices.resource-mappings.truststore=/etc/server-truststore.p12 +quarkus.keycloak.devservices.show-logs=true quarkus.http.auth.inclusive=true quarkus.http.ssl.client-auth=REQUIRED quarkus.http.insecure-requests=DISABLED -quarkus.native.additional-build-args=-H:IncludeResources=target/certificates/.*\\.p12 +quarkus.native.additional-build-args=-H:IncludeResources=.*\\.p12 + +quarkus.log.category."io.quarkus.oidc.runtime".min-level=TRACE +quarkus.log.category."io.quarkus.oidc.runtime".level=TRACE diff --git a/integration-tests/oidc-mtls/src/main/resources/quarkus-realm.json b/integration-tests/oidc-mtls/src/main/resources/quarkus-realm.json new file mode 100644 index 0000000000000..519db168561d3 --- /dev/null +++ b/integration-tests/oidc-mtls/src/main/resources/quarkus-realm.json @@ -0,0 +1,2530 @@ +{ + "id": "quarkus", + "realm": "quarkus", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxTemporaryLockouts": 0, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "3ce83241-464b-4ca0-8f0f-17002a797aab", + "name": "admin", + "composite": false, + "clientRole": false, + "containerId": "quarkus", + "attributes": {} + }, + { + "id": "68615956-51ca-49ca-865a-f9cb2571b027", + "name": "confidential", + "composite": false, + "clientRole": false, + "containerId": "quarkus", + "attributes": {} + }, + { + "id": "c6d57a00-eb97-460d-91b0-89e6a94a7aa5", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "quarkus", + "attributes": {} + }, + { + "id": "c50286f6-3562-473f-ad45-9767b982ff45", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "quarkus", + "attributes": {} + }, + { + "id": "ecf82b72-870a-4b33-9c73-57c960c888bd", + "name": "default-roles-quarkus", + "description": "${role_default-roles}", + "composite": false, + "clientRole": false, + "containerId": "quarkus", + "attributes": {} + }, + { + "id": "d3246456-8f5d-4722-8364-a46a8d25dc7c", + "name": "user", + "composite": false, + "clientRole": false, + "containerId": "quarkus", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "4b24739e-3a0a-48d2-b202-713430d775d2", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "1238e880-907f-4e8b-a032-4d09a922adf8", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "bcc6637a-294c-4529-a706-33b8c49f40fc", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-groups", + "query-users" + ] + } + }, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "f65a9a54-d689-4c45-87cd-f177babdeaef", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "183e58f4-136b-4c91-b20a-5c76857a671e", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "9aec187f-d623-45c7-a8b3-5aa32d115f50", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "52521d81-e7d6-4929-95cb-0a084c5bacb8", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "e92c753a-7b17-4adc-9962-04f24040e404", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "1285d11d-08f4-4753-b27e-d5f7b0e76fca", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "b0ee027f-5aa6-48eb-837f-4635590576ec", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "61ac3405-ccbd-4cdf-8cac-c918e1d77e1f", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "f1176efb-e24b-4fab-8b37-8265aefd10e1", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "968be265-6868-416a-91a1-e5bd882349ab", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "e77611fc-5ec5-4438-96c3-b291aae78d0c", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "165b24e1-9488-4cc7-87cd-e74b1cdc5619", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "f5163480-f5fc-4355-8be1-8cc96ff7d99d", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-identity-providers", + "query-clients", + "view-users", + "view-identity-providers", + "view-events", + "view-clients", + "manage-events", + "query-realms", + "manage-clients", + "view-authorization", + "query-groups", + "query-users", + "manage-authorization", + "manage-users", + "manage-realm", + "create-client", + "view-realm", + "impersonation" + ] + } + }, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "64ec1233-2cee-4d9b-ab6f-0bd06702c684", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "6e633885-b1fb-4ca8-9ef9-7c4c8f8732e8", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + }, + { + "id": "683bddad-81c6-4dca-87b6-e14b0b2ae524", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "dd29e998-54e9-4067-884e-4f986e990c1d", + "attributes": {} + } + ], + "backend-client-with-secret": [ + { + "id": "b12a77ee-b342-4ee5-8267-29bcd9ba5fdc", + "name": "uma_protection", + "composite": false, + "clientRole": true, + "containerId": "4023904e-f71d-4498-ac85-a786b871b035", + "attributes": {} + } + ], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "backend-service": [ + { + "id": "5b9947c6-eb74-4de6-8623-0285720993f3", + "name": "uma_protection", + "composite": false, + "clientRole": true, + "containerId": "302430aa-3929-42cf-8ba2-2b9d2e71dc3a", + "attributes": {} + } + ], + "broker": [ + { + "id": "bee1f77b-34a9-4386-9eca-eb19db248394", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "2a02328b-6aa6-49a8-b56c-7036c273c70b", + "attributes": {} + } + ], + "account": [ + { + "id": "e2cd9235-026b-4637-aa2e-1bc01a829a1b", + "name": "view-groups", + "description": "${role_view-groups}", + "composite": false, + "clientRole": true, + "containerId": "35b5a50f-a32a-4bd1-b4b3-50f0ade135c7", + "attributes": {} + }, + { + "id": "540d80ab-2eb1-4f1c-84ad-4fe0a84e2d2a", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "35b5a50f-a32a-4bd1-b4b3-50f0ade135c7", + "attributes": {} + }, + { + "id": "d3ffeda8-8d57-4b63-ae1d-90f88bc4b068", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "35b5a50f-a32a-4bd1-b4b3-50f0ade135c7", + "attributes": {} + }, + { + "id": "1ffcc7fe-50a8-4300-b172-10f651e5a5bd", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "35b5a50f-a32a-4bd1-b4b3-50f0ade135c7", + "attributes": {} + }, + { + "id": "74f86380-8e18-407f-ad16-529044f9c7dc", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "35b5a50f-a32a-4bd1-b4b3-50f0ade135c7", + "attributes": {} + }, + { + "id": "87f13502-eb23-4c51-be92-aeda4d9e9f28", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "35b5a50f-a32a-4bd1-b4b3-50f0ade135c7", + "attributes": {} + }, + { + "id": "350c9ea0-5222-47d6-862b-91b34a0a1ba9", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "35b5a50f-a32a-4bd1-b4b3-50f0ade135c7", + "attributes": {} + }, + { + "id": "6bfb0d41-8f2b-4adf-a5a7-e0ba1d1fad10", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "35b5a50f-a32a-4bd1-b4b3-50f0ade135c7", + "attributes": {} + } + ] + } + }, + "groups": [], + "defaultRole": { + "id": "ecf82b72-870a-4b33-9c73-57c960c888bd", + "name": "default-roles-quarkus", + "description": "${role_default-roles}", + "composite": false, + "clientRole": false, + "containerId": "quarkus" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": [ + "totpAppFreeOTPName", + "totpAppGoogleName", + "totpAppMicrosoftAuthenticatorName" + ], + "localizationTexts": {}, + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyExtraOrigins": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "webAuthnPolicyPasswordlessExtraOrigins": [], + "users": [ + { + "id": "8587742e-638b-4b6f-8197-5bdba72cd137", + "username": "service-account-backend-client-with-secret", + "emailVerified": false, + "createdTimestamp": 1734350109683, + "enabled": true, + "totp": false, + "serviceAccountClientId": "backend-client-with-secret", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "default-roles-quarkus" + ], + "clientRoles": { + "backend-client-with-secret": [ + "uma_protection" + ] + }, + "notBefore": 0, + "groups": [] + }, + { + "id": "948c59ec-46ed-4d99-aa43-02900029b930", + "username": "service-account-backend-service", + "email": "service-account-backend-service@placeholder.org", + "emailVerified": false, + "createdTimestamp": 1554245880023, + "enabled": true, + "totp": false, + "serviceAccountClientId": "backend-service", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "offline_access" + ], + "clientRoles": { + "backend-service": [ + "uma_protection" + ], + "account": [ + "view-profile", + "manage-account" + ] + }, + "notBefore": 0, + "groups": [] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account", + "view-groups" + ] + } + ] + }, + "clients": [ + { + "id": "35b5a50f-a32a-4bd1-b4b3-50f0ade135c7", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/quarkus/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/realms/quarkus/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "d19cba64-7238-44a9-b4b0-cc7705395d39", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/quarkus/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/quarkus/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "e0ac5df3-56e1-428e-9122-4995a298530e", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "c6e812f9-326b-4e66-9197-157a5d43b172", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "4023904e-f71d-4498-ac85-a786b871b035", + "clientId": "backend-client-with-secret", + "name": "", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "secret", + "redirectUris": [ + "/*" + ], + "webOrigins": [ + "/*" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "authorizationServicesEnabled": true, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "oidc.ciba.grant.enabled": "false", + "client.secret.creation.time": "1734350109", + "backchannel.logout.session.required": "true", + "oauth2.device.authorization.grant.enabled": "false", + "display.on.consent.screen": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [ + { + "id": "fc141cea-7f20-4e8d-98cb-3ad12271f5f5", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "client_id", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + }, + { + "id": "000c1afd-626e-4ece-b63a-c389288ed90f", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "314891f7-b541-44f1-9549-2a53a40eeb3c", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "302430aa-3929-42cf-8ba2-2b9d2e71dc3a", + "clientId": "backend-service", + "name": "", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-x509", + "secret": "**********", + "redirectUris": [ + "*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "authorizationServicesEnabled": true, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "x509.subjectdn": "CN=backend-service", + "client.introspection.response.allow.jwt.claim.enabled": "false", + "post.logout.redirect.uris": "+", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "use.refresh.tokens": "true", + "oidc.ciba.grant.enabled": "false", + "client.use.lightweight.access.token.enabled": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "tls.client.certificate.bound.access.tokens": "true", + "require.pushed.authorization.requests": "false", + "acr.loa.map": "{}", + "display.on.consent.screen": "false", + "x509.allow.regex.pattern.comparison": "false", + "token.response.type.bearer.lower-case": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [ + { + "id": "1390addb-ba10-4455-a1ea-8455c3770cf1", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientId", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientId", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "cdafda09-f6d9-41e3-87ef-6789e861689a", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "95b47211-912c-43f5-84ce-5bfbc761325d", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "2a02328b-6aa6-49a8-b56c-7036c273c70b", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "dd29e998-54e9-4067-884e-4f986e990c1d", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "6517b152-0693-4b28-a798-a0deea3e8644", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/quarkus/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/quarkus/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "9c7093a9-4da1-47e4-b2a5-afe180782220", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "1cd1a093-aec5-4949-912d-d5f61fff5705", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "8b5d72e1-cfd6-4832-8432-efedf34c265b", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "83e275f7-b171-45fa-99c7-7c04f91fbe41", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "9eb470cc-8157-46f2-8233-8cae169c6591", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "eebdefd0-c446-4bf3-b945-08db42f0ea92", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + }, + { + "id": "37c62d93-c670-487c-8c3a-a6329a9924b0", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "7eaa8ede-9a92-487a-9444-60a5d7355542", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "e7616dd3-8886-4d47-8645-74e4565d7606", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "35bfd94e-681f-456a-bca0-0d0d8d986a96", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "1f710637-5a3c-45f3-b4d3-74046993e0eb", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "eb0bdf87-6cda-4684-89a8-f7bd6f0c7bba", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "1ea39fbb-c692-4a1d-a143-a05b030889cb", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "f97bd1de-6c95-4c5b-804c-f8b354457453", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "58e57c6f-18bf-4347-9ab0-b8325ef522e0", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "5a4a2c20-fef2-40b5-9406-136475442b47", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "97aca0c9-7f14-4783-bb48-681de54f0b31", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "55621a1e-cd6b-45a7-9f06-a678e0801b9c", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "6c4f32b0-8ae4-4b4b-b4fa-a053df0bbb3a", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "userinfo.token.claim": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + }, + { + "id": "2687cb87-1dbf-435c-8ef9-f2fe38127405", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "d20498e8-4ec8-4496-9d8f-c09131dd5d15", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "7da35ca7-5c93-4d23-b6b7-761d80c966c8", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "a443a633-7cd2-406d-85f1-6e3d3173eff9", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "d04d2dd6-04fc-4230-90eb-7074056cfdee", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "ef68a07b-ed0a-418b-9c6d-7ecd58946813", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "144acdba-ee08-4349-b806-a4394bd5f351", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "4b435d62-1f62-4513-a131-208318731d7b", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "794b162d-460a-4465-b90d-66dabc4b3cce", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "779b131a-d0cc-420d-90b3-075b19210379", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "0e0f1e8d-60f9-4435-b753-136d70e56af8", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "8451d26b-904d-4858-9db1-87fe137c1172", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "011fe224-355f-4e3c-a3d4-6a325eec561d", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "06f656a1-67f1-4c53-92df-9e5823853191", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "03293b81-5599-4163-81b8-eb05c3d14ed2", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "d21642b7-8190-4de4-8d0d-09b0e505c02c", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "541f2eae-d481-4d00-be30-89f4f60d169f", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${phoneScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "eda935c3-7294-403c-85bd-fee7216af822", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String", + "userinfo.token.claim": "true" + } + }, + { + "id": "0b8c0161-5042-4912-a753-c262569ed5bc", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "688a0898-d197-48cb-889a-1e6dc892f69f", + "name": "basic", + "description": "OpenID Connect scope for add all basic claims to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "ff13d88f-ad9f-417d-92b4-8d2b223e556b", + "name": "auth_time", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "AUTH_TIME", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "auth_time", + "jsonType.label": "long" + } + }, + { + "id": "55e915a1-a832-4246-9ac4-7fb777f5efcd", + "name": "sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-sub-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email", + "acr", + "basic" + ], + "defaultOptionalClientScopes": [ + "address", + "phone", + "microprofile-jwt", + "offline_access" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "referrerPolicy": "no-referrer", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "7ebad719-3c5e-4880-a9f1-3242dd9dbe24", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "8fe9bd3a-a11c-4c97-948e-90ba7fbe008f", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-full-name-mapper", + "oidc-usermodel-attribute-mapper", + "saml-role-list-mapper", + "saml-user-property-mapper", + "saml-user-attribute-mapper", + "oidc-usermodel-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-address-mapper" + ] + } + }, + { + "id": "e9b76eee-365f-4b5f-80cb-316eb07b36fa", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "8ed9d103-7a79-47b4-9426-9e4a84340d22", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "a07e90f1-5662-4344-8529-f284c361a25e", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "9b4e5b69-1d07-489b-b8a5-07329c957141", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "e2f513d3-44e3-435c-8b2a-68a5d384fd97", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "43a5aac2-b395-4935-94cb-12f4d9b4eb05", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-address-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper", + "saml-user-attribute-mapper", + "oidc-full-name-mapper", + "oidc-usermodel-property-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-property-mapper" + ] + } + } + ], + "org.keycloak.userprofile.UserProfileProvider": [ + { + "id": "e813f916-9006-4e55-8f7b-3c174aa13d33", + "providerId": "declarative-user-profile", + "subComponents": {}, + "config": { + "kc.user.profile.config": [ + "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "066f8625-06ba-4463-995f-93a058d2d800", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "19c225cc-b499-48b1-aed6-3e1dd5bcf04c", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + }, + { + "id": "d100e4f5-8ef1-4c52-bbdf-5434ddb09268", + "name": "hmac-generated-hs512", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS512" + ] + } + }, + { + "id": "4008d665-26c4-4056-a028-232bc0636029", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "55f3ddc5-0f36-496d-817f-3aa8f426ee45", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "2d0ccc2f-888c-495f-91ae-dfffba572d33", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "b7ff5812-2bc2-4f8f-9913-bd3b97a08618", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "ddbfb446-21d8-44c2-a207-7f83d760e94f", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "21dc8a77-3900-46e7-b1e4-40f5bcbd9b8e", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "329ed4e1-d3a8-42aa-a9ff-991a0e8f2851", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "66b4a633-6ba0-41e2-944f-0b13369c1e78", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "fce169a3-c245-4dc8-a3c5-295bfa7057a4", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "4c5476fa-9aef-440b-bd14-25bf8cbfcd16", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "75d65771-3bfb-4def-a539-656de7d1af58", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "a6a9036b-192e-461f-91c7-d8117435188d", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "f86bdf88-8bee-480b-8e81-67dcd674e46c", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "6f87019e-c995-4049-b8bf-d08a9c3a13f3", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "fadc7c73-7fae-4c28-ad69-51bb03ba17bf", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "d930f23e-ae58-45b2-9e01-20691200c926", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "8d62b1dd-6066-454d-bc76-f783d50fecaa", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f99be349-ce0b-44a4-9f70-73f57cb8c164", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "33ee7503-bd12-4e5a-903c-5ae580f48709", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "6970ebc8-0b24-414c-8544-3cc48b1a0e4c", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "d14b76f4-b608-4b13-b51c-b9e162ad784b", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "TERMS_AND_CONDITIONS", + "name": "Terms and Conditions", + "providerId": "TERMS_AND_CONDITIONS", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "delete_credential", + "name": "Delete Credential", + "providerId": "delete_credential", + "enabled": true, + "defaultAction": false, + "priority": 100, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "parRequestUriLifespan": "60", + "cibaInterval": "5", + "realmReusableOtpCode": "false" + }, + "users" : [ { + "id" : "af134cab-f41c-4675-b141-205f975db679", + "username" : "admin", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "credentials" : [ { + "type" : "password", + "hashedSaltedValue" : "NICTtwsvSxJ5hL8hLAuleDUv9jwZcuXgxviMXvR++cciyPtiIEStEaJUyfA9DOir59awjPrHOumsclPVjNBplA==", + "salt" : "T/2P5o5oxFJUEk68BRURRg==", + "hashIterations" : 27500, + "counter" : 0, + "algorithm" : "pbkdf2-sha256", + "digits" : 0, + "period" : 0, + "createdDate" : 1554245879354, + "config" : { } + } ], + "disableableCredentialTypes" : [ "password" ], + "requiredActions" : [ ], + "realmRoles" : [ "admin", "user" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "eb4123a3-b722-4798-9af5-8957f823657a", + "username" : "alice", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "credentials" : [ { + "type" : "password", + "hashedSaltedValue" : "A3okqV2T/ybXTVEgKfosoSjP8Yc9IZbFP/SY4cEd6hag7TABQrQ6nUSuwagGt96l8cw1DTijO75PqX6uiTXMzw==", + "salt" : "sl4mXx6T9FypPH/s9TngfQ==", + "hashIterations" : 27500, + "counter" : 0, + "algorithm" : "pbkdf2-sha256", + "digits" : 0, + "period" : 0, + "createdDate" : 1554245879116, + "config" : { } + } ], + "disableableCredentialTypes" : [ "password" ], + "requiredActions" : [ ], + "realmRoles" : [ "user" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "1eed6a8e-a853-4597-b4c6-c4c2533546a0", + "username" : "jdoe", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "credentials" : [ { + "type" : "password", + "hashedSaltedValue" : "JV3DUNLjqOadjbBOtC4rvacQI553CGaDGAzBS8MR5ReCr7SwF3E6CsW3T7/XO8ITZAsch8+A/6loeuCoVLLJrg==", + "salt" : "uCbOH7HZtyDtMd0E9DG/nw==", + "hashIterations" : 27500, + "counter" : 0, + "algorithm" : "pbkdf2-sha256", + "digits" : 0, + "period" : 0, + "createdDate" : 1554245879227, + "config" : { } + } ], + "disableableCredentialTypes" : [ "password" ], + "requiredActions" : [ ], + "realmRoles" : [ "confidential", "user" ], + "notBefore" : 0, + "groups" : [ ] + }, + { + "id": "948c59ec-46ed-4d99-aa43-02900029b930", + "username": "service-account-backend-service", + "email": "service-account-backend-service@placeholder.org", + "emailVerified": false, + "createdTimestamp": 1554245880023, + "enabled": true, + "totp": false, + "serviceAccountClientId": "backend-service", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "offline_access" + ], + "clientRoles": { + "backend-service": [ + "uma_protection" + ], + "account": [ + "view-profile", + "manage-account" + ] + }, + "notBefore": 0, + "groups": [] + } ], + "keycloakVersion": "25.0.6", + "userManagedAccessAllowed": false, + "organizationsEnabled": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} diff --git a/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/KeycloakTestResourceLifecycleManager.java b/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/KeycloakTestResourceLifecycleManager.java new file mode 100644 index 0000000000000..fbbe85f5fdc5e --- /dev/null +++ b/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/KeycloakTestResourceLifecycleManager.java @@ -0,0 +1,49 @@ +package io.quarkus.it.oidc; + +import java.io.InputStream; +import java.net.URL; +import java.util.Map; + +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.util.JsonSerialization; + +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import io.quarkus.test.keycloak.client.KeycloakTestClient; +import io.quarkus.test.keycloak.client.KeycloakTestClient.Tls; + +public class KeycloakTestResourceLifecycleManager implements QuarkusTestResourceLifecycleManager, + DevServicesContext.ContextAware { + + KeycloakTestClient client = new KeycloakTestClient( + new Tls("target/certificates/oidc-client-keystore.p12", + "target/certificates/oidc-client-truststore.p12")); + + @Override + public Map start() { + + client.createRealm(loadRealm()); + + return Map.of(); + } + + private static RealmRepresentation loadRealm() { + try { + URL realmPathUrl = Thread.currentThread().getContextClassLoader().getResource("quarkus-realm.json"); + try (InputStream is = realmPathUrl.openStream()) { + return JsonSerialization.readValue(is, RealmRepresentation.class); + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + @Override + public void setIntegrationTestContext(DevServicesContext context) { + client.setIntegrationTestContext(context); + } + + @Override + public void stop() { + } +} diff --git a/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/OidcMtlsTest.java b/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/OidcMtlsTest.java index 458c37b26b1ea..0529704d89240 100644 --- a/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/OidcMtlsTest.java +++ b/integration-tests/oidc-mtls/src/test/java/io/quarkus/it/oidc/OidcMtlsTest.java @@ -14,9 +14,11 @@ import io.quarkus.oidc.common.runtime.OidcConstants; import io.quarkus.runtime.util.ClassPathUtils; +import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.keycloak.client.KeycloakTestClient; +import io.quarkus.test.keycloak.client.KeycloakTestClient.Tls; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.net.KeyStoreOptions; @@ -25,31 +27,67 @@ import io.vertx.mutiny.ext.web.client.WebClient; @QuarkusTest +@QuarkusTestResource(KeycloakTestResourceLifecycleManager.class) public class OidcMtlsTest { + KeycloakTestClient client = new KeycloakTestClient( + new Tls("target/certificates/oidc-client-keystore.p12", + "target/certificates/oidc-client-truststore.p12")); + @TestHTTPResource(tls = true) URL url; - KeycloakTestClient keycloakClient = new KeycloakTestClient(); + @Test + public void testMtlsJwt() throws Exception { + Vertx vertx = Vertx.vertx(); + try { + WebClientOptions options = createWebClientOptions(); + WebClient webClient = WebClient.create(new io.vertx.mutiny.core.Vertx(vertx), options); + + // HTTP 200 + HttpResponse resp = webClient.get("/service/mtls-jwt") + .putHeader("Authorization", + OidcConstants.BEARER_SCHEME + " " + getAccessToken("backend-service", null, "alice")) + .send().await() + .indefinitely(); + assertEquals(200, resp.statusCode()); + String name = resp.bodyAsString(); + assertEquals("Identities: CN=backend-service, alice;" + + " Client: backend-service;" + + " JWT cert thumbprint: true, introspection cert thumbprint: false", name); + + // HTTP 401, invalid token + resp = webClient.get("/service/mtls-jwt") + .putHeader("Authorization", OidcConstants.BEARER_SCHEME + " " + "123") + .send().await() + .indefinitely(); + assertEquals(401, resp.statusCode()); + } finally { + vertx.close(); + } + } @Test - public void testGetIdentityNames() throws Exception { + public void testMtlsIntrospection() throws Exception { Vertx vertx = Vertx.vertx(); try { WebClientOptions options = createWebClientOptions(); WebClient webClient = WebClient.create(new io.vertx.mutiny.core.Vertx(vertx), options); // HTTP 200 - HttpResponse resp = webClient.get("/service/name") - .putHeader("Authorization", OidcConstants.BEARER_SCHEME + " " + keycloakClient.getAccessToken("alice")) + HttpResponse resp = webClient.get("/service/mtls-introspection") + .putHeader("Authorization", + OidcConstants.BEARER_SCHEME + " " + getAccessToken("backend-service", null, "alice")) .send().await() .indefinitely(); assertEquals(200, resp.statusCode()); String name = resp.bodyAsString(); - assertEquals("Identities: CN=backend-service, alice", name); + assertEquals("Identities: CN=backend-service, alice;" + + " Client: backend-service;" + + " JWT cert thumbprint: false, introspection cert thumbprint: true", name); // HTTP 401, invalid token - resp = webClient.get("/service/name") + resp = webClient.get("/service/mtls-introspection") .putHeader("Authorization", OidcConstants.BEARER_SCHEME + " " + "123") .send().await() .indefinitely(); @@ -59,6 +97,42 @@ public void testGetIdentityNames() throws Exception { } } + @Test + public void testMtlsClientWithSecret() throws Exception { + Vertx vertx = Vertx.vertx(); + try { + WebClientOptions options = createWebClientOptions(); + WebClient webClient = WebClient.create(new io.vertx.mutiny.core.Vertx(vertx), options); + + String accessToken = getAccessToken("backend-client-with-secret", "secret", "alice"); + // HTTP 200 + HttpResponse resp = webClient.get("/service/mtls-client-with-secret") + .putHeader("Authorization", + OidcConstants.BEARER_SCHEME + " " + accessToken) + .send().await() + .indefinitely(); + assertEquals(200, resp.statusCode()); + String name = resp.bodyAsString(); + assertEquals("Identities: CN=backend-service, alice;" + + " Client: backend-client-with-secret;" + + " JWT cert thumbprint: false, introspection cert thumbprint: false", name); + + // HTTP 401, token is valid but it is not certificate bound + resp = webClient.get("/service/mtls-jwt") + .putHeader("Authorization", OidcConstants.BEARER_SCHEME + " " + accessToken) + .send().await() + .indefinitely(); + assertEquals(401, resp.statusCode()); + + } finally { + vertx.close(); + } + } + + private String getAccessToken(String clientName, String clientSecret, String userName) { + return client.getAccessToken(userName, userName, clientName, clientSecret); + } + private WebClientOptions createWebClientOptions() throws Exception { WebClientOptions webClientOptions = new WebClientOptions().setDefaultHost(url.getHost()) .setDefaultPort(url.getPort()).setSsl(true).setVerifyHost(false); From 3f5c0651bda8886050615a078940774a9c49bd16 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 20 Dec 2024 21:25:50 +0100 Subject: [PATCH 195/207] Update to Gradle 8.12 --- build-parent/pom.xml | 2 +- devtools/gradle/gradle/wrapper/gradle-wrapper.properties | 4 ++-- independent-projects/bootstrap/pom.xml | 2 +- .../devtools-testing/src/main/resources/fake-catalog.json | 2 +- independent-projects/tools/pom.xml | 2 +- .../gradle/gradle/wrapper/gradle-wrapper.properties | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index dfbc9cd07aa5c..c6967ec6df271 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -61,7 +61,7 @@ 3.9.9 3.3.2 - 8.9 + 8.12 ${project.version} ${project.version} 3.8.1 diff --git a/devtools/gradle/gradle/wrapper/gradle-wrapper.properties b/devtools/gradle/gradle/wrapper/gradle-wrapper.properties index c6fbf17f75a50..5d1e008d55ebb 100644 --- a/devtools/gradle/gradle/wrapper/gradle-wrapper.properties +++ b/devtools/gradle/gradle/wrapper/gradle-wrapper.properties @@ -1,8 +1,8 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists # https://gradle.org/release-checksums/ -distributionSha256Sum=258e722ec21e955201e31447b0aed14201765a3bfbae296a46cf60b70e66db70 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip +distributionSha256Sum=7ebdac923867a3cec0098302416d1e3c6c0c729fc4e2e05c10637a8af33a76c5 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml index 495a5a5d39e30..ae844f75f7c3a 100644 --- a/independent-projects/bootstrap/pom.xml +++ b/independent-projects/bootstrap/pom.xml @@ -72,7 +72,7 @@ 3.5.1 2.9.0 1.5.2 - 8.9 + 8.12 0.0.10 0.1.3 diff --git a/independent-projects/tools/devtools-testing/src/main/resources/fake-catalog.json b/independent-projects/tools/devtools-testing/src/main/resources/fake-catalog.json index e1114ab5712d3..a8e0a6cfc653f 100644 --- a/independent-projects/tools/devtools-testing/src/main/resources/fake-catalog.json +++ b/independent-projects/tools/devtools-testing/src/main/resources/fake-catalog.json @@ -447,7 +447,7 @@ "recommended-java-version": "17", "proposed-maven-version": "3.9.9", "maven-wrapper-version": "3.3.2", - "gradle-wrapper-version": "8.9" + "gradle-wrapper-version": "8.12" } }, "codestarts-artifacts": [ diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml index 37aeeb9664e78..0752969643256 100644 --- a/independent-projects/tools/pom.xml +++ b/independent-projects/tools/pom.xml @@ -39,7 +39,7 @@ 3.9.9 3.3.2 - 8.9 + 8.12 3.13.0 diff --git a/integration-tests/gradle/gradle/wrapper/gradle-wrapper.properties b/integration-tests/gradle/gradle/wrapper/gradle-wrapper.properties index c6fbf17f75a50..5d1e008d55ebb 100644 --- a/integration-tests/gradle/gradle/wrapper/gradle-wrapper.properties +++ b/integration-tests/gradle/gradle/wrapper/gradle-wrapper.properties @@ -1,8 +1,8 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists # https://gradle.org/release-checksums/ -distributionSha256Sum=258e722ec21e955201e31447b0aed14201765a3bfbae296a46cf60b70e66db70 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip +distributionSha256Sum=7ebdac923867a3cec0098302416d1e3c6c0c729fc4e2e05c10637a8af33a76c5 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 14c38f53f93c227de524aea1f2653e74ed3c368c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:54:29 +0000 Subject: [PATCH 196/207] Bump com.nimbusds:nimbus-jose-jwt from 9.47 to 9.48 Bumps [com.nimbusds:nimbus-jose-jwt](https://bitbucket.org/connect2id/nimbus-jose-jwt) from 9.47 to 9.48. - [Changelog](https://bitbucket.org/connect2id/nimbus-jose-jwt/src/master/CHANGELOG.txt) - [Commits](https://bitbucket.org/connect2id/nimbus-jose-jwt/branches/compare/9.48..9.47) --- updated-dependencies: - dependency-name: com.nimbusds:nimbus-jose-jwt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 5a8aebeed6654..3cee1f96babcd 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -206,7 +206,7 @@ 7.1.0.202411261347-r 0.15.0 - 9.47 + 9.48 0.9.6 0.0.12 0.1.3 From fcbd842f4b4ecd50d4515112fa8d65650653d90b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:55:24 +0000 Subject: [PATCH 197/207] Bump artemis.version from 2.38.0 to 2.39.0 Bumps `artemis.version` from 2.38.0 to 2.39.0. Updates `org.apache.activemq:artemis-server` from 2.38.0 to 2.39.0 Updates `org.apache.activemq:artemis-amqp-protocol` from 2.38.0 to 2.39.0 --- updated-dependencies: - dependency-name: org.apache.activemq:artemis-server dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.apache.activemq:artemis-amqp-protocol dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index dfbc9cd07aa5c..b6893f38e268c 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -109,7 +109,7 @@ 7.3.0 - 2.38.0 + 2.39.0 From 0304e70ab06af7a53680c3524c1dae01ade36d1d Mon Sep 17 00:00:00 2001 From: Peter Skopek Date: Fri, 13 Sep 2024 09:07:29 +0200 Subject: [PATCH 198/207] Use keycloak-client libraries instead of keycloak-common, keycloak-core and keycloak-adapter-spi Closes #43259 Signed-off-by: Peter Skopek --- bom/application/pom.xml | 32 +++++-------------- build-parent/pom.xml | 5 ++- extensions/devservices/keycloak/pom.xml | 8 +---- .../runtime/pom.xml | 10 ------ .../ResteasyReactiveClientProvider.java | 16 ++++++++-- .../runtime/pom.xml | 10 ------ .../KeycloakReflectionBuildStep.java | 4 +++ .../keycloak-authorization/runtime/pom.xml | 15 --------- .../deployment/pom.xml | 4 +++ extensions/oidc-client/deployment/pom.xml | 8 +---- .../oidc-client-reactive/pom.xml | 10 ------ integration-tests/oidc-client/pom.xml | 15 +++------ integration-tests/oidc-code-flow/pom.xml | 9 ++---- integration-tests/oidc-tenancy/pom.xml | 15 +++------ .../oidc-token-propagation/pom.xml | 15 +++------ integration-tests/oidc/pom.xml | 11 +++++-- .../smallrye-jwt-oidc-webapp/pom.xml | 15 +++------ .../smallrye-jwt-token-propagation/pom.xml | 15 +++------ test-framework/keycloak-server/pom.xml | 8 +---- 19 files changed, 70 insertions(+), 155 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 3cee1f96babcd..d85cf5c0e4fe5 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -177,7 +177,7 @@ 5.14.2 5.8.0 2.2.0 - 25.0.6 + 26.0.3 1.15.1 3.48.3 2.36.0 @@ -6110,41 +6110,25 @@ ${quarkus-spring-boot-api.version} - - org.keycloak - keycloak-core - ${keycloak.version} - - - org.keycloak - keycloak-common - ${keycloak.version} - org.keycloak keycloak-admin-client - ${keycloak.version} - - - org.checkerframework - checker-qual - - + ${keycloak-client.version} org.keycloak - keycloak-adapter-spi - ${keycloak.version} + keycloak-authz-client + ${keycloak-client.version} org.keycloak - keycloak-authz-client - ${keycloak.version} + keycloak-policy-enforcer + ${keycloak-client.version} org.keycloak - keycloak-policy-enforcer - ${keycloak.version} + keycloak-client-common-synced + ${keycloak-client.version} io.quarkus diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 3b555ee9c5c18..8a9ff77592ff5 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -95,10 +95,9 @@ 4.13.2 - - 25.0.6 + 25.0.6 19.0.3 - quay.io/keycloak/keycloak:${keycloak.version} + quay.io/keycloak/keycloak:${keycloak.server.version} quay.io/keycloak/keycloak:${keycloak.wildfly.version}-legacy 7.0.2 diff --git a/extensions/devservices/keycloak/pom.xml b/extensions/devservices/keycloak/pom.xml index a12beb74331f8..14a45e3b38b00 100644 --- a/extensions/devservices/keycloak/pom.xml +++ b/extensions/devservices/keycloak/pom.xml @@ -34,13 +34,7 @@ org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - + keycloak-client-common-synced diff --git a/extensions/keycloak-admin-rest-client/runtime/pom.xml b/extensions/keycloak-admin-rest-client/runtime/pom.xml index 7daec9e854335..175cc28cbb2ac 100644 --- a/extensions/keycloak-admin-rest-client/runtime/pom.xml +++ b/extensions/keycloak-admin-rest-client/runtime/pom.xml @@ -22,16 +22,6 @@ io.quarkus quarkus-tls-registry - - org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - - org.eclipse.angus angus-activation diff --git a/extensions/keycloak-admin-rest-client/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java b/extensions/keycloak-admin-rest-client/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java index ad35c9f994dba..0690fbcdff3d7 100644 --- a/extensions/keycloak-admin-rest-client/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java +++ b/extensions/keycloak-admin-rest-client/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java @@ -20,6 +20,8 @@ import org.jboss.resteasy.reactive.server.jackson.JacksonBasicMessageBodyReader; import org.keycloak.admin.client.spi.ResteasyClientProvider; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import io.quarkus.arc.Arc; @@ -93,7 +95,7 @@ private ClientBuilderImpl registerJacksonProviders(ClientBuilderImpl clientBuild clientBuilder = clientBuilder.register(new ClientJacksonMessageBodyWriter(objectMapper)); } } else { - ObjectMapper newObjectMapper = new ObjectMapper(); + ObjectMapper newObjectMapper = newKeycloakAdminClientObjectMapper(); clientBuilder = clientBuilder .registerMessageBodyReader(new JacksonBasicMessageBodyReader(newObjectMapper), Object.class, HANDLED_MEDIA_TYPES, true, @@ -136,11 +138,21 @@ private boolean canReuseObjectMapper(InstanceHandle objectMapperIn private ObjectMapper getObjectMapper(ObjectMapper value, InstanceHandle objectMapperInstance) { if (value == null) { - return objectMapperInstance.isAvailable() ? objectMapperInstance.get() : new ObjectMapper(); + return objectMapperInstance.isAvailable() ? objectMapperInstance.get() : newKeycloakAdminClientObjectMapper(); } return value; } + // creates new ObjectMapper compatible with Keycloak Admin Client + private ObjectMapper newKeycloakAdminClientObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + // Same like JSONSerialization class. Makes it possible to use admin-client against older versions of Keycloak server where the properties on representations might be different + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + // The client must work with the newer versions of Keycloak server, which might contain the JSON fields not yet known by the client. So unknown fields will be ignored. + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return objectMapper; + } + @Override public R targetProxy(WebTarget target, Class targetClass) { return ((WebTargetImpl) target).proxy(targetClass); diff --git a/extensions/keycloak-admin-resteasy-client/runtime/pom.xml b/extensions/keycloak-admin-resteasy-client/runtime/pom.xml index dc3f73112bcf5..cb9eb007af6f6 100644 --- a/extensions/keycloak-admin-resteasy-client/runtime/pom.xml +++ b/extensions/keycloak-admin-resteasy-client/runtime/pom.xml @@ -30,16 +30,6 @@ io.quarkus quarkus-resteasy-client-jaxb - - org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - - org.eclipse.angus angus-activation diff --git a/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakReflectionBuildStep.java b/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakReflectionBuildStep.java index d450e440b913f..69130cacf970d 100644 --- a/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakReflectionBuildStep.java +++ b/extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/deployment/KeycloakReflectionBuildStep.java @@ -5,6 +5,8 @@ import org.keycloak.adapters.authorization.cip.spi.ClaimInformationPointProviderFactory; import org.keycloak.authorization.client.representation.ServerConfiguration; import org.keycloak.authorization.client.representation.TokenIntrospectionResponse; +import org.keycloak.authorization.client.util.crypto.AuthzClientCryptoProvider; +import org.keycloak.common.crypto.CryptoProvider; import org.keycloak.jose.jwk.JSONWebKeySet; import org.keycloak.jose.jwk.JWK; import org.keycloak.jose.jws.JWSHeader; @@ -78,6 +80,8 @@ public void registerServiceProviders(BuildProducer ser serviceProvider.produce(new ServiceProviderBuildItem(ClaimInformationPointProviderFactory.class.getName(), HttpClaimInformationPointProviderFactory.class.getName(), ClaimsInformationPointProviderFactory.class.getName())); + serviceProvider.produce(new ServiceProviderBuildItem(CryptoProvider.class.getName(), + AuthzClientCryptoProvider.class.getName())); } @BuildStep diff --git a/extensions/keycloak-authorization/runtime/pom.xml b/extensions/keycloak-authorization/runtime/pom.xml index a49332d94f3ad..64d92dd5df310 100644 --- a/extensions/keycloak-authorization/runtime/pom.xml +++ b/extensions/keycloak-authorization/runtime/pom.xml @@ -22,29 +22,14 @@ io.quarkus quarkus-tls-registry - - org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - - org.keycloak keycloak-policy-enforcer - ${keycloak.version} org.eclipse.angus angus-activation - - org.keycloak - keycloak-adapter-spi - org.keycloak keycloak-authz-client diff --git a/extensions/oidc-client-reactive-filter/deployment/pom.xml b/extensions/oidc-client-reactive-filter/deployment/pom.xml index f9af84357e3f6..1ee3b2fbe7d55 100644 --- a/extensions/oidc-client-reactive-filter/deployment/pom.xml +++ b/extensions/oidc-client-reactive-filter/deployment/pom.xml @@ -45,6 +45,10 @@ junit junit + + org.jboss.resteasy + * + diff --git a/extensions/oidc-client/deployment/pom.xml b/extensions/oidc-client/deployment/pom.xml index 4a9351f66e255..3a5ba97d0858c 100644 --- a/extensions/oidc-client/deployment/pom.xml +++ b/extensions/oidc-client/deployment/pom.xml @@ -50,14 +50,8 @@ org.keycloak - keycloak-core + keycloak-client-common-synced test - - - com.sun.activation - jakarta.activation - - org.eclipse.angus diff --git a/integration-tests/oidc-client-reactive/pom.xml b/integration-tests/oidc-client-reactive/pom.xml index 3ea6362e1a7f0..caab893e3c940 100644 --- a/integration-tests/oidc-client-reactive/pom.xml +++ b/integration-tests/oidc-client-reactive/pom.xml @@ -19,16 +19,6 @@ - - org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - - org.eclipse.angus angus-activation diff --git a/integration-tests/oidc-client/pom.xml b/integration-tests/oidc-client/pom.xml index 5cb7970336c4d..1fcd8c441d6d1 100644 --- a/integration-tests/oidc-client/pom.xml +++ b/integration-tests/oidc-client/pom.xml @@ -20,21 +20,16 @@ - - org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - - org.eclipse.angus angus-activation + + org.keycloak + keycloak-client-common-synced + test + io.quarkus quarkus-junit5 diff --git a/integration-tests/oidc-code-flow/pom.xml b/integration-tests/oidc-code-flow/pom.xml index 5edca73ef37c8..aba6c5e4957d2 100644 --- a/integration-tests/oidc-code-flow/pom.xml +++ b/integration-tests/oidc-code-flow/pom.xml @@ -53,13 +53,8 @@ org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - + keycloak-client-common-synced + test org.eclipse.angus diff --git a/integration-tests/oidc-tenancy/pom.xml b/integration-tests/oidc-tenancy/pom.xml index efc494393105d..dcdce9632edc1 100644 --- a/integration-tests/oidc-tenancy/pom.xml +++ b/integration-tests/oidc-tenancy/pom.xml @@ -30,22 +30,17 @@ io.quarkus quarkus-resteasy-jackson - - org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - - org.eclipse.angus angus-activation + + org.keycloak + keycloak-client-common-synced + test + io.quarkus quarkus-test-keycloak-server diff --git a/integration-tests/oidc-token-propagation/pom.xml b/integration-tests/oidc-token-propagation/pom.xml index 96757a10b9381..16b004cd972b5 100644 --- a/integration-tests/oidc-token-propagation/pom.xml +++ b/integration-tests/oidc-token-propagation/pom.xml @@ -18,21 +18,16 @@ org.jboss.logging commons-logging-jboss-logging - - org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - - org.eclipse.angus angus-activation + + org.keycloak + keycloak-client-common-synced + test + io.quarkus quarkus-test-keycloak-server diff --git a/integration-tests/oidc/pom.xml b/integration-tests/oidc/pom.xml index e63f4b8707ff2..2c28fac8bc068 100644 --- a/integration-tests/oidc/pom.xml +++ b/integration-tests/oidc/pom.xml @@ -31,6 +31,11 @@ quarkus-test-keycloak-server test + + org.keycloak + keycloak-client-common-synced + test + org.eclipse.angus angus-activation @@ -40,7 +45,7 @@ quarkus-test-security-oidc test - + io.quarkus quarkus-junit5 @@ -177,7 +182,7 @@ false - ${keycloak.version} + ${keycloak.server.version} @@ -186,7 +191,7 @@ false - ${keycloak.version} + ${keycloak.server.version} diff --git a/integration-tests/smallrye-jwt-oidc-webapp/pom.xml b/integration-tests/smallrye-jwt-oidc-webapp/pom.xml index 802c1498e549c..634885871c998 100644 --- a/integration-tests/smallrye-jwt-oidc-webapp/pom.xml +++ b/integration-tests/smallrye-jwt-oidc-webapp/pom.xml @@ -28,21 +28,16 @@ io.quarkus quarkus-oidc-db-token-state-manager - - org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - - org.eclipse.angus angus-activation + + org.keycloak + keycloak-client-common-synced + test + io.quarkus quarkus-junit5 diff --git a/integration-tests/smallrye-jwt-token-propagation/pom.xml b/integration-tests/smallrye-jwt-token-propagation/pom.xml index 40ec80ae74834..189f841943cfb 100644 --- a/integration-tests/smallrye-jwt-token-propagation/pom.xml +++ b/integration-tests/smallrye-jwt-token-propagation/pom.xml @@ -19,16 +19,6 @@ - - org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - - org.eclipse.angus angus-activation @@ -38,6 +28,11 @@ quarkus-grpc + + org.keycloak + keycloak-client-common-synced + test + io.quarkus quarkus-test-security-jwt diff --git a/test-framework/keycloak-server/pom.xml b/test-framework/keycloak-server/pom.xml index 704f2b9e24481..ed2869755b1f0 100644 --- a/test-framework/keycloak-server/pom.xml +++ b/test-framework/keycloak-server/pom.xml @@ -15,13 +15,7 @@ org.keycloak - keycloak-core - - - com.sun.activation - jakarta.activation - - + keycloak-client-common-synced org.testcontainers From 27d6bc291de928f4016d912f315845d72be5e7eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Sun, 22 Dec 2024 14:43:53 +0100 Subject: [PATCH 199/207] Use leniant non-managed ObjectMapper in Keycloak Admin clients --- .../ResteasyReactiveClientProvider.java | 74 ++----------------- .../KeycloakAdminClientProcessor.java | 9 +-- .../ResteasyKeycloakAdminClientRecorder.java | 36 +++++++-- 3 files changed, 37 insertions(+), 82 deletions(-) diff --git a/extensions/keycloak-admin-rest-client/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java b/extensions/keycloak-admin-rest-client/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java index 0690fbcdff3d7..aa08f7edb66c5 100644 --- a/extensions/keycloak-admin-rest-client/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java +++ b/extensions/keycloak-admin-rest-client/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java @@ -6,13 +6,11 @@ import javax.net.ssl.SSLContext; -import jakarta.enterprise.inject.Instance; import jakarta.ws.rs.Priorities; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.WebTarget; import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.config.ConfigProvider; import org.jboss.resteasy.reactive.client.TlsConfig; import org.jboss.resteasy.reactive.client.api.ClientLogger; import org.jboss.resteasy.reactive.client.impl.ClientBuilderImpl; @@ -27,7 +25,6 @@ import io.quarkus.arc.Arc; import io.quarkus.arc.ArcContainer; import io.quarkus.arc.InstanceHandle; -import io.quarkus.jackson.ObjectMapperCustomizer; import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyWriter; import io.quarkus.tls.TlsConfiguration; import io.vertx.core.net.KeyCertOptions; @@ -71,38 +68,13 @@ private ClientBuilderImpl registerJacksonProviders(ClientBuilderImpl clientBuild if (arcContainer == null) { throw new IllegalStateException(this.getClass().getName() + " should only be used in a Quarkus application"); } else { - InstanceHandle objectMapperInstance = arcContainer.instance(ObjectMapper.class); - boolean canReuseObjectMapper = canReuseObjectMapper(objectMapperInstance, arcContainer); - if (canReuseObjectMapper) { - - ObjectMapper objectMapper = null; - - InstanceHandle readerInstance = arcContainer - .instance(JacksonBasicMessageBodyReader.class); - if (readerInstance.isAvailable()) { - clientBuilder = clientBuilder.register(readerInstance.get()); - } else { - objectMapper = getObjectMapper(objectMapper, objectMapperInstance); - clientBuilder = clientBuilder.register(new JacksonBasicMessageBodyReader(objectMapper)); - } - - InstanceHandle writerInstance = arcContainer - .instance(ClientJacksonMessageBodyWriter.class); - if (writerInstance.isAvailable()) { - clientBuilder = clientBuilder.register(writerInstance.get()); - } else { - objectMapper = getObjectMapper(objectMapper, objectMapperInstance); - clientBuilder = clientBuilder.register(new ClientJacksonMessageBodyWriter(objectMapper)); - } - } else { - ObjectMapper newObjectMapper = newKeycloakAdminClientObjectMapper(); - clientBuilder = clientBuilder - .registerMessageBodyReader(new JacksonBasicMessageBodyReader(newObjectMapper), Object.class, - HANDLED_MEDIA_TYPES, true, - READER_PROVIDER_PRIORITY) - .registerMessageBodyWriter(new ClientJacksonMessageBodyWriter(newObjectMapper), Object.class, - HANDLED_MEDIA_TYPES, true, WRITER_PROVIDER_PRIORITY); - } + ObjectMapper newObjectMapper = newKeycloakAdminClientObjectMapper(); + clientBuilder = clientBuilder + .registerMessageBodyReader(new JacksonBasicMessageBodyReader(newObjectMapper), Object.class, + HANDLED_MEDIA_TYPES, true, + READER_PROVIDER_PRIORITY) + .registerMessageBodyWriter(new ClientJacksonMessageBodyWriter(newObjectMapper), Object.class, + HANDLED_MEDIA_TYPES, true, WRITER_PROVIDER_PRIORITY); InstanceHandle clientLogger = arcContainer.instance(ClientLogger.class); if (clientLogger.isAvailable()) { clientBuilder.clientLogger(clientLogger.get()); @@ -111,38 +83,6 @@ private ClientBuilderImpl registerJacksonProviders(ClientBuilderImpl clientBuild return clientBuilder; } - // the idea is to only reuse the ObjectMapper if no known customizations would break Keycloak - // TODO: in the future we could also look into checking the ObjectMapper bean itself to see how it has been configured - private boolean canReuseObjectMapper(InstanceHandle objectMapperInstance, ArcContainer arcContainer) { - if (objectMapperInstance.isAvailable() && !objectMapperInstance.getBean().isDefaultBean()) { - // in this case a user provided a completely custom ObjectMapper, so we can't use it - return false; - } - - Instance customizers = arcContainer.beanManager().createInstance() - .select(ObjectMapperCustomizer.class); - if (!customizers.isUnsatisfied()) { - // ObjectMapperCustomizer can make arbitrary changes, so in order to be safe we won't allow reuse - return false; - } - // if any Jackson properties were configured, disallow reuse - this is done in order to provide forward compatibility with new Jackson configuration options - for (String propertyName : ConfigProvider.getConfig().getPropertyNames()) { - if (propertyName.startsWith("quarkus.jackson")) { - return false; - } - } - return true; - } - - // the whole idea here is to reuse the ObjectMapper instance - private ObjectMapper getObjectMapper(ObjectMapper value, - InstanceHandle objectMapperInstance) { - if (value == null) { - return objectMapperInstance.isAvailable() ? objectMapperInstance.get() : newKeycloakAdminClientObjectMapper(); - } - return value; - } - // creates new ObjectMapper compatible with Keycloak Admin Client private ObjectMapper newKeycloakAdminClientObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); diff --git a/extensions/keycloak-admin-resteasy-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientProcessor.java b/extensions/keycloak-admin-resteasy-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientProcessor.java index 1a5726456b56c..981e6dc89cd9a 100644 --- a/extensions/keycloak-admin-resteasy-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientProcessor.java +++ b/extensions/keycloak-admin-resteasy-client/deployment/src/main/java/io/quarkus/keycloak/adminclient/deployment/KeycloakAdminClientProcessor.java @@ -14,8 +14,6 @@ import io.quarkus.arc.BeanDestroyer; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; -import io.quarkus.deployment.Capabilities; -import io.quarkus.deployment.Capability; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.ExecutionTime; @@ -58,11 +56,8 @@ void avoidRuntimeInitIssueInClientBuilderWrapper(ResteasyKeycloakAdminClientReco @Record(ExecutionTime.RUNTIME_INIT) @Produce(ServiceStartBuildItem.class) @BuildStep - public void integrate(ResteasyKeycloakAdminClientRecorder recorder, Capabilities capabilities, - TlsRegistryBuildItem tlsRegistryBuildItem) { - boolean areJSONBProvidersPresent = capabilities.isPresent(Capability.RESTEASY_JSON_JSONB) - || capabilities.isPresent(Capability.RESTEASY_JSON_JSONB_CLIENT); - recorder.setClientProvider(areJSONBProvidersPresent, tlsRegistryBuildItem.registry()); + public void integrate(ResteasyKeycloakAdminClientRecorder recorder, TlsRegistryBuildItem tlsRegistryBuildItem) { + recorder.setClientProvider(tlsRegistryBuildItem.registry()); } @Record(ExecutionTime.RUNTIME_INIT) diff --git a/extensions/keycloak-admin-resteasy-client/runtime/src/main/java/io/quarkus/keycloak/adminclient/ResteasyKeycloakAdminClientRecorder.java b/extensions/keycloak-admin-resteasy-client/runtime/src/main/java/io/quarkus/keycloak/adminclient/ResteasyKeycloakAdminClientRecorder.java index 069f72648e1b3..6cfc88870ff58 100644 --- a/extensions/keycloak-admin-resteasy-client/runtime/src/main/java/io/quarkus/keycloak/adminclient/ResteasyKeycloakAdminClientRecorder.java +++ b/extensions/keycloak-admin-resteasy-client/runtime/src/main/java/io/quarkus/keycloak/adminclient/ResteasyKeycloakAdminClientRecorder.java @@ -18,6 +18,10 @@ import org.keycloak.admin.client.KeycloakBuilder; import org.keycloak.admin.client.spi.ResteasyClientProvider; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + import io.quarkus.keycloak.admin.client.common.KeycloakAdminClientConfig; import io.quarkus.resteasy.common.runtime.jackson.QuarkusJacksonSerializer; import io.quarkus.runtime.RuntimeValue; @@ -66,7 +70,7 @@ public Keycloak get() { }; } - public void setClientProvider(boolean areJSONBProvidersPresent, Supplier registrySupplier) { + public void setClientProvider(Supplier registrySupplier) { var registry = registrySupplier.get(); var namedTlsConfig = TlsConfiguration.from(registry, keycloakAdminClientConfigRuntimeValue.getValue().tlsConfigurationName()).orElse(null); @@ -100,12 +104,10 @@ public Client newRestEasyClient(Object customJacksonProvider, SSLContext sslCont } } - // point here is to use default Quarkus providers rather than org.keycloak.admin.client.JacksonProvider - // as it doesn't work properly in native mode - if (areJSONBProvidersPresent) { - // when both Jackson and JSONB providers are present, we need to ensure Jackson is used - builder.register(new AppJsonQuarkusJacksonSerializer(), 100); - } + // this ensures we don't customize managed (shared) ObjectMapper available in the CDI container + // and that we use QuarkusJacksonSerializer that works in native mode + builder.register(new AppJsonQuarkusJacksonSerializer(), 100); + return builder.build(); } @@ -126,6 +128,24 @@ public void avoidRuntimeInitIssueInClientBuilderWrapper() { // makes media type more specific which ensures that it will be used first @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - static class AppJsonQuarkusJacksonSerializer extends QuarkusJacksonSerializer { + static final class AppJsonQuarkusJacksonSerializer extends QuarkusJacksonSerializer { + + private final ObjectMapper objectMapper; + + private AppJsonQuarkusJacksonSerializer() { + this.objectMapper = new ObjectMapper(); + // Same like JSONSerialization class. Makes it possible to use admin-client against older + // versions of Keycloak server where the properties on representations might be different + this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + // The client must work with the newer versions of Keycloak server, which might contain the JSON fields + // not yet known by the client. So unknown fields will be ignored. + this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + @Override + public ObjectMapper locateMapper(Class type, MediaType mediaType) { + return objectMapper; + } + } } From 3630e0f723b5261ef108c477a4fb959d18adbb0b Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 23 Dec 2024 15:40:20 +0100 Subject: [PATCH 200/207] Fix a few infelicities in @WithTestResource documentation --- .../src/main/asciidoc/getting-started-testing.adoc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/src/main/asciidoc/getting-started-testing.adoc b/docs/src/main/asciidoc/getting-started-testing.adoc index 35c28cc97071a..aa1e151a1f5f0 100644 --- a/docs/src/main/asciidoc/getting-started-testing.adoc +++ b/docs/src/main/asciidoc/getting-started-testing.adoc @@ -1224,20 +1224,20 @@ public @interface WithRepeatableTestResource { } ---- -=== Usage of `@WithTestResources` +=== Usage of `@WithTestResource` -While test resources provided by `@QuarkusTestResource` are available either globally or restricted to the annotated test class (`restrictToAnnotatedClass`), the annotation `@WithTestResources` allows to additionally group tests by test resources for execution. -`@WithTestResources` has a `scope` property that takes a `TestResourceScope` enum value: +While test resources provided by `@QuarkusTestResource` are available either globally or restricted to the annotated test class (`restrictToAnnotatedClass`), the annotation `@WithTestResource` allows to additionally group tests by test resources for execution. +`@WithTestResource` has a `scope` property that takes a `TestResourceScope` enum value: - `TestResourceScope.MATCHING_RESOURCES` (default): Quarkus will group tests with the same test resources and run them together. After a group has been executed, all test resources will be stopped, and the next group will be executed. - `TestResourceScope.RESTRICTED_TO_CLASS`: The test resource is available only for the annotated test class and will be stopped after the test class has been executed. -- `TestResourceScope.GLOBAL`: Test resources apply to all tests in the testsuite +- `TestResourceScope.GLOBAL`: Test resources apply to all tests in the test suite Quarkus needs to restart if one of the following is true: -- At least one the existing test resources is restricted to the test class -- At least one the next test resources is restricted to the test class -- Different {@code MATCHING_RESOURCE} scoped test resources are being used +- At least one of the test resources of the current test is restricted to the test class +- At least one of the test resources of the next test is restricted to the test class +- Different `MATCHING_RESOURCES` scoped test resources are being used == Hang Detection From 4340d690ec05fccf5ed6ce204ac2ab890b22a6fd Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 23 Dec 2024 15:40:46 +0100 Subject: [PATCH 201/207] Fix a small typo in a variable name in QuarkusTestProfileAwareClassOrderer --- .../junit/util/QuarkusTestProfileAwareClassOrderer.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrderer.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrderer.java index a3d13b02f0436..9a9c4e683fe16 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrderer.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/util/QuarkusTestProfileAwareClassOrderer.java @@ -122,12 +122,12 @@ public void orderClasses(ClassOrdererContext context) { }) .orElseGet(ClassName::new).orderClasses(context); - var classDecriptors = context.getClassDescriptors(); - var firstPassIndexMap = IntStream.range(0, classDecriptors.size()).boxed() - .collect(Collectors.toMap(classDecriptors::get, i -> String.format("%06d", i))); + var classDescriptors = context.getClassDescriptors(); + var firstPassIndexMap = IntStream.range(0, classDescriptors.size()).boxed() + .collect(Collectors.toMap(classDescriptors::get, i -> String.format("%06d", i))); // second pass: apply the actual Quarkus aware ordering logic, using the first pass indices as order key suffixes - classDecriptors.sort(Comparator.comparing(classDescriptor -> { + classDescriptors.sort(Comparator.comparing(classDescriptor -> { var secondaryOrderSuffix = firstPassIndexMap.get(classDescriptor); Optional customOrderKey = getCustomOrderKey(classDescriptor, context, secondaryOrderSuffix) .or(() -> getCustomOrderKey(classDescriptor, context)); From 48d51cdd253eddc6d3ff8b9db8cac87b4632fb11 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 23 Dec 2024 15:41:10 +0100 Subject: [PATCH 202/207] Make sure configAnnotation entry is always added Otherwise we were comparing items with and without this entry, leading to us restarting Quarkus a lot more often than necessary. Spotted while playing with a modified version of @WithKubernetesTestServer/ --- .../test/common/TestResourceManager.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java b/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java index b7dc8f2467de3..92439a7a1559a 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/TestResourceManager.java @@ -106,8 +106,7 @@ public TestResourceManager(Class testClass, this.testResourceComparisonInfo = new HashSet<>(); for (TestResourceClassEntry uniqueEntry : uniqueEntries) { - testResourceComparisonInfo.add(new TestResourceComparisonInfo( - uniqueEntry.testResourceLifecycleManagerClass().getName(), uniqueEntry.getScope(), uniqueEntry.args)); + testResourceComparisonInfo.add(prepareTestResourceComparisonInfo(uniqueEntry)); } Set remainingUniqueEntries = initParallelTestResources(uniqueEntries); @@ -331,7 +330,7 @@ private Set uniqueTestResourceClassEntries(Path testClas } /** - * Allows Quarkus to extra basic information about which test resources a test class will require + * Allows Quarkus to extract basic information about which test resources a test class will require */ public static Set testResourceComparisonInfo(Class testClass, Path testClassLocation, List entriesFromProfile) { @@ -343,16 +342,24 @@ public static Set testResourceCo allEntries.addAll(entriesFromProfile); Set result = new HashSet<>(allEntries.size()); for (TestResourceClassEntry entry : allEntries) { - Map args = new HashMap<>(entry.args); - if (entry.configAnnotation != null) { - args.put("configAnnotation", entry.configAnnotation.annotationType().getName()); - } - result.add(new TestResourceComparisonInfo(entry.testResourceLifecycleManagerClass().getName(), entry.getScope(), - args)); + result.add(prepareTestResourceComparisonInfo(entry)); } return result; } + private static TestResourceComparisonInfo prepareTestResourceComparisonInfo(TestResourceClassEntry entry) { + Map args; + if (entry.configAnnotation != null) { + args = new HashMap<>(entry.args); + args.put("configAnnotation", entry.configAnnotation.annotationType().getName()); + } else { + args = entry.args; + } + + return new TestResourceComparisonInfo(entry.testResourceLifecycleManagerClass().getName(), entry.getScope(), + args); + } + private static Set getUniqueTestResourceClassEntries(Class testClass, Path testClassLocation, Consumer> afterMetaAnnotationAction) { From ab5ac962ed09db20946f07316abc60e6ee4c33ae Mon Sep 17 00:00:00 2001 From: Johnathan Gilday Date: Mon, 23 Dec 2024 10:13:20 -0500 Subject: [PATCH 203/207] Typo in Proxy Configuration Guidance HTTP documentation includes guidance for configuring a reverse proxy. It states that the proxy should strip "X-Forwarded" and "X-Forwarded-*" headers, but I believe it meant "Forwarded" and "X-Forwarded-*" headers. --- docs/src/main/asciidoc/http-reference.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/http-reference.adoc b/docs/src/main/asciidoc/http-reference.adoc index 10b58e6b2866b..3b1aa4bc1df4a 100644 --- a/docs/src/main/asciidoc/http-reference.adoc +++ b/docs/src/main/asciidoc/http-reference.adoc @@ -554,7 +554,7 @@ quarkus.http.proxy.trusted-proxies=127.0.0.1 <1> ---- <1> Configure trusted proxy with the IP address `127.0.0.1`. Request headers from any other address are going to be ignored. -Both configurations related to standard and non-standard headers can be combined, although the standard headers configuration will have precedence. However, combining them has security implications as clients can forge requests with a forwarded header that is not overwritten by the proxy. Therefore, proxies should strip unexpected `X-Forwarded` or `X-Forwarded-*` headers from the client. +Both configurations related to standard and non-standard headers can be combined, although the standard headers configuration will have precedence. However, combining them has security implications as clients can forge requests with a forwarded header that is not overwritten by the proxy. Therefore, proxies should strip unexpected `Forwarded` or `X-Forwarded-*` headers from the client. Supported forwarding address headers are: From 0b097eb581c7edaa5bad901eb1421b1e4f3a5a0c Mon Sep 17 00:00:00 2001 From: Johnathan Gilday Date: Mon, 23 Dec 2024 12:50:57 -0500 Subject: [PATCH 204/207] Typo in ProxyConfig `X-Forwarded` means to refer to `Forwarded` --- .../main/java/io/quarkus/vertx/http/runtime/ProxyConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/ProxyConfig.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/ProxyConfig.java index eabd1c5928085..3dbff59327cb6 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/ProxyConfig.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/ProxyConfig.java @@ -35,7 +35,7 @@ public class ProxyConfig { * the precedence. * Activating this together with {@code quarkus.http.proxy.allow-x-forwarded} has security implications as clients can forge * requests with a forwarded header that is not overwritten by the proxy. Therefore, proxies should strip unexpected - * `X-Forwarded` or `X-Forwarded-*` headers from the client. + * `Forwarded` or `X-Forwarded-*` headers from the client. */ @ConfigItem public boolean allowForwarded; @@ -47,7 +47,7 @@ public class ProxyConfig { * precedence. * Activating this together with {@code quarkus.http.proxy.allow-forwarded} has security implications as clients can forge * requests with a forwarded header that is not overwritten by the proxy. Therefore, proxies should strip unexpected - * `X-Forwarded` or `X-Forwarded-*` headers from the client. + * `Forwarded` or `X-Forwarded-*` headers from the client. */ @ConfigItem public Optional allowXForwarded; From c4dde5a25cf16a61a25f0bcb5fd03105310afa69 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 23 Dec 2024 19:36:40 +0100 Subject: [PATCH 205/207] Update Develocity extension to 1.1.9 --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 2292cd139ef03..b8529bff74821 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -17,6 +17,6 @@ io.quarkus.develocity quarkus-project-develocity-extension - 1.1.8 + 1.1.9 From 981d34d0965a2cfe6b2fe3b706ed524b5e4bb63e Mon Sep 17 00:00:00 2001 From: Rolfe Dlugy-Hegwer Date: Mon, 23 Dec 2024 14:16:01 -0500 Subject: [PATCH 206/207] Update xrefs to use .adoc consistently --- .../main/asciidoc/deploying-to-openshift.adoc | 2 +- .../asciidoc/extension-maturity-matrix.adoc | 12 ++++++------ .../asciidoc/security-oidc-auth0-tutorial.adoc | 4 ++-- ...urity-oidc-bearer-token-authentication.adoc | 4 ++-- ...security-oidc-code-flow-authentication.adoc | 6 +++--- ...ity-openid-connect-client-registration.adoc | 18 +++++++++--------- .../security-openid-connect-providers.adoc | 2 +- docs/src/main/asciidoc/web.adoc | 4 ++-- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/src/main/asciidoc/deploying-to-openshift.adoc b/docs/src/main/asciidoc/deploying-to-openshift.adoc index 523c6308fec4a..f9bf9d4f0910e 100644 --- a/docs/src/main/asciidoc/deploying-to-openshift.adoc +++ b/docs/src/main/asciidoc/deploying-to-openshift.adoc @@ -417,7 +417,7 @@ You can provide the arguments that will be used by the Kubernetes Job via the pr Finally, the Kubernetes job will be launched every time that is installed in OpenShift. You can know more about how to run Kubernetes jobs in this https://kubernetes.io/docs/concepts/workloads/controllers/job/#running-an-example-job[link]. -You can configure the rest of the Kubernetes Job configuration using the properties under `quarkus.openshift.job.xxx` (see xref:deploying-to-openshift#quarkus-kubernetes_quarkus-openshift-job-parallelism[link]). +You can configure the rest of the Kubernetes Job configuration using the properties under `quarkus.openshift.job.xxx` (see xref:deploying-to-openshift.adoc#quarkus-kubernetes_quarkus-openshift-job-parallelism[link]). ===== Generating CronJob resources diff --git a/docs/src/main/asciidoc/extension-maturity-matrix.adoc b/docs/src/main/asciidoc/extension-maturity-matrix.adoc index 43dfed1e028e9..a9bb187d9e9f5 100644 --- a/docs/src/main/asciidoc/extension-maturity-matrix.adoc +++ b/docs/src/main/asciidoc/extension-maturity-matrix.adoc @@ -27,7 +27,7 @@ It's completely OK to publish a first version of an extension that doesn't handl Also note that this list only includes the technical features of your extension. You might also want to think about how you share your extension, and how it presents itself to the world. The link:https://hub.quarkiverse.io/checklistfornewprojects/[new extension checklist] on the Quarkiverse Hub has a useful list of ways extensions can participate in the ecosystem. -It's also a good idea to spend some time on the metadata in the xref:extension-metadata#quarkus-extension-yaml[`quarkus-extension.yaml` file], which is used by Quarkus tooling. +It's also a good idea to spend some time on the metadata in the xref:extension-metadata.adoc#quarkus-extension-yaml[`quarkus-extension.yaml` file], which is used by Quarkus tooling. Here are some pointers on how to achieve those capabilities. @@ -66,7 +66,7 @@ The Writing Extensions guide has more guidance on xref:writing-extensions.adoc#h === CDI Beans Quarkus extensions should aim to xref:writing-extensions.adoc#expose-your-components-via-cdi[expose components via CDI], so that they can be consumed in a frictionless way by user applications. -Having everything injectable as CDI beans also helps testing, especially xref:getting-started-testing#mock-support[mocking]. +Having everything injectable as CDI beans also helps testing, especially xref:getting-started-testing.adoc#mock-support[mocking]. === Dev Service @@ -95,7 +95,7 @@ A good starting point is usually to use Although providing new, joyful, ways to do things is good, it's important to not break the normal patterns that users may be familiar with. -For some inspiration in this area, have a look at xref:logging#simplified-logging[simplified logging], xref:hibernate-orm-panache.adoc[simplified Hibernate ORM with Panache], the xref:rest-client.adoc#query-parameters[`@RestQuery` annotation], or the way Quarkus allows test containers to be used xref:getting-started-dev-services.adoc[without any configuration]. +For some inspiration in this area, have a look at xref:logging.adoc#simplified-logging[simplified logging], xref:hibernate-orm-panache.adoc[simplified Hibernate ORM with Panache], the xref:rest-client.adoc#query-parameters[`@RestQuery` annotation], or the way Quarkus allows test containers to be used xref:getting-started-dev-services.adoc[without any configuration]. === Codestart application template @@ -124,7 +124,7 @@ For a case study of how to eliminate reflection and what the performance benefit === Virtual thread support Not every library is suitable for using with virtual threads, out of the box. -xref:virtual-threads#why-not["Why not virtual threads everywhere?"] explains why. +xref:virtual-threads.adoc#why-not["Why not virtual threads everywhere?"] explains why. To get your library working properly with virtual threads, you should make sure the library is not pinning the carrier thread. Quarkus has xref:virtual-threads.adoc#testing-virtual-thread-applications[test helpers to do these checks in an automated way]. @@ -157,7 +157,7 @@ Avoid using errors and warnings for conditions that will not affect normal opera === Define health endpoints -Extensions may wish to xref:writing-extensions#extension-defined-endpoints[define library-specific endpoints] for health criteria which are specific to that extension. To add a new endpoint, extensions should produce a `NonApplicationRootPathBuildItem`. +Extensions may wish to xref:writing-extensions.adoc#extension-defined-endpoints[define library-specific endpoints] for health criteria which are specific to that extension. To add a new endpoint, extensions should produce a `NonApplicationRootPathBuildItem`. === Tracing context @@ -175,4 +175,4 @@ Being Kubernetes-native implies being container-native. At a minimum, extensions - xref:writing-extensions.adoc[Writing your own extension] guide - xref:building-my-first-extension.adoc[Building your first extension] -- link:https://hub.quarkiverse.io.adoc[The Quarkiverse Hub documentation] \ No newline at end of file +- link:https://hub.quarkiverse.io.adoc[The Quarkiverse Hub documentation] diff --git a/docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc b/docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc index d5e9dfe2b9953..66bdaa41cc42a 100644 --- a/docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc +++ b/docs/src/main/asciidoc/security-oidc-auth0-tutorial.adoc @@ -928,7 +928,7 @@ Press `r` and notice this test failing with `403` which is expected because the image::auth0-test-failure-403.png[Auth0 test failure 403] -Before fixing the test, let's review the options available for testing Quarkus endpoints secured by OIDC. These options might vary, depending on which flow your application supports and how you prefer to test. Endpoints which use OIDC authorization code flow can be tested using xref:security-oidc-code-flow-authentication#code-flow-integration-testing[one of these options] and endpoints which use Bearer token authentication can be tested using xref:security-oidc-bearer-token-authentication#bearer-token-integration-testing[one of these options]. +Before fixing the test, let's review the options available for testing Quarkus endpoints secured by OIDC. These options might vary, depending on which flow your application supports and how you prefer to test. Endpoints which use OIDC authorization code flow can be tested using xref:security-oidc-code-flow-authentication.adoc#code-flow-integration-testing[one of these options] and endpoints which use Bearer token authentication can be tested using xref:security-oidc-bearer-token-authentication.adoc#bearer-token-integration-testing[one of these options]. As you can see, testing of the endpoints secured with Auth0 can be done with the help of `Wiremock`, or `@TestSecurity` annotation. Experiment with writing such tests on your own and reach out if you encounter any problems. @@ -956,7 +956,7 @@ image::auth0-password-grant.png[Auth0 password grant] It is important to clarify that we do not recommend using the deprecated OAuth2 `password` token grant in production. However using it can help testing the endpoint with tokens acquired from the live dev Auth0 tenant. ==== -`OidcTestClient` should be used to test applications accepting bearer tokens which will work for the endpoint developed in this tutorial as it supports both authorization code flow and bearer token authentication. You would need to use OIDC WireMock or `HtmlUnit` directly against the Auth0 dev tenant if only the authorization code flow was supported - in the latter case `HtmlUnit` test code would have to be aligned with how Auth0 challenges users to enter their credentials. If you like, you can copy the xref:security-oidc-code-flow-authentication#code-flow-integration-testing-wiremock[HtmlUnit test fragment] from the documentation and experiment with it. +`OidcTestClient` should be used to test applications accepting bearer tokens which will work for the endpoint developed in this tutorial as it supports both authorization code flow and bearer token authentication. You would need to use OIDC WireMock or `HtmlUnit` directly against the Auth0 dev tenant if only the authorization code flow was supported - in the latter case `HtmlUnit` test code would have to be aligned with how Auth0 challenges users to enter their credentials. If you like, you can copy the xref:security-oidc-code-flow-authentication.adoc#code-flow-integration-testing-wiremock[HtmlUnit test fragment] from the documentation and experiment with it. In meantime we will now proceed with fixing the currently failing test using `OidcTestClient`. diff --git a/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc b/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc index aa7554a5a75db..b2e24e4553944 100644 --- a/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc +++ b/docs/src/main/asciidoc/security-oidc-bearer-token-authentication.adoc @@ -1280,7 +1280,7 @@ quarkus.tls.oidc-server-mtls.trust-store.p12.password=password The above configuration is sufficient to require that OIDC bearer tokens are bound to the client certificates. -Next, if you need to access both mTLS and OIDC bearer security identities, consider enabling xref:security-authentication-mechanisms#combining-authentication-mechanisms[Inclusive authentication] with `quarkus.http.auth.inclusive=true`. +Next, if you need to access both mTLS and OIDC bearer security identities, consider enabling xref:security-authentication-mechanisms.adoc#combining-authentication-mechanisms[Inclusive authentication] with `quarkus.http.auth.inclusive=true`. Now you can access both MTLS and OIDC security identities as follows: @@ -1419,7 +1419,7 @@ Authentication that requires a dynamic tenant will fail. == OIDC request filters You can filter OIDC requests made by Quarkus to the OIDC provider by registering one or more `OidcRequestFilter` implementations, which can update or add new request headers, and log requests. -For more information, see xref:security-oidc-code-flow-authentication#code-flow-oidc-request-filters[OIDC request filters]. +For more information, see xref:security-oidc-code-flow-authentication.adoc#code-flow-oidc-request-filters[OIDC request filters]. [[bearer-token-oidc-response-filters]] === OIDC response filters diff --git a/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc b/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc index 7c656133d0329..967ac4335e01b 100644 --- a/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc +++ b/docs/src/main/asciidoc/security-oidc-code-flow-authentication.adoc @@ -300,7 +300,7 @@ quarkus.tls.oidc.trust-store.p12.password=${trust-store-password} ==== POST query -Some providers, such as the xref:security-openid-connect-providers#strava[Strava OAuth2 provider], require client credentials be posted as HTTP POST query parameters: +Some providers, such as the xref:security-openid-connect-providers.adoc#strava[Strava OAuth2 provider], require client credentials be posted as HTTP POST query parameters: [source,properties] ---- @@ -416,7 +416,7 @@ import io.quarkus.oidc.runtime.OidcUtils; @Unremovable @OidcEndpoint(value = Type.TOKEN) <1> public class TokenEndpointResponseFilter implements OidcResponseFilter { - + @Override public void filter(OidcResponseContext rc) { String contentType = rc.responseHeaders().get("Content-Type"); <2> @@ -1853,7 +1853,7 @@ To import a custom realm file into Keycloak before running the tests, configure quarkus.keycloak.devservices.realm-path=quarkus-realm.json ---- -Finally, write the test code as described in the <> section. +Finally, write the test code as described in the <> section. The only difference is that `@QuarkusTestResource` is no longer required: [source, java] diff --git a/docs/src/main/asciidoc/security-openid-connect-client-registration.adoc b/docs/src/main/asciidoc/security-openid-connect-client-registration.adoc index efdd913d67ae4..71035c4af5812 100644 --- a/docs/src/main/asciidoc/security-openid-connect-client-registration.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-client-registration.adoc @@ -19,12 +19,12 @@ You can read more about it in the https://openid.net/specs/openid-connect-regist You can use Quarkus `quarkus-oidc-client-registration` extension to register one or more clients using OIDC client registration configurations and read, update and delete metadata of the registered clients. -xref:security-openid-connect-multitenancy#tenant-config-resolver[OIDC TenantConfigResolver] can be used to create OIDC tenant configurations using the metadata of the registered clients. +xref:security-openid-connect-multitenancy.adoc#tenant-config-resolver[OIDC TenantConfigResolver] can be used to create OIDC tenant configurations using the metadata of the registered clients. [IMPORTANT] ==== Currently, Quarkus `quarkus-oidc-client-registration` extension has an `experimental` status. -Dynamic client registration API provided by this extension may change while this extension has an experiemental status. +Dynamic client registration API provided by this extension may change while this extension has an experiemental status. ==== == OIDC Client Registration @@ -41,7 +41,7 @@ Add the following dependency: The `quarkus-oidc-client-registration` extension allows register one or more clients using OIDC client registration configurations, either on start-up or on demand, and read, update and delete metadata of the registered clients. -You can register and manage client registrations from the custom xref:security-openid-connect-multitenancy#tenant-config-resolver[OIDC TenantConfigResolver]. +You can register and manage client registrations from the custom xref:security-openid-connect-multitenancy.adoc#tenant-config-resolver[OIDC TenantConfigResolver]. Alternatively, you can register clients without even using OIDC. For example, it can be a command line tool which registers clients and passes metadata of the registered clients to Quarkus services which require them. @@ -61,7 +61,7 @@ quarkus.oidc-client-registration.auth-server-url=${quarkus.oidc.auth-server-url} quarkus.oidc-client-registration.metadata.client-name=Default Client quarkus.oidc-client-registration.metadata.redirect-uri=http://localhost:8081/protected -# Named OIDC client registration which configures a registration endpoint path: +# Named OIDC client registration which configures a registration endpoint path: # It require an initial registration token for a client registration to succeed. quarkus.oidc-client-registration.tenant-client.registration-path=${quarkus.oidc.auth-server-url}/clients-registrations/openid-connect @@ -72,7 +72,7 @@ quarkus.oidc-client-registration.initial-token=${initial-registration-token} The above configuration will lead to two new client registrations created in your OIDC provider. -You or may not need to acquire an initial registration access token. If you don't, then you will have to enable one or more client registration policies in your OIDC provider's dashboard. For example, see https://www.keycloak.org/docs/latest/securing_apps/#_client_registration_policies[Keycloak client registration policies]. +You or may not need to acquire an initial registration access token. If you don't, then you will have to enable one or more client registration policies in your OIDC provider's dashboard. For example, see https://www.keycloak.org/docs/latest/securing_apps/#_client_registration_policies[Keycloak client registration policies]. The next step is to inject either `quarkus.oidc.client.registration.OidcClientRegistration` if only a single default client registration is done, or `quarkus.oidc.client.registration.OidcClientRegistrations` if more than one registration is configured, and use metadata of the clients registered with these configurations. @@ -114,7 +114,7 @@ public class CustomTenantConfigResolver implements TenantConfigResolver { @Override public Uni resolve(RoutingContext routingContext, OidcRequestContext requestContext) { - + if (routingContext.request().path().endsWith("/protected")) { // Use the registered client created from the default OIDC client registration return clientReg.registeredClient().onItem().transform(client -> createTenantConfig("registered-client", client)); @@ -148,7 +148,7 @@ public class CustomTenantConfigResolver implements TenantConfigResolver { [[register-clients-on-demand]] === Register clients on demand -You can register new clients on demand. +You can register new clients on demand. You can add new clients to the existing, already configured `OidcClientConfiguration` or to a newly created `OidcClientConfiguration`. Start from configuring one or more OIDC client registrations: @@ -201,7 +201,7 @@ public class CustomTenantConfigResolver implements TenantConfigResolver { ClientMetadata metadata = createMetadata("http://localhost:8081/protected/dynamic-tenant", "Dynamic Tenant Client"); - return clientReg.registerClient(metadata).onItem().transform(r -> + return clientReg.registerClient(metadata).onItem().transform(r -> createTenantConfig("registered-client-dynamically", r)); } return null; @@ -280,7 +280,7 @@ public class CustomTenantConfigResolver implements TenantConfigResolver { .build(); return clientRegs.newClientRegistration(clientRegConfig) - .onItem().transform(reg -> + .onItem().transform(reg -> createTenantConfig("registered-client-dynamically", reg.registeredClient()); } diff --git a/docs/src/main/asciidoc/security-openid-connect-providers.adoc b/docs/src/main/asciidoc/security-openid-connect-providers.adoc index 240922f2a9249..d7ea4feb8d638 100644 --- a/docs/src/main/asciidoc/security-openid-connect-providers.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-providers.adoc @@ -771,7 +771,7 @@ It may not be a problem when Quarkus fetches public verification keys from OIDC- Therefore, UserInfo is embedded in an internally generated ID token and is encrypted in the session cookie. You can disable it with `quarkus.oidc.cache-user-info-in-idtoken=false`. -Alternatively, use a default or custom UserInfo cache provider, please see the xref:security-oidc-bearer-token-authentication#bearer-token-token-introspection-userinfo-cache[Token Introspection and UserInfo cache] section of the "OpenID Connect (OIDC) Bearer token authentication" guide. +Alternatively, use a default or custom UserInfo cache provider, please see the xref:security-oidc-bearer-token-authentication.adoc#bearer-token-token-introspection-userinfo-cache[Token Introspection and UserInfo cache] section of the "OpenID Connect (OIDC) Bearer token authentication" guide. == References diff --git a/docs/src/main/asciidoc/web.adoc b/docs/src/main/asciidoc/web.adoc index bf1e0100bce2b..76b7e803e9a0d 100644 --- a/docs/src/main/asciidoc/web.adoc +++ b/docs/src/main/asciidoc/web.adoc @@ -21,7 +21,7 @@ Quarkus provides several extensions to create web applications, this document ai Let's assume you have a Quarkus backend, and you want to serve static files. This is the most basic case, it is supported out of the box with all our Vert.x based extensions, you must place them in the `META-INF/resources` directory of your application. -You can find more information in the xref:http-reference#serving-static-resources[HTTP reference guide]. +You can find more information in the xref:http-reference.adoc#serving-static-resources[HTTP reference guide]. === Serving scripts, styles, and web libraries @@ -266,4 +266,4 @@ You could also split it in two services: one for the backend and one for the fro If your application involves a substantial number of static resources, consider using a CDN. Both the Web Bundler and Quinoa can be configured to work seamlessly with a CDN, providing improved performance and distribution of assets. -// It would be nice to have a blog article and benchmark about this topic. \ No newline at end of file +// It would be nice to have a blog article and benchmark about this topic. From a7a8380540c706609d3f2416fe8b0ed90d9de2e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:28:10 +0000 Subject: [PATCH 207/207] Bump org.freemarker:freemarker from 2.3.33 to 2.3.34 Bumps org.freemarker:freemarker from 2.3.33 to 2.3.34. --- updated-dependencies: - dependency-name: org.freemarker:freemarker dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 8a9ff77592ff5..56e16d5db6b72 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -39,7 +39,7 @@ 6.0.1 - 2.3.33 + 2.3.34 0.24.0

    Quarkus${build.quarkusVersion}
    App Name${unsafeHTML(build.name)}
    Group${build.group}
    Artifact${build.artifact}
    Version${build.version}

    @@ -420,6 +435,7 @@ private static final class FailingDefaultAuthFailureHandler implements BiConsume @Override public void accept(RoutingContext event, Throwable throwable) { + markIfOtherAuthenticationFailure(event, throwable); if (!event.failed()) { event.fail(extractRootCause(throwable)); } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java index 3ec1ae277341f..1f1faee90d42d 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java @@ -33,6 +33,7 @@ import io.quarkus.runtime.annotations.Recorder; import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.security.AuthenticationCompletionException; +import io.quarkus.security.AuthenticationException; import io.quarkus.security.AuthenticationFailedException; import io.quarkus.security.AuthenticationRedirectException; import io.quarkus.security.identity.SecurityIdentity; @@ -171,6 +172,12 @@ public Map get() { public static abstract class DefaultAuthFailureHandler implements BiConsumer { + /** + * A {@link RoutingContext#get(String)} key added for exceptions raised during authentication that are not + * the {@link io.quarkus.security.AuthenticationException}. + */ + private static final String OTHER_AUTHENTICATION_FAILURE = "io.quarkus.vertx.http.runtime.security.other-auth-failure"; + protected DefaultAuthFailureHandler() { } @@ -206,6 +213,7 @@ public void accept(Throwable throwable) { event.response().headers().set("Pragma", "no-cache"); proceed(throwable); } else { + event.put(OTHER_AUTHENTICATION_FAILURE, Boolean.TRUE); event.fail(throwable); } } @@ -227,6 +235,20 @@ public static Throwable extractRootCause(Throwable throwable) { } return throwable; } + + public static void markIfOtherAuthenticationFailure(RoutingContext event, Throwable throwable) { + if (!(throwable instanceof AuthenticationException)) { + event.put(OTHER_AUTHENTICATION_FAILURE, Boolean.TRUE); + } + } + + public static void removeMarkAsOtherAuthenticationFailure(RoutingContext event) { + event.remove(OTHER_AUTHENTICATION_FAILURE); + } + + public static boolean isOtherAuthenticationFailure(RoutingContext event) { + return Boolean.TRUE.equals(event.get(OTHER_AUTHENTICATION_FAILURE)); + } } public static final class AuthenticationHandler implements Handler { From 73ed76fe18f31ccd8fd0ccccfae11cd3e3c63945 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Sat, 7 Dec 2024 11:51:48 -0300 Subject: [PATCH 056/207] Fix ci.yml for Gradle projects - Should use gradle/actions/setup-gradle action instead too --- .../base/.github/workflows/ci.tpl.qute.yml | 17 +++++++------ .../QuarkusCodestartGenerationTest.java | 23 ++++++++++++++--- .../.github_workflows_ci.yml | 11 +++++--- .../.github_workflows_ci.yml | 9 +++++-- .../.github_workflows_ci.yml | 25 +++++++++++++++++++ 5 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateMavenGithubAction/.github_workflows_ci.yml diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/github-action/base/.github/workflows/ci.tpl.qute.yml b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/github-action/base/.github/workflows/ci.tpl.qute.yml index 7dece3c9e74cd..9e6edad446fe2 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/github-action/base/.github/workflows/ci.tpl.qute.yml +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/github-action/base/.github/workflows/ci.tpl.qute.yml @@ -12,22 +12,23 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - name: Set up JDK {java.version} uses: actions/setup-java@v4 with: java-version: {java.version} distribution: temurin - {#if buildtool.cli == 'gradle'} + {#if buildtool.cli.contains('gradle')} cache: gradle {#else} cache: maven {/if} + + {#if buildtool.cli.contains('gradle')} + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + {/if} - name: Build - {#if buildtool.cli == 'gradle'} - uses: eskatos/gradle-command-action@v1 - with: - arguments: {buildtool.cmd.build-ci} - {#else} run: {buildtool.cli} {buildtool.cmd.build-ci} - {/if} diff --git a/independent-projects/tools/devtools-testing/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartGenerationTest.java b/independent-projects/tools/devtools-testing/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartGenerationTest.java index 4723c18d9d018..6e8e919af572b 100644 --- a/independent-projects/tools/devtools-testing/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartGenerationTest.java +++ b/independent-projects/tools/devtools-testing/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartGenerationTest.java @@ -262,7 +262,23 @@ public void generateGradleWrapperGithubAction(TestInfo testInfo) throws Throwabl checkGradle(projectDir); assertThatMatchSnapshot(testInfo, projectDir, ".github/workflows/ci.yml") - .satisfies(checkContains("run: ./gradlew build")); + .satisfies( + checkContains("cache: gradle"), + checkContains("run: ./gradlew build")); + } + + @Test + public void generateMavenGithubAction(TestInfo testInfo) throws Throwable { + final QuarkusCodestartProjectInput input = newInputBuilder() + .buildTool(BuildTool.MAVEN) + .addData(getGenerationTestInputData()) + .addCodestarts(Collections.singletonList("tooling-github-action")) + .build(); + Path projectDir = testDirPath.resolve("maven-github"); + getCatalog().createProject(input).generate(projectDir); + + assertThatMatchSnapshot(testInfo, projectDir, ".github/workflows/ci.yml") + .satisfies(checkContains("cache: maven")); } @Test @@ -279,8 +295,9 @@ public void generateGradleNoWrapperGithubAction(TestInfo testInfo) throws Throwa checkGradle(projectDir); assertThatMatchSnapshot(testInfo, projectDir, ".github/workflows/ci.yml") - .satisfies(checkContains("uses: eskatos/gradle-command-action@v1")) - .satisfies(checkContains("arguments: build")); + .satisfies( + checkContains("uses: gradle/actions/setup-gradle"), + checkContains("cache: gradle")); } private void checkDockerfiles(Path projectDir, BuildTool buildTool) { diff --git a/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateGradleNoWrapperGithubAction/.github_workflows_ci.yml b/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateGradleNoWrapperGithubAction/.github_workflows_ci.yml index 92af3184ba738..49fc6c79c53da 100644 --- a/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateGradleNoWrapperGithubAction/.github_workflows_ci.yml +++ b/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateGradleNoWrapperGithubAction/.github_workflows_ci.yml @@ -12,14 +12,17 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: 17 distribution: temurin cache: gradle + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + - name: Build - uses: eskatos/gradle-command-action@v1 - with: - arguments: build + run: gradle build diff --git a/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateGradleWrapperGithubAction/.github_workflows_ci.yml b/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateGradleWrapperGithubAction/.github_workflows_ci.yml index eb4e47391ac89..76078bfd44367 100644 --- a/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateGradleWrapperGithubAction/.github_workflows_ci.yml +++ b/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateGradleWrapperGithubAction/.github_workflows_ci.yml @@ -12,12 +12,17 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: 17 distribution: temurin - cache: maven + cache: gradle + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + - name: Build run: ./gradlew build diff --git a/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateMavenGithubAction/.github_workflows_ci.yml b/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateMavenGithubAction/.github_workflows_ci.yml new file mode 100644 index 0000000000000..593d3aeb9b2bf --- /dev/null +++ b/independent-projects/tools/devtools-testing/src/test/resources/__snapshots__/QuarkusCodestartGenerationTest/generateMavenGithubAction/.github_workflows_ci.yml @@ -0,0 +1,25 @@ +## A basic GitHub Actions workflow for your Quarkus application. + +name: CI build + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: temurin + cache: maven + + - name: Build + run: ./mvnw verify -B From 298daf3cac69f3acb09e90d30177a719fad1beb8 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Sat, 7 Dec 2024 17:18:35 +0000 Subject: [PATCH 057/207] Minor OIDC updates --- .../main/java/io/quarkus/oidc/OidcConfigurationMetadata.java | 4 ++++ .../main/java/io/quarkus/oidc/runtime/OidcProviderClient.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcConfigurationMetadata.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcConfigurationMetadata.java index 9281aa23e226e..bcdde90ad1f74 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcConfigurationMetadata.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcConfigurationMetadata.java @@ -107,6 +107,10 @@ public String getEndSessionUri() { return endSessionUri; } + public String getRegistrationUri() { + return registrationUri; + } + public List getSupportedScopes() { return getStringList(SCOPES_SUPPORTED); } diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java index 24395a65e3254..d1edf36eb1e72 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java @@ -251,7 +251,7 @@ private UniOnItem> getHttpResponse(OidcRequestContextProper private AuthorizationCodeTokens getAuthorizationCodeTokens(OidcRequestContextProperties requestProps, HttpResponse resp) { - JsonObject json = getJsonObject(requestProps, metadata.getAuthorizationUri(), resp, OidcEndpoint.Type.TOKEN); + JsonObject json = getJsonObject(requestProps, metadata.getTokenUri(), resp, OidcEndpoint.Type.TOKEN); final String idToken = json.getString(OidcConstants.ID_TOKEN_VALUE); final String accessToken = json.getString(OidcConstants.ACCESS_TOKEN_VALUE); final String refreshToken = json.getString(OidcConstants.REFRESH_TOKEN_VALUE); From 35c39a95b4063ffc13f41f2c8873c8fe6dcb1a70 Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Sun, 8 Dec 2024 16:09:23 -0300 Subject: [PATCH 058/207] Convert azure-functions to use @ConfigMapping --- extensions/azure-functions/deployment/pom.xml | 3 - .../deployment/AzureFunctionsConfig.java | 131 ++++++++---------- .../AzureFunctionsDeployCommand.java | 42 +++--- .../deployment/AzureFunctionsProcessor.java | 2 +- .../deployment/AzureFunctionsRunCommand.java | 6 +- extensions/azure-functions/runtime/pom.xml | 3 - 6 files changed, 84 insertions(+), 103 deletions(-) diff --git a/extensions/azure-functions/deployment/pom.xml b/extensions/azure-functions/deployment/pom.xml index 10437cac5561b..f01b722b1d4d1 100644 --- a/extensions/azure-functions/deployment/pom.xml +++ b/extensions/azure-functions/deployment/pom.xml @@ -132,9 +132,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsConfig.java b/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsConfig.java index b2994e55bd132..75e3954f397cf 100644 --- a/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsConfig.java +++ b/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsConfig.java @@ -9,7 +9,6 @@ import java.util.Properties; import org.apache.commons.lang3.StringUtils; -import org.jboss.logging.Logger; import com.azure.core.management.AzureEnvironment; import com.microsoft.azure.toolkit.lib.Azure; @@ -31,27 +30,29 @@ import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; /** * Azure Functions configuration. * Most options supported and name similarly to azure-functions-maven-plugin config */ @ConfigRoot(phase = ConfigPhase.BUILD_TIME) -public class AzureFunctionsConfig { +@ConfigMapping(prefix = "quarkus.azure-functions") +public interface AzureFunctionsConfig { /** * App name for azure function project. This is required setting. * * Defaults to the base artifact name */ - @ConfigItem - public Optional appName; + Optional appName(); /** * Azure Resource Group for your Azure Functions */ - @ConfigItem(defaultValue = "quarkus") - public String resourceGroup; + @WithDefault("quarkus") + String resourceGroup(); /** * Specifies the region where your Azure Functions will be hosted; default value is westus. @@ -59,114 +60,105 @@ public class AzureFunctionsConfig { * "https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-regions">Valid * values */ - @ConfigItem(defaultValue = "westus") - public String region; + @WithDefault("westus") + String region(); /** * Specifies whether to disable application insights for your function app */ - @ConfigItem(defaultValue = "false") - public boolean disableAppInsights; + @WithDefault("false") + boolean disableAppInsights(); /** * Specifies the instrumentation key of application insights which will bind to your function app */ - @ConfigItem - public Optional appInsightsKey; + Optional appInsightsKey(); - public RuntimeConfig runtime; + RuntimeConfig runtime(); - public AuthConfig auth; + AuthConfig auth(); /** * Specifies the name of the existing App Service Plan when you do not want to create a new one. */ - @ConfigItem(defaultValue = "java-functions-app-service-plan") - public String appServicePlanName; + @WithDefault("java-functions-app-service-plan") + String appServicePlanName(); /** * The app service plan resource group. */ - @ConfigItem - public Optional appServicePlanResourceGroup; + Optional appServicePlanResourceGroup(); /** * Azure subscription id. Required only if there are more than one subscription in your account */ - @ConfigItem - public Optional subscriptionId; + Optional subscriptionId(); /** * The pricing tier. */ - @ConfigItem - public Optional pricingTier; + Optional pricingTier(); /** * Port to run azure function in local runtime. * Will default to quarkus.http.test-port or 8081 */ - @ConfigItem - public Optional funcPort; + Optional funcPort(); /** * Config String for local debug */ - @ConfigItem(defaultValue = "transport=dt_socket,server=y,suspend=n,address=5005") - public String localDebugConfig; + @WithDefault("transport=dt_socket,server=y,suspend=n,address=5005") + String localDebugConfig(); /** * Specifies the application settings for your Azure Functions, which are defined in name-value pairs */ @ConfigItem @ConfigDocMapKey("setting-name") - public Map appSettings = Collections.emptyMap(); + Map appSettings = Collections.emptyMap(); @ConfigGroup - public static class RuntimeConfig { + interface RuntimeConfig { /** * Valid values are linux, windows, and docker */ - @ConfigItem(defaultValue = "linux") - public String os; + @WithDefault("linux") + String os(); /** * Valid values are 8, 11, and 17 */ - @ConfigItem(defaultValue = "11") - public String javaVersion; + @WithDefault("11") + String javaVersion(); /** * URL of docker image if deploying via docker */ - @ConfigItem - public Optional image; + Optional image(); /** * If using docker, url of registry */ - @ConfigItem - public Optional registryUrl; + Optional registryUrl(); } - public FunctionAppConfig toFunctionAppConfig(String subscriptionId, String appName) { + default FunctionAppConfig toFunctionAppConfig(String subscriptionId, String appName) { Map appSettings = this.appSettings; if (appSettings.isEmpty()) { appSettings = new HashMap<>(); appSettings.put("FUNCTIONS_EXTENSION_VERSION", "~4"); } return (FunctionAppConfig) new FunctionAppConfig() - .disableAppInsights(disableAppInsights) - .appInsightsKey(appInsightsKey.orElse(null)) - .appInsightsInstance(appInsightsKey.orElse(null)) + .disableAppInsights(disableAppInsights()) + .appInsightsKey(appInsightsKey().orElse(null)) + .appInsightsInstance(appInsightsKey().orElse(null)) .subscriptionId(subscriptionId) - .resourceGroup(resourceGroup) + .resourceGroup(resourceGroup()) .appName(appName) - .servicePlanName(appServicePlanName) - .servicePlanResourceGroup(appServicePlanResourceGroup.orElse(null)) - //.deploymentSlotName(getDeploymentSlotName()) - //.deploymentSlotConfigurationSource(getDeploymentSlotConfigurationSource()) + .servicePlanName(appServicePlanName()) + .servicePlanResourceGroup(appServicePlanResourceGroup().orElse(null)) .pricingTier(getParsedPricingTier(subscriptionId)) .region(getParsedRegion()) .runtime(getRuntimeConfig(subscriptionId)) @@ -174,42 +166,42 @@ public FunctionAppConfig toFunctionAppConfig(String subscriptionId, String appNa } private PricingTier getParsedPricingTier(String subscriptionId) { - return Optional.ofNullable(this.pricingTier.orElse(null)).map(PricingTier::fromString) + return Optional.ofNullable(this.pricingTier().orElse(null)).map(PricingTier::fromString) .orElseGet(() -> Optional.ofNullable(getServicePlan(subscriptionId)).map(AppServicePlan::getPricingTier) .orElse(null)); } private AppServicePlan getServicePlan(String subscriptionId) { - final String servicePlan = this.appServicePlanName; - final String servicePlanGroup = StringUtils.firstNonBlank(this.appServicePlanResourceGroup.orElse(null), - this.resourceGroup); + final String servicePlan = this.appServicePlanName(); + final String servicePlanGroup = StringUtils.firstNonBlank(this.appServicePlanResourceGroup().orElse(null), + this.resourceGroup()); return StringUtils.isAnyBlank(subscriptionId, servicePlan, servicePlanGroup) ? null : Azure.az(AzureAppService.class).plans(subscriptionId).get(servicePlan, servicePlanGroup); } private com.microsoft.azure.toolkit.lib.appservice.config.RuntimeConfig getRuntimeConfig(String subscriptionId) { - final RuntimeConfig runtime = this.runtime; + final RuntimeConfig runtime = this.runtime(); if (runtime == null) { return null; } - final OperatingSystem os = Optional.ofNullable(runtime.os).map(OperatingSystem::fromString) + final OperatingSystem os = Optional.ofNullable(runtime.os()).map(OperatingSystem::fromString) .orElseGet( () -> Optional.ofNullable(getServicePlan(subscriptionId)).map(AppServicePlan::getOperatingSystem) .orElse(null)); - final JavaVersion javaVersion = Optional.ofNullable(runtime.javaVersion).map(JavaVersion::fromString).orElse(null); + final JavaVersion javaVersion = Optional.ofNullable(runtime.javaVersion()).map(JavaVersion::fromString).orElse(null); final com.microsoft.azure.toolkit.lib.appservice.config.RuntimeConfig result = new com.microsoft.azure.toolkit.lib.appservice.config.RuntimeConfig() .os(os) .javaVersion(javaVersion).webContainer(WebContainer.JAVA_OFF) - .image(runtime.image.orElse(null)).registryUrl(runtime.registryUrl.orElse(null)); + .image(runtime.image().orElse(null)).registryUrl(runtime.registryUrl().orElse(null)); return result; } private Region getParsedRegion() { - return Optional.ofNullable(region).map(Region::fromName).orElse(null); + return Optional.ofNullable(region()).map(Region::fromName).orElse(null); } @ConfigGroup - public static class AuthConfig { + interface AuthConfig { /** * Description of each type can be found @@ -234,28 +226,23 @@ public static class AuthConfig { * * Defaults to "azure_cli" for authentication */ - @ConfigItem(defaultValue = "azure_cli") - public String type; + @WithDefault("azure_cli") + String type(); /** * Filesystem path to properties file if using file type */ - @ConfigItem - public Optional path; + Optional path(); /** * Client or App Id required if using managed_identity type */ - @ConfigItem - public Optional client; + Optional client(); /** - * Tenant Id required if using oauth2 or device_code type + * Tenant ID required if using oauth2 or device_code type */ - @ConfigItem - public Optional tenant; - - private static final Logger log = Logger.getLogger(AzureFunctionsConfig.class); + Optional tenant(); private static String findValue(Properties props, String key) { if (props.contains(key)) @@ -301,15 +288,15 @@ private static AuthConfiguration fromFile(Optional path) { } } - public AuthConfiguration toAuthConfiguration() { + default AuthConfiguration toAuthConfiguration() { try { - if (this.type.equalsIgnoreCase("file")) { - return fromFile(this.path); + if (this.type().equalsIgnoreCase("file")) { + return fromFile(this.path()); } - final AuthType type = AuthType.parseAuthType(this.type); + final AuthType type = AuthType.parseAuthType(this.type()); final AuthConfiguration authConfiguration = new AuthConfiguration(type); - authConfiguration.setClient(client.orElse(null)); - authConfiguration.setTenant(tenant.orElse(null)); + authConfiguration.setClient(client().orElse(null)); + authConfiguration.setTenant(tenant().orElse(null)); authConfiguration.setEnvironment(AzureEnvironmentUtils.azureEnvironmentToString(AzureEnvironment.AZURE)); return authConfiguration; } catch (InvalidConfigurationException e) { diff --git a/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsDeployCommand.java b/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsDeployCommand.java index aff10a43c92f2..544240480aead 100644 --- a/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsDeployCommand.java +++ b/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsDeployCommand.java @@ -167,22 +167,22 @@ protected void validateParameters(AzureFunctionsConfig config, String appName) t throw new BuildException(INVALID_APP_NAME); } // resource group - if (StringUtils.isBlank(config.resourceGroup)) { + if (StringUtils.isBlank(config.resourceGroup())) { throw new BuildException(EMPTY_RESOURCE_GROUP); } - if (config.resourceGroup.endsWith(".") || !config.resourceGroup.matches(RESOURCE_GROUP_PATTERN)) { + if (config.resourceGroup().endsWith(".") || !config.resourceGroup().matches(RESOURCE_GROUP_PATTERN)) { throw new BuildException(INVALID_RESOURCE_GROUP_NAME); } // asp name & resource group - if (StringUtils.isNotEmpty(config.appServicePlanName) - && !config.appServicePlanName.matches(APP_SERVICE_PLAN_NAME_PATTERN)) { + if (StringUtils.isNotEmpty(config.appServicePlanName()) + && !config.appServicePlanName().matches(APP_SERVICE_PLAN_NAME_PATTERN)) { throw new BuildException(String.format(INVALID_SERVICE_PLAN_NAME, APP_SERVICE_PLAN_NAME_PATTERN)); } - if (config.appServicePlanResourceGroup.isPresent() - && StringUtils.isNotEmpty(config.appServicePlanResourceGroup.orElse(null)) + if (config.appServicePlanResourceGroup().isPresent() + && StringUtils.isNotEmpty(config.appServicePlanResourceGroup().orElse(null)) && - (config.appServicePlanResourceGroup.orElse(null).endsWith(".") - || !config.appServicePlanResourceGroup.orElse(null).matches(RESOURCE_GROUP_PATTERN))) { + (config.appServicePlanResourceGroup().orElse(null).endsWith(".") + || !config.appServicePlanResourceGroup().orElse(null).matches(RESOURCE_GROUP_PATTERN))) { throw new BuildException(INVALID_SERVICE_PLAN_RESOURCE_GROUP_NAME); } // slot name @@ -196,26 +196,26 @@ protected void validateParameters(AzureFunctionsConfig config, String appName) t * */ // region - if (StringUtils.isNotEmpty(config.region) && Region.fromName(config.region).isExpandedValue()) { - log.warn(String.format(EXPANDABLE_REGION_WARNING, config.region)); + if (StringUtils.isNotEmpty(config.region()) && Region.fromName(config.region()).isExpandedValue()) { + log.warn(String.format(EXPANDABLE_REGION_WARNING, config.region())); } // os - if (StringUtils.isNotEmpty(config.runtime.os) && OperatingSystem.fromString(config.runtime.os) == null) { + if (StringUtils.isNotEmpty(config.runtime().os()) && OperatingSystem.fromString(config.runtime().os()) == null) { throw new BuildException(INVALID_OS); } // java version - if (StringUtils.isNotEmpty(config.runtime.javaVersion) - && JavaVersion.fromString(config.runtime.javaVersion).isExpandedValue()) { - log.warn(String.format(EXPANDABLE_JAVA_VERSION_WARNING, config.runtime.javaVersion)); + if (StringUtils.isNotEmpty(config.runtime().javaVersion()) + && JavaVersion.fromString(config.runtime().javaVersion()).isExpandedValue()) { + log.warn(String.format(EXPANDABLE_JAVA_VERSION_WARNING, config.runtime().javaVersion())); } // pricing tier - if (config.pricingTier.isPresent() && StringUtils.isNotEmpty(config.pricingTier.orElse(null)) - && PricingTier.fromString(config.pricingTier.orElse(null)).isExpandedValue()) { - log.warn(String.format(EXPANDABLE_PRICING_TIER_WARNING, config.pricingTier.orElse(null))); + if (config.pricingTier().isPresent() && StringUtils.isNotEmpty(config.pricingTier().orElse(null)) + && PricingTier.fromString(config.pricingTier().orElse(null)).isExpandedValue()) { + log.warn(String.format(EXPANDABLE_PRICING_TIER_WARNING, config.pricingTier().orElse(null))); } // docker image - if (OperatingSystem.fromString(config.runtime.os) == OperatingSystem.DOCKER - && StringUtils.isEmpty(config.runtime.image.orElse(null))) { + if (OperatingSystem.fromString(config.runtime().os()) == OperatingSystem.DOCKER + && StringUtils.isEmpty(config.runtime().image().orElse(null))) { throw new BuildException(EMPTY_IMAGE_NAME); } } @@ -226,9 +226,9 @@ protected void validateParameters(AzureFunctionsConfig config, String appName) t protected AzureAppService initAzureAppServiceClient(AzureFunctionsConfig config) throws BuildException { if (appServiceClient == null) { - final Account account = loginAzure(config.auth); + final Account account = loginAzure(config.auth()); final List subscriptions = account.getSubscriptions(); - final String targetSubscriptionId = getTargetSubscriptionId(config.subscriptionId.orElse(null), subscriptions, + final String targetSubscriptionId = getTargetSubscriptionId(config.subscriptionId().orElse(null), subscriptions, account.getSelectedSubscriptions()); checkSubscription(subscriptions, targetSubscriptionId); com.microsoft.azure.toolkit.lib.Azure.az(AzureAccount.class).account() diff --git a/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsProcessor.java b/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsProcessor.java index 04ef96151d917..438d5a70fe8f6 100644 --- a/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsProcessor.java +++ b/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsProcessor.java @@ -71,7 +71,7 @@ FeatureBuildItem feature() { @BuildStep AzureFunctionsAppNameBuildItem appName(OutputTargetBuildItem output, AzureFunctionsConfig functionsConfig) { - String appName = functionsConfig.appName.orElse(output.getBaseName()); + String appName = functionsConfig.appName().orElse(output.getBaseName()); return new AzureFunctionsAppNameBuildItem(appName); } diff --git a/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsRunCommand.java b/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsRunCommand.java index 7797fd7b49901..890e08a6f7ec5 100644 --- a/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsRunCommand.java +++ b/extensions/azure-functions/deployment/src/main/java/io/quarkus/azure/functions/deployment/AzureFunctionsRunCommand.java @@ -77,15 +77,15 @@ protected String getCheckRuntimeCommand() { protected String getStartFunctionHostCommand(AzureFunctionsConfig azureConfig) { int funcPort; - if (azureConfig.funcPort.isPresent()) { - funcPort = azureConfig.funcPort.get(); + if (azureConfig.funcPort().isPresent()) { + funcPort = azureConfig.funcPort().get(); } else { Config config = ConfigProviderResolver.instance().getConfig(); funcPort = config.getValue("quarkus.http.test-port", OptionalInt.class).orElse(8081); } final String enableDebug = System.getProperty("enableDebug"); if (StringUtils.isNotEmpty(enableDebug) && enableDebug.equalsIgnoreCase("true")) { - return String.format(FUNC_HOST_START_WITH_DEBUG_CMD, funcPort, azureConfig.localDebugConfig); + return String.format(FUNC_HOST_START_WITH_DEBUG_CMD, funcPort, azureConfig.localDebugConfig()); } else { return String.format(FUNC_HOST_START_CMD, funcPort); } diff --git a/extensions/azure-functions/runtime/pom.xml b/extensions/azure-functions/runtime/pom.xml index 5440764ba4778..0901929c5192b 100644 --- a/extensions/azure-functions/runtime/pom.xml +++ b/extensions/azure-functions/runtime/pom.xml @@ -53,9 +53,6 @@ ${project.version} - - -AlegacyConfigRoot=true - From 325ccfcc4bf4db8f9ae9ab5ebda4662b634a138f Mon Sep 17 00:00:00 2001 From: Michael Edgar Date: Sun, 8 Dec 2024 21:14:20 -0500 Subject: [PATCH 059/207] Bump smallrye-open-api.version from 4.0.4 to 4.0.5 Signed-off-by: Michael Edgar --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index a4a4d85c2f2df..e697541501d52 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -50,7 +50,7 @@ 3.10.2 4.1.0 4.0.0 - 4.0.4 + 4.0.5 2.11.0 6.7.0 4.6.1 From 9d3d9001ef1ac120c22456679620678f370a268a Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Mon, 9 Dec 2024 09:55:24 -0300 Subject: [PATCH 060/207] Fix code indentation When creating a new Quarkiverse extension, the build fails because these generated files are not indented properly --- .../test/{class-name-base}DevModeTest.tpl.qute.java | 2 +- .../{package-name.dir}/test/{class-name-base}Test.tpl.qute.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/devmode-test/java/deployment/src/test/java/{package-name.dir}/test/{class-name-base}DevModeTest.tpl.qute.java b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/devmode-test/java/deployment/src/test/java/{package-name.dir}/test/{class-name-base}DevModeTest.tpl.qute.java index 8ebe59bdc97a8..e328f4ce8a569 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/devmode-test/java/deployment/src/test/java/{package-name.dir}/test/{class-name-base}DevModeTest.tpl.qute.java +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/devmode-test/java/deployment/src/test/java/{package-name.dir}/test/{class-name-base}DevModeTest.tpl.qute.java @@ -13,7 +13,7 @@ public class {class-name-base}DevModeTest { // Start hot reload (DevMode) test with your extension loaded @RegisterExtension static final QuarkusDevModeTest devModeTest = new QuarkusDevModeTest() - .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)); + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)); @Test public void writeYourOwnDevModeTest() { diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/unit-test/java/deployment/src/test/java/{package-name.dir}/test/{class-name-base}Test.tpl.qute.java b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/unit-test/java/deployment/src/test/java/{package-name.dir}/test/{class-name-base}Test.tpl.qute.java index d6bea80075268..4be355825e191 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/unit-test/java/deployment/src/test/java/{package-name.dir}/test/{class-name-base}Test.tpl.qute.java +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/unit-test/java/deployment/src/test/java/{package-name.dir}/test/{class-name-base}Test.tpl.qute.java @@ -13,7 +13,7 @@ public class {class-name-base}Test { // Start unit test with your extension loaded @RegisterExtension static final QuarkusUnitTest unitTest = new QuarkusUnitTest() - .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)); + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)); @Test public void writeYourOwnUnitTest() { From c09ade9ede0decf314b0bfa0c1e57bc4569dac54 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Mon, 9 Dec 2024 15:15:10 +0200 Subject: [PATCH 061/207] Update documentation for handling proxies in native-mode * Merge "Managing Proxy Classes" sections. * Remove outdated mention to `-H:DynamicProxyConfigurationResources` Quarkus no longer uses `-H:DynamicProxyConfigurationResources` for dynamic proxies. Instead it generates the corresponding necessary metadata in `META-INF/native-image/proxy-config.json` --- .../writing-native-applications-tips.adoc | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/docs/src/main/asciidoc/writing-native-applications-tips.adoc b/docs/src/main/asciidoc/writing-native-applications-tips.adoc index b7ca08afcc0c3..e4e19d35f0d73 100644 --- a/docs/src/main/asciidoc/writing-native-applications-tips.adoc +++ b/docs/src/main/asciidoc/writing-native-applications-tips.adoc @@ -320,21 +320,6 @@ and in the case of using the Maven configuration instead of `application.propert ---- ==== -=== Managing Proxy Classes - -While writing native application you'll need to define proxy classes at image build time by specifying the list of interfaces that they implement. - -In such a situation, the error you might encounter is: - -[source] ----- -com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface org.apache.http.conn.HttpClientConnectionManager, interface org.apache.http.pool.ConnPoolControl, interface com.amazonaws.http.conn.Wrapped] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles= and -H:DynamicProxyConfigurationResources= options. ----- - -Solving this issue requires creating a `proxy-config.json` file under the `src/main/resources/META-INF/native-image//` folder. -This way the configuration will be automatically parsed by the native build, without additional configuration. -For more information about the format of this file, see the link:https://www.graalvm.org/{graalvm-docs-version}/reference-manual/native-image/metadata/#dynamic-proxy-metadata-in-json[Dynamic Proxy Metadata in JSON] documentation. - [[modularity-benefits]] === Modularity Benefits @@ -635,7 +620,16 @@ For more information about the `--initialize-at-run-time` option, see the link:h === Managing Proxy Classes -Very similarly, Quarkus allows extensions authors to register a `NativeImageProxyDefinitionBuildItem`. An example of doing so is: +While writing native application you'll need to define proxy classes at image build time by specifying the list of interfaces that they implement. + +In such a situation, the error you might encounter is: + +[source] +---- +com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface org.apache.http.conn.HttpClientConnectionManager, interface org.apache.http.pool.ConnPoolControl, interface com.amazonaws.http.conn.Wrapped] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles= and -H:DynamicProxyConfigurationResources= options. +---- + +Quarkus allows extensions authors to register a `NativeImageProxyDefinitionBuildItem`. An example of doing so is: [source,java] ---- @@ -650,11 +644,15 @@ public class S3Processor { } ---- -Using such a construct means that a `-H:DynamicProxyConfigurationResources` option will automatically be added to the `native-image` command line. +This will allow Quarkus to generate the necessary configuration for handling the proxy class. +Alternatively, you may create a `proxy-config.json` file under the `src/main/resources/META-INF/native-image//` folder. +For more information about the format of this file, see the https://www.graalvm.org/{graalvm-docs-version}/reference-manual/native-image/metadata/#dynamic-proxy-metadata-in-json[Dynamic Proxy Metadata in JSON] documentation. [NOTE] ==== -For more information about Proxy Classes, see the link:https://www.graalvm.org/{graalvm-docs-version}/reference-manual/native-image/guides/configure-dynamic-proxies/[GraalVM Configure Dynamic Proxies Manually] guide. +In both cases the configuration will be automatically parsed by the native build, without additional configuration. + +For more information about using Proxy Classes in native executables, see https://www.graalvm.org/jdk21/reference-manual/native-image/dynamic-features/DynamicProxy/[Dynamic Proxy in Native Image] and https://www.graalvm.org/{graalvm-docs-version}/reference-manual/native-image/guides/configure-dynamic-proxies/[GraalVM Configure Dynamic Proxies Manually]. ==== === Logging with Native Image From da40415df864d56dd05c80c76b8ed27b8f1d9d02 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 9 Dec 2024 15:52:18 +0100 Subject: [PATCH 062/207] Properly substitute {quarkus-version} in native-reference.adoc --- docs/src/main/asciidoc/native-reference.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/main/asciidoc/native-reference.adoc b/docs/src/main/asciidoc/native-reference.adoc index f4e6e491bf800..a9e8baa63417d 100644 --- a/docs/src/main/asciidoc/native-reference.adoc +++ b/docs/src/main/asciidoc/native-reference.adoc @@ -598,7 +598,7 @@ invoke Maven's `verify` goal with `-DskipITs=false -Dquarkus.test.integration-te generate the native image configuration. For example: -[source,bash] +[source,bash,subs=attributes+] ---- $ ./mvnw verify -DskipITs=false -Dquarkus.test.integration-test-profile=test-with-native-agent ... @@ -660,7 +660,7 @@ This can be useful to verify that the native integration tests work as expected, assuming that the JVM unit tests have generated the correct native image configuration. The typical workflow here would be to first run the integration tests with the native image agent as shown in the previous section: -[source,bash] +[source,bash,subs=attributes+] ---- $ ./mvnw verify -DskipITs=false -Dquarkus.test.integration-test-profile=test-with-native-agent ... @@ -671,7 +671,7 @@ $ ./mvnw verify -DskipITs=false -Dquarkus.test.integration-test-profile=test-wit And then request a native build passing in the configuration apply flag. A message during the native build process will indicate that the native image agent generated configuration files are being applied: -[source,bash] +[source,bash,subs=attributes+] ---- $ ./mvnw verify -Dnative -Dquarkus.native.agent-configuration-apply ... @@ -702,7 +702,7 @@ and confirm that the class and/or package making the call or being accessed is n If the missing entry is related to some resource, you should inspect the Quarkus build debug output and verify which resource patterns are being discarded, e.g. -[source,bash] +[source,bash,subs=attributes+] ---- $ ./mvnw -X verify -DskipITs=false -Dquarkus.test.integration-test-profile=test-with-native-agent ... From ebd69b0a3ae4e48d5b68fbb92a0fa3530dbd511c Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 9 Dec 2024 16:03:02 +0100 Subject: [PATCH 063/207] Improve Dev Services network output in dev mode when typing c Just use proper spacing instead of something weird :). --- .../io/quarkus/deployment/dev/devservices/ContainerInfo.java | 2 +- .../quarkus/devservices/deployment/DevServicesProcessor.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/ContainerInfo.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/ContainerInfo.java index 9227f0b1a06e1..12594375ee6f0 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/ContainerInfo.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/devservices/ContainerInfo.java @@ -100,7 +100,7 @@ public String formatPorts() { return Arrays.stream(getExposedPorts()) .filter(p -> p.getPublicPort() != null) .map(c -> c.getIp() + ":" + c.getPublicPort() + "->" + c.getPrivatePort() + "/" + c.getType()) - .collect(Collectors.joining(" ,")); + .collect(Collectors.joining(", ")); } public static class ContainerPort { diff --git a/extensions/devservices/deployment/src/main/java/io/quarkus/devservices/deployment/DevServicesProcessor.java b/extensions/devservices/deployment/src/main/java/io/quarkus/devservices/deployment/DevServicesProcessor.java index da9de6071daba..48b2e42fbd829 100644 --- a/extensions/devservices/deployment/src/main/java/io/quarkus/devservices/deployment/DevServicesProcessor.java +++ b/extensions/devservices/deployment/src/main/java/io/quarkus/devservices/deployment/DevServicesProcessor.java @@ -213,10 +213,10 @@ private static String[] getNetworks(Container container) { return networks.entrySet().stream() .map(e -> { List aliases = e.getValue().getAliases(); - if (aliases == null) { + if (aliases == null || aliases.isEmpty()) { return e.getKey(); } - return e.getKey() + " (" + String.join(",", aliases) + ")"; + return e.getKey() + " (" + String.join(", ", aliases) + ")"; }) .toArray(String[]::new); } From ada5bf9db2c84874bd502d55feb4cb637379c916 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 9 Dec 2024 16:36:38 +0100 Subject: [PATCH 064/207] Hint about -e/--errors when CLI errors out Fixes #35953 --- .../main/java/io/quarkus/cli/common/OutputOptionMixin.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/devtools/cli/src/main/java/io/quarkus/cli/common/OutputOptionMixin.java b/devtools/cli/src/main/java/io/quarkus/cli/common/OutputOptionMixin.java index 50bb36be6c48f..1da00c356683b 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/common/OutputOptionMixin.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/common/OutputOptionMixin.java @@ -162,6 +162,11 @@ public int handleCommandException(Exception ex, String message) { CommandLine.UnmatchedArgumentException.printSuggestions((CommandLine.ParameterException) ex, out()); } error(message); + + if (!isShowErrors()) { + info("\nAdd the -e/--errors option to get more information about the error. Add the --verbose option to get even more details."); + } + return cmd.getExitCodeExceptionMapper() != null ? cmd.getExitCodeExceptionMapper().getExitCode(ex) : mixee.exitCodeOnInvalidInput(); } From 8f44d0d8d2caa733ca6f191974d2bd9ac6024407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Mon, 9 Dec 2024 17:53:11 +0100 Subject: [PATCH 065/207] fix(security): call @PermissionChecker methods with final augmented identity --- ...entityAugmentorsPermissionCheckerTest.java | 127 ++++++++++++++++++ .../QuarkusIdentityProviderManagerImpl.java | 11 +- ...usPermissionSecurityIdentityAugmentor.java | 6 + .../security/test/utils/IdentityMock.java | 46 ++++--- 4 files changed, 169 insertions(+), 21 deletions(-) create mode 100644 extensions/security/deployment/src/test/java/io/quarkus/security/test/permissionsallowed/checker/SecurityIdentityAugmentorsPermissionCheckerTest.java diff --git a/extensions/security/deployment/src/test/java/io/quarkus/security/test/permissionsallowed/checker/SecurityIdentityAugmentorsPermissionCheckerTest.java b/extensions/security/deployment/src/test/java/io/quarkus/security/test/permissionsallowed/checker/SecurityIdentityAugmentorsPermissionCheckerTest.java new file mode 100644 index 0000000000000..4fdba98068504 --- /dev/null +++ b/extensions/security/deployment/src/test/java/io/quarkus/security/test/permissionsallowed/checker/SecurityIdentityAugmentorsPermissionCheckerTest.java @@ -0,0 +1,127 @@ +package io.quarkus.security.test.permissionsallowed.checker; + +import static io.quarkus.security.test.utils.IdentityMock.ADMIN; +import static io.quarkus.security.test.utils.IdentityMock.USER; +import static io.quarkus.security.test.utils.SecurityTestUtils.assertFailureFor; +import static io.quarkus.security.test.utils.SecurityTestUtils.assertSuccess; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.logging.Log; +import io.quarkus.security.ForbiddenException; +import io.quarkus.security.PermissionChecker; +import io.quarkus.security.PermissionsAllowed; +import io.quarkus.security.identity.AuthenticationRequestContext; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.identity.SecurityIdentityAugmentor; +import io.quarkus.security.runtime.QuarkusSecurityIdentity; +import io.quarkus.security.test.utils.AuthData; +import io.quarkus.security.test.utils.IdentityMock; +import io.quarkus.security.test.utils.SecurityTestUtils; +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.mutiny.Uni; + +public class SecurityIdentityAugmentorsPermissionCheckerTest { + + private static final AuthData USER_WITH_AUGMENTORS = new AuthData(USER, true); + private static final AuthData ADMIN_WITH_AUGMENTORS = new AuthData(ADMIN, true); + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar.addClasses(IdentityMock.class, AuthData.class, SecurityTestUtils.class)); + + @Inject + SecuredBean bean; + + /** + * Tests that {@link SecurityIdentity} passed to the {@link PermissionChecker} methods is augmented by all the + * augmentors (because that's the last operation we do on the identity, then it's de facto final). + */ + @Test + public void testPermissionCheckerUsesAugmentedIdentity() { + assertSuccess(bean::securedMethod, "secured", ADMIN_WITH_AUGMENTORS); + assertFailureFor(bean::securedMethod, ForbiddenException.class, USER_WITH_AUGMENTORS); + } + + @ApplicationScoped + public static class SecuredBean { + + @PermissionsAllowed("canCallSecuredMethod") + String securedMethod() { + return "secured"; + } + + @PermissionChecker("canCallSecuredMethod") + boolean canCallSecuredMethod(SecurityIdentity identity) { + if (!identity.hasRole("lowest-priority-augmentor")) { + Log.error("Role granted by the augmentor with the smallest priority is missing"); + return false; + } + if (!identity.hasRole("default-priority-augmentor")) { + Log.error("Role granted by the augmentor with a default priority is missing"); + return false; + } + if (!identity.hasRole("highest-priority-augmentor")) { + Log.error("Role granted by the augmentor with the highest priority is missing"); + return false; + } + return "admin".equals(identity.getPrincipal().getName()); + } + } + + @ApplicationScoped + public static class AugmentorWithLowestPriority implements SecurityIdentityAugmentor { + + @Override + public int priority() { + return Integer.MIN_VALUE; + } + + @Override + public Uni augment(SecurityIdentity securityIdentity, + AuthenticationRequestContext authenticationRequestContext) { + return Uni.createFrom().item( + QuarkusSecurityIdentity + .builder(securityIdentity) + .addRole("lowest-priority-augmentor") + .build()); + } + } + + @ApplicationScoped + public static class AugmentorWithDefaultPriority implements SecurityIdentityAugmentor { + + @Override + public Uni augment(SecurityIdentity securityIdentity, + AuthenticationRequestContext authenticationRequestContext) { + return Uni.createFrom().item( + QuarkusSecurityIdentity + .builder(securityIdentity) + .addRole("default-priority-augmentor") + .build()); + } + } + + @ApplicationScoped + public static class AugmentorWithHighestPriority implements SecurityIdentityAugmentor { + + @Override + public int priority() { + return Integer.MAX_VALUE; + } + + @Override + public Uni augment(SecurityIdentity securityIdentity, + AuthenticationRequestContext authenticationRequestContext) { + return Uni.createFrom().item( + QuarkusSecurityIdentity + .builder(securityIdentity) + .addRole("highest-priority-augmentor") + .build()); + } + } +} diff --git a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImpl.java b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImpl.java index 6749d79d9c230..783e09e325fd5 100644 --- a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImpl.java +++ b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImpl.java @@ -182,6 +182,7 @@ public static class Builder { private final Map, List>> providers = new HashMap<>(); private final List augmentors = new ArrayList<>(); + private QuarkusPermissionSecurityIdentityAugmentor quarkusPermissionAugmentor = null; private BlockingSecurityExecutor blockingExecutor; private boolean built = false; @@ -206,7 +207,11 @@ public Builder addProvider(IdentityProvider pro * @return this builder */ public Builder addSecurityIdentityAugmentor(SecurityIdentityAugmentor augmentor) { - augmentors.add(augmentor); + if (augmentor instanceof QuarkusPermissionSecurityIdentityAugmentor quarkusPermissionAugmentor) { + this.quarkusPermissionAugmentor = quarkusPermissionAugmentor; + } else { + augmentors.add(augmentor); + } return this; } @@ -254,6 +259,10 @@ public int compare(SecurityIdentityAugmentor o1, SecurityIdentityAugmentor o2) { return Integer.compare(o2.priority(), o1.priority()); } }); + if (quarkusPermissionAugmentor != null) { + // @PermissionChecker methods must always run with the final SecurityIdentity + augmentors.add(quarkusPermissionAugmentor); + } return new QuarkusIdentityProviderManagerImpl(this); } } diff --git a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusPermissionSecurityIdentityAugmentor.java b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusPermissionSecurityIdentityAugmentor.java index 7ca713dc4c4bd..6557b84a3b1fc 100644 --- a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusPermissionSecurityIdentityAugmentor.java +++ b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusPermissionSecurityIdentityAugmentor.java @@ -61,4 +61,10 @@ public Uni apply(Permission requiredpermission) { }) .build()); } + + @Override + public int priority() { + // we do not rely on this value and always add this augmentor as the last one manually + return Integer.MAX_VALUE; + } } diff --git a/extensions/security/test-utils/src/main/java/io/quarkus/security/test/utils/IdentityMock.java b/extensions/security/test-utils/src/main/java/io/quarkus/security/test/utils/IdentityMock.java index 78240d4fd25f8..5e2ee21aaa923 100644 --- a/extensions/security/test-utils/src/main/java/io/quarkus/security/test/utils/IdentityMock.java +++ b/extensions/security/test-utils/src/main/java/io/quarkus/security/test/utils/IdentityMock.java @@ -6,21 +6,19 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.Supplier; import jakarta.annotation.Priority; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Alternative; -import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; -import io.quarkus.arc.Arc; import io.quarkus.security.credential.Credential; import io.quarkus.security.identity.AuthenticationRequestContext; +import io.quarkus.security.identity.IdentityProvider; +import io.quarkus.security.identity.IdentityProviderManager; import io.quarkus.security.identity.SecurityIdentity; -import io.quarkus.security.identity.SecurityIdentityAugmentor; +import io.quarkus.security.identity.request.BaseAuthenticationRequest; import io.quarkus.security.runtime.SecurityIdentityAssociation; -import io.quarkus.security.spi.runtime.BlockingSecurityExecutor; import io.smallrye.mutiny.Uni; /** @@ -107,16 +105,17 @@ public Uni checkPermission(Permission permission) { @ApplicationScoped @Priority(1) public static class IdentityAssociationMock extends SecurityIdentityAssociation { + @Inject IdentityMock identity; @Inject - Instance augmentors; + IdentityProviderManager identityProviderManager; @Override public Uni getDeferredIdentity() { if (applyAugmentors) { - return augmentIdentity(identity); + return identityProviderManager.authenticate(new IdentityMockAuthenticationRequest()); } return Uni.createFrom().item(identity); } @@ -124,25 +123,32 @@ public Uni getDeferredIdentity() { @Override public SecurityIdentity getIdentity() { if (applyAugmentors) { - return augmentIdentity(identity).await().indefinitely(); + return getDeferredIdentity().await().indefinitely(); } return identity; } - private Uni augmentIdentity(SecurityIdentity identity) { - var authReqContexts = new TestAuthenticationRequestContext(); - Uni result = Uni.createFrom().item(identity); - for (SecurityIdentityAugmentor augmentor : augmentors) { - result = result.flatMap(si -> augmentor.augment(si, authReqContexts, Map.of())); - } - return result; + } + + public static final class IdentityMockAuthenticationRequest extends BaseAuthenticationRequest { + + } + + @ApplicationScoped + public static final class IdentityMockProvider implements IdentityProvider { + + @Inject + IdentityMock identity; + + @Override + public Class getRequestType() { + return IdentityMockAuthenticationRequest.class; } - private static final class TestAuthenticationRequestContext implements AuthenticationRequestContext { - @Override - public Uni runBlocking(Supplier function) { - return Arc.container().instance(BlockingSecurityExecutor.class).get().executeBlocking(function); - } + @Override + public Uni authenticate(IdentityMockAuthenticationRequest identityMockAuthenticationRequest, + AuthenticationRequestContext authenticationRequestContext) { + return Uni.createFrom().item(identity); } } } From 776bbf73d0ddeefc9ea32fb973b80f494e1cd559 Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Mon, 9 Dec 2024 14:20:17 -0300 Subject: [PATCH 066/207] Convert websocket to use @CofigMapping --- extensions/websockets/client/deployment/pom.xml | 3 --- .../deployment/WebsocketClientProcessor.java | 4 ++-- .../client/deployment/WebsocketConfig.java | 14 ++++++++------ extensions/websockets/client/runtime/pom.xml | 3 --- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/extensions/websockets/client/deployment/pom.xml b/extensions/websockets/client/deployment/pom.xml index 165456e8d7476..9b61a1c37c51c 100644 --- a/extensions/websockets/client/deployment/pom.xml +++ b/extensions/websockets/client/deployment/pom.xml @@ -52,9 +52,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/websockets/client/deployment/src/main/java/io/quarkus/websockets/client/deployment/WebsocketClientProcessor.java b/extensions/websockets/client/deployment/src/main/java/io/quarkus/websockets/client/deployment/WebsocketClientProcessor.java index 7d1d2544dca8d..98d8a1e56f3a4 100644 --- a/extensions/websockets/client/deployment/src/main/java/io/quarkus/websockets/client/deployment/WebsocketClientProcessor.java +++ b/extensions/websockets/client/deployment/src/main/java/io/quarkus/websockets/client/deployment/WebsocketClientProcessor.java @@ -131,8 +131,8 @@ public ServerWebSocketContainerBuildItem deploy(final CombinedIndexBuildItem ind .build()); RuntimeValue deploymentInfo = recorder.createDeploymentInfo(annotated, endpoints, config, - websocketConfig.maxFrameSize, - websocketConfig.dispatchToWorker); + websocketConfig.maxFrameSize(), + websocketConfig.dispatchToWorker()); infoBuildItemBuildProducer.produce(new WebSocketDeploymentInfoBuildItem(deploymentInfo)); RuntimeValue serverContainer = recorder.createServerContainer( beanContainerBuildItem.getValue(), diff --git a/extensions/websockets/client/deployment/src/main/java/io/quarkus/websockets/client/deployment/WebsocketConfig.java b/extensions/websockets/client/deployment/src/main/java/io/quarkus/websockets/client/deployment/WebsocketConfig.java index 51a5000d50698..b6ce071d63f82 100644 --- a/extensions/websockets/client/deployment/src/main/java/io/quarkus/websockets/client/deployment/WebsocketConfig.java +++ b/extensions/websockets/client/deployment/src/main/java/io/quarkus/websockets/client/deployment/WebsocketConfig.java @@ -1,24 +1,26 @@ package io.quarkus.websockets.client.deployment; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; @ConfigRoot(phase = ConfigPhase.BUILD_TIME) -public class WebsocketConfig { +@ConfigMapping(prefix = "quarkus.websocket") +public interface WebsocketConfig { /** * The maximum amount of data that can be sent in a single frame. * * Messages larger than this must be broken up into continuation frames. */ - @ConfigItem(defaultValue = "65536") - public int maxFrameSize; + @WithDefault("65536") + int maxFrameSize(); /** * If the websocket methods should be run in a worker thread. This allows them to run * blocking tasks, however it will not be as fast as running directly in the IO thread. */ - @ConfigItem(defaultValue = "false") - public boolean dispatchToWorker; + @WithDefault("false") + boolean dispatchToWorker(); } diff --git a/extensions/websockets/client/runtime/pom.xml b/extensions/websockets/client/runtime/pom.xml index 9286ecd0313fa..03b9e72318f5d 100644 --- a/extensions/websockets/client/runtime/pom.xml +++ b/extensions/websockets/client/runtime/pom.xml @@ -71,9 +71,6 @@ ${project.version} - - -AlegacyConfigRoot=true - From f3b9bc2326357ba5924c0999bc873e357a0df623 Mon Sep 17 00:00:00 2001 From: Christian Pieczewski Date: Mon, 9 Dec 2024 21:54:07 +0100 Subject: [PATCH 067/207] Correct dependency notation in documentation for observability-devservices-lgtm.adoc --- docs/src/main/asciidoc/observability-devservices-lgtm.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/observability-devservices-lgtm.adoc b/docs/src/main/asciidoc/observability-devservices-lgtm.adoc index 90b65608a3dc5..5d207a4791ecc 100644 --- a/docs/src/main/asciidoc/observability-devservices-lgtm.adoc +++ b/docs/src/main/asciidoc/observability-devservices-lgtm.adoc @@ -30,7 +30,7 @@ Add the Quarkus Grafana OTel LGTM sink (where data goes) extension to your build [source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] .build.gradle ---- -implementation("quarkus-observability-devservices-lgtm") +implementation("io.quarkus:quarkus-observability-devservices-lgtm") ---- === Metrics From 890c787ea85ab68fa4330476025a7c83482078d0 Mon Sep 17 00:00:00 2001 From: Thomas Canava Date: Thu, 5 Dec 2024 21:20:19 +0100 Subject: [PATCH 068/207] docs: Add doc for @RunOnVirtualThread on class --- .../src/main/asciidoc/websockets-next-reference.adoc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/src/main/asciidoc/websockets-next-reference.adoc b/docs/src/main/asciidoc/websockets-next-reference.adoc index 1ff21130b0d13..899010757a947 100644 --- a/docs/src/main/asciidoc/websockets-next-reference.adoc +++ b/docs/src/main/asciidoc/websockets-next-reference.adoc @@ -240,15 +240,19 @@ WebSocket Next supports _blocking_ and _non-blocking_ logic, akin to Quarkus RES Here are the rules governing execution: * Methods annotated with `@RunOnVirtualThread`, `@Blocking` or `@Transactional` are considered blocking. +* Methods declared in a class annotated with `@RunOnVirtualThread` are considered blocking. * Methods annotated with `@NonBlocking` are considered non-blocking. -* Methods declared on a class annotated with `@Transactional` are considered blocking unless annotated with `@NonBlocking`. +* Methods declared in a class annotated with `@Transactional` are considered blocking unless annotated with `@NonBlocking`. * If the method does not declare any of the annotations listed above the execution model is derived from the return type: ** Methods returning `Uni` and `Multi` are considered non-blocking. ** Methods returning `void` or any other type are considered blocking. -* Kotlin `suspend` functions are always considered non-blocking and may not be annotated with `@Blocking`, `@NonBlocking` or `@RunOnVirtualThread`. +* Kotlin `suspend` functions are always considered non-blocking and may not be annotated with `@Blocking`, `@NonBlocking` + or `@RunOnVirtualThread` and may not be in a class annotated with `@RunOnVirtualThread`. * Non-blocking methods must execute on the connection's event loop thread. -* Blocking methods must execute on a worker thread unless annotated with `@RunOnVirtualThread`. -* Methods annotated with `@RunOnVirtualThread` must execute on a virtual thread, each invocation spawns a new virtual thread. +* Blocking methods must execute on a worker thread unless annotated with `@RunOnVirtualThread` or in a class annotated + with `@RunOnVirtualThread`. +* Methods annotated with `@RunOnVirtualThread` or declared in class annotated with `@RunOnVirtualThread` must execute on + a virtual thread, each invocation spawns a new virtual thread. ==== Method parameters From 213db8ade14346bf9e4fa0bd9daeea46a4261cea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 22:25:04 +0000 Subject: [PATCH 069/207] Bump org.apache.maven.plugins:maven-invoker-plugin from 3.8.1 to 3.9.0 Bumps [org.apache.maven.plugins:maven-invoker-plugin](https://github.com/apache/maven-invoker-plugin) from 3.8.1 to 3.9.0. - [Release notes](https://github.com/apache/maven-invoker-plugin/releases) - [Commits](https://github.com/apache/maven-invoker-plugin/compare/maven-invoker-plugin-3.8.1...maven-invoker-plugin-3.9.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-invoker-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build-parent/pom.xml | 2 +- independent-projects/enforcer-rules/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 90f8d96630628..62dea85311132 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -116,7 +116,7 @@ 2.0.0 0.45.1 - 3.8.1 + 3.9.0 0.14.7 diff --git a/independent-projects/enforcer-rules/pom.xml b/independent-projects/enforcer-rules/pom.xml index 488f1e42a002c..ef71299114d21 100644 --- a/independent-projects/enforcer-rules/pom.xml +++ b/independent-projects/enforcer-rules/pom.xml @@ -34,7 +34,7 @@ 3.0.0-M3 - 3.8.1 + 3.9.0 3.9.9 1.20.4 3.4.0 From 6ef81f93985de99924c9b3d58b836a6fcb5b2aa6 Mon Sep 17 00:00:00 2001 From: Holly Cummins Date: Mon, 9 Dec 2024 20:05:41 +1000 Subject: [PATCH 071/207] Add tests for simple @QuarkusMain case I also slightly clarified the wording on the docs. Co-Authored-By: Ladislav Thon --- .../main/asciidoc/command-mode-reference.adoc | 2 +- .../it/testsupport/commandmode/CdiBean.java | 5 ++ .../testsupport/commandmode/DefaultBean.java | 11 ++++ .../it/testsupport/commandmode/MainApp.java | 23 ++++++++ ...uarkusMainTestWithTestProfileTestCase.java | 52 +++++++++++++++++++ 5 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/CdiBean.java create mode 100644 integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/DefaultBean.java create mode 100644 integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/MainApp.java create mode 100644 integration-tests/test-extension/tests/src/test/java/io/quarkus/it/testsupport/commandmode/QuarkusMainTestWithTestProfileTestCase.java diff --git a/docs/src/main/asciidoc/command-mode-reference.adoc b/docs/src/main/asciidoc/command-mode-reference.adoc index 14f8f2f1831d0..074fe72adc894 100644 --- a/docs/src/main/asciidoc/command-mode-reference.adoc +++ b/docs/src/main/asciidoc/command-mode-reference.adoc @@ -255,7 +255,7 @@ Consequently, mocking CDI beans with `QuarkusMock` or `@InjectMock` is not suppo It is possible to mock CDI beans by leveraging xref:getting-started-testing.adoc#testing_different_profiles[test profiles] though. -For instance, in the following test, the singleton `CdiBean1` will be mocked by `MockedCdiBean1`: +For instance, in the following test, the launched application would receive a mocked singleton `CdiBean1`. The implementation `MockedCdiBean1` is provided by the test: [source,java] ---- diff --git a/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/CdiBean.java b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/CdiBean.java new file mode 100644 index 0000000000000..610105ab90ff8 --- /dev/null +++ b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/CdiBean.java @@ -0,0 +1,5 @@ +package io.quarkus.it.testsupport.commandmode; + +public interface CdiBean { + String myMethod(); +} \ No newline at end of file diff --git a/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/DefaultBean.java b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/DefaultBean.java new file mode 100644 index 0000000000000..0ffdc6de16578 --- /dev/null +++ b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/DefaultBean.java @@ -0,0 +1,11 @@ +package io.quarkus.it.testsupport.commandmode; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class DefaultBean implements CdiBean { + @Override + public String myMethod() { + return "default bean"; + } +} diff --git a/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/MainApp.java b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/MainApp.java new file mode 100644 index 0000000000000..4557b5c5b033d --- /dev/null +++ b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/testsupport/commandmode/MainApp.java @@ -0,0 +1,23 @@ +package io.quarkus.it.testsupport.commandmode; + +import jakarta.inject.Inject; + +import io.quarkus.runtime.QuarkusApplication; +import io.quarkus.runtime.annotations.QuarkusMain; + +/* + * Because this app co-exists in a module with a QuarkusIntegrationTest, it needs to not be on the default path. + * Otherwise, this application is executed by the QuarkusIntegrationTest and exits early, causing test failures elsewhere. + */ +@QuarkusMain(name = "test") +public class MainApp implements QuarkusApplication { + + @Inject + CdiBean myBean; + + @Override + public int run(String... args) throws Exception { + System.out.println("The bean is " + myBean.myMethod()); + return 0; + } +} \ No newline at end of file diff --git a/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/testsupport/commandmode/QuarkusMainTestWithTestProfileTestCase.java b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/testsupport/commandmode/QuarkusMainTestWithTestProfileTestCase.java new file mode 100644 index 0000000000000..1e69dc60e5012 --- /dev/null +++ b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/testsupport/commandmode/QuarkusMainTestWithTestProfileTestCase.java @@ -0,0 +1,52 @@ +package io.quarkus.it.testsupport.commandmode; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; +import java.util.Set; + +import jakarta.enterprise.inject.Alternative; +import jakarta.inject.Singleton; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTestProfile; +import io.quarkus.test.junit.TestProfile; +import io.quarkus.test.junit.main.Launch; +import io.quarkus.test.junit.main.LaunchResult; +import io.quarkus.test.junit.main.QuarkusMainTest; + +@QuarkusMainTest +@TestProfile(QuarkusMainTestWithTestProfileTestCase.MyTestProfile.class) +public class QuarkusMainTestWithTestProfileTestCase { + + @Test + @Launch(value = {}) + public void testLaunchCommand(LaunchResult result) { + assertThat(result.getOutput()) + .contains("The bean is mocked value"); + } + + public static class MyTestProfile implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Map.of("quarkus.package.main-class", "test"); + } + + @Override + public Set> getEnabledAlternatives() { + return Set.of(MockedCdiBean.class); + } + } + + @Alternative + @Singleton + public static class MockedCdiBean implements CdiBean { + + @Override + public String myMethod() { + return "mocked value"; + } + } +} \ No newline at end of file From 090ff31228a9c7bb071f6d452b140492d40b196c Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 10 Dec 2024 10:08:58 +0200 Subject: [PATCH 072/207] Document @Url usage in REST Client Co-authored-by: Guillaume Smet --- docs/src/main/asciidoc/rest-client.adoc | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/src/main/asciidoc/rest-client.adoc b/docs/src/main/asciidoc/rest-client.adoc index 71900e4abfd9d..3c2c2a2be1d30 100644 --- a/docs/src/main/asciidoc/rest-client.adoc +++ b/docs/src/main/asciidoc/rest-client.adoc @@ -325,6 +325,38 @@ public interface ExtensionsService { } ---- +=== Dynamic base URLs + +The REST client allows for a per invocation override of the base URL using the `io.quarkus.rest.client.reactive.Url` annotation. + +Here is a simple example: + +[source, java] +---- +package org.acme.rest.client; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.QueryParam; +import java.util.Set; + +import io.quarkus.rest.client.reactive.Url; + +@Path("/extensions") +@RegisterRestClient +public interface ExtensionsService { + + @GET + @Path("/stream/{stream}") + Set getByStream(@Url String url, @PathParam("stream") String stream, @QueryParam("id") String id); +} +---- + +When the `url` parameter is non-null, it will override the base URL that is configured for the client (the default base URL configuration is still mandatory). + === Sending large payloads The REST Client is capable of sending arbitrarily large HTTP bodies without buffering the contents in memory, if one of the following types is used: From abb83ca74cf0063ae4217600a81dfe860a3ca573 Mon Sep 17 00:00:00 2001 From: Rostislav Svoboda Date: Tue, 10 Dec 2024 10:55:07 +0100 Subject: [PATCH 073/207] Move from vectorized/redpanda images to redpandadata/redpanda --- docs/src/main/asciidoc/kafka-dev-services.adoc | 4 ++-- .../kafka/client/deployment/DevServicesKafkaProcessor.java | 2 +- .../client/deployment/KafkaDevServicesBuildTimeConfig.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/main/asciidoc/kafka-dev-services.adoc b/docs/src/main/asciidoc/kafka-dev-services.adoc index cbe41d890c621..590f2ffda8770 100644 --- a/docs/src/main/asciidoc/kafka-dev-services.adoc +++ b/docs/src/main/asciidoc/kafka-dev-services.adoc @@ -56,8 +56,8 @@ Dev Services for Kafka supports https://redpanda.com[Redpanda], https://github/o and https://strimzi.io[Strimzi] (in https://github.com/apache/kafka/blob/trunk/config/kraft/README.md[Kraft] mode) images. **Redpanda** is a Kafka compatible event streaming platform. -Because it provides a fast startup times, Dev Services defaults to Redpanda images from `vectorized/redpanda`. -You can select any version from https://hub.docker.com/r/vectorized/redpanda. +Because it provides a fast startup times, Dev Services defaults to Redpanda images from `redpandadata/redpanda`. +You can select any version from https://hub.docker.com/r/redpandadata/redpanda. **kafka-native** provides images of standard Apache Kafka distribution compiled to native binary using Quarkus and GraalVM. While still being _experimental_, it provides very fast startup times with small footprint. diff --git a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/DevServicesKafkaProcessor.java b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/DevServicesKafkaProcessor.java index 53a0f45a83e39..f6a3c35aa8f3d 100644 --- a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/DevServicesKafkaProcessor.java +++ b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/DevServicesKafkaProcessor.java @@ -228,7 +228,7 @@ private RunningDevService startKafka(DockerStatusBuildItem dockerStatusBuildItem switch (config.provider) { case REDPANDA: RedpandaKafkaContainer redpanda = new RedpandaKafkaContainer( - DockerImageName.parse(config.imageName).asCompatibleSubstituteFor("vectorized/redpanda"), + DockerImageName.parse(config.imageName).asCompatibleSubstituteFor("redpandadata/redpanda"), config.fixedExposedPort, launchMode.getLaunchMode() == LaunchMode.DEVELOPMENT ? config.serviceName : null, useSharedNetwork, config.redpanda); diff --git a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaDevServicesBuildTimeConfig.java b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaDevServicesBuildTimeConfig.java index d3bbc818fc103..4207faf0f521b 100644 --- a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaDevServicesBuildTimeConfig.java +++ b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaDevServicesBuildTimeConfig.java @@ -34,7 +34,7 @@ public class KafkaDevServicesBuildTimeConfig { * Redpanda, Strimzi and kafka-native container providers are supported. Default is redpanda. *