From ddfd07bbd086ed18e02986ab045840e05053cc65 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Tue, 3 Dec 2024 14:04:51 +0000 Subject: [PATCH 01/15] Copy attributes from Elytron SecurityIdentity to Quarkus SecurityIdentity (cherry picked from commit 3d7c659d75fc42b2e046d1be7d71c8605a313c76) --- .../security/ldap/LdapSecurityRealmTest.java | 8 ++++++-- .../security/ldap/MinimalConfigurationTest.java | 3 +++ .../ldap/rest/SubjectExposingResource.java | 17 +++++++++++++---- .../minimal-config/application.properties | 5 +++++ .../ElytronPasswordIdentityProvider.java | 5 +++++ .../runtime/ElytronTokenIdentityProvider.java | 4 ++++ .../runtime/ElytronTrustedIdentityProvider.java | 4 ++++ .../ldap/src/main/resources/quarkus-io.ldif | 2 ++ 8 files changed, 42 insertions(+), 6 deletions(-) diff --git a/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/LdapSecurityRealmTest.java b/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/LdapSecurityRealmTest.java index f873ea5f1b76e..1b9ae328bad0e 100644 --- a/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/LdapSecurityRealmTest.java +++ b/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/LdapSecurityRealmTest.java @@ -128,7 +128,7 @@ public void testJaxrsUserRoleSuccess() { setupAuth("standardUser", "standardUserPassword") .when().get("/jaxrs-secured/subject/secured").then() .statusCode(200) - .body(equalTo("standardUser")); + .body(equalTo(expectedStandardUserName())); } @Test @@ -136,7 +136,11 @@ public void testJaxrsInjectedPrincipalSuccess() { setupAuth("standardUser", "standardUserPassword") .when().get("/jaxrs-secured/subject/principal-secured").then() .statusCode(200) - .body(equalTo("standardUser")); + .body(equalTo(expectedStandardUserName())); + } + + protected String expectedStandardUserName() { + return "standardUser"; } /** diff --git a/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/MinimalConfigurationTest.java b/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/MinimalConfigurationTest.java index 9d9dc2d3e506f..470ce70fbad40 100644 --- a/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/MinimalConfigurationTest.java +++ b/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/MinimalConfigurationTest.java @@ -12,4 +12,7 @@ public class MinimalConfigurationTest extends LdapSecurityRealmTest { .addClasses(testClasses) .addAsResource("minimal-config/application.properties", "application.properties")); + protected String expectedStandardUserName() { + return "standardUser:Standard User"; + } } diff --git a/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/rest/SubjectExposingResource.java b/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/rest/SubjectExposingResource.java index f54c4a300f88d..0bc6dfafaa8da 100644 --- a/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/rest/SubjectExposingResource.java +++ b/extensions/elytron-security-ldap/deployment/src/test/java/io/quarkus/elytron/security/ldap/rest/SubjectExposingResource.java @@ -11,19 +11,27 @@ import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.SecurityContext; +import org.wildfly.security.authz.Attributes; + +import io.quarkus.security.identity.SecurityIdentity; + @Path("subject") public class SubjectExposingResource { @Inject Principal principal; + @Inject + SecurityIdentity identity; + @GET @RolesAllowed("standardRole") @Path("secured") - public String getSubjectSecured(@Context SecurityContext sec) { - Principal user = sec.getUserPrincipal(); + public String getSubjectSecured() { + Principal user = identity.getPrincipal(); String name = user != null ? user.getName() : "anonymous"; - return name; + Attributes.Entry attributeEntry = (Attributes.Entry) identity.getAttributes().get("displayName"); + return attributeEntry == null ? name : name + ":" + attributeEntry.get(0); } @GET @@ -34,7 +42,8 @@ public String getPrincipalSecured(@Context SecurityContext sec) { throw new IllegalStateException("No injected principal"); } String name = principal.getName(); - return name; + Attributes.Entry attributeEntry = (Attributes.Entry) identity.getAttributes().get("displayName"); + return attributeEntry == null ? name : name + ":" + attributeEntry.get(0); } @GET diff --git a/extensions/elytron-security-ldap/deployment/src/test/resources/minimal-config/application.properties b/extensions/elytron-security-ldap/deployment/src/test/resources/minimal-config/application.properties index e5d01d25ea966..5877ab0cd3335 100644 --- a/extensions/elytron-security-ldap/deployment/src/test/resources/minimal-config/application.properties +++ b/extensions/elytron-security-ldap/deployment/src/test/resources/minimal-config/application.properties @@ -9,3 +9,8 @@ quarkus.security.ldap.identity-mapping.search-base-dn=ou=Users,dc=quarkus,dc=io quarkus.security.ldap.identity-mapping.attribute-mappings."0".from=cn quarkus.security.ldap.identity-mapping.attribute-mappings."0".filter=(member=uid={0},ou=Users,dc=quarkus,dc=io) quarkus.security.ldap.identity-mapping.attribute-mappings."0".filter-base-dn=ou=Roles,dc=quarkus,dc=io + +quarkus.security.ldap.identity-mapping.attribute-mappings."1".from=displayName +quarkus.security.ldap.identity-mapping.attribute-mappings."1".to=displayName +quarkus.security.ldap.identity-mapping.attribute-mappings."1".filter=(uid={0}) +quarkus.security.ldap.identity-mapping.attribute-mappings."1".filter-base-dn=ou=Users,dc=quarkus,dc=io \ No newline at end of file diff --git a/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronPasswordIdentityProvider.java b/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronPasswordIdentityProvider.java index 5118f6b612034..61e7a1f1c15a5 100644 --- a/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronPasswordIdentityProvider.java +++ b/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronPasswordIdentityProvider.java @@ -8,6 +8,7 @@ import org.jboss.logging.Logger; import org.wildfly.security.auth.server.RealmUnavailableException; import org.wildfly.security.auth.server.SecurityDomain; +import org.wildfly.security.authz.Attributes; import org.wildfly.security.evidence.PasswordGuessEvidence; import io.quarkus.security.AuthenticationFailedException; @@ -52,6 +53,10 @@ public SecurityIdentity get() { throw new AuthenticationFailedException(); } QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(); + for (Attributes.Entry entry : result.getAttributes().entries()) { + builder.addAttribute(entry.getKey(), entry); + } + builder.setPrincipal(result.getPrincipal()); for (String i : result.getRoles()) { builder.addRole(i); diff --git a/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronTokenIdentityProvider.java b/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronTokenIdentityProvider.java index 9c913152b2a89..c19a51b3d4114 100644 --- a/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronTokenIdentityProvider.java +++ b/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronTokenIdentityProvider.java @@ -8,6 +8,7 @@ import org.jboss.logging.Logger; import org.wildfly.security.auth.server.RealmUnavailableException; import org.wildfly.security.auth.server.SecurityDomain; +import org.wildfly.security.authz.Attributes; import org.wildfly.security.evidence.BearerTokenEvidence; import io.quarkus.security.AuthenticationFailedException; @@ -51,6 +52,9 @@ public SecurityIdentity get() { throw new AuthenticationFailedException(); } QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(); + for (Attributes.Entry entry : result.getAttributes().entries()) { + builder.addAttribute(entry.getKey(), entry); + } builder.setPrincipal(result.getPrincipal()); for (String i : result.getRoles()) { builder.addRole(i); diff --git a/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronTrustedIdentityProvider.java b/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronTrustedIdentityProvider.java index 314d2492e2785..7cb447fdf8d6f 100644 --- a/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronTrustedIdentityProvider.java +++ b/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronTrustedIdentityProvider.java @@ -10,6 +10,7 @@ import org.wildfly.security.auth.server.RealmUnavailableException; import org.wildfly.security.auth.server.SecurityDomain; import org.wildfly.security.auth.server.ServerAuthenticationContext; +import org.wildfly.security.authz.Attributes; import org.wildfly.security.credential.PasswordCredential; import io.quarkus.security.AuthenticationFailedException; @@ -62,6 +63,9 @@ public SecurityIdentity get() { throw new AuthenticationFailedException(); } QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(); + for (Attributes.Entry entry : result.getAttributes().entries()) { + builder.addAttribute(entry.getKey(), entry); + } builder.setPrincipal(result.getPrincipal()); for (String i : result.getRoles()) { builder.addRole(i); diff --git a/test-framework/ldap/src/main/resources/quarkus-io.ldif b/test-framework/ldap/src/main/resources/quarkus-io.ldif index cbe108e20e6c3..48e9f426e06ab 100644 --- a/test-framework/ldap/src/main/resources/quarkus-io.ldif +++ b/test-framework/ldap/src/main/resources/quarkus-io.ldif @@ -31,6 +31,8 @@ cn: StandardUser sn: standardUser uid: standardUser userPassword: standardUserPassword +displayName: Standard User + dn: uid=adminUser,ou=Users,dc=quarkus,dc=io objectClass: top From 14b6cfa1e428ac012b3f6717b969fdefc495c563 Mon Sep 17 00:00:00 2001 From: brunobat Date: Thu, 5 Dec 2024 09:21:49 +0000 Subject: [PATCH 02/15] Reduce log level of otel side exporter classes (cherry picked from commit 0bf88b67c7eeea1d1346752e823c315bdcf39fa9) --- .../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 3e1dd6a9aad291d16bcd2679d60a906a04228c2c 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 03/15] 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] (cherry picked from commit 529267983841e6056d5cf2d6e47e68aeff4bc647) --- 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 3c95f001f5ca6..b9a6b0acaa950 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -47,7 +47,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 8deda9caa9649..e56120c41ce35 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 bc04949e63dfb..63cd689794698 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -57,7 +57,7 @@ 3.1.0 2.6.2 - 2.8.0 + 2.9.0 4.5.11 5.5.0 1.0.0.Final From f3cc34dcb45faf506376b769e7a353980a886b7c Mon Sep 17 00:00:00 2001 From: Thibault Meyer Date: Thu, 5 Dec 2024 20:49:37 +0100 Subject: [PATCH 04/15] Spring Cloud Configuration ordinal customization Resolves: #44923 Signed-off-by: Thibault Meyer (cherry picked from commit 20c598ded9d513acb2f742ef47ec4ff4f0d6c81d) --- .../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 094110944549eec1c8dfcd03927977c2fbb1a878 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Sat, 7 Dec 2024 11:51:48 -0300 Subject: [PATCH 05/15] Fix ci.yml for Gradle projects - Should use gradle/actions/setup-gradle action instead too (cherry picked from commit 73ed76fe18f31ccd8fd0ccccfae11cd3e3c63945) --- .../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 8ddbf9132830132dd2d00737a6c6ad551709af62 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Sat, 7 Dec 2024 17:18:35 +0000 Subject: [PATCH 06/15] Minor OIDC updates (cherry picked from commit 298daf3cac69f3acb09e90d30177a719fad1beb8) --- .../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 c818e0d28549e..f1f82be32fa7f 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 2666994f298b8b42bc330f4f490e2f5ace0701ce Mon Sep 17 00:00:00 2001 From: Michael Edgar Date: Sun, 8 Dec 2024 21:14:20 -0500 Subject: [PATCH 07/15] Bump smallrye-open-api.version from 4.0.4 to 4.0.5 Signed-off-by: Michael Edgar (cherry picked from commit 325ccfcc4bf4db8f9ae9ab5ebda4662b634a138f) --- 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 b9a6b0acaa950..ae106d00f59c0 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -51,7 +51,7 @@ 3.10.2 4.1.0 4.0.0 - 4.0.4 + 4.0.5 2.11.0 6.6.3 4.6.1 From 74ac1dde8bd0ef9fb94a76bfa6c3708967480d7f Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Fri, 6 Dec 2024 10:51:04 +0100 Subject: [PATCH 08/15] Fix InjectionPointModifier for repeated annotations on method parameters; add grpc test (cherry picked from commit 8ce87793abd1ffe47d718ced32c1968f7ba3411b) --- ...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 cace10e40f8cf4747d1541c16dbd8008712c1854 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Mon, 9 Dec 2024 09:55:24 -0300 Subject: [PATCH 09/15] Fix code indentation When creating a new Quarkiverse extension, the build fails because these generated files are not indented properly (cherry picked from commit 9d3d9001ef1ac120c22456679620678f370a268a) --- .../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 e1c6de0c3ed4776213b20b74d2d5d56bfbb2fa89 Mon Sep 17 00:00:00 2001 From: Christian Pieczewski Date: Mon, 9 Dec 2024 21:54:07 +0100 Subject: [PATCH 10/15] Correct dependency notation in documentation for observability-devservices-lgtm.adoc (cherry picked from commit f3b9bc2326357ba5924c0999bc873e357a0df623) --- 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 0bfbd8b75e99e647c1525ef4669764f481170f68 Mon Sep 17 00:00:00 2001 From: Rostislav Svoboda Date: Tue, 10 Dec 2024 10:55:07 +0100 Subject: [PATCH 11/15] Move from vectorized/redpanda images to redpandadata/redpanda (cherry picked from commit abb83ca74cf0063ae4217600a81dfe860a3ca573) --- 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 d1d34a97f868f..a49b2242cb8f1 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. *

* 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 beca34308de77459a5ef16830166b600d47305e8 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 9 Dec 2024 15:52:18 +0100 Subject: [PATCH 12/15] Properly substitute {quarkus-version} in native-reference.adoc (cherry picked from commit da40415df864d56dd05c80c76b8ed27b8f1d9d02) --- 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 d95c219d10dc1884f9bb637fe73b280bf9a53c95 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 9 Dec 2024 16:03:02 +0100 Subject: [PATCH 13/15] Improve Dev Services network output in dev mode when typing c Just use proper spacing instead of something weird :). (cherry picked from commit ebd69b0a3ae4e48d5b68fbb92a0fa3530dbd511c) --- .../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 fc565f9323242556a7a763cf9e53098a5cd1623c Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 10 Dec 2024 10:08:58 +0200 Subject: [PATCH 14/15] Document @Url usage in REST Client Co-authored-by: Guillaume Smet (cherry picked from commit 090ff31228a9c7bb071f6d452b140492d40b196c) --- 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 5cb6e2b44395c..934be7cc3cfa9 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 f21e1149fa7907283401c786868de81593f74091 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 15/15] fix(security): call @PermissionChecker methods with final augmented identity (cherry picked from commit 8f44d0d8d2caa733ca6f191974d2bd9ac6024407) --- ...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); } } }