diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 44948bf0ca6b7..2ee4b572e3bb5 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -74,6 +74,7 @@ updates:
# RX Java 2
- dependency-name: io.reactivex.rxjava2:rxjava
# Test dependencies
+ - dependency-name: net.sourceforge.htmlunit:htmlunit
- dependency-name: io.rest-assured:*
- dependency-name: org.junit:junit-bom
- dependency-name: org.junit.jupiter:*
diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index a51f41a83f576..ab2df2c0b3d83 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -86,7 +86,7 @@
22.3.0
${graal-sdk.version}
1.6.0.Final
- 2.14.1
+ 2.14.2
1.0.0.Final
3.12.0
1.15
@@ -122,7 +122,7 @@
2.3.2
2.1.214
42.5.1
- 3.1.1
+ 3.1.2
8.0.30
11.2.3.jre11
1.6.7
@@ -131,7 +131,7 @@
11.5.8.0
1.2.6
4.5.1
- 5.9.1
+ 5.9.2
1.5.0
6.14.2
14.0.6.Final
@@ -141,7 +141,7 @@
1.8.0
1.0.3
3.5.0.Final
- 1.8.0
+ 1.9.0
3.3.2
1.8.0
1.1.8.4
@@ -188,7 +188,7 @@
0.23.0
1.42.3
2.1
- 4.7.0
+ 4.7.1
1.0.4
1.22
1.10.0
diff --git a/build-parent/pom.xml b/build-parent/pom.xml
index 7735ec174fae5..cb4600cfb6af7 100644
--- a/build-parent/pom.xml
+++ b/build-parent/pom.xml
@@ -38,7 +38,7 @@
1.0.0
2.5.7
- 2.40.0
+ 2.70.0
3.24.2
2.0.3.Final
5.2.8
diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/extension/QuarkusPluginExtension.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/extension/QuarkusPluginExtension.java
index ee4fd9f4100fc..499ca60d7a3cc 100644
--- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/extension/QuarkusPluginExtension.java
+++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/extension/QuarkusPluginExtension.java
@@ -3,7 +3,6 @@
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
@@ -19,6 +18,7 @@
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFile;
import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSet;
@@ -39,7 +39,7 @@ public class QuarkusPluginExtension {
private final Property finalName;
- private Map quarkusBuildProperties;
+ private final MapProperty quarkusBuildProperties;
private final SourceSetExtension sourceSetExtension;
public QuarkusPluginExtension(Project project) {
@@ -49,7 +49,7 @@ public QuarkusPluginExtension(Project project) {
finalName.convention(project.provider(() -> String.format("%s-%s", project.getName(), project.getVersion())));
this.sourceSetExtension = new SourceSetExtension();
- quarkusBuildProperties = new HashMap<>();
+ this.quarkusBuildProperties = project.getObjects().mapProperty(String.class, String.class);
}
public void beforeTest(Test task) {
@@ -99,7 +99,7 @@ public void beforeTest(Test task) {
public String buildNativeRunnerName(final Map taskSystemProps) {
Properties properties = new Properties(taskSystemProps.size());
properties.putAll(taskSystemProps);
- quarkusBuildProperties.entrySet()
+ quarkusBuildProperties.get().entrySet()
.forEach(buildEntry -> properties.putIfAbsent(buildEntry.getKey(), buildEntry.getValue()));
System.getProperties().entrySet()
.forEach(propEntry -> properties.putIfAbsent(propEntry.getKey(), propEntry.getValue()));
@@ -215,7 +215,7 @@ public Path appJarOrClasses() {
return classesDir;
}
- public Map getQuarkusBuildProperties() {
+ public MapProperty getQuarkusBuildProperties() {
return quarkusBuildProperties;
}
@@ -223,4 +223,8 @@ public void set(String name, @Nullable String value) {
quarkusBuildProperties.put(String.format("quarkus.%s", name), value);
}
+ public void set(String name, Property value) {
+ quarkusBuildProperties.put(String.format("quarkus.%s", name), value);
+ }
+
}
diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/GradleLogger.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/GradleLogger.java
deleted file mode 100644
index 8acbe9319c964..0000000000000
--- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/GradleLogger.java
+++ /dev/null
@@ -1,197 +0,0 @@
-package io.quarkus.gradle.tasks;
-
-import java.text.MessageFormat;
-import java.util.Collections;
-import java.util.Map;
-import java.util.function.Supplier;
-
-import org.jboss.logging.Logger;
-import org.jboss.logging.LoggerProvider;
-import org.wildfly.common.Assert;
-
-public class GradleLogger implements LoggerProvider {
- static final Object[] NO_PARAMS = new Object[0];
-
- public static volatile Supplier logSupplier;
-
- @Override
- public Logger getLogger(final String name) {
- return new Logger(name) {
- @Override
- protected void doLog(final Level level, final String loggerClassName, final Object message,
- final Object[] parameters, final Throwable thrown) {
- final Supplier logSupplier = GradleLogger.logSupplier;
- if (logSupplier != null) {
- org.gradle.api.logging.Logger log = logSupplier.get();
- String text;
- if (parameters == null || parameters.length == 0) {
- text = String.valueOf(message);
- } else
- try {
- text = MessageFormat.format(String.valueOf(message), parameters);
- } catch (Exception e) {
- text = invalidFormat(String.valueOf(message), parameters);
- }
- doActualLog(log, level, text, thrown);
- }
- }
-
- @Override
- protected void doLogf(final Level level, final String loggerClassName, final String format,
- final Object[] parameters, final Throwable thrown) {
- final Supplier logSupplier = GradleLogger.logSupplier;
- if (logSupplier != null) {
- org.gradle.api.logging.Logger log = logSupplier.get();
- String text;
- if (parameters == null)
- try {
- //noinspection RedundantStringFormatCall
- text = String.format(format);
- } catch (Exception e) {
- text = invalidFormat(format, NO_PARAMS);
- }
- else
- try {
- text = String.format(format, (Object[]) parameters);
- } catch (Exception e) {
- text = invalidFormat(format, parameters);
- }
- if (!text.startsWith("JBoss Threads version")) {
- doActualLog(log, level, text, thrown);
- }
- }
- }
-
- @Override
- public boolean isEnabled(final Level level) {
- final Supplier logSupplier = GradleLogger.logSupplier;
- if (logSupplier == null)
- return false;
- org.gradle.api.logging.Logger log = logSupplier.get();
- switch (level) {
- case FATAL:
- case ERROR:
- return log.isErrorEnabled();
- case WARN:
- return log.isWarnEnabled();
- case INFO:
- return log.isInfoEnabled();
- default:
- return log.isDebugEnabled();
- }
- }
-
- void doActualLog(final org.gradle.api.logging.Logger log, final Level level, final String message,
- final Throwable thrown) {
- //TODO: will fix this in the upcoming version of æsh
- // style options are limited unless we crack into jansi ourselves
- //buffer.strong("[").project(name).strong("]").a(" ").a(message);
- StringBuilder buffer = new StringBuilder();
- buffer.append("[").append(name).append("]").append(" ").append(message);
- if (thrown != null) {
- switch (level) {
- case FATAL:
- case ERROR:
- log.error(buffer.toString(), thrown);
- break;
- case WARN:
- log.warn(buffer.toString(), thrown);
- break;
- case INFO:
- log.info(buffer.toString(), thrown);
- break;
- default:
- log.debug(buffer.toString(), thrown);
- break;
- }
- } else {
- switch (level) {
- case FATAL:
- case ERROR:
- log.error(buffer.toString());
- break;
- case WARN:
- log.warn(buffer.toString());
- break;
- case INFO:
- log.info(buffer.toString());
- break;
- default:
- log.debug(buffer.toString());
- break;
- }
- }
- }
- };
- }
-
- String invalidFormat(final String format, final Object[] parameters) {
- final StringBuilder b = new StringBuilder("** invalid format \'" + format + "\'");
- if (parameters != null && parameters.length > 0) {
- b.append(" [").append(parameters[0]);
- for (int i = 1; i < parameters.length; i++) {
- b.append(',').append(parameters[i]);
- }
- b.append("]");
- }
- return b.toString();
- }
-
- @Override
- public void clearMdc() {
- }
-
- @Override
- public Object putMdc(final String key, final Object value) {
- //throw Assert.unsupported();
- return null;
- }
-
- @Override
- public Object getMdc(final String key) {
- return null;
- }
-
- @Override
- public void removeMdc(final String key) {
- }
-
- @Override
- public Map getMdcMap() {
- return Collections.emptyMap();
- }
-
- @Override
- public void clearNdc() {
- }
-
- @Override
- public String getNdc() {
- return "";
- }
-
- @Override
- public int getNdcDepth() {
- return 0;
- }
-
- @Override
- public String popNdc() {
- return "";
- }
-
- @Override
- public String peekNdc() {
- return "";
- }
-
- @Override
- public void pushNdc(final String message) {
- throw Assert.unsupported();
- }
-
- @Override
- public void setNdcMaxDepth(final int maxDepth) {
- }
-
-}
diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuild.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuild.java
index 4d98e2e99a3d8..1b3698e4f668a 100644
--- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuild.java
+++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusBuild.java
@@ -256,8 +256,9 @@ private String getPropValueWithPrecedence(final String propName, final java.util
}
});
}
- if (extension().getQuarkusBuildProperties().containsKey(propName)) {
- return extension().getQuarkusBuildProperties().get(propName);
+ Map quarkusBuildProperties = extension().getQuarkusBuildProperties().get();
+ if (quarkusBuildProperties.containsKey(propName)) {
+ return quarkusBuildProperties.get(propName);
} else if (applicationProperties.contains(propName)) {
return applicationProperties.getProperty(propName);
} else if (getQuarkusBuildEnvProperties().containsKey(propName)) {
diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusTask.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusTask.java
index 254433b5155c3..e16c737d6009f 100644
--- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusTask.java
+++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusTask.java
@@ -13,8 +13,6 @@ public abstract class QuarkusTask extends DefaultTask {
private QuarkusPluginExtension extension;
QuarkusTask(String description) {
- GradleLogger.logSupplier = this::getLogger;
-
setDescription(description);
setGroup("quarkus");
}
@@ -36,8 +34,9 @@ protected Properties getBuildSystemProperties(ResolvedDependency appArtifact) {
realProperties.setProperty(key, (String) value);
}
}
- if (!extension().getQuarkusBuildProperties().isEmpty()) {
- extension().getQuarkusBuildProperties().entrySet().stream().filter(entry -> entry.getKey().startsWith("quarkus."))
+ Map quarkusBuildProperties = extension().getQuarkusBuildProperties().get();
+ if (!quarkusBuildProperties.isEmpty()) {
+ quarkusBuildProperties.entrySet().stream().filter(entry -> entry.getKey().startsWith("quarkus."))
.forEach(entry -> {
realProperties.put(entry.getKey(), entry.getValue());
});
diff --git a/docs/src/main/asciidoc/micrometer.adoc b/docs/src/main/asciidoc/micrometer.adoc
index b8fefe6a3e7d5..ee3eb4039b207 100644
--- a/docs/src/main/asciidoc/micrometer.adoc
+++ b/docs/src/main/asciidoc/micrometer.adoc
@@ -367,11 +367,11 @@ timers, look for `http_server_requests_seconds_count`, `http_server_requests_sec
----
# HELP http_server_requests_seconds
# TYPE http_server_requests_seconds summary
-http_server_requests_seconds_count{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}",} 1.0
-http_server_requests_seconds_sum{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}",} 0.017385896
+http_server_requests_seconds_count{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}"} 1.0
+http_server_requests_seconds_sum{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}"} 0.017385896
# HELP http_server_requests_seconds_max
# TYPE http_server_requests_seconds_max gauge
-http_server_requests_seconds_max{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}",} 0.017385896
+http_server_requests_seconds_max{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}"} 0.017385896
#
----
@@ -398,6 +398,11 @@ string. For example, setting
`quarkus.micrometer.binder.http-server.match-patterns=/example/prime/[0-9]+=/example/{jellybeans}` would use the value
`/example/{jellybeans}` for the uri attribute any time the requested uri matches `/example/prime/[0-9]+`.
+.Exported metrics format
+
+By default, the metrics are exported using the Prometheus format `application/openmetrics-text`,
+you can revert to the former format by specifying the `Accept` request header to `plain/text` (`curl -H "Accept: plain/text" localhost:8080/q/metrics/`).
+
== Using MeterFilter to configure metrics
Micrometer uses `MeterFilter` instances to customize the metrics emitted by `MeterRegistry` instances.
diff --git a/docs/src/main/asciidoc/resteasy-reactive.adoc b/docs/src/main/asciidoc/resteasy-reactive.adoc
index a33ab14484ae5..97549a0a2fc4d 100644
--- a/docs/src/main/asciidoc/resteasy-reactive.adoc
+++ b/docs/src/main/asciidoc/resteasy-reactive.adoc
@@ -723,6 +723,79 @@ public class Endpoint {
}
----
+=== Redirect support
+
+When handling a `@POST`, `@PUT` or `@DELETE` endpoint, it is common practice to redirect to a `@GET` endpoint after the action has been performed to allow the user to reload the page without triggering the action a second time.
+There are multiple ways to achieve this.
+
+==== Using RestResponse
+
+Using `RestResponse` as the return type while making sure the proper redirection URI is created can be done as in the following example:
+
+[source,java]
+----
+package org.acme.rest;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+import org.jboss.resteasy.reactive.RestResponse;
+
+@Path("/fruits")
+public class FruitResource {
+
+ public static class Fruit {
+ public Long id;
+ public String name;
+ public String description;
+
+ public Fruit() {
+ }
+
+ public Fruit(Long id, String name, String description) {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ }
+ }
+
+ private final Map fruits = new ConcurrentHashMap<>();
+ private final AtomicLong ids = new AtomicLong(0);
+
+
+ public FruitResource() {
+ Fruit apple = new Fruit(ids.incrementAndGet(), "Apple", "Winter fruit");
+ fruits.put(apple.id, apple);
+ Fruit pinneapple = new Fruit(ids.incrementAndGet(), "Pineapple", "Tropical fruit");
+ fruits.put(pinneapple.id, pinneapple);
+ }
+
+ // when invoked, this method will result in an HTTP redirect to the GET method that obtains the fruit by id
+ @POST
+ public RestResponse add(Fruit fruit, @Context UriInfo uriInfo) {
+ fruit.id = ids.incrementAndGet();
+ fruits.put(fruit.id, fruit);
+ // seeOther results in an HTTP 303 response with the Location header set to the value of the URI
+ return RestResponse.seeOther(uriInfo.getAbsolutePathBuilder().path(Long.toString(fruit.id)).build());
+ }
+
+ @GET
+ @Path("{id}")
+ public Fruit byId(Long id) {
+ return fruits.get(id);
+ }
+}
+----
+
+==== Using RedirectException
+
+Users can also throw `javax.ws.rs.RedirectionException` from a method body to get RESTEasy Reactive to perform the desired redirect.
+
=== Async/reactive support
[[reactive]]
diff --git a/docs/src/main/asciidoc/telemetry-micrometer-tutorial.adoc b/docs/src/main/asciidoc/telemetry-micrometer-tutorial.adoc
index 57cc8b870a00e..5a2d0068d735f 100644
--- a/docs/src/main/asciidoc/telemetry-micrometer-tutorial.adoc
+++ b/docs/src/main/asciidoc/telemetry-micrometer-tutorial.adoc
@@ -77,16 +77,21 @@ Dimensional labels are added for the request uri, the HTTP method
----
# HELP http_server_requests_seconds
# TYPE http_server_requests_seconds summary
-http_server_requests_seconds_count{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}",} 2.0
-http_server_requests_seconds_sum{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}",} 0.017385896
+http_server_requests_seconds_count{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}"} 2.0
+http_server_requests_seconds_sum{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}"} 0.017385896
# HELP http_server_requests_seconds_max
# TYPE http_server_requests_seconds_max gauge
-http_server_requests_seconds_max{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}",} 0.017385896
+http_server_requests_seconds_max{method="GET",outcome="SUCCESS",status="200",uri="/example/prime/{number}"} 0.017385896
#
----
NOTE: Metrics appear lazily, you often won't see any data for your endpoint until it is accessed.
+.Exported metrics format
+
+By default, the metrics are exported using the Prometheus format `application/openmetrics-text`,
+you can revert to the former format by specifying the `Accept` request header to `plain/text` (`curl -H "Accept: plain/text" localhost:8080/q/metrics/`).
+
== Inject the MeterRegistry
To register meters, you need a reference to the `MeterRegistry` that is configured and maintained by the Micrometer extension.
diff --git a/extensions/funqy/funqy-server-common/deployment/src/main/java/io/quarkus/funqy/deployment/FunctionScannerBuildStep.java b/extensions/funqy/funqy-server-common/deployment/src/main/java/io/quarkus/funqy/deployment/FunctionScannerBuildStep.java
index 2b250b7c68540..dcf4096de963a 100644
--- a/extensions/funqy/funqy-server-common/deployment/src/main/java/io/quarkus/funqy/deployment/FunctionScannerBuildStep.java
+++ b/extensions/funqy/funqy-server-common/deployment/src/main/java/io/quarkus/funqy/deployment/FunctionScannerBuildStep.java
@@ -201,7 +201,8 @@ public ClassVisitor apply(String className, ClassVisitor classVisitor) {
public void visit(int version, int access, String name, String signature, String superName,
String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
- MethodVisitor ctor = visitMethod(Modifier.PUBLIC, "", "()V", null,
+ MethodVisitor ctor = visitMethod(Modifier.PUBLIC | Opcodes.ACC_SYNTHETIC, "", "()V",
+ null,
null);
ctor.visitCode();
ctor.visitVarInsn(Opcodes.ALOAD, 0);
diff --git a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/CodeFlowDevModeDefaultTenantTestCase.java b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/CodeFlowDevModeDefaultTenantTestCase.java
index ab820fbd643f0..7262a3cd300fd 100644
--- a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/CodeFlowDevModeDefaultTenantTestCase.java
+++ b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/CodeFlowDevModeDefaultTenantTestCase.java
@@ -59,7 +59,7 @@ public void testAccessAndRefreshTokenInjectionDevMode() throws IOException, Inte
page = loginForm.getInputByName("login").click();
- assertEquals("alice", page.getBody().asText());
+ assertEquals("alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
diff --git a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/CodeFlowDevModeTestCase.java b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/CodeFlowDevModeTestCase.java
index 1684c3ee95b83..00e003db3d7da 100644
--- a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/CodeFlowDevModeTestCase.java
+++ b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/CodeFlowDevModeTestCase.java
@@ -51,7 +51,7 @@ public void testAccessAndRefreshTokenInjectionDevMode() throws IOException, Inte
// Default tenant is disabled and client secret is wrong
HtmlPage page = webClient.getPage("http://localhost:8080/unprotected");
- assertEquals("unprotected", page.getBody().asText());
+ assertEquals("unprotected", page.getBody().asNormalizedText());
try {
webClient.getPage("http://localhost:8080/protected");
@@ -95,7 +95,7 @@ public void testAccessAndRefreshTokenInjectionDevMode() throws IOException, Inte
page = loginForm.getInputByName("login").click();
- assertEquals("alice", page.getBody().asText());
+ assertEquals("alice", page.getBody().asNormalizedText());
assertEquals("custom", page.getWebClient().getCookieManager().getCookie("q_session").getValue().split("\\|")[3]);
@@ -122,7 +122,7 @@ private void useTenantConfigResolver() throws IOException, InterruptedException
page = loginForm.getInputByName("login").click();
- assertEquals("tenant-config-resolver:alice", page.getBody().asText());
+ assertEquals("tenant-config-resolver:alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
diff --git a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/SecurityDisabledTestCase.java b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/SecurityDisabledTestCase.java
index 003f8063bde6f..4227e587a8a08 100644
--- a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/SecurityDisabledTestCase.java
+++ b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/SecurityDisabledTestCase.java
@@ -30,7 +30,7 @@ public void testAccessUnprotectedResource() throws IOException, InterruptedExcep
try (final WebClient webClient = createWebClient()) {
HtmlPage page = webClient.getPage("http://localhost:8081/unprotected");
- assertEquals("unprotected", page.getBody().asText());
+ assertEquals("unprotected", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
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 e25c963ca59bd..ebe214e2d7ea3 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
@@ -603,7 +603,7 @@ public static enum Source {
public static class Authentication {
/**
- * SameSite attribute values for the session, state and post logout cookies.
+ * SameSite attribute values for the session cookie.
*/
public enum CookieSameSite {
STRICT,
@@ -767,7 +767,7 @@ public enum ResponseMode {
public Optional cookieDomain = Optional.empty();
/**
- * SameSite attribute for the session, state and post logout cookies.
+ * SameSite attribute for the session cookie.
*/
@ConfigItem(defaultValue = "strict")
public CookieSameSite cookieSameSite = CookieSameSite.STRICT;
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 4dd98f1943255..fdf6a4fb4df6a 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
@@ -799,7 +799,7 @@ public Uni extends Void> apply(Void t) {
public Void apply(String cookieValue) {
String sessionCookie = createCookie(context, configContext.oidcConfig,
getSessionCookieName(configContext.oidcConfig),
- cookieValue, sessionMaxAge).getValue();
+ cookieValue, sessionMaxAge, true).getValue();
if (sessionCookie.length() >= MAX_COOKIE_VALUE_LENGTH) {
LOG.warnf(
"Session cookie length for the tenant %s is equal or greater than %d bytes."
@@ -914,6 +914,11 @@ private String generatePostLogoutState(RoutingContext context, TenantConfigConte
static ServerCookie createCookie(RoutingContext context, OidcTenantConfig oidcConfig,
String name, String value, long maxAge) {
+ return createCookie(context, oidcConfig, name, value, maxAge, false);
+ }
+
+ static ServerCookie createCookie(RoutingContext context, OidcTenantConfig oidcConfig,
+ String name, String value, long maxAge, boolean sessionCookie) {
ServerCookie cookie = new CookieImpl(name, value);
cookie.setHttpOnly(true);
cookie.setSecure(oidcConfig.authentication.cookieForceSecure || context.request().isSSL());
@@ -924,7 +929,9 @@ static ServerCookie createCookie(RoutingContext context, OidcTenantConfig oidcCo
if (auth.cookieDomain.isPresent()) {
cookie.setDomain(auth.getCookieDomain().get());
}
- cookie.setSameSite(CookieSameSite.valueOf(auth.cookieSameSite.name()));
+ if (sessionCookie) {
+ cookie.setSameSite(CookieSameSite.valueOf(auth.cookieSameSite.name()));
+ }
context.response().addCookie(cookie);
return cookie;
}
diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/CollectionsResource.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/CollectionsResource.java
index 853e593fb6faa..e24f791173789 100644
--- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/CollectionsResource.java
+++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/CollectionsResource.java
@@ -3,9 +3,11 @@
import io.quarkus.hibernate.reactive.rest.data.panache.PanacheRepositoryResource;
import io.quarkus.rest.data.panache.MethodProperties;
import io.quarkus.rest.data.panache.ResourceProperties;
+import io.smallrye.mutiny.Uni;
@ResourceProperties(hal = true, paged = false, halCollectionName = "item-collections", rolesAllowed = "user")
public interface CollectionsResource extends PanacheRepositoryResource {
+
@MethodProperties(rolesAllowed = "admin")
- boolean delete(String name);
+ Uni delete(String name);
}
diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourcePathCustomisationTest.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourcePathCustomisationTest.java
index d2eee7539c501..276493f06b93f 100644
--- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourcePathCustomisationTest.java
+++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourcePathCustomisationTest.java
@@ -11,6 +11,7 @@
import io.quarkus.rest.data.panache.MethodProperties;
import io.quarkus.rest.data.panache.ResourceProperties;
import io.quarkus.test.QuarkusUnitTest;
+import io.smallrye.mutiny.Uni;
class PanacheRepositoryResourcePathCustomisationTest extends AbstractPathCustomisationTest {
@@ -27,18 +28,18 @@ public interface CustomPathCollectionsResource
extends PanacheRepositoryResource {
@MethodProperties(path = "api")
- List list(Page page, Sort sort);
+ Uni> list(Page page, Sort sort);
@MethodProperties(path = "api")
- Collection get(String name);
+ Uni get(String name);
@MethodProperties(path = "api")
- Collection add(Collection collection);
+ Uni add(Collection collection);
@MethodProperties(path = "api")
- Collection update(String name, Collection collection);
+ Uni update(String name, Collection collection);
@MethodProperties(path = "api")
- boolean delete(String name);
+ Uni delete(String name);
}
}
diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/PanacheRepositoryResource.java b/extensions/panache/hibernate-reactive-rest-data-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/PanacheRepositoryResource.java
index 8fa61c3a2e5ca..27a7edfb55fc9 100644
--- a/extensions/panache/hibernate-reactive-rest-data-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/PanacheRepositoryResource.java
+++ b/extensions/panache/hibernate-reactive-rest-data-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/PanacheRepositoryResource.java
@@ -2,6 +2,7 @@
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import io.quarkus.rest.data.panache.MethodProperties;
+import io.quarkus.rest.data.panache.ReactiveRestDataResource;
import io.quarkus.rest.data.panache.ResourceProperties;
import io.quarkus.rest.data.panache.RestDataResource;
@@ -18,6 +19,6 @@
* @param ID type of the entity.
*/
public interface PanacheRepositoryResource, Entity, ID>
- extends RestDataResource {
+ extends ReactiveRestDataResource {
}
diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/RolesAllowedResource.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/RolesAllowedResource.java
index 16fc9378d18f5..5c612b4a7cd1e 100644
--- a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/RolesAllowedResource.java
+++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/RolesAllowedResource.java
@@ -2,15 +2,22 @@
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
+import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
+import io.quarkus.security.identity.CurrentIdentityAssociation;
+
/**
* @author Michal Szynkiewicz, michal.l.szynkiewicz@gmail.com
*/
@Path("/roles")
@PermitAll
public class RolesAllowedResource {
+
+ @Inject
+ CurrentIdentityAssociation currentIdentityAssociation;
+
@GET
@RolesAllowed({ "user", "admin" })
public String defaultSecurity() {
@@ -24,4 +31,10 @@ public String admin() {
return "admin";
}
+ @Path("/admin/security-identity")
+ @RolesAllowed("admin")
+ @GET
+ public String getSecurityIdentity() {
+ return currentIdentityAssociation.getIdentity().getPrincipal().getName();
+ }
}
diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/SecurityIdentityAugmentorTest.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/SecurityIdentityAugmentorTest.java
new file mode 100644
index 0000000000000..92ceac105166e
--- /dev/null
+++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/SecurityIdentityAugmentorTest.java
@@ -0,0 +1,67 @@
+package io.quarkus.resteasy.test.security;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.control.ActivateRequestContext;
+
+import org.hamcrest.Matchers;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.builder.Version;
+import io.quarkus.maven.dependency.Dependency;
+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.TestIdentityController;
+import io.quarkus.security.test.utils.TestIdentityProvider;
+import io.quarkus.test.QuarkusUnitTest;
+import io.restassured.RestAssured;
+import io.smallrye.mutiny.Uni;
+
+public class SecurityIdentityAugmentorTest {
+
+ @RegisterExtension
+ static QuarkusUnitTest runner = new QuarkusUnitTest()
+ .withApplicationRoot((jar) -> jar
+ .addAsResource(new StringAsset("quarkus.http.auth.basic=true\n"), "application.properties")
+ .addClasses(TestIdentityProvider.class, RolesAllowedResource.class, TestIdentityController.class))
+ .setForcedDependencies(List.of(Dependency.of("io.quarkus", "quarkus-undertow", Version.getVersion())));
+
+ @BeforeAll
+ public static void setupUsers() {
+ TestIdentityController.resetRoles().add("admin", "admin");
+ }
+
+ @Test
+ public void testSecurityIdentityAugmentor() {
+ RestAssured.given().auth().basic("admin", "admin").get("/roles/admin/security-identity").then().statusCode(200)
+ .body(Matchers.is("admin"));
+ }
+
+ @ApplicationScoped
+ public static class CustomAugmentor implements SecurityIdentityAugmentor {
+
+ @Override
+ public Uni augment(SecurityIdentity identity, AuthenticationRequestContext context) {
+ if (identity.isAnonymous()) {
+ return Uni.createFrom().item(identity);
+ }
+ return context.runBlocking(build(identity));
+ }
+
+ @ActivateRequestContext
+ Supplier build(SecurityIdentity identity) {
+ QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(identity);
+ builder.addRole("admin");
+ return builder::build;
+ }
+
+ }
+
+}
diff --git a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java
index 0975c2cce33f4..aabc3a1964e85 100644
--- a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java
+++ b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java
@@ -564,6 +564,15 @@ public T call(HttpServerExchange exchange, C context) throws Exception {
// Not sure what to do here
ManagedContext requestContext = beanContainer.requestContext();
if (requestContext.isActive()) {
+ if (currentVertxRequest.getCurrent() == null && exchange != null
+ && exchange.getDelegate() instanceof VertxHttpExchange) {
+ // goal here is to add event to the Vert.X request when Smallrye Context Propagation
+ // creates fresh instance of request context without the event; we experienced
+ // the request context activated and terminated by ActivateRequestContextInterceptor
+ // invoked for the SecurityIdentityAugmentor that was (re)created during permission checks
+ addEventToVertxRequest(exchange);
+ }
+
return action.call(exchange, context);
} else if (exchange == null) {
requestContext.activate();
@@ -578,9 +587,7 @@ public T call(HttpServerExchange exchange, C context) throws Exception {
try {
requestContext.activate(existingRequestContext);
- VertxHttpExchange delegate = (VertxHttpExchange) exchange.getDelegate();
- RoutingContext rc = (RoutingContext) delegate.getContext();
- currentVertxRequest.setCurrent(rc);
+ RoutingContext rc = addEventToVertxRequest(exchange);
if (association != null) {
QuarkusHttpUser existing = (QuarkusHttpUser) rc.user();
@@ -631,6 +638,13 @@ public void onStartAsync(AsyncEvent event) throws IOException {
}
}
}
+
+ private RoutingContext addEventToVertxRequest(HttpServerExchange exchange) {
+ VertxHttpExchange delegate = (VertxHttpExchange) exchange.getDelegate();
+ RoutingContext rc = (RoutingContext) delegate.getContext();
+ currentVertxRequest.setCurrent(rc);
+ return rc;
+ }
};
}
});
diff --git a/independent-projects/arc/pom.xml b/independent-projects/arc/pom.xml
index a157973981934..4b7e9db488ed1 100644
--- a/independent-projects/arc/pom.xml
+++ b/independent-projects/arc/pom.xml
@@ -43,7 +43,7 @@
2.0.2
1.3.3
3.0.5
- 5.9.1
+ 5.9.2
3.8.6
3.23.1
3.5.0.Final
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Beans.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Beans.java
index 60ca6948c5742..772c7e8b11ab3 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Beans.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Beans.java
@@ -913,7 +913,7 @@ public void visit(int version, int access, String name, String signature,
String superName,
String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
- MethodVisitor mv = visitMethod(Modifier.PUBLIC, Methods.INIT, "()V", null,
+ MethodVisitor mv = visitMethod(Modifier.PUBLIC | Opcodes.ACC_SYNTHETIC, Methods.INIT, "()V", null,
null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
diff --git a/independent-projects/bootstrap/pom.xml b/independent-projects/bootstrap/pom.xml
index 05ffd4aa556e1..c7e9b21875bcc 100644
--- a/independent-projects/bootstrap/pom.xml
+++ b/independent-projects/bootstrap/pom.xml
@@ -42,7 +42,7 @@
3.23.1
0.9.5
3.5.0.Final
- 5.9.1
+ 5.9.2
3.8.6
0.3.5
3.6.0
@@ -51,7 +51,7 @@
3.5.1
4.4.16
1.0.0.Final
- 2.14.1
+ 2.14.2
1.3.5
2.0.2
1.0
diff --git a/independent-projects/extension-maven-plugin/pom.xml b/independent-projects/extension-maven-plugin/pom.xml
index 6597a0a7787d8..18bb872a15986 100644
--- a/independent-projects/extension-maven-plugin/pom.xml
+++ b/independent-projects/extension-maven-plugin/pom.xml
@@ -35,8 +35,8 @@
11
3.0.0-M7
1.6.8
- 2.14.1
- 5.9.1
+ 2.14.2
+ 5.9.2
diff --git a/independent-projects/qute/pom.xml b/independent-projects/qute/pom.xml
index 431a5555cf1be..9be201d5d3f16 100644
--- a/independent-projects/qute/pom.xml
+++ b/independent-projects/qute/pom.xml
@@ -40,14 +40,14 @@
11
11
11
- 5.9.1
+ 5.9.2
3.23.1
3.0.5
1.6.0.Final
3.5.0.Final
3.0.0-M7
1.6.8
- 1.8.0
+ 1.9.0
diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/providers/serialisers/FileBodyHandler.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/providers/serialisers/FileBodyHandler.java
index e8cc9f3fbcf04..04d1f9fbfa4c9 100644
--- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/providers/serialisers/FileBodyHandler.java
+++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/providers/serialisers/FileBodyHandler.java
@@ -10,6 +10,7 @@
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
+import java.nio.file.Files;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
@@ -32,7 +33,7 @@ public boolean isReadable(Class> type, Type genericType, Annotation[] annotati
public File readFrom(Class type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap httpHeaders, InputStream entityStream) throws IOException {
- File downloadedFile = File.createTempFile(PREFIX, SUFFIX);
+ File downloadedFile = Files.createTempFile(PREFIX, SUFFIX).toFile();
if (HeaderUtil.isContentLengthZero(httpHeaders)) {
return downloadedFile;
}
diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml
index 51f989ad90ed8..37a22165691b8 100644
--- a/independent-projects/resteasy-reactive/pom.xml
+++ b/independent-projects/resteasy-reactive/pom.xml
@@ -43,7 +43,7 @@
2.0.2
3.0.5
1.12.12
- 5.9.1
+ 5.9.2
3.8.6
3.23.1
3.5.0.Final
@@ -55,13 +55,13 @@
1.6.8
2.0.1.Final
1.1.6
- 1.8.0
+ 1.9.0
1.13.2
4.3.5
4.5.1
1.0.0.Final
2.0.0.Final
- 2.14.1
+ 2.14.2
1.3.0
2.0.2
1.0.11
diff --git a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/multipart/MultipartTransformer.java b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/multipart/MultipartTransformer.java
index 136a806f84e9c..2fecb582fde29 100644
--- a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/multipart/MultipartTransformer.java
+++ b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/multipart/MultipartTransformer.java
@@ -70,7 +70,8 @@ public FieldVisitor visitField(int access, String name, String descriptor, Strin
@Override
public void visitEnd() {
- MethodVisitor injectMethod = visitMethod(Opcodes.ACC_PUBLIC, INJECT_METHOD_NAME, INJECT_METHOD_DESCRIPTOR, null,
+ MethodVisitor injectMethod = visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, INJECT_METHOD_NAME,
+ INJECT_METHOD_DESCRIPTOR, null,
null);
injectMethod.visitParameter("ctx", 0 /* modifiers */);
injectMethod.visitCode();
diff --git a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/ClassInjectorTransformer.java b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/ClassInjectorTransformer.java
index d93ebec5de522..ae69d399728f5 100644
--- a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/ClassInjectorTransformer.java
+++ b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/ClassInjectorTransformer.java
@@ -223,7 +223,8 @@ public void visitEnd() {
public void visitEnd() {
// FIXME: handle setters
// FIXME: handle multi fields
- MethodVisitor injectMethod = visitMethod(Opcodes.ACC_PUBLIC, INJECT_METHOD_NAME, INJECT_METHOD_DESCRIPTOR, null,
+ MethodVisitor injectMethod = visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, INJECT_METHOD_NAME,
+ INJECT_METHOD_DESCRIPTOR, null,
null);
injectMethod.visitParameter("ctx", 0 /* modifiers */);
injectMethod.visitCode();
@@ -333,7 +334,7 @@ public void visitEnd() {
if (!seenClassInit && !partTypes.isEmpty()) {
// add a class init method for the part types special fields
- MethodVisitor mv = super.visitMethod(Opcodes.ACC_STATIC, "", "()V", null, null);
+ MethodVisitor mv = super.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, "", "()V", null, null);
for (Entry entry : partTypes.entrySet()) {
generateMultipartFormStaticInit(mv, entry.getKey(), entry.getValue());
}
diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseBroadcasterImpl.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseBroadcasterImpl.java
index 1a5b77c30badc..1700f89b43a93 100644
--- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseBroadcasterImpl.java
+++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/SseBroadcasterImpl.java
@@ -1,5 +1,6 @@
package org.jboss.resteasy.reactive.server.jaxrs;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -37,8 +38,9 @@ public synchronized void onClose(Consumer onClose) {
public synchronized void register(SseEventSink sseEventSink) {
Objects.requireNonNull(sseEventSink);
checkClosed();
- if (sseEventSink instanceof SseEventSinkImpl == false)
+ if (sseEventSink instanceof SseEventSinkImpl == false) {
throw new IllegalArgumentException("Can only work with Quarkus-REST instances: " + sseEventSink);
+ }
((SseEventSinkImpl) sseEventSink).register(this);
sinks.add(sseEventSink);
}
@@ -50,20 +52,62 @@ public synchronized CompletionStage> broadcast(OutboundSseEvent event) {
CompletableFuture>[] cfs = new CompletableFuture[sinks.size()];
for (int i = 0; i < sinks.size(); i++) {
SseEventSink sseEventSink = sinks.get(i);
- cfs[i] = sseEventSink.send(event).toCompletableFuture();
+ CompletionStage> cs;
+ try {
+ cs = sseEventSink.send(event).exceptionally((t) -> {
+ // do not propagate the exception to the returned CF
+ // apparently, the goal is to close this sink and not report the error
+ // of the broadcast operation
+ notifyOnErrorListeners(sseEventSink, t);
+ return null;
+ });
+ } catch (Exception e) {
+ // do not propagate the exception to the returned CF
+ // apparently, the goal is to close this sink and not report the error
+ // of the broadcast operation
+ notifyOnErrorListeners(sseEventSink, e);
+ cs = CompletableFuture.completedFuture(null);
+ }
+ cfs[i] = cs.toCompletableFuture();
}
return CompletableFuture.allOf(cfs);
}
+ private void notifyOnErrorListeners(SseEventSink eventSink, Throwable throwable) {
+ // We have to notify close listeners if the SSE event output has been
+ // closed (either by client closing the connection (IOException) or by
+ // calling SseEventSink.close() (IllegalStateException) on the server
+ // side).
+ if (throwable instanceof IOException || throwable instanceof IllegalStateException) {
+ notifyOnCloseListeners(eventSink);
+ }
+ onErrorListeners.forEach(consumer -> {
+ consumer.accept(eventSink, throwable);
+ });
+ }
+
+ private void notifyOnCloseListeners(SseEventSink eventSink) {
+ // First remove the eventSink from the outputQueue to ensure that
+ // concurrent calls to this method will notify listeners only once for a
+ // given eventSink instance.
+ if (sinks.remove(eventSink)) {
+ onCloseListeners.forEach(consumer -> {
+ consumer.accept(eventSink);
+ });
+ }
+ }
+
private void checkClosed() {
- if (isClosed)
+ if (isClosed) {
throw new IllegalStateException("Broadcaster has been closed");
+ }
}
@Override
public synchronized void close() {
- if (isClosed)
+ if (isClosed) {
return;
+ }
isClosed = true;
for (SseEventSink sink : sinks) {
// this will in turn fire close events to our listeners
diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml
index a650cd7361cbd..30fb2f3cec3b1 100644
--- a/independent-projects/tools/pom.xml
+++ b/independent-projects/tools/pom.xml
@@ -49,9 +49,9 @@
3.23.1
- 2.14.1
+ 2.14.2
2.0.2
- 5.9.1
+ 5.9.2
1.22
3.5.0.Final
3.8.6
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 0f4f9ad874da3..67f549bef42b0 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
@@ -55,9 +55,9 @@ public void testCodeFlowNoConsent() throws IOException {
.loadWebResponse(new WebRequest(URI.create("http://localhost:8081/index.html").toURL()));
verifyLocationHeader(webClient, webResponse.getResponseHeaderValue("location"), null, "web-app", false);
- String stateCookieString = webResponse.getResponseHeaderValue("Set-Cookie");
- assertTrue(stateCookieString.startsWith("q_auth_Default_test="));
- assertTrue(stateCookieString.contains("SameSite=Strict"));
+ Cookie stateCookie = getStateCookie(webClient, null);
+ assertNotNull(stateCookie);
+ assertNull(stateCookie.getSameSite());
webClient.getCookieManager().clearCookies();
@@ -86,15 +86,16 @@ public void testCodeFlowNoConsent() throws IOException {
assertEquals(
client.getAuthServerUrl(),
- page.asText());
+ page.asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app/configMetadataScopes");
- assertTrue(page.asText().contains("openid"));
- assertTrue(page.asText().contains("profile"));
+ assertTrue(page.asNormalizedText().contains("openid"));
+ assertTrue(page.asNormalizedText().contains("profile"));
Cookie sessionCookie = getSessionCookie(webClient, null);
assertNotNull(sessionCookie);
+ assertEquals("strict", sessionCookie.getSameSite());
webClient.getCookieManager().clearCookies();
}
@@ -157,7 +158,7 @@ public void testCodeFlowScopeErrorWithErrorPage() throws IOException {
HtmlPage page = webClient.getPage(URI.create(endpointErrorLocation).toURL());
assertEquals("code: b, error: invalid_scope, error_description: Invalid scopes: unknown",
- page.getBody().asText());
+ page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -176,10 +177,6 @@ public void testCodeFlowForceHttpsRedirectUriAndPkce() throws Exception {
verifyLocationHeader(webClient, keycloakUrl, "tenant-https_test", "xforwarded%2Ftenant-https",
true);
- String stateCookieString = webResponse.getResponseHeaderValue("Set-Cookie");
- assertTrue(stateCookieString.startsWith("q_auth_tenant-https_test="));
- assertTrue(stateCookieString.contains("SameSite=Lax"));
-
HtmlPage page = webClient.getPage(keycloakUrl);
assertEquals("Sign in to quarkus", page.getTitleText());
@@ -195,6 +192,7 @@ public void testCodeFlowForceHttpsRedirectUriAndPkce() throws Exception {
String endpointLocation = webResponse.getResponseHeaderValue("location");
Cookie stateCookie = getStateCookie(webClient, "tenant-https_test");
+ assertNull(stateCookie.getSameSite());
verifyCodeVerifier(stateCookie, keycloakUrl);
assertTrue(endpointLocation.startsWith("https"));
@@ -219,9 +217,10 @@ public void testCodeFlowForceHttpsRedirectUriAndPkce() throws Exception {
assertNull(endpointLocationWithoutQueryUri.getRawQuery());
page = webClient.getPage(endpointLocationWithoutQueryUri.toURL());
- assertEquals("tenant-https:reauthenticated", page.getBody().asText());
+ assertEquals("tenant-https:reauthenticated", page.getBody().asNormalizedText());
Cookie sessionCookie = getSessionCookie(webClient, "tenant-https_test");
assertNotNull(sessionCookie);
+ assertEquals("lax", sessionCookie.getSameSite());
webClient.getCookieManager().clearCookies();
}
}
@@ -279,7 +278,7 @@ public void testCodeFlowForceHttpsRedirectUriWithQueryAndPkce() throws Exception
JsonObject idToken = OidcUtils.decodeJwtContent(sessionCookie.getValue().split("\\|")[0]);
String expiresAt = idToken.getInteger("exp").toString();
page = webClient.getPage(endpointLocationWithoutQueryUri.toURL());
- String response = page.getBody().asText();
+ String response = page.getBody().asNormalizedText();
assertTrue(
response.startsWith("tenant-https:reauthenticated?code=b&expiresAt=" + expiresAt + "&expiresInDuration="));
Integer duration = Integer.valueOf(response.substring(response.length() - 1));
@@ -430,11 +429,11 @@ public void testRPInitiatedLogout() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("Tenant Logout, refreshed: false", page.asText());
+ assertEquals("Tenant Logout, refreshed: false", page.asNormalizedText());
assertNotNull(getSessionCookie(webClient, "tenant-logout"));
page = webClient.getPage("http://localhost:8081/tenant-logout/logout");
- assertTrue(page.asText().contains("You were logged out"));
+ assertTrue(page.asNormalizedText().contains("You were logged out"));
assertNull(getSessionCookie(webClient, "tenant-logout"));
page = webClient.getPage("http://localhost:8081/tenant-logout");
@@ -452,7 +451,7 @@ public void testTokenRefresh() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("Tenant Refresh, refreshed: false", page.asText());
+ assertEquals("Tenant Refresh, refreshed: false", page.asNormalizedText());
Cookie sessionCookie = getSessionCookie(webClient, "tenant-refresh");
assertNotNull(sessionCookie);
@@ -479,7 +478,7 @@ public Boolean call() throws Exception {
// local session refreshed and still valid
page = webClient.getPage("http://localhost:8081/tenant-refresh");
- assertEquals("Tenant Refresh, refreshed: false", page.asText());
+ assertEquals("Tenant Refresh, refreshed: false", page.asNormalizedText());
assertNotNull(getSessionCookie(webClient, "tenant-refresh"));
//wait now so that we reach the refresh timeout
@@ -526,7 +525,7 @@ public void testTokenAutoRefresh() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("Tenant AutoRefresh, refreshed: false", page.asText());
+ assertEquals("Tenant AutoRefresh, refreshed: false", page.asNormalizedText());
Cookie sessionCookie = getSessionCookie(webClient, "tenant-autorefresh");
assertNotNull(sessionCookie);
@@ -535,7 +534,7 @@ public void testTokenAutoRefresh() throws IOException {
// Auto-refresh-interval is 30 secs so every call auto-refreshes the token
// Right now the original ID token is still valid but will be auto-refreshed
page = webClient.getPage("http://localhost:8081/tenant-autorefresh");
- assertEquals("Tenant AutoRefresh, refreshed: true", page.asText());
+ assertEquals("Tenant AutoRefresh, refreshed: true", page.asNormalizedText());
sessionCookie = getSessionCookie(webClient, "tenant-autorefresh");
assertNotNull(sessionCookie);
String nextIdToken = getIdToken(sessionCookie);
@@ -564,7 +563,7 @@ public void testIdTokenInjection() throws IOException {
page = webClient.getPage("http://localhost:8081/web-app");
- assertEquals("alice", page.getBody().asText());
+ assertEquals("alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -585,7 +584,7 @@ public void testIdTokenInjectionWithoutRestoredPath() throws IOException, Interr
page = loginForm.getInputByName("login").click();
- assertEquals("callback:alice", page.getBody().asText());
+ assertEquals("callback:alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -621,7 +620,7 @@ public void testIdTokenInjectionJwtMethod() throws IOException, InterruptedExcep
assertNull(endpointLocationUri2.getRawQuery());
page = webClient.getPage(endpointLocationUri2.toString());
- assertEquals("callback-jwt:alice", page.getBody().asText());
+ assertEquals("callback-jwt:alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -667,11 +666,11 @@ public void testIdTokenInjectionWithoutRestoredPathDifferentRoot() throws IOExce
page = loginForm.getInputByName("login").click();
- assertEquals("web-app2:alice", page.getBody().asText());
+ assertEquals("web-app2:alice", page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app2/name");
- assertEquals("web-app2:alice", page.getBody().asText());
+ assertEquals("web-app2:alice", page.getBody().asNormalizedText());
assertNull(getStateCookie(webClient, "tenant-2"));
Cookie sessionCookie = getSessionCookie(webClient, "tenant-2");
@@ -735,7 +734,7 @@ public void testAuthenticationCompletionFailedWrongRedirectUri() throws IOExcept
loginForm.getInputByName("password").setValueAttribute("alice");
try {
page = loginForm.getInputByName("login").click();
- fail("401 status error is expected: " + page.getBody().asText());
+ fail("401 status error is expected: " + page.getBody().asNormalizedText());
} catch (FailingHttpStatusCodeException ex) {
assertEquals(401, ex.getStatusCode());
assertEquals("http://localhost:8081/web-app/callback-before-wrong-redirect",
@@ -764,7 +763,7 @@ public void testAccessTokenInjection() throws IOException {
page = webClient.getPage("http://localhost:8081/web-app/access");
- assertEquals("AT injected", page.getBody().asText());
+ assertEquals("AT injected", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -788,7 +787,7 @@ public void testAccessAndRefreshTokenInjection() throws IOException {
page = webClient.getPage("http://localhost:8081/web-app/refresh");
- assertEquals("RT injected", page.getBody().asText());
+ assertEquals("RT injected", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -808,7 +807,7 @@ public void testAccessAndRefreshTokenInjectionWithoutIndexHtml() throws IOExcept
page = loginForm.getInputByName("login").click();
- assertEquals("RT injected", page.getBody().asText());
+ assertEquals("RT injected", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -827,12 +826,12 @@ public void testDefaultSessionManagerIdTokenOnly() throws IOException, Interrupt
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("tenant-idtoken-only:alice", page.getBody().asText());
+ assertEquals("tenant-idtoken-only:alice", page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app/access/tenant-idtoken-only");
- assertEquals("tenant-idtoken-only:no access", page.getBody().asText());
+ assertEquals("tenant-idtoken-only:no access", page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app/refresh/tenant-idtoken-only");
- assertEquals("tenant-idtoken-only:no refresh", page.getBody().asText());
+ assertEquals("tenant-idtoken-only:no refresh", page.getBody().asNormalizedText());
Cookie idTokenCookie = getSessionCookie(page.getWebClient(), "tenant-idtoken-only");
checkSingleTokenCookie(idTokenCookie, "ID");
@@ -858,12 +857,12 @@ public void testDefaultSessionManagerIdRefreshTokens() throws IOException, Inter
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("tenant-id-refresh-token:alice", page.getBody().asText());
+ assertEquals("tenant-id-refresh-token:alice", page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app/access/tenant-id-refresh-token");
- assertEquals("tenant-id-refresh-token:no access", page.getBody().asText());
+ assertEquals("tenant-id-refresh-token:no access", page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app/refresh/tenant-id-refresh-token");
- assertEquals("tenant-id-refresh-token:RT injected", page.getBody().asText());
+ assertEquals("tenant-id-refresh-token:RT injected", page.getBody().asNormalizedText());
Cookie idTokenCookie = getSessionCookie(page.getWebClient(), "tenant-id-refresh-token");
String[] parts = idTokenCookie.getValue().split("\\|");
@@ -894,12 +893,12 @@ public void testDefaultSessionManagerSplitTokens() throws IOException, Interrupt
page = loginForm.getInputByName("login").click();
assertEquals("tenant-split-tokens:alice, id token has 5 parts, access token has 5 parts, refresh token has 5 parts",
- page.getBody().asText());
+ page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app/access/tenant-split-tokens");
- assertEquals("tenant-split-tokens:AT injected", page.getBody().asText());
+ assertEquals("tenant-split-tokens:AT injected", page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app/refresh/tenant-split-tokens");
- assertEquals("tenant-split-tokens:RT injected", page.getBody().asText());
+ assertEquals("tenant-split-tokens:RT injected", page.getBody().asNormalizedText());
Cookie idTokenCookie = getSessionCookie(page.getWebClient(), "tenant-split-tokens");
checkSingleTokenCookie(idTokenCookie, "ID", true);
@@ -949,12 +948,12 @@ public void testDefaultSessionManagerIdRefreshSplitTokens() throws IOException,
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("tenant-split-id-refresh-token:alice", page.getBody().asText());
+ assertEquals("tenant-split-id-refresh-token:alice", page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app/access/tenant-split-id-refresh-token");
- assertEquals("tenant-split-id-refresh-token:no access", page.getBody().asText());
+ assertEquals("tenant-split-id-refresh-token:no access", page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/web-app/refresh/tenant-split-id-refresh-token");
- assertEquals("tenant-split-id-refresh-token:RT injected", page.getBody().asText());
+ assertEquals("tenant-split-id-refresh-token:RT injected", page.getBody().asNormalizedText());
Cookie idTokenCookie = getSessionCookie(page.getWebClient(), "tenant-split-id-refresh-token");
checkSingleTokenCookie(idTokenCookie, "ID");
@@ -1026,7 +1025,8 @@ public void testAccessAndRefreshTokenInjectionWithoutIndexHtmlAndListener() thro
page = loginForm.getInputByName("login").click();
- assertEquals("RT injected(event:OIDC_LOGIN,tenantId:tenant-listener,blockingApi:true)", page.getBody().asText());
+ assertEquals("RT injected(event:OIDC_LOGIN,tenantId:tenant-listener,blockingApi:true)",
+ page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -1046,7 +1046,7 @@ public void testAccessAndRefreshTokenInjectionWithQuery() throws Exception {
page = loginForm.getInputByName("login").click();
- assertEquals("RT injected:aValue", page.getBody().asText());
+ assertEquals("RT injected:aValue", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -1129,7 +1129,7 @@ public void testCustomLogin() throws Exception {
page = loginForm.getInputByName("login").click();
- assertEquals("alice", page.getBody().asText());
+ assertEquals("alice", page.getBody().asNormalizedText());
}
}
diff --git a/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java b/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java
index 1608749e307e6..4079d17c26ff5 100644
--- a/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java
+++ b/integration-tests/oidc-tenancy/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java
@@ -56,19 +56,19 @@ public void testResolveTenantIdentifierWebApp() throws IOException {
// First call after a redirect, tenant-id is initially calculated from the state `q_auth` cookie.
// 'reauthenticated' flag is set is because, in fact, it is actually a 2nd call due to
// quarkus-oidc doing a final redirect after completing a code flow to drop the redirect OIDC parameters
- assertEquals("tenant-web-app:alice:reauthenticated", page.getBody().asText());
+ assertEquals("tenant-web-app:alice:reauthenticated", page.getBody().asNormalizedText());
assertNotNull(getSessionCookie(webClient, "tenant-web-app"));
assertNull(getStateCookie(webClient, "tenant-web-app"));
// Second call after a redirect, tenant-id is calculated from the state `q_session` cookie
page = webClient.getPage("http://localhost:8081/tenant/tenant-web-app/api/user/webapp");
- assertEquals("tenant-web-app:alice:reauthenticated", page.getBody().asText());
+ assertEquals("tenant-web-app:alice:reauthenticated", page.getBody().asNormalizedText());
assertNotNull(getSessionCookie(webClient, "tenant-web-app"));
assertNull(getStateCookie(webClient, "tenant-web-app"));
// Local logout
page = webClient.getPage("http://localhost:8081/tenant/tenant-web-app/api/user/webapp?logout=true");
- assertEquals("tenant-web-app:alice:reauthenticated:logout", page.getBody().asText());
+ assertEquals("tenant-web-app:alice:reauthenticated:logout", page.getBody().asNormalizedText());
assertNull(getSessionCookie(webClient, "tenant-web-app"));
assertNull(getStateCookie(webClient, "tenant-web-app"));
@@ -98,7 +98,7 @@ public void testResolveTenantIdentifierWebApp2() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("tenant-web-app2:alice", page.getBody().asText());
+ assertEquals("tenant-web-app2:alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -114,7 +114,7 @@ public void testCodeFlowRefreshTokens() throws IOException, InterruptedException
page = loginForm.getInputByName("login").click();
assertEquals("userName: alice, idToken: true, accessToken: true, refreshToken: true",
- page.getBody().asText());
+ page.getBody().asNormalizedText());
Cookie sessionCookie = getSessionCookie(page.getWebClient(), "tenant-web-app-refresh");
assertNotNull(sessionCookie);
@@ -181,7 +181,7 @@ public void testHybridWebApp() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("alice:web-app", page.getBody().asText());
+ assertEquals("alice:web-app", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -205,7 +205,7 @@ public void testHybridWebAppService() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("alice:web-app", page.getBody().asText());
+ assertEquals("alice:web-app", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
RestAssured.given().auth().oauth2(getAccessToken("alice", "hybrid"))
@@ -228,10 +228,10 @@ public void testResolveTenantIdentifierWebAppNoDiscovery() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("tenant-web-app-no-discovery:alice", page.getBody().asText());
+ assertEquals("tenant-web-app-no-discovery:alice", page.getBody().asNormalizedText());
page = webClient.getPage("http://localhost:8081/tenant/tenant-web-app-no-discovery/api/user/webapp-no-discovery");
- assertEquals("tenant-web-app-no-discovery:alice", page.getBody().asText());
+ assertEquals("tenant-web-app-no-discovery:alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
@@ -247,7 +247,7 @@ public void testReAuthenticateWhenSwitchingTenants() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("tenant-web-app:alice:reauthenticated", page.getBody().asText());
+ assertEquals("tenant-web-app:alice:reauthenticated", page.getBody().asNormalizedText());
// tenant-web-app2
page = webClient.getPage("http://localhost:8081/tenant/tenant-web-app2/api/user/webapp2");
assertNull(getStateCookieSavedPath(webClient, "tenant-web-app2"));
@@ -256,7 +256,7 @@ public void testReAuthenticateWhenSwitchingTenants() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("tenant-web-app2:alice", page.getBody().asText());
+ assertEquals("tenant-web-app2:alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
@@ -568,7 +568,7 @@ public void testResolveTenantIdentifierWebAppDynamic() throws IOException {
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
- assertEquals("tenant-web-app-dynamic:alice", page.getBody().asText());
+ assertEquals("tenant-web-app-dynamic:alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}
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 ce862339115e9..7bbd13ba2e3cb 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
@@ -69,11 +69,11 @@ public void testCodeFlow() throws IOException {
page = form.getInputByValue("login").click();
- assertEquals("alice, cache size: 0", page.getBody().asText());
+ assertEquals("alice, cache size: 0", page.getBody().asNormalizedText());
assertNotNull(getSessionCookie(webClient, "code-flow"));
page = webClient.getPage("http://localhost:8081/code-flow/logout");
- assertEquals("Welcome, clientId: quarkus-web-app", page.getBody().asText());
+ assertEquals("Welcome, clientId: quarkus-web-app", page.getBody().asNormalizedText());
assertNull(getSessionCookie(webClient, "code-flow"));
// Clear the post logout cookie
webClient.getCookieManager().clearCookies();
@@ -97,7 +97,7 @@ private void doTestCodeFlowEncryptedIdToken(String tenant) throws IOException {
page = form.getInputByValue("login").click();
- assertEquals("user: alice", page.getBody().asText());
+ assertEquals("user: alice", page.getBody().asNormalizedText());
Cookie sessionCookie = getSessionCookie(webClient, tenant);
assertNotNull(sessionCookie);
// default session cookie format: "idtoken|accesstoken|refreshtoken"
@@ -105,7 +105,7 @@ private void doTestCodeFlowEncryptedIdToken(String tenant) throws IOException {
// repeat the call with the session cookie containing the encrypted id token
page = webClient.getPage("http://localhost:8081/code-flow-encrypted-id-token/" + tenant);
- assertEquals("user: alice", page.getBody().asText());
+ assertEquals("user: alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
@@ -124,12 +124,12 @@ public void testCodeFlowFormPostAndBackChannelLogout() throws IOException {
page = form.getInputByValue("login").click();
- assertEquals("alice", page.getBody().asText());
+ assertEquals("alice", page.getBody().asNormalizedText());
assertNotNull(getSessionCookie(webClient, "code-flow-form-post"));
page = webClient.getPage("http://localhost:8081/code-flow-form-post");
- assertEquals("alice", page.getBody().asText());
+ assertEquals("alice", page.getBody().asNormalizedText());
// Session is still active
assertNotNull(getSessionCookie(webClient, "code-flow-form-post"));
@@ -166,12 +166,12 @@ public void testCodeFlowFormPostAndFrontChannelLogout() throws IOException {
page = form.getInputByValue("login").click();
- assertEquals("alice", page.getBody().asText());
+ assertEquals("alice", page.getBody().asNormalizedText());
assertNotNull(getSessionCookie(webClient, "code-flow-form-post"));
page = webClient.getPage("http://localhost:8081/code-flow-form-post");
- assertEquals("alice", page.getBody().asText());
+ assertEquals("alice", page.getBody().asNormalizedText());
// Session is still active
Cookie sessionCookie = getSessionCookie(webClient, "code-flow-form-post");
@@ -225,7 +225,7 @@ private void doTestCodeFlowUserInfo(String tenantId, long internalIdTokenLifetim
page = form.getInputByValue("login").click();
- assertEquals("alice:alice:alice, cache size: 1", page.getBody().asText());
+ assertEquals("alice:alice:alice, cache size: 1", page.getBody().asNormalizedText());
Cookie sessionCookie = getSessionCookie(webClient, tenantId);
assertNotNull(sessionCookie);
@@ -250,7 +250,7 @@ private void doTestCodeFlowUserInfoCashedInIdToken() throws Exception {
page = form.getInputByValue("login").click();
- assertEquals("alice:alice:alice, cache size: 0", page.getBody().asText());
+ assertEquals("alice:alice:alice, cache size: 0", page.getBody().asNormalizedText());
Cookie sessionCookie = getSessionCookie(webClient, "code-flow-user-info-github-cached-in-idtoken");
assertNotNull(sessionCookie);
@@ -260,7 +260,7 @@ private void doTestCodeFlowUserInfoCashedInIdToken() throws Exception {
// refresh
Thread.sleep(3000);
page = webClient.getPage("http://localhost:8081/code-flow-user-info-github-cached-in-idtoken");
- assertEquals("alice:alice:bob, cache size: 0", page.getBody().asText());
+ assertEquals("alice:alice:bob, cache size: 0", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
diff --git a/integration-tests/smallrye-jwt-oidc-webapp/src/test/java/io/quarkus/it/keycloak/SmallRyeJwtOidcWebAppTest.java b/integration-tests/smallrye-jwt-oidc-webapp/src/test/java/io/quarkus/it/keycloak/SmallRyeJwtOidcWebAppTest.java
index ac0f1e81522da..54fb9c01b92db 100644
--- a/integration-tests/smallrye-jwt-oidc-webapp/src/test/java/io/quarkus/it/keycloak/SmallRyeJwtOidcWebAppTest.java
+++ b/integration-tests/smallrye-jwt-oidc-webapp/src/test/java/io/quarkus/it/keycloak/SmallRyeJwtOidcWebAppTest.java
@@ -75,7 +75,7 @@ public void testGetUserNameWithCodeFlow() throws Exception {
page = loginForm.getInputByName("login").click();
- assertEquals("alice", page.getBody().asText());
+ assertEquals("alice", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
}