Skip to content

ClientUpdaterSourceGroupsCondition and ClientUpdaterSourceRolesCondition prevent usage of CIMD - #52601

Open
reda-alaoui wants to merge 1 commit into
keycloak:mainfrom
Cosium:issue-52152
Open

ClientUpdaterSourceGroupsCondition and ClientUpdaterSourceRolesCondition prevent usage of CIMD#52601
reda-alaoui wants to merge 1 commit into
keycloak:mainfrom
Cosium:issue-52152

Conversation

@reda-alaoui

Copy link
Copy Markdown
Contributor

Closes #52152

…ion prevent usage of CIMD

Closes keycloak#52152

Signed-off-by: Réda Housni Alaoui <reda-alaoui@hey.com>
@reda-alaoui
reda-alaoui marked this pull request as ready for review September 9, 2026 20:47
@reda-alaoui
reda-alaoui requested a review from a team as a code owner September 9, 2026 20:47
Copilot AI balanced review requested due to automatic review settings September 9, 2026 20:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Fixes Keycloak issue #52152 where configuring ClientUpdaterSourceGroupsCondition / ClientUpdaterSourceRolesCondition could break Client ID Metadata Document (CIMD) create/update flows by throwing on non-CRUD contexts.

Changes:

  • Update source-groups/roles client policy conditions to avoid throwing on unexpected context types.
  • Add CIMD create/update regression tests covering both groups and roles conditions.
  • Generalize the redirect-uris policy helper to support a configurable condition provider/config.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
tests/base/src/test/java/org/keycloak/tests/client/policies/ClientIdMetadataDocumentTest.java Adds regression tests for CIMD with updater-source conditions and extends a policy helper to accept a pluggable condition.
services/src/main/java/org/keycloak/services/clientpolicy/condition/ClientUpdaterSourceRolesCondition.java Avoids throwing ClientPolicyException on unsupported context types by returning a vote instead.
services/src/main/java/org/keycloak/services/clientpolicy/condition/ClientUpdaterSourceGroupsCondition.java Avoids throwing ClientPolicyException on unsupported context types by returning a vote instead.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

return getVoteForGroupsMatched(((ClientCRUDContext)context).getToken());
} else {
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
return ClientPolicyVote.NO;
return getVoteForRolesMatched(((ClientCRUDContext)context).getToken());
} else {
throw new ClientPolicyException(OAuthErrorException.SERVER_ERROR, "unexpected context type.");
return ClientPolicyVote.NO;
Comment on lines +463 to +539
@Test
public void testClientUpdaterSourceGroupsConditionOnCimdCreateAndUpdate() throws Exception {
// https://github.com/keycloak/keycloak/issues/52152
ClientIdUriSchemeCondition.Configuration conditionConfig = createDefaultConditionConfig();
ClientIdMetadataDocumentExecutor.Configuration executorConfig = createDefaultExecutorConfig();

SecureRedirectUrisEnforcerExecutor.Configuration redirectUrisConfig = new SecureRedirectUrisEnforcerExecutor.Configuration();
redirectUrisConfig.setAllowHttpScheme(false);
redirectUrisConfig.setAllowIPv4LoopbackAddress(true);

ClientUpdaterSourceGroupsCondition.Configuration updaterSourceConditionConfig = new ClientUpdaterSourceGroupsCondition.Configuration();
updaterSourceConditionConfig.setGroups(List.of("topGroup"));

updateCimdAndSecureRedirectUrisPolicy(conditionConfig, executorConfig, redirectUrisConfig,
ClientUpdaterSourceGroupsConditionFactory.PROVIDER_ID, updaterSourceConditionConfig);

setCimdPublicClient();
String code = loginUserAndGetCode(true);
AccessTokenResponse tokenResponse = oauth.client(CLIENT_ID).accessTokenRequest(code).send();
Assertions.assertEquals(200, tokenResponse.getStatusCode());

ClientRepresentation clientRepresentation = findByClientIdByAdmin();
Assertions.assertTrue(clientRepresentation.isPublicClient());

logout(tokenResponse.getIdToken());

timeOffSet.set(CIMD_EXECUTOR_MIN_CACHE_TIME_SEC + 3);

cimd.getRepresentation().setLogoUri("http://localhost:8500/logo2.png");
code = loginUserAndGetCode(false);
tokenResponse = oauth.client(CLIENT_ID).accessTokenRequest(code).send();
Assertions.assertEquals(200, tokenResponse.getStatusCode());

clientRepresentation = findByClientIdByAdmin();
Assertions.assertEquals("http://localhost:8500/logo2.png", clientRepresentation.getAttributes().get("logoUri"));

logoutAndDelete(clientRepresentation.getId(), tokenResponse.getIdToken());
}

@Test
public void testClientUpdaterSourceRolesConditionOnCimdCreateAndUpdate() throws Exception {
// https://github.com/keycloak/keycloak/issues/52152
ClientIdUriSchemeCondition.Configuration conditionConfig = createDefaultConditionConfig();
ClientIdMetadataDocumentExecutor.Configuration executorConfig = createDefaultExecutorConfig();

SecureRedirectUrisEnforcerExecutor.Configuration redirectUrisConfig = new SecureRedirectUrisEnforcerExecutor.Configuration();
redirectUrisConfig.setAllowHttpScheme(false);
redirectUrisConfig.setAllowIPv4LoopbackAddress(true);

ClientUpdaterSourceRolesCondition.Configuration updaterSourceConditionConfig = new ClientUpdaterSourceRolesCondition.Configuration();
updaterSourceConditionConfig.setRoles(List.of("admin"));

updateCimdAndSecureRedirectUrisPolicy(conditionConfig, executorConfig, redirectUrisConfig,
ClientUpdaterSourceRolesConditionFactory.PROVIDER_ID, updaterSourceConditionConfig);

setCimdPublicClient();
String code = loginUserAndGetCode(true);
AccessTokenResponse tokenResponse = oauth.client(CLIENT_ID).accessTokenRequest(code).send();
Assertions.assertEquals(200, tokenResponse.getStatusCode());

ClientRepresentation clientRepresentation = findByClientIdByAdmin();
Assertions.assertTrue(clientRepresentation.isPublicClient());

logout(tokenResponse.getIdToken());

timeOffSet.set(CIMD_EXECUTOR_MIN_CACHE_TIME_SEC + 3);

cimd.getRepresentation().setLogoUri("http://localhost:8500/logo2.png");
code = loginUserAndGetCode(false);
tokenResponse = oauth.client(CLIENT_ID).accessTokenRequest(code).send();
Assertions.assertEquals(200, tokenResponse.getStatusCode());

clientRepresentation = findByClientIdByAdmin();
Assertions.assertEquals("http://localhost:8500/logo2.png", clientRepresentation.getAttributes().get("logoUri"));

logoutAndDelete(clientRepresentation.getId(), tokenResponse.getIdToken());
}

logout(tokenResponse.getIdToken());

timeOffSet.set(CIMD_EXECUTOR_MIN_CACHE_TIME_SEC + 3);

logout(tokenResponse.getIdToken());

timeOffSet.set(CIMD_EXECUTOR_MIN_CACHE_TIME_SEC + 3);
Comment on lines +1145 to +1146
String redirectUrisConditionProvider,
ClientPolicyConditionConfigurationRepresentation redirectUrisConditionConfig) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CIMD] ClientUpdaterSourceGroupsCondition and ClientUpdaterSourceRolesCondition prevent usage of CIMD

2 participants