CAMEL-23453: camel-keycloak - add federated identity linking operations#25091
CAMEL-23453: camel-keycloak - add federated identity linking operations#25091oscerd wants to merge 1 commit into
Conversation
The component exposed user CRUD but not federated-identity (IdP) link management, which is needed for SSO scenarios where a Keycloak user is linked to an external identity-provider account, and for provisioning users with pre-linked accounts during a migration. Add three operations backed by the admin client's UserResource: - addFederatedIdentity - link a user to an identity provider account - removeFederatedIdentity - unlink a user from an identity provider - getFederatedIdentities - list all identity provider links for a user New headers: CamelKeycloakIdentityProvider, CamelKeycloakFederatedUserId and CamelKeycloakFederatedUsername. The username is optional: when it is not supplied the external user id is used, so the link is never created with a blank username (Keycloak surfaces that field in the admin console). addFederatedIdentity checks the returned status and fails with the status code when the link could not be created, rather than reporting success. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 11 tested, 27 compile-only — current: 9 all testedMaveniverse Scalpel detected 38 affected modules (current approach: 9).
|
davsclaus
left a comment
There was a problem hiding this comment.
Nice, clean PR — the implementation follows the existing producer pattern well, the documentation is thorough with both Java and YAML examples, and the test coverage is solid with 9 tests. CI checks all pass.
A few suggestions below, mostly around test conventions. Nothing blocking.
This is a rules-and-conventions review. It does not replace specialized review tools such as CodeRabbit or Sourcery, or static analysis tools such as SonarCloud.
This review was generated by an AI agent (Claude Code on behalf of @davsclaus) and may contain inaccuracies. Please verify all suggestions before applying.
| * Unit tests for the federated identity (identity provider link) operations. | ||
| */ | ||
| public class KeycloakProducerFederatedIdentityTest extends CamelTestSupport { | ||
|
|
There was a problem hiding this comment.
Per project test conventions, new test classes should be package-private (no public modifier). Same applies to all @Test methods in this file. The existing KeycloakProducerTest uses public (pre-existing style), but new files should follow the current convention.
| class KeycloakProducerFederatedIdentityTest extends CamelTestSupport { |
| assertTrue(e.getCause().getMessage().contains("409"), | ||
| "The failing status should be reported — was: " + e.getCause().getMessage()); | ||
| } | ||
| } |
There was a problem hiding this comment.
This try-catch pattern silently passes if the exception is never thrown — a broken status check would go unnoticed. The same pattern exists in KeycloakProducerTest, but for new code assertThrows is more robust:
Exception e = assertThrows(Exception.class, () ->
template.sendBodyAndHeaders("direct:addFederatedIdentity", null,
headers(KeycloakConstants.IDENTITY_PROVIDER, "google",
KeycloakConstants.FEDERATED_USER_ID, "google-123")));
assertThat(e.getCause().getMessage()).contains("409");Same concern applies to testMissingIdentityProvider, testMissingFederatedUserId, testMissingUserId, and testMissingRealmName below.
| verify(userResource).addFederatedIdentity(eq("google"), captor.capture()); | ||
|
|
||
| FederatedIdentityRepresentation sent = captor.getValue(); | ||
| assertEquals("google", sent.getIdentityProvider()); |
There was a problem hiding this comment.
Minor: project guidelines prefer AssertJ assertions (assertThat(...)) over JUnit assertions for new test code. The existing KeycloakProducerTest uses JUnit style, but new files should prefer the updated convention. For example:
assertThat(sent.getIdentityProvider()).isEqualTo("google");
assertThat(sent.getUserId()).isEqualTo("google-123");
assertThat(sent.getUserName()).isEqualTo("jane@example.com");
Motivation
CAMEL-23453. The component exposed user CRUD but no federated-identity (IdP) link management. Those links are what connect a Keycloak user to an external identity-provider account (Google, GitHub, a SAML provider), so they matter for SSO scenarios and for provisioning users with pre-linked accounts during a migration.
Changes
Three new operations, implemented against the admin client's
UserResourceand following the existing producer pattern (header validation, then the admin-client call, then the response on the out-message):addFederatedIdentityaddFederatedIdentity(alias, rep)CamelKeycloakIdentityProvider,CamelKeycloakFederatedUserIdremoveFederatedIdentityremoveFederatedIdentity(alias)CamelKeycloakIdentityProvidergetFederatedIdentitiesgetFederatedIdentity()New header constants, as proposed on the issue:
CamelKeycloakIdentityProvider,CamelKeycloakFederatedUserId,CamelKeycloakFederatedUsername.getFederatedIdentitiessets the body to theList<FederatedIdentityRepresentation>.Two behaviours worth calling out for review:
CamelKeycloakFederatedUsernameis optional; when it is absent the external user id is used as the username rather than creating the link with a blank one, since Keycloak surfaces that field in the admin console. A test pins this — happy to switch it to leaving the field null if you'd prefer.addFederatedIdentityreturns a JAX-RSResponse; the producer checks it and fails with the status code on a non-2xx (e.g. a 409 when the link already exists) instead of reporting success. The response is closed via try-with-resources.Testing
KeycloakProducerFederatedIdentityTest— 9 tests, all passing — using the same mocked-admin-client approach as the existingKeycloakProducerTest:FederatedIdentityRepresentationcarries the right provider/userId/usernameremoveFederatedIdentityis called with the aliasFull reactor
mvn clean install -DskipTestsfrom root: success, with catalog and endpoint-DSL metadata regenerated.Docs: a Federated Identity Operations section in
keycloak-component.adocwith the header contract and Java/YAML examples.Main-only (4.22.0), additive — no backport.
Claude Code on behalf of Andrea Cosentino (@oscerd).
🤖 Generated with Claude Code