{{ message }}
Adjust role requirements for user.list and user.edit#5949
Open
mdpearson wants to merge 2 commits into
Open
Conversation
UserController used to bind request params directly to the User domain, which would allow Grails' data binding rules, not our policy, to determine which roles could be assigned. Extract role IDs at the controller and pass them to the service as explicit arguments; make the service reject any role-shaped keys still in the params map (`rejectRoleKeysInParams()`) so the boundary is enforced from both sides. A `popRoleParamsBeforeBinding()` helper applies the same extraction pattern consistently in `save()` and `update()`. Consolidate the permission checks themselves into `checkCanAddOrRemoveRoles()` and `checkCanAddOrRemoveLocationRoles()`, used by every path that can change role assignments: `saveUser`, `updateUser`, `saveLocationRole`, `deleteLocationRole`. Role validation logic moves into `validateAndApplyRoleChanges()` and `validateAndApplyLocationRoleChanges()`, which add and remove roles one at a time to steer clear of any GORM/Hibernate cascade quirks. `checkCanAddOrRemove*Roles()` takes the target `User` as a parameter so validation errors attach to the right object. A new `rejectRoleChange` helper throws `ValidationException` with a localized message that UserController surfaces directly in `flash.message` instead of re-localizing. Separately, `user.edit` and `user.show` had no entry in any of `RoleInterceptor`'s role lists. Any authenticated, browse-capable user could reach them through the default fall-through path. Add them to `managerActions` so the interceptor enforces at least manager-level access for both. This gets exercise in a big Spock table in `RoleInterceptorSpec`. While I was in there: - Hoisted `deleteLocationRole` logic from `UserController` into `UserService`. - Added five message keys to clarify error conditions to users. - Added Javadoc on `saveUser`, `updateUser`, and `rejectRoleKeysInParams()` to explain why role IDs must not travel inside the params map. - Covered the controller/service boundary with a new `UserServiceRoleValidationSpec` exercising role assignment, role removal, and params-map rejection. - Updated `UserControllerSpec` setup to stub `session.user`, since `saveUser`'s new signature reads `session.user.id` to identify the requesting user. - Used idiomatic Spock in `RoleInterceptorSpec`: `@Unroll` hoisted to the class, `||` separator marking expected output, `assert` used in expectations that delegate via a helper method. Signed-off-by: Matthew Pearson <matthewpearson@gmail.com>
0564e1e to
dcc95b9
Compare
- `user.list` now requires manager (was admin) - `user.edit` now requires admin (was manager) - `user.show` stays at manager `RoleInterceptorSpec`'s expected-values table is updated to match. `UserController.deleteLocationRole` no longer produces `/user/edit/null` when it can't resolve a user id. It now falls back to the user list. I don't know if this ever happened, but it was a straightforward enough backstop to implement. `UserService` now raises `ValidationException` when a role assignment references an unresolvable role or location id, rather than silently filtering it out or letting a downstream permission check NPE on a null `Role`. Added some more tests. Signed-off-by: Matthew Pearson <matthewpearson@gmail.com>
dcc95b9 to
5fc91cc
Compare
jmiranda
approved these changes
May 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

user.listnow requires manager (was admin)user.editnow requires admin (was manager)user.showstays at managerRoleInterceptorSpec's expected-values table is updated to match.UserController.deleteLocationRoleno longer produces/user/edit/nullwhen it can't resolve a user id. It now falls back to the user list. I don't know if this ever happened, but it was a straightforward enough backstop to implement, and was a response to this comment on a related PR.