diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 52a87a02356fc..c937f51950862 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -178,7 +178,7 @@ 5.12.0 5.8.0 2.1.0 - 24.0.4 + 25.0.0 1.15.1 3.44.0 2.28.0 @@ -5959,18 +5959,6 @@ ${quarkus-spring-boot-api.version} - - - org.keycloak - keycloak-adapter-core - ${keycloak.version} - - - commons-logging - commons-logging - - - org.keycloak keycloak-core diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 1dd725b5233a9..48dfabb947163 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -102,7 +102,7 @@ - 24.0.4 + 25.0.0 19.0.3 quay.io/keycloak/keycloak:${keycloak.version} quay.io/keycloak/keycloak:${keycloak.wildfly.version}-legacy diff --git a/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc b/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc index 32ebe11900fc0..f8d398f50a74d 100644 --- a/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc @@ -258,7 +258,7 @@ For more information, see xref:security-oidc-bearer-token-authentication.adoc#in [[keycloak-initialization]] === Keycloak initialization -The `quay.io/keycloak/keycloak:24.0.4` image which contains a Keycloak distribution powered by Quarkus is used to start a container by default. +The `quay.io/keycloak/keycloak:25.0.0` image which contains a Keycloak distribution powered by Quarkus is used to start a container by default. `quarkus.keycloak.devservices.image-name` can be used to change the Keycloak image name. For example, set it to `quay.io/keycloak/keycloak:19.0.3-legacy` to use a Keycloak distribution powered by WildFly. Be aware that a Quarkus-based Keycloak distribution is only available starting from Keycloak `20.0.0`. diff --git a/extensions/keycloak-admin-resteasy-client/runtime/pom.xml b/extensions/keycloak-admin-resteasy-client/runtime/pom.xml index 8d372fe884843..00afe7ca465f6 100644 --- a/extensions/keycloak-admin-resteasy-client/runtime/pom.xml +++ b/extensions/keycloak-admin-resteasy-client/runtime/pom.xml @@ -30,10 +30,6 @@ io.quarkus quarkus-resteasy-client-jaxb - - org.keycloak - keycloak-adapter-core - org.keycloak keycloak-core diff --git a/extensions/oidc-client/deployment/pom.xml b/extensions/oidc-client/deployment/pom.xml index 7c9b963b973d0..bfed4a40847b6 100644 --- a/extensions/oidc-client/deployment/pom.xml +++ b/extensions/oidc-client/deployment/pom.xml @@ -49,11 +49,6 @@ rest-assured test - - org.keycloak - keycloak-adapter-core - test - org.keycloak keycloak-core diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java index 5a9ace88d43d5..9f71002fb2e7f 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java @@ -34,7 +34,7 @@ public class DevServicesConfig { * ends with `-legacy`. * Override with `quarkus.keycloak.devservices.keycloak-x-image`. */ - @ConfigItem(defaultValue = "quay.io/keycloak/keycloak:24.0.4") + @ConfigItem(defaultValue = "quay.io/keycloak/keycloak:25.0.0") public String imageName; /** diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java index f7f2e1cdff083..4ab77d13b638a 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java @@ -109,7 +109,7 @@ public class KeycloakDevServicesProcessor { private static final String KEYCLOAK_QUARKUS_HOSTNAME = "KC_HOSTNAME"; private static final String KEYCLOAK_QUARKUS_ADMIN_PROP = "KEYCLOAK_ADMIN"; private static final String KEYCLOAK_QUARKUS_ADMIN_PASSWORD_PROP = "KEYCLOAK_ADMIN_PASSWORD"; - private static final String KEYCLOAK_QUARKUS_START_CMD = "start --http-enabled=true --hostname-strict=false --hostname-strict-https=false " + private static final String KEYCLOAK_QUARKUS_START_CMD = "start --http-enabled=true --hostname-strict=false " + "--spi-user-profile-declarative-user-profile-config-file=/opt/keycloak/upconfig.json"; private static final String JAVA_OPTS = "JAVA_OPTS"; diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java index 1797e8f2812ce..70e50c2a359e3 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java @@ -431,7 +431,7 @@ private static JsonObject getRolesJson(Map requestData, TenantCo private Uni verifyCodeFlowAccessTokenUni(Map requestData, TokenAuthenticationRequest request, TenantConfigContext resolvedContext, UserInfo userInfo) { - if (request.getToken() instanceof IdTokenCredential + if (isIdToken(request) && (resolvedContext.oidcConfig.authentication.verifyAccessToken || resolvedContext.oidcConfig.roles.source.orElse(null) == Source.accesstoken)) { final String codeAccessToken = (String) requestData.get(OidcConstants.ACCESS_TOKEN_VALUE); @@ -469,7 +469,7 @@ private Uni verifyTokenUni(Map requestD return introspectTokenUni(resolvedContext, token, false); } else if (resolvedContext.oidcConfig.jwks.resolveEarly) { // Verify JWT token with the local JWK keys with a possible remote introspection fallback - final String nonce = (String) requestData.get(OidcConstants.NONCE); + final String nonce = tokenCred instanceof IdTokenCredential ? (String) requestData.get(OidcConstants.NONCE) : null; try { LOG.debug("Verifying the JWT token with the local JWK keys"); return Uni.createFrom() diff --git a/integration-tests/oidc-client-reactive/pom.xml b/integration-tests/oidc-client-reactive/pom.xml index 35cb2616b04d7..3ea6362e1a7f0 100644 --- a/integration-tests/oidc-client-reactive/pom.xml +++ b/integration-tests/oidc-client-reactive/pom.xml @@ -19,10 +19,6 @@ - - org.keycloak - keycloak-adapter-core - org.keycloak keycloak-core diff --git a/integration-tests/oidc-client/pom.xml b/integration-tests/oidc-client/pom.xml index d121b609b21bd..5cb7970336c4d 100644 --- a/integration-tests/oidc-client/pom.xml +++ b/integration-tests/oidc-client/pom.xml @@ -20,10 +20,6 @@ - - org.keycloak - keycloak-adapter-core - org.keycloak keycloak-core diff --git a/integration-tests/oidc-code-flow/pom.xml b/integration-tests/oidc-code-flow/pom.xml index fb37f2ceb8635..5edca73ef37c8 100644 --- a/integration-tests/oidc-code-flow/pom.xml +++ b/integration-tests/oidc-code-flow/pom.xml @@ -51,11 +51,6 @@ quarkus-test-keycloak-server test - - org.keycloak - keycloak-adapter-core - test - org.keycloak keycloak-core diff --git a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java index 759473eea051a..22a1a4056aff9 100644 --- a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java +++ b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/CustomTenantResolver.java @@ -57,8 +57,7 @@ public String resolve(RoutingContext context) { } if (path.contains("tenant-https")) { - if (context.getCookie("q_session_tenant-https_test_chunk_1") != null - && context.getCookie("q_session_tenant-https_test_chunk_2") != null) { + if (context.getCookie("q_session_tenant-https_test") != null) { context.put("reauthenticated", "true"); return context.get(OidcUtils.TENANT_ID_ATTRIBUTE); } else { @@ -67,8 +66,7 @@ public String resolve(RoutingContext context) { } if (path.contains("tenant-nonce")) { - if (context.getCookie("q_session_tenant-nonce_chunk_1") != null - && context.getCookie("q_session_tenant-nonce_chunk_2") != null) { + if (context.getCookie("q_session_tenant-nonce") != null) { context.put("reauthenticated", "true"); return context.get(OidcUtils.TENANT_ID_ATTRIBUTE); } else { 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 e4d0d732f453f..9629c61ce5dab 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 @@ -13,11 +13,7 @@ import java.net.URI; import java.nio.charset.StandardCharsets; import java.time.Duration; -import java.util.ArrayList; import java.util.Base64; -import java.util.List; -import java.util.SortedMap; -import java.util.TreeMap; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; @@ -25,7 +21,6 @@ import javax.crypto.spec.SecretKeySpec; import org.hamcrest.Matchers; -import org.htmlunit.CookieManager; import org.htmlunit.FailingHttpStatusCodeException; import org.htmlunit.SilentCssErrorHandler; import org.htmlunit.TextPage; @@ -228,9 +223,8 @@ public void testCodeFlowForceHttpsRedirectUriAndPkce() throws Exception { page = webClient.getPage(endpointLocationWithoutQueryUri.toURL()); assertEquals("tenant-https:reauthenticated", page.getBody().asNormalizedText()); - List sessionCookies = verifyTenantHttpTestCookies(webClient); - assertEquals("strict", sessionCookies.get(0).getSameSite()); - assertEquals("strict", sessionCookies.get(1).getSameSite()); + Cookie sessionCookie = getSessionCookie(webClient, "tenant-https_test"); + assertEquals("strict", sessionCookie.getSameSite()); // Check both session cookie chunks are removed if the new authentication is enforced webClient.getOptions().setRedirectEnabled(false); @@ -238,7 +232,7 @@ public void testCodeFlowForceHttpsRedirectUriAndPkce() throws Exception { TextPage textPage = webClient.getPage("http://localhost:8081/index.html"); assertEquals(302, textPage.getWebResponse().getStatusCode()); - assertNull(getSessionCookies(webClient, "tenant-https")); + assertNull(getSessionCookie(webClient, "tenant-https_test")); webClient.getCookieManager().clearCookies(); } @@ -349,17 +343,12 @@ public void testCodeFlowForceHttpsRedirectUriWithQueryAndPkce() throws Exception URI endpointLocationWithoutQueryUri = URI.create(endpointLocationWithoutQuery); assertEquals("code=b", endpointLocationWithoutQueryUri.getRawQuery()); - List sessionCookies = verifyTenantHttpTestCookies(webClient); - - StringBuilder sessionCookieValue = new StringBuilder(); - for (Cookie c : sessionCookies) { - sessionCookieValue.append(c.getValue()); - } + Cookie sessionCookie = getSessionCookie(webClient, "tenant-https_test"); SecretKey key = new SecretKeySpec(OidcUtils .getSha256Digest("secret".getBytes(StandardCharsets.UTF_8)), "AES"); - String decryptedSessionCookieValue = OidcUtils.decryptString(sessionCookieValue.toString(), key); + String decryptedSessionCookieValue = OidcUtils.decryptString(sessionCookie.getValue(), key); String encodedIdToken = decryptedSessionCookieValue.split("\\|")[0]; @@ -372,21 +361,12 @@ public void testCodeFlowForceHttpsRedirectUriWithQueryAndPkce() throws Exception Integer duration = Integer.valueOf(response.substring(response.length() - 1)); assertTrue(duration > 1 && duration < 5); - verifyTenantHttpTestCookies(webClient); + assertNull(getSessionCookie(webClient, "tenant-https")); webClient.getCookieManager().clearCookies(); } } - private List verifyTenantHttpTestCookies(WebClient webClient) { - List sessionCookies = getSessionCookies(webClient, "tenant-https_test"); - assertNotNull(sessionCookies); - assertEquals(2, sessionCookies.size()); - assertEquals("q_session_tenant-https_test_chunk_1", sessionCookies.get(0).getName()); - assertEquals("q_session_tenant-https_test_chunk_2", sessionCookies.get(1).getName()); - return sessionCookies; - } - @Test public void testCodeFlowNonce() throws Exception { doTestCodeFlowNonce(false); @@ -448,11 +428,9 @@ private void doTestCodeFlowNonce(boolean wrongRedirect) throws Exception { // At this point the session cookie is already available, this 2nd redirect only drops // OIDC code flow parameters such as `code` and `state` - List sessionCookies = getSessionCookies(webClient, "tenant-nonce"); - assertNotNull(sessionCookies); - assertEquals(2, sessionCookies.size()); - assertEquals("q_session_tenant-nonce_chunk_1", sessionCookies.get(0).getName()); - assertEquals("q_session_tenant-nonce_chunk_2", sessionCookies.get(1).getName()); + Cookie sessionCookie = getSessionCookie(webClient, "tenant-nonce"); + assertNotNull(sessionCookie); + assertEquals("q_session_tenant-nonce", sessionCookie.getName()); String endpointLocationWithoutQuery = webResponse.getResponseHeaderValue("location"); URI endpointLocationWithoutQueryUri = URI.create(endpointLocationWithoutQuery); @@ -462,7 +440,7 @@ private void doTestCodeFlowNonce(boolean wrongRedirect) throws Exception { assertEquals("tenant-nonce:reauthenticated", page.getBody().asNormalizedText()); // both cookies should be gone now. - assertNull(getSessionCookies(webClient, "tenant-nonce")); + assertNull(getSessionCookie(webClient, "tenant-nonce")); webClient.getCookieManager().clearCookies(); } } @@ -1595,19 +1573,6 @@ private Cookie getSessionCookie(WebClient webClient, String tenantId) { return webClient.getCookieManager().getCookie("q_session" + (tenantId == null ? "_Default_test" : "_" + tenantId)); } - private List getSessionCookies(WebClient webClient, String tenantId) { - String sessionCookieNameChunk = "q_session" + (tenantId == null ? "_Default_test" : "_" + tenantId) + "_chunk_"; - CookieManager cookieManager = webClient.getCookieManager(); - SortedMap sessionCookies = new TreeMap<>(); - for (Cookie cookie : cookieManager.getCookies()) { - if (cookie.getName().startsWith(sessionCookieNameChunk)) { - sessionCookies.put(cookie.getName(), cookie); - } - } - - return sessionCookies.isEmpty() ? null : new ArrayList(sessionCookies.values()); - } - private Cookie getSessionAtCookie(WebClient webClient, String tenantId) { return webClient.getCookieManager().getCookie("q_session_at" + (tenantId == null ? "_Default_test" : "_" + tenantId)); } diff --git a/integration-tests/oidc-tenancy/pom.xml b/integration-tests/oidc-tenancy/pom.xml index de7d04c6100c0..efc494393105d 100644 --- a/integration-tests/oidc-tenancy/pom.xml +++ b/integration-tests/oidc-tenancy/pom.xml @@ -30,10 +30,6 @@ io.quarkus quarkus-resteasy-jackson - - org.keycloak - keycloak-adapter-core - org.keycloak keycloak-core 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 fc2c666eb54b2..72d591502e151 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 @@ -11,14 +11,10 @@ import java.io.IOException; import java.net.URI; import java.time.Duration; -import java.util.ArrayList; import java.util.List; -import java.util.SortedMap; -import java.util.TreeMap; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; -import org.htmlunit.CookieManager; import org.htmlunit.FailingHttpStatusCodeException; import org.htmlunit.SilentCssErrorHandler; import org.htmlunit.WebClient; @@ -310,9 +306,8 @@ public void testReAuthenticateWhenSwitchingTenants() throws IOException { page = loginForm.getInputByName("login").click(); assertEquals("tenant-web-app2:alice", page.getBody().asNormalizedText()); assertNull(getSessionCookie(webClient, "tenant-web-app")); - List sessionCookieChunks = getSessionCookies(webClient, "tenant-web-app2"); - assertNotNull(sessionCookieChunks); - assertEquals(2, sessionCookieChunks.size()); + Cookie sessionCookie = getSessionCookie(webClient, "tenant-web-app2"); + assertNotNull(sessionCookie); webClient.getCookieManager().clearCookies(); } } @@ -937,17 +932,4 @@ private Cookie getSessionAtCookie(WebClient webClient, String tenantId) { private Cookie getSessionRtCookie(WebClient webClient, String tenantId) { return webClient.getCookieManager().getCookie("q_session_rt" + (tenantId == null ? "_Default_test" : "_" + tenantId)); } - - private List getSessionCookies(WebClient webClient, String tenantId) { - String sessionCookieNameChunk = "q_session" + (tenantId == null ? "" : "_" + tenantId) + "_chunk_"; - CookieManager cookieManager = webClient.getCookieManager(); - SortedMap sessionCookies = new TreeMap<>(); - for (Cookie cookie : cookieManager.getCookies()) { - if (cookie.getName().startsWith(sessionCookieNameChunk)) { - sessionCookies.put(cookie.getName(), cookie); - } - } - - return sessionCookies.isEmpty() ? null : new ArrayList(sessionCookies.values()); - } } diff --git a/integration-tests/oidc-token-propagation/pom.xml b/integration-tests/oidc-token-propagation/pom.xml index 7152184c09b7e..96757a10b9381 100644 --- a/integration-tests/oidc-token-propagation/pom.xml +++ b/integration-tests/oidc-token-propagation/pom.xml @@ -14,10 +14,6 @@ Quarkus - Integration Tests - RESTEasy Client OpenID Connect Token Propagation - - org.keycloak - keycloak-adapter-core - org.jboss.logging commons-logging-jboss-logging diff --git a/integration-tests/oidc/pom.xml b/integration-tests/oidc/pom.xml index d279684696577..8e4c5c8e9dafb 100644 --- a/integration-tests/oidc/pom.xml +++ b/integration-tests/oidc/pom.xml @@ -27,11 +27,6 @@ quarkus-websockets - - org.keycloak - keycloak-adapter-core - test - org.keycloak keycloak-core diff --git a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/KeycloakXTestResourceLifecycleManager.java b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/KeycloakXTestResourceLifecycleManager.java index abe4321c0789d..813c1d8e7cac7 100644 --- a/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/KeycloakXTestResourceLifecycleManager.java +++ b/integration-tests/oidc/src/test/java/io/quarkus/it/keycloak/KeycloakXTestResourceLifecycleManager.java @@ -54,7 +54,7 @@ public Map start() { .withClasspathResourceMapping("/upconfig.json", "/opt/keycloak/upconfig.json", BindMode.READ_ONLY) .withCommand("build --https-client-auth=required") .withCommand(String.format( - "start --https-client-auth=required --hostname-strict=false --hostname-strict-https=false" + "start --https-client-auth=required --hostname-strict=false" + " --https-key-store-file=%s --https-trust-store-file=%s --https-trust-store-password=password" + " --spi-user-profile-declarative-user-profile-config-file=/opt/keycloak/upconfig.json", SERVER_KEYSTORE_MOUNTED_PATH, SERVER_TRUSTSTORE_MOUNTED_PATH)); diff --git a/integration-tests/smallrye-jwt-oidc-webapp/pom.xml b/integration-tests/smallrye-jwt-oidc-webapp/pom.xml index 2d89d6642b982..802c1498e549c 100644 --- a/integration-tests/smallrye-jwt-oidc-webapp/pom.xml +++ b/integration-tests/smallrye-jwt-oidc-webapp/pom.xml @@ -20,10 +20,6 @@ - - org.keycloak - keycloak-adapter-core - io.quarkus quarkus-reactive-oracle-client diff --git a/integration-tests/smallrye-jwt-token-propagation/pom.xml b/integration-tests/smallrye-jwt-token-propagation/pom.xml index 71fbe6c39c452..40ec80ae74834 100644 --- a/integration-tests/smallrye-jwt-token-propagation/pom.xml +++ b/integration-tests/smallrye-jwt-token-propagation/pom.xml @@ -19,10 +19,6 @@ - - org.keycloak - keycloak-adapter-core - org.keycloak keycloak-core diff --git a/test-framework/keycloak-server/pom.xml b/test-framework/keycloak-server/pom.xml index 6e6bceb661fb9..704f2b9e24481 100644 --- a/test-framework/keycloak-server/pom.xml +++ b/test-framework/keycloak-server/pom.xml @@ -13,10 +13,6 @@ quarkus-test-keycloak-server Quarkus - Test Framework - Keycloak Server support - - org.keycloak - keycloak-adapter-core - org.keycloak keycloak-core