Skip to content

fix scope grants after creating new members#129

Merged
raphael-frank merged 1 commit into
mainfrom
fix/new-member-scope
Jul 14, 2026
Merged

fix scope grants after creating new members#129
raphael-frank merged 1 commit into
mainfrom
fix/new-member-scope

Conversation

@raphael-frank

@raphael-frank raphael-frank commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

There was an issue that member creation doesn't automatically grant member role in keycloak. I fixed this issue now.

Summary by CodeRabbit

  • New Features

    • Newly created users are automatically assigned the baseline “member” role.
  • Bug Fixes

    • Improved error handling when role assignment lacks permission or the required role is unavailable.
    • User creation now clearly reports failures during role assignment.

@raphael-frank raphael-frank self-assigned this Jul 10, 2026
@raphael-frank raphael-frank added the bug Something isn't working label Jul 10, 2026
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

User creation now assigns the member realm role after receiving the created user UUID from Keycloak. Role lookup, assignment, exception mapping, and corresponding success and failure tests were added.

Member role assignment

Layer / File(s) Summary
Role lookup and assignment
services/spring-member/src/main/java/.../KeycloakService.java
createUser retrieves the available realm roles, selects member, assigns it to the new user, and handles missing-role and forbidden responses.
Role assignment test coverage
services/spring-member/src/test/java/.../KeycloakServiceTest.java
Tests cover successful assignment, forbidden responses, missing roles, and the expected Keycloak requests.
Estimated code review effort: 3 (Moderate) ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant KeycloakService
  participant Keycloak
  Caller->>KeycloakService: createUser
  KeycloakService->>Keycloak: Create user
  Keycloak-->>KeycloakService: User UUID
  KeycloakService->>Keycloak: Get available realm roles
  Keycloak-->>KeycloakService: Return member role
  KeycloakService->>Keycloak: Assign member role
  Keycloak-->>KeycloakService: 204 NO_CONTENT
  KeycloakService-->>Caller: Return user UUID
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the main change: newly created members now receive the member role in Keycloak.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/new-member-scope

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@services/spring-member/src/main/java/tum/devoops/memberservice/service/KeycloakService.java`:
- Around line 87-121: Handle failures from assignMemberRealmRole in
MemberService.createMember by deleting the newly created Keycloak user before
propagating the error, ensuring cleanup occurs for any assignment failure and
preserving the original exception. Use the existing Keycloak user identifier and
deletion client/service method, and keep successful creation behavior unchanged;
alternatively, make both creation and role assignment idempotent so retries do
not leave orphaned users.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4f5d2ed2-362b-43fb-9a2e-afe22524403a

📥 Commits

Reviewing files that changed from the base of the PR and between 7cbd693 and fbdecdf.

📒 Files selected for processing (2)
  • services/spring-member/src/main/java/tum/devoops/memberservice/service/KeycloakService.java
  • services/spring-member/src/test/java/tum/devoops/memberservice/service/KeycloakServiceTest.java

Comment on lines +87 to +121
UUID userId = UUID.fromString(path.substring(path.lastIndexOf("/") + 1));

assignMemberRealmRole(userId);

return userId;
}

// Looked up via the user's own "available realm roles" endpoint rather than the
// realm-wide /roles/{role-name} resource: the org-role-sync service account only
// holds the manage-users client role (see realm-config.json), which covers a
// user's own role-mappings sub-resource but not the separate view-realm permission
// that GET /roles/{role-name} would require.
private void assignMemberRealmRole(UUID userId) {
try {
RoleRepresentation[] availableRoles = restClient.get()
.uri("/admin/realms/{realm}/users/{id}/role-mappings/realm/available", realm, userId)
.header(HttpHeaders.AUTHORIZATION, authorizationHeader())
.retrieve()
.body(RoleRepresentation[].class);

RoleRepresentation memberRole = Arrays.stream(availableRoles != null ? availableRoles : new RoleRepresentation[0])
.filter(role -> MEMBER_ROLE_NAME.equals(role.name()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("Keycloak realm role not found: " + MEMBER_ROLE_NAME));

restClient.post()
.uri("/admin/realms/{realm}/users/{id}/role-mappings/realm", realm, userId)
.header(HttpHeaders.AUTHORIZATION, authorizationHeader())
.contentType(MediaType.APPLICATION_JSON)
.body(List.of(memberRole))
.retrieve()
.toBodilessEntity();
} catch (HttpClientErrorException.Forbidden e) {
throw new SecurityException("Insufficient permissions to assign the member realm role");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find callers of createUser to see how failures/rollback are handled
rg -nP --type=java -C4 '\bcreateUser\s*\(' -g '!**/test/**'

Repository: AET-DevOps26/team-devoops

Length of output: 163


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the service implementation around createUser and role assignment
FILE="services/spring-member/src/main/java/tum/devoops/memberservice/service/KeycloakService.java"
wc -l "$FILE"
sed -n '1,260p' "$FILE"

# Find any usages of KeycloakService and createUser in the repo
rg -n --hidden --glob '!**/test/**' 'KeycloakService|createUser\s*\(' services . || true

Repository: AET-DevOps26/team-devoops

Length of output: 11917


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="services/spring-member/src/main/java/tum/devoops/memberservice/service/MemberService.java"
wc -l "$FILE"
sed -n '1,220p' "$FILE"

# Check whether the member creation flow compensates for a Keycloak failure
rg -n --hidden --glob '!**/test/**' 'deleteUser\s*\(|createUser\(|`@Transactional`|rollback|catch .*createUser|KeycloakService' services/spring-member/src/main/java

Repository: AET-DevOps26/team-devoops

Length of output: 5907


Handle cleanup when Keycloak role assignment fails

assignMemberRealmRole() can throw after the Keycloak user has already been created, leaving an orphaned account with no local member record. MemberService.createMember() wraps that failure as a BadRequestException, so the flow is not retry-safe. Delete the new user on failure or make the create/assign flow idempotent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@services/spring-member/src/main/java/tum/devoops/memberservice/service/KeycloakService.java`
around lines 87 - 121, Handle failures from assignMemberRealmRole in
MemberService.createMember by deleting the newly created Keycloak user before
propagating the error, ensuring cleanup occurs for any assignment failure and
preserving the original exception. Use the existing Keycloak user identifier and
deletion client/service method, and keep successful creation behavior unchanged;
alternatively, make both creation and role assignment idempotent so retries do
not leave orphaned users.

@f-s-h f-s-h left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lgtm

@f-s-h
f-s-h removed the request for review from FadyGergesRezk July 14, 2026 16:02
@raphael-frank
raphael-frank merged commit 174a28e into main Jul 14, 2026
18 checks passed
@raphael-frank
raphael-frank deleted the fix/new-member-scope branch July 14, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants