From f67ee868bb82fb6e6975a8bcc1d09e81e88a5454 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 20 May 2026 08:39:26 +0000 Subject: [PATCH 1/2] chore(camel-test-infra-keycloak): upgrade keycloak.container to 26.6.2 Update keycloak.container from 26.6.1 to 26.6.2 --- .../camel/test/infra/keycloak/services/container.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-infra/camel-test-infra-keycloak/src/main/resources/org/apache/camel/test/infra/keycloak/services/container.properties b/test-infra/camel-test-infra-keycloak/src/main/resources/org/apache/camel/test/infra/keycloak/services/container.properties index 7aa15f03c587f..33cdb963e0134 100644 --- a/test-infra/camel-test-infra-keycloak/src/main/resources/org/apache/camel/test/infra/keycloak/services/container.properties +++ b/test-infra/camel-test-infra-keycloak/src/main/resources/org/apache/camel/test/infra/keycloak/services/container.properties @@ -15,6 +15,6 @@ ## limitations under the License. ## --------------------------------------------------------------------------- ## Keycloak container configuration for test-infra -keycloak.container=mirror.gcr.io/keycloak/keycloak:26.6.1 +keycloak.container=mirror.gcr.io/keycloak/keycloak:26.6.2 keycloak.container.ppc64le=icr.io/ppc64le-oss/keycloak-ppc64le:v26.0.5-bv keycloak.container.version.exclude=nightly From f1684226f8ef9d6ac75173c0716a3ece4beceb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Pupier?= Date: Thu, 21 May 2026 17:55:18 +0200 Subject: [PATCH 2/2] Configure Keycloak 26.6.2 test to include the client ID in the aud claim of issued tokens, ensuring that when the same client performs token introspection, the validation passes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this is now required https://www.keycloak.org/docs/latest/upgrading/index.html#token-introspection-now-validates-audience-claim ``` Token introspection now validates audience claim The OAuth2 token introspection endpoint now validates that the authenticated client is present in the token’s audience (aud) claim before allowing introspection. Previously, any authenticated client could introspect any valid token. Now, the introspection endpoint returns {"active": false} if the authenticated client is not in the token’s audience ``` Co-authored-by: IBM Bob IDE 1.0.2 Signed-off-by: Aurélien Pupier --- .../KeycloakTokenIntrospectionIT.java | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakTokenIntrospectionIT.java b/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakTokenIntrospectionIT.java index 72715c0a2a077..6ea0dd76db85d 100644 --- a/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakTokenIntrospectionIT.java +++ b/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakTokenIntrospectionIT.java @@ -17,6 +17,7 @@ package org.apache.camel.component.keycloak.security; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -53,6 +54,7 @@ import org.keycloak.admin.client.resource.UserResource; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.UserRepresentation; @@ -172,6 +174,11 @@ private static void createTestClient() { // Get client secret TEST_CLIENT_SECRET = clientResource.getSecret().getValue(); + + // Add audience mapper to include this client in the token audience + // This is required for Keycloak 26.6.2+ token introspection + addAudienceMapper(clientResource); + LOG.info("Created test client: {} with secret for introspection", TEST_CLIENT_ID); } else { throw new RuntimeException("Failed to create client. Status: " + response.getStatus()); @@ -179,6 +186,23 @@ private static void createTestClient() { response.close(); } + private static void addAudienceMapper(ClientResource clientResource) { + ProtocolMapperRepresentation audienceMapper + = new ProtocolMapperRepresentation(); + audienceMapper.setName("audience-mapper"); + audienceMapper.setProtocol("openid-connect"); + audienceMapper.setProtocolMapper("oidc-audience-mapper"); + + Map config = new HashMap<>(); + config.put("included.client.audience", TEST_CLIENT_ID); + config.put("access.token.claim", "true"); + config.put("id.token.claim", "false"); + audienceMapper.setConfig(config); + + clientResource.getProtocolMappers().createMapper(audienceMapper); + LOG.info("Added audience mapper to client: {}", TEST_CLIENT_ID); + } + private static void createTestRoles() { // Create admin role RoleRepresentation adminRole = new RoleRepresentation(); @@ -725,8 +749,8 @@ void testCaffeineCacheClearOperation() throws Exception { */ private String getAccessToken(String username, String password) { try (Client client = ClientBuilder.newClient()) { - String tokenUrl = keycloakService.getKeycloakServerUrl() + "/realms/" + TEST_REALM_NAME - + "/protocol/openid-connect/token"; + String serverRealm = keycloakService.serverUrl() + "/realms/" + TEST_REALM_NAME; + String tokenUrl = serverRealm + "/protocol/openid-connect/token"; Form form = new Form() .param("grant_type", "password")