Skip to content

Commit

Permalink
Merge pull request #41162 from sberyozkin/keycloak_25.0.0
Browse files Browse the repository at this point in the history
Bump Keycloak version to 25.0.0
  • Loading branch information
sberyozkin authored Jun 12, 2024
2 parents 4e2000c + 7b22585 commit 210bd72
Show file tree
Hide file tree
Showing 21 changed files with 22 additions and 136 deletions.
14 changes: 1 addition & 13 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@
<mockito.version>5.12.0</mockito.version>
<jna.version>5.8.0</jna.version><!-- should satisfy both testcontainers and mongodb -->
<quarkus-security.version>2.1.0</quarkus-security.version>
<keycloak.version>24.0.4</keycloak.version>
<keycloak.version>25.0.0</keycloak.version>
<logstash-gelf.version>1.15.1</logstash-gelf.version>
<checker-qual.version>3.44.0</checker-qual.version>
<error-prone-annotations.version>2.28.0</error-prone-annotations.version>
Expand Down Expand Up @@ -5959,18 +5959,6 @@
<version>${quarkus-spring-boot-api.version}</version>
</dependency>

<!-- Keycloak -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<version>${keycloak.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@

<!-- The image to use for tests that run Keycloak -->
<!-- IMPORTANT: If this is changed you must also update bom/application/pom.xml and KeycloakBuildTimeConfig/DevServicesConfig in quarkus-oidc/deployment to match the version -->
<keycloak.version>24.0.4</keycloak.version>
<keycloak.version>25.0.0</keycloak.version>
<keycloak.wildfly.version>19.0.3</keycloak.wildfly.version>
<keycloak.docker.image>quay.io/keycloak/keycloak:${keycloak.version}</keycloak.docker.image>
<keycloak.docker.legacy.image>quay.io/keycloak/keycloak:${keycloak.wildfly.version}-legacy</keycloak.docker.legacy.image>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
4 changes: 0 additions & 4 deletions extensions/keycloak-admin-resteasy-client/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-client-jaxb</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
Expand Down
5 changes: 0 additions & 5 deletions extensions/oidc-client/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ private static JsonObject getRolesJson(Map<String, Object> requestData, TenantCo
private Uni<TokenVerificationResult> verifyCodeFlowAccessTokenUni(Map<String, Object> 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);
Expand Down Expand Up @@ -469,7 +469,7 @@ private Uni<TokenVerificationResult> verifyTokenUni(Map<String, Object> 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()
Expand Down
4 changes: 0 additions & 4 deletions integration-tests/oidc-client-reactive/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
</properties>

<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
Expand Down
4 changes: 0 additions & 4 deletions integration-tests/oidc-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@
</properties>

<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
Expand Down
5 changes: 0 additions & 5 deletions integration-tests/oidc-code-flow/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,6 @@
<artifactId>quarkus-test-keycloak-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,14 @@
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;

import javax.crypto.SecretKey;
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;
Expand Down Expand Up @@ -228,17 +223,16 @@ public void testCodeFlowForceHttpsRedirectUriAndPkce() throws Exception {
page = webClient.getPage(endpointLocationWithoutQueryUri.toURL());
assertEquals("tenant-https:reauthenticated", page.getBody().asNormalizedText());

List<Cookie> 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);
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);

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();
}
Expand Down Expand Up @@ -349,17 +343,12 @@ public void testCodeFlowForceHttpsRedirectUriWithQueryAndPkce() throws Exception
URI endpointLocationWithoutQueryUri = URI.create(endpointLocationWithoutQuery);
assertEquals("code=b", endpointLocationWithoutQueryUri.getRawQuery());

List<Cookie> 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];

Expand All @@ -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<Cookie> verifyTenantHttpTestCookies(WebClient webClient) {
List<Cookie> 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);
Expand Down Expand Up @@ -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<Cookie> 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);
Expand All @@ -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();
}
}
Expand Down Expand Up @@ -1595,19 +1573,6 @@ private Cookie getSessionCookie(WebClient webClient, String tenantId) {
return webClient.getCookieManager().getCookie("q_session" + (tenantId == null ? "_Default_test" : "_" + tenantId));
}

private List<Cookie> getSessionCookies(WebClient webClient, String tenantId) {
String sessionCookieNameChunk = "q_session" + (tenantId == null ? "_Default_test" : "_" + tenantId) + "_chunk_";
CookieManager cookieManager = webClient.getCookieManager();
SortedMap<String, Cookie> sessionCookies = new TreeMap<>();
for (Cookie cookie : cookieManager.getCookies()) {
if (cookie.getName().startsWith(sessionCookieNameChunk)) {
sessionCookies.put(cookie.getName(), cookie);
}
}

return sessionCookies.isEmpty() ? null : new ArrayList<Cookie>(sessionCookies.values());
}

private Cookie getSessionAtCookie(WebClient webClient, String tenantId) {
return webClient.getCookieManager().getCookie("q_session_at" + (tenantId == null ? "_Default_test" : "_" + tenantId));
}
Expand Down
4 changes: 0 additions & 4 deletions integration-tests/oidc-tenancy/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Cookie> sessionCookieChunks = getSessionCookies(webClient, "tenant-web-app2");
assertNotNull(sessionCookieChunks);
assertEquals(2, sessionCookieChunks.size());
Cookie sessionCookie = getSessionCookie(webClient, "tenant-web-app2");
assertNotNull(sessionCookie);
webClient.getCookieManager().clearCookies();
}
}
Expand Down Expand Up @@ -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<Cookie> getSessionCookies(WebClient webClient, String tenantId) {
String sessionCookieNameChunk = "q_session" + (tenantId == null ? "" : "_" + tenantId) + "_chunk_";
CookieManager cookieManager = webClient.getCookieManager();
SortedMap<String, Cookie> sessionCookies = new TreeMap<>();
for (Cookie cookie : cookieManager.getCookies()) {
if (cookie.getName().startsWith(sessionCookieNameChunk)) {
sessionCookies.put(cookie.getName(), cookie);
}
}

return sessionCookies.isEmpty() ? null : new ArrayList<Cookie>(sessionCookies.values());
}
}
4 changes: 0 additions & 4 deletions integration-tests/oidc-token-propagation/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@
<name>Quarkus - Integration Tests - RESTEasy Client OpenID Connect Token Propagation</name>

<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>commons-logging-jboss-logging</artifactId>
Expand Down
5 changes: 0 additions & 5 deletions integration-tests/oidc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@
<artifactId>quarkus-websockets</artifactId>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public Map<String, String> 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));
Expand Down
4 changes: 0 additions & 4 deletions integration-tests/smallrye-jwt-oidc-webapp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@
</properties>

<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-oracle-client</artifactId>
Expand Down
4 changes: 0 additions & 4 deletions integration-tests/smallrye-jwt-token-propagation/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
</properties>

<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
Expand Down
Loading

0 comments on commit 210bd72

Please sign in to comment.