Skip to content

feat: add realm role and client role syncing and provisioning - #23

Open
c1-dev-bot[bot] wants to merge 1 commit into
mainfrom
feature/table-level-role-provisioning
Open

feat: add realm role and client role syncing and provisioning#23
c1-dev-bot[bot] wants to merge 1 commit into
mainfrom
feature/table-level-role-provisioning

Conversation

@c1-dev-bot

@c1-dev-bot c1-dev-bot Bot commented May 21, 2026

Copy link
Copy Markdown

Summary

  • Adds realm role resource type with sync and Grant/Revoke provisioning for assigning/removing realm-level roles from users
  • Adds client resource type (sync-only, serves as parent container for client roles)
  • Adds client role resource type with sync and Grant/Revoke provisioning for assigning/removing per-client roles from users
  • Updates baton_capabilities.json to declare the new resource types and their capabilities

This expands the Keycloak connector from only group membership provisioning to covering the full RBAC model (groups + realm roles + client roles), enabling table-level access control through ConductorOne.

New Resource Types

Resource Type Trait Sync Provision
realm_role TRAIT_ROLE Yes Yes (Grant/Revoke)
client TRAIT_APP Yes No (parent container)
client_role TRAIT_ROLE Yes Yes (Grant/Revoke)

API Methods Added

  • GetRealmRoles / GetUsersByRealmRoleName / AddRealmRoleToUser / DeleteRealmRoleFromUser
  • GetClients / GetClientRoles / GetUsersByClientRoleName / AddClientRoleToUser / DeleteClientRoleFromUser

All methods use the existing gocloak/v13 library and follow the same authentication and pagination patterns as existing methods.

Fixes: CXH-1530

Test plan

  • Verify realm roles are synced from Keycloak
  • Verify clients are synced from Keycloak
  • Verify client roles are synced as children of their parent client
  • Test Grant: assign a realm role to a user via ConductorOne
  • Test Revoke: remove a realm role from a user via ConductorOne
  • Test Grant: assign a client role to a user via ConductorOne
  • Test Revoke: remove a client role from a user via ConductorOne
  • Verify existing group membership sync and provisioning still works
  • Verify pagination works correctly for large numbers of roles/clients

Automated PR Notice

This PR was automatically created by c1-dev-bot as a potential implementation.

This code requires:

  • Human review of the implementation approach
  • Manual testing to verify correctness
  • Approval from the appropriate team before merging

Add three new resource types to expand Keycloak access provisioning
beyond group membership to cover the full RBAC model:

- Realm Role: syncs realm-level roles with Grant/Revoke provisioning
  for assigning/removing roles from users
- Client: syncs Keycloak clients as parent resources for client roles
- Client Role: syncs per-client roles with Grant/Revoke provisioning
  for assigning/removing client-specific roles from users

This enables table-level access control by exposing all dimensions of
Keycloak's access model (groups, realm roles, client roles) through
ConductorOne's provisioning workflows.

Fixes: CXH-1530
@c1-dev-bot
c1-dev-bot Bot requested a review from a team May 21, 2026 21:34
@linear-code

linear-code Bot commented May 21, 2026

Copy link
Copy Markdown

CXH-1530

Comment on lines +112 to +113

if err := o.client.AddRealmRoleToUser(ctx, userID, role); err != nil {

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.

🟡 Suggestion: Grant does not handle the "role already assigned" case as idempotent success. If Keycloak returns a distinguishable error when the user already has this realm role, catch it and return nil error with a GrantAlreadyExists annotation. Same applies to Revoke (line 144) for "role not assigned" → GrantAlreadyRevoked. The existing group builder has the same gap, but fixing it here would prevent spurious failures on retries. See also client_roles.go Grant (line 133) and Revoke (line 171).

@github-actions

Copy link
Copy Markdown
Contributor

Connector PR Review: feat: add realm role and client role syncing and provisioning

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Review mode: full
View review run

Review Summary

This PR adds three new resource types (realm role, client, client role) with sync and provisioning for realm/client roles, plus the corresponding client methods and capability declarations. The implementation follows existing connector patterns well — pagination, error handling, entity sources, resource ID stability, and parent hierarchy are all correct. One suggestion for idempotent Grant/Revoke handling.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • pkg/connector/realm_roles.go:112-113, client_roles.go:133, and their Revoke counterparts: Grant/Revoke do not handle "already exists" / "not found" as idempotent success (P3).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/connector/realm_roles.go`:
- Around line 112-113: Grant does not catch "role already assigned" errors from Keycloak and return success with a GrantAlreadyExists annotation. If the gocloak error for duplicate role assignment is distinguishable, add a check like `if isAlreadyExistsError(err) { return nil, annotations.New(&v2.GrantAlreadyExists{}), nil }`. Apply the same pattern in Revoke (around line 144) for "not found" errors using GrantAlreadyRevoked.

In `pkg/connector/client_roles.go`:
- Around line 133: Same as above — Grant should handle "already assigned" as idempotent success with GrantAlreadyExists annotation. Apply the same in Revoke (around line 171) for "not found" using GrantAlreadyRevoked.

@github-actions github-actions Bot 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.

No blocking issues found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants