Skip to content

Fix addManagedMember adding user as unmanaged when user is cache-wrapped#51161

Open
simonbleher wants to merge 1 commit into
keycloak:mainfrom
simonbleher:fix/org-add-managed-member-cached-user
Open

Fix addManagedMember adding user as unmanaged when user is cache-wrapped#51161
simonbleher wants to merge 1 commit into
keycloak:mainfrom
simonbleher:fix/org-add-managed-member-cached-user

Conversation

@simonbleher

Copy link
Copy Markdown

Problem

OrganizationProvider.addManagedMember is supposed to add a user to an
organization with MembershipType.MANAGED, but the user ends up UNMANAGED
instead whenever the UserModel passed in came from the standard cached
user provider (e.g. session.users().getUserById(...), as used by custom
AdminRealmResourceProviders and other real callers of addManagedMember).

Root cause

JpaOrganizationProvider.addMember() calls user.joinGroup(group, metadata).
UserModel has a default implementation for that overload:

default void joinGroup(GroupModel group, MembershipMetadata metadata) {
    joinGroup(group);
}

The infinispan cache UserAdapter only overrides the single-arg
joinGroup(GroupModel), not the metadata-aware overload. So when user is
a cache-wrapped UserAdapter, the call falls through to the default
above, silently drops the MANAGED metadata, and ends up at the JPA
layer's joinGroup(group) -> joinGroup(group, null), which defaults the
membership type to UNMANAGED.

Fix

Added the missing joinGroup(GroupModel, MembershipMetadata) override to
the infinispan UserAdapter, mirroring the existing joinGroup(GroupModel)
override exactly, so the metadata is passed through to the delegate
instead of being dropped.

Testing

Added OrganizationCacheTest#testAddManagedMemberWithCachedUser, which
fetches a user through the normal cached user provider, calls
addManagedMember, and asserts isManagedMember is true.

  • Verified the new test fails on the unfixed code
    (expected: but was: ) and passes with the fix.
  • Ran the broader organization/cache/member test suites
    (OrganizationCacheTest, OrganizationMemberTest,
    OrganizationMemberIdpLinkTest, OrganizationInternalGroupTest,
    OrganizationGroupMembershipTest) - 60 tests, all passing, no
    regressions.
  • ./mvnw spotless:check passes on the changed modules.

Closes #43094

UserModel.joinGroup(GroupModel, MembershipMetadata) has a default
implementation that drops the metadata and calls the single-arg
joinGroup(GroupModel), which defaults the membership to UNMANAGED.
The infinispan cache UserAdapter only overrode the single-arg variant,
so any UserModel obtained through the standard cached user provider
(e.g. session.users().getUserById(...), as used by custom admin
resource providers and other real callers of addManagedMember) fell
through to that default and silently lost the MANAGED metadata.

Add the missing override so the metadata is passed through to the
delegate, mirroring the existing joinGroup(GroupModel) override.

Closes keycloak#43094

Signed-off-by: simonbleher <blehersimon69@gmail.com>
Copilot AI review requested due to automatic review settings July 25, 2026 14:45
@simonbleher
simonbleher requested review from a team as code owners July 25, 2026 14:45

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.

Pull request overview

Fixes #43094 by preserving managed-membership metadata for cache-wrapped users.

Changes:

  • Adds metadata-aware joinGroup delegation to the Infinispan user adapter.
  • Adds regression coverage for managed organization membership with cached users.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java Forwards membership metadata to persistence.
tests/base/src/test/java/org/keycloak/tests/organization/cache/OrganizationCacheTest.java Verifies cached users remain managed members.

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.

OrganizationProvider.addManagedMember still adds member as unmanaged

2 participants