Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.17] 3.17.5 backports 1 #45192

Merged
merged 22 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
14535b1
Revert "Bump org.mariadb.jdbc:mariadb-java-client from 3.4.1 to 3.5.0"
gsmet Dec 10, 2024
fadd689
Priority of REST Client Config changed to Quarkus FQN, config key, si…
radcortez Dec 10, 2024
53c8759
Properly create REST Client template path when @Url is used
geoand Dec 10, 2024
71c8aba
Add test for case where RestClient uses @Url and observability features
brunobat Dec 9, 2024
c40b005
Make sure Redis dev-service doesn't start in test that doesn't need it
geoand Dec 11, 2024
7af7816
Upgrade to quarkus-http 5.3.4
Dec 10, 2024
1b42724
Update OIDC MTLS test to use generated certificates
sberyozkin Dec 11, 2024
9b69d41
fix(oidc,security): OIDC must auth before mTLS when disabled inclusiv…
michalvavrik Dec 12, 2024
1ce8edc
Ensure that jakarta json types can be deserialized in native mode
geoand Dec 12, 2024
fbcb767
Generate certificates in the OIDC integration test
sberyozkin Dec 12, 2024
d111801
logstash conf file fix
Dec 13, 2024
1f679b2
Bump org.hibernate.validator:hibernate-validator
dependabot[bot] Dec 13, 2024
629188f
Update documentation for handling proxies in native-mode
zakkak Dec 9, 2024
72f3a70
Update OIDC bearer doc with a section about response filters
sberyozkin Dec 16, 2024
df84c0d
Bump org.asynchttpclient:async-http-client from 2.12.3 to 2.12.4
gastaldi Dec 16, 2024
82cda43
Break build cycle between OTel, logging and Flyway
geoand Dec 16, 2024
dda0b14
Register for reflection Pageable class for not missing paged/unpaged …
aureamunoz Dec 13, 2024
44f09de
Improve documentation for handling proxies in native-mode
zakkak Dec 17, 2024
6359779
Fix local proxy handling in REST Client module
geoand Dec 17, 2024
ac91de2
Docs: Correct word form in Native Applications Tips
MaciejDromin Dec 17, 2024
b73587d
Unable to use custom handlers for HTTP OPTIONS method in subresources
mabartos Dec 17, 2024
c6608bf
Fix matrix computation for Ubuntu 24
gsmet Dec 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci-actions-incremental.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<opentelemetry.version>1.42.1</opentelemetry.version>
<opentelemetry-alpha.version>2.8.0-alpha</opentelemetry-alpha.version>
<opentelemetry-semconv.version>1.27.0-alpha</opentelemetry-semconv.version>
<quarkus-http.version>5.3.3</quarkus-http.version>
<quarkus-http.version>5.3.4</quarkus-http.version>
<micrometer.version>1.13.7</micrometer.version><!-- keep in sync with hdrhistogram -->
<hdrhistogram.version>2.2.2</hdrhistogram.version><!-- keep in sync with micrometer -->
<google-auth.version>0.22.0</google-auth.version>
Expand Down Expand Up @@ -119,7 +119,7 @@
<h2.version>2.3.230</h2.version> <!-- When updating, needs to be matched in io.quarkus.hibernate.orm.runtime.config.DialectVersions
and the dependency jts-core needs to be updated in extensions/jdbc/jdbc-h2/runtime/pom.xml -->
<postgresql-jdbc.version>42.7.4</postgresql-jdbc.version>
<mariadb-jdbc.version>3.5.0</mariadb-jdbc.version>
<mariadb-jdbc.version>3.4.1</mariadb-jdbc.version>
<mysql-jdbc.version>8.3.0</mysql-jdbc.version>
<mssql-jdbc.version>12.8.1.jre11</mssql-jdbc.version>
<adal4j.version>1.6.7</adal4j.version>
Expand Down Expand Up @@ -214,7 +214,7 @@
<mime4j.version>0.8.11</mime4j.version>
<mutiny-zero.version>1.1.0</mutiny-zero.version>
<pulsar-client.version>3.3.0</pulsar-client.version>
<async-http-client.version>2.12.3</async-http-client.version>
<async-http-client.version>2.12.4</async-http-client.version>
<!-- keep in-sync, if possible, with Micrometer registry Prometheus -->
<prometheus.version>0.16.0</prometheus.version>
<!-- Dev UI -->
Expand Down
5 changes: 5 additions & 0 deletions build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,11 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.smallrye.certs</groupId>
<artifactId>smallrye-certificate-generator-maven-plugin</artifactId>
<version>${smallrye-certificate-generator.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/centralized-log-management.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <<mutual-tls>> and basic authentication mechanism authentications are required,
the <<mutual-tls>> authentication mechanism will create `SecurityIdentity` first.
the <<mutual-tls>> mechanism will create `SecurityIdentity` first.

NOTE: The <<mutual-tls>> mechanism has the highest priority when inclusive authentication is enabled, to ensure
that an injected `SecurityIdentity` always represents <<mutual-tls>> 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1345,6 +1345,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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -405,16 +404,15 @@ 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>
if (contentType.equals("application/json")
&& 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'");
}
}
}
Expand Down
21 changes: 14 additions & 7 deletions docs/src/main/asciidoc/writing-native-applications-tips.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -320,6 +320,7 @@ 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.
Expand All @@ -331,9 +332,10 @@ In such a situation, the error you might encounter is:
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=<comma-separated-config-files> and -H:DynamicProxyConfigurationResources=<comma-separated-config-resources> options.
----

Solving this issue requires creating a `proxy-config.json` file under the `src/main/resources/META-INF/native-image/<group-id>/<artifact-id>` 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.
To solve the issue you can create a `proxy-config.json` file under the `src/main/resources/META-INF/native-image/<group-id>/<artifact-id>` 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 <<managing-proxy-classes-extension>>.

[[modularity-benefits]]
=== Modularity Benefits
Expand Down Expand Up @@ -633,9 +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

Very similarly, 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]
----
Expand All @@ -650,11 +653,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` as described in <<managing-proxy-classes-app>>.

[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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -184,7 +183,6 @@ private void addJavaMigrations(Collection<ClassInfo> candidates, RecorderContext

@BuildStep
@Produce(SyntheticBeansRuntimeInitBuildItem.class)
@Consume(LoggingSetupBuildItem.class)
@Record(ExecutionTime.RUNTIME_INIT)
void createBeans(FlywayRecorder recorder,
List<JdbcDataSourceBuildItem> jdbcDataSourceBuildItems,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
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.redis.devservices.enabled", "false")
.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");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "/";
Expand Down
5 changes: 5 additions & 0 deletions extensions/oidc/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@
<artifactId>quarkus-elytron-security-properties-file-deployment</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.smallrye.certs</groupId>
<artifactId>smallrye-certificate-generator-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Loading
Loading