Repository navigation
feat: optional authorisation without groups - #116
Conversation
Some OIDC providers (e.g. LS Login) give no group memberships, so the group-based authorisation of TESK API cannot be used with them. Add tesk.api.authorisation.claim.enabled/name/values (off by default). When on, users whose user info has one of the values in the claim may create tasks without a group, and list, get and cancel their own tasks without a group. Group members, team admins and super admins keep their rules; super admins still list all tasks (no user-ID selector). The setting fails at startup without a claim name or a non-blank value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Settings, rules and security implications in the access control and configuration docs; an entry in the upgrade notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Trim the configured claim values; drop the array branch (user info comes from JSON: a string or a list). - List the default of tesk.api.authorisation.claim.enabled in application.properties. - Tests: null and trimmed values, non-string claims, equals/hashCode, setting off for get and cancel, cancel without or with a wrong claim, admins and members with the claim, creating for the own group. - Docs: mention the claim in the intros, the 403 of the API and the index; document that members and team admins with the claim do not list their own tasks without a team. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewer's GuideData structuresAdd claim-authorisation state to
APIExtend the service authorization contracts so claim users can create ungrouped tasks, access their own ungrouped tasks, list tasks, and reach cancellation subject to ownership checks.
ImplementationExtract the configured claim from user-info responses, validate enabled configuration at startup, and mark users authorised when a string claim value matches exactly.
ConfigurationIntroduce claim-authorisation configuration properties and document the default-off setting in application properties.
DocumentationExplain claim-based authorisation, its settings and security implications, and update the API, configuration, index and upgrade documentation.
TestsCover enabled and disabled claim authorisation across user-info extraction, task permissions, configuration errors, selectors, and preservation of group-based rights.
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #116 +/- ##
==========================================
+ Coverage 63.24% 64.05% +0.81%
==========================================
Files 66 66
Lines 2530 2579 +49
Branches 262 268 +6
==========================================
+ Hits 1600 1652 +52
+ Misses 790 778 -12
- Partials 140 149 +9 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/main/java/uk/ac/ebi/tsc/tesk/config/security/User.java" line_range="138" />
<code_context>
+ // above, so that they keep seeing all tasks)
+ return Constants.LABEL_USERID_KEY
+ + "="
+ + getUsername()
+ + ",!"
+ + Constants.LABEL_GROUPNAME_KEY;
</code_context>
<issue_to_address>
**Colliding subjects expose ungrouped tasks**
When two distinct subjects that are both authorised by the claim become equal after `@` is replaced with `_`, `getUsername()` maps both `a@b` and `a_b` to the same label value, so the selector returns both users’ ungrouped tasks and the ownership check also lets either user get or cancel the other’s task.
Use a collision-resistant, Kubernetes-label-safe encoding of the raw subject consistently for task labels, selectors, and ownership checks.
</issue_to_address>Linked issues
#78 feat: optional authorisation without groups · 3 of 3 met
| # | Requirement | Status | Notes |
|---|---|---|---|
| 1 | Opt-in authorisation without group membership, with the policy decided and documented | ✅ Met | The configurable-claim policy is off by default, validates its configuration at startup, and is described with its rules and security implications in the access-control docs. |
| 2 | Admins can still list all tasks with the setting on | ✅ Met | The admin branch in User.getLabelSelector() returns null before the claim-user selector; ClaimAuthIT tests listing with and without the claim. |
| 3 | Tests cover the setting on and off, for users and admins | ✅ Met | ClaimAuthIT covers users and admins with the setting on; AuthIT covers users with it off and includes the existing super-admin list test with the default setting off. |
Sourcery assessment
Needs a human reviewer. 1 finding to address first, and a matching user-info claim now lets a user without group membership submit tasks, including containers and commands that run on the cluster. Reverting removes that authorization for future requests, but it cannot undo jobs already launched or their side effects.
Blocking findings: src/main/java/uk/ac/ebi/tsc/tesk/config/security/User.java:138
Summary
This adds opt-in authorisation without groups, with the "configurable claim" policy, for OIDC providers that release no group memberships (e.g. LS Login). It is off by default; with the setting off, behaviour is unchanged.
New settings (
tesk.api.authorisation.claim.*):The Helm chart of TESK doesn't set these yet; that follows separately.
With the setting on:
GROUP_NAMEtag is refused unless the group rules allow it. They may list, get and cancel their own tasks without a group, and no others. Their list selector iscreator-user-id=<user>,!creator-group-name.getLabelSelectorreturns null for admins before the claim branch.docs/access-control.mdgets a new section "Authorisation without groups": settings, rules, security implications, and the listing caveat for members and team admins with the claim.docs/configuration.mdanddocs/upgrading.md.index.mdand the 403 row ofapi.md.application.propertieslists the default.Closes #78
Verification
ClaimAuthorisationTest(unit) andClaimAuthIT(integration, setting on), plusAuthIT.claimWithoutGroups_settingOff(setting off). With compile stubs, 7 unit and 5 integration tests failed; after the implementation, all pass.dev(with fix: validate paging parameters of ListTasks #115):./mvnw -B spotless:check checkstyle:check clean verify(Temurin 8) gives BUILD SUCCESS, with 7348 unit tests and 77 integration tests and no failures.Declined review findings
docs/access-control.md.cancelTask's@PreAuthorizelets claim users through, and ownership is checked by the controller'sgetTask(@PostAuthorize), as it already was for group members.claimUser_cancelOthersTaskcovers this, and the Javadoc says so.ClaimAuthITandAuthIT; they keep the existing self-contained style. The stub for a task without a group moved toMockUtil.IllegalStateException.subvalues that collide after@is replaced by_would share tasks. This mapping predates this PR and applies to group members as well; changing it would orphan the labels of existing tasks, so it needs its own change with a migration path.tags: {"GROUP_NAME": null}passes like no tag; this was already the case for members before, so it is out of scope.Open questions
None.
🤖 Generated with Claude Code