Adjust role requirements for user.list and user.edit by mdpearson · Pull Request #5949 · openboxes/openboxes · GitHub
Skip to content

Adjust role requirements for user.list and user.edit#5949

Open
mdpearson wants to merge 2 commits into
developfrom
user-management-develop
Open

Adjust role requirements for user.list and user.edit#5949
mdpearson wants to merge 2 commits into
developfrom
user-management-develop

Conversation

@mdpearson

Copy link
Copy Markdown
Member
  • 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, and was a response to this comment on a related PR.

Copilot AI review requested due to automatic review settings May 27, 2026 19:44
@mdpearson mdpearson self-assigned this May 27, 2026
@github-actions github-actions Bot added domain: backend Changes or discussions relating to the backend server domain: l10n Changes or discussions relating to localization & Internationalization labels May 27, 2026

This comment was marked as resolved.

@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

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>

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

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comment thread grails-app/services/org/pih/warehouse/core/UserService.groovy
- `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>
@mdpearson mdpearson force-pushed the user-management-develop branch from dcc95b9 to 5fc91cc Compare May 27, 2026 21:35
@mdpearson mdpearson requested a review from jmiranda May 27, 2026 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: backend Changes or discussions relating to the backend server domain: l10n Changes or discussions relating to localization & Internationalization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants