wip: Support authenticating multiple principals in a single request
Related issue(s)
closes #921 replaces #1317
Checklist
- [x] I agree to follow this project's Code of Conduct.
- [x] I have read, and I am following this repository's Contributing Guidelines.
- [x] I have read the Security Policy.
- [x] I have referenced an issue describing the bug/feature request.
- [ ] I have added tests that prove the correctness of my implementation.
- [ ] I have updated the documentation.
Description
Certain use cases, e.g. like described in the referenced FR #921 require information from multiple independent identity sources (e.g., user identity + client identity, or user identity + workload identity) to be available within the same request context. Previously, heimdall’s authenticators were evaluated in a sequential fallback manner — subsequent authenticators were only invoked if the preceding ones failed.
This PR continues the work done in #1487, #2260, #2665, #2825 and #2827, and extends heimdall’s authentication capabilities to support multiple principals within a single request. Authenticators can now be combined to produce distinct Principal objects, enabling the definition of multi-principal subjects. As a result, multiple authenticators can execute successfully and contribute separate identity data to the request’s Subject object, allowing policies and authorization decisions to leverage richer contextual information.
Behaviour
- When multiple authenticators are configured with different principals, they will all be executed, and each successful authenticator contributes to the resulting subject.
- When multiple authenticators are configured with the same principal, the evaluation follows the previous fallback behavior (the first successful authenticator wins).
- The overall evaluation follows a conjunctive (CNF-like) composition model (see examples below)
Configuration and Access Model
Each authenticator step in the pipeline can now define an optional principal property that specifies the name of the principal it produces:
- authenticator: A
principal: user
- authenticator: B
principal: client
If the principal property is omitted, the authenticator writes to the "default" Principal:
- authenticator: A
- authenticator: B
The default principal is mandatory and is always expected to be created.
Subsequent pipeline stages can access principal data via the following syntax:
-
Subject.IDandSubject.Attributes→ refer toSubject.default.IDandSubject.default.Attributes(syntactic sugar). -
Subject.<principal-name>.IDandSubject.<principal-name>.Attributes→ access explicitly named principals.
Examples
-
Independent authenticators (A and B):
- authenticator: A principal: default - authenticator: B principal: bBoth A and B are executed; both principals
defaultandbare established. If some of the authenticator steps fails, the entire authenticate stage fails. -
Fallback authenticators (A or B):
- authenticator: A - authenticator: BBoth write to the
defaultprincipal; B acts as fallback if A fails. It basically defines the behavior which was available before this PR. -
Combined example (A and (B or C)):
- authenticator: A - authenticator: B principal: b - authenticator: C principal: bA must succeed (creates
defaultprincipal), and either B or C must succeed (createsbprincipal).
Codecov Report
:x: Patch coverage is 88.66750% with 91 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 90.86%. Comparing base (afd5552) to head (1e7fccb).
:white_check_mark: All tests successful. No failed tests found.
Additional details and impacted files
@@ Coverage Diff @@
## main #2849 +/- ##
==========================================
- Coverage 91.21% 90.86% -0.35%
==========================================
Files 298 295 -3
Lines 11196 11214 +18
==========================================
- Hits 10212 10190 -22
- Misses 715 757 +42
+ Partials 269 267 -2
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.