Skip to content

Add Groups resource type and scopes to authorization schema#6

Draft
ShashankFC wants to merge 1 commit into
feature-groups-authz-baselinefrom
feature-groups-authz-implementation
Draft

Add Groups resource type and scopes to authorization schema#6
ShashankFC wants to merge 1 commit into
feature-groups-authz-baselinefrom
feature-groups-authz-implementation

Conversation

@ShashankFC

Copy link
Copy Markdown
Collaborator

Test 6nn---nReplicated from ai-code-review-evaluation/keycloak-greptile#6

…ation implementation

Closes #35562

Signed-off-by: vramik <vramik@redhat.com>
@GitHoobar

Copy link
Copy Markdown

@claude

1 similar comment
@ShashankFC

Copy link
Copy Markdown
Collaborator Author

@claude

@claude

claude Bot commented Jan 12, 2026

Copy link
Copy Markdown

Claude finished @ShashankFC's task in 2m 19s —— View job


Code Review Complete

Tasks

  • Check for repository guidelines (CLAUDE.md)
  • Review PR changes and understand scope
  • Examine key modified files
  • Analyze code quality, correctness, and potential issues
  • Provide comprehensive review feedback

Summary

This PR adds support for Groups as a first-class resource type in the Fine-Grained Authorization Permissions (FGAP) V2 system. The implementation follows the existing pattern established for Users and Clients resources, adding granular permission scopes for group management.

Key Changes

  1. New Groups Resource Type (AdminPermissionsSchema.java:56-79)

    • Adds GROUPS_RESOURCE_TYPE with 5 scopes: manage, view, manage-membership, manage-members, view-members
    • Follows consistent pattern with existing USERS and CLIENTS resource types
  2. GroupPermissionsV2 Implementation (new file)

    • 211 lines implementing V2-style group permissions
    • Implements fallback to "all-groups" resource type when specific group resource not found
    • Properly integrates with authorization evaluation framework
  3. Enhanced User Permissions (UserPermissionsV2.java)

    • Adds group-based user access control via canViewByGroup() and canManageByGroup()
    • Users can now be managed through their group membership permissions
  4. Comprehensive Tests (GroupResourceTypeEvaluationTest.java)

    • 320 lines of integration tests covering all permission scenarios
    • Tests cover view/manage groups, member management, and membership management

Issues Found

🔴 Critical Issues

1. Logic Error in GroupPermissionsV2.canManage()

Location: GroupPermissionsV2.java:65-71

@Override
public boolean canManage() {
    if (root.hasOneAdminRole(AdminRoles.MANAGE_USERS)) {
        return true;
    }

    return hasPermission(null, AdminPermissionsSchema.VIEW, AdminPermissionsSchema.MANAGE);
}

Issue: The method checks for VIEW permission when determining if a user can manage all groups. This is incorrect - only MANAGE scope should grant management capability.

Impact: Users with only VIEW permission on "all-groups" would be incorrectly granted management rights.

Fix: Remove VIEW from the scopes check:

return hasPermission(null, AdminPermissionsSchema.MANAGE);

🟡 Medium Issues

2. Inconsistent Resource ID Usage in GroupPermissionsV2

Location: GroupPermissionsV2.java:121-123

resourceStore.findByType(server, AdminPermissionsSchema.GROUPS_RESOURCE_TYPE, groupResource -> {
    if (hasPermission(groupResource.getId(), AdminPermissionsSchema.VIEW_MEMBERS, AdminPermissionsSchema.MANAGE_MEMBERS)) {
        granted.add(groupResource.getId());
    }
});

Issue: The method passes groupResource.getId() (the resource DB ID) to hasPermission(), but then at line 141, hasPermission() expects either null or a group ID and uses resourceStore.findByName(server, groupId). This is inconsistent - the resource ID and group ID are different things.

Impact: The getGroupIdsWithViewPermission() method likely returns incorrect data (resource IDs instead of group IDs), breaking user filtering by group permissions.

Fix: The method should use groupResource.getName() instead, since resources are named with the group ID in V2:

granted.add(groupResource.getName());

3. Potential NPE in GroupPermissionsV2.hasPermission()

Location: GroupPermissionsV2.java:147-149

// check if there is a permission for "all-groups". If so, proceed with the evaluation to check scopes
if (policyStore.findByResource(server, resource).isEmpty()) {
    return false;
}

Issue: If resource is null at line 144 when getResourceTypeResource() returns null, this will cause a NullPointerException.

Impact: Crashes when authorization schema is misconfigured or resource type resource doesn't exist.

Fix: Add null check:

if (resource == null || policyStore.findByResource(server, resource).isEmpty()) {
    return false;
}

4. Missing Documentation Consistency

Location: GroupPermissionsV2.java:37

The class extends GroupPermissions but lacks class-level documentation explaining:

  • What V2 means and how it differs from V1
  • Why certain methods throw UnsupportedOperationException
  • The relationship with AdminPermissionsSchema

Recommendation: Add comprehensive class-level JavaDoc.


🟢 Minor Issues / Suggestions

5. Code Duplication in Permission Checking

Pattern repeated across: GroupPermissionsV2, UserPermissionsV2

The hasPermission() pattern is duplicated between these classes with minor variations. Consider extracting to a shared base class or utility.

6. Test Code Quality

Location: GroupResourceTypeEvaluationTest.java:68

private final GroupRepresentation topGroup = new GroupRepresentation();;

Double semicolon - minor style issue.

7. Deprecated Method in Interface

Location: UserPermissionEvaluator.java:163

@Deprecated
boolean isImpersonatable(UserModel user, ClientModel requester);

The method is deprecated but still in the interface. Consider documenting the migration path in the deprecation annotation:

@Deprecated(since = "FGAP-V2", forRemoval = true)

8. Magic String in resolveGroup

Location: AdminPermissionsSchema.java:181-186

private String resolveGroup(KeycloakSession session, String id) {
    RealmModel realm = session.getContext().getRealm();
    GroupModel group = session.groups().getGroupById(realm, id);
    
    return group == null ? null : group.getId();
}

Issue: This method just returns the same id that was passed in (if the group exists). This seems redundant - it's essentially just a validation that the group exists.

Suggestion: Either:

  • Remove this method and inline the validation where needed
  • Or rename to validateGroupExists() to clarify intent

Security Analysis

No security vulnerabilities detected

The implementation correctly:

  • Validates realm context before permission checks
  • Uses proper authorization evaluation framework
  • Prevents cross-realm permission escalation
  • Properly integrates with existing admin role checks

Architectural Observations

Positive:

  • Follows established V2 patterns from Users implementation
  • Clean separation between V1 and V2 with UnsupportedOperationException for V1-specific methods
  • Comprehensive test coverage for all permission scenarios
  • Proper integration with group hierarchy via canViewByGroup() and canManageByGroup()

Concerns:

  • Growing code duplication between UserPermissionsV2 and GroupPermissionsV2
  • No clear migration path documented from V1 to V2
  • The "throw UnsupportedOperationException" pattern for V1 methods could be cleaner with interface segregation

Test Coverage

Well covered:

  • ✅ View permissions (individual groups and all-groups)
  • ✅ Manage permissions (individual groups and all-groups)
  • ✅ Member viewing and management
  • ✅ Membership management
  • ✅ Fallback to all-groups permission

Could be improved:


Recommendations

  1. Fix the critical logic error in canManage() (Issue Fixing Re-authentication with passkeys #1) before merging
  2. Fix the resource ID vs group ID confusion (Issue Add caching support for IdentityProviderStorageProvider.getForLogin operations #2) - this will cause bugs
  3. Add null safety in hasPermission() (Issue Add AuthzClientCryptoProvider for authorization client cryptographic operations #3)
  4. Consider refactoring shared permission logic to reduce duplication
  5. Add class-level documentation for V2 classes
  6. Add more edge case tests

Action Items

  • Fix critical logic error in GroupPermissionsV2.canManage() - line 70
  • Fix resource ID usage in getGroupIdsWithViewPermission() - line 123
  • Add null check in hasPermission() - line 147
  • Add class-level JavaDoc to GroupPermissionsV2
  • Consider extracting shared permission logic to reduce duplication
  • Remove double semicolon in test file

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.

3 participants