Skip to content

[PM-40209] Add PAM access claim and ManageAccessRules permission - #8160

Open
Hinton wants to merge 1 commit into
mainfrom
pam/claims-permission-plumbing
Open

[PM-40209] Add PAM access claim and ManageAccessRules permission#8160
Hinton wants to merge 1 commit into
mainfrom
pam/claims-permission-plumbing

Conversation

@Hinton

@Hinton Hinton commented Aug 7, 2026

Copy link
Copy Markdown
Member

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-40209

📔 Objective

The identity/authorization spine for PAM, mirroring the Secrets Manager shape throughout: an accesspam claim beside accesssecretsmanager, and the one PAM custom permission, ManageAccessRules. Holding AccessPam is the access grant — there is no separate "can access PAM items" permission; ManageAccessRules only gates Access Rule authorship.

Consumption is left to the IOrganizationRequirement pattern (ADR-0022) in PM-40211, so this only touches claim emission and the claims-parsing path the requirement handler reads.

Worth flagging for review:

  • CurrentContext is untouched — no AccessPam(orgId)/ManageAccessRules(orgId) helpers, no changes to its hand-rolled claims parsers. That's the legacy path requirements replace.
  • PamAccess is deliberately not in UserIdentityClaimTypes. It's an authorization claim, so it must be rebuilt from the database on every issuance rather than carried across a refresh.
  • Two additions beyond the ticket's scope. ApiResources declares Claims.PamAccess where SecretsManagerAccess already sits (not load-bearing, but keeps the declared resource claims honest). The public API's hand-rolled PermissionsModel gains ManageAccessRules, because ToData() rebuilds the whole object and would otherwise silently clear it on PUT /public/members/{id}; ToData_RoundTripsEveryPermission guards that mirror against future drift.
  • Known gap: OrganizationService.ValidateCustomPermissionsGrant enumerates permissions against ICurrentContext, so it doesn't cover ManageAccessRules — a Custom member with ManageUsers could grant it without holding it. The newer OrganizationUserValidationService uses ClaimsMap and is covered. Closing the legacy path needs the CurrentContext helpers this story excludes.

Depends on PM-40208 (the OrganizationUser.AccessPam column), already merged.

@Hinton Hinton added the t:feature Change Type - Feature Development label Aug 7, 2026
@Hinton
Hinton marked this pull request as ready for review August 7, 2026 09:31
@Hinton
Hinton requested review from a team as code owners August 7, 2026 09:31
@Hinton
Hinton requested review from JaredScar and enmande August 7, 2026 09:31
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed the PAM identity/authorization spine: the accesspam claim emission in CoreHelpers.BuildIdentityClaims, the ManageAccessRules custom permission, and the claims-parsing path in OrganizationClaimsExtensions. Traced the claim end-to-end — CurrentContextOrganization gates AccessPam on AccessPam && UsePam && Enabled (mirroring Secrets Manager), ProfileService rebuilds claims from the database on every issuance, and PamAccess is correctly excluded from the UserIdentityClaimTypes allowlist so it cannot survive a refresh. Verified ManageAccessRules reaches every hand-rolled mirror that would otherwise drop it (Permissions.ClaimsMap, public PermissionsModel, OrganizationClaimsExtensions), and that OrganizationUserValidationService.ValidateCustomPermissionsGrant picks it up automatically via ClaimsMap on DB-sourced OrganizationUser actors. No findings met the confidence threshold for an inline comment.

Code Review Details

No findings.

Notes considered and intentionally not raised as findings:

  • The OrganizationService.ValidateCustomPermissionsGrant gap (legacy ICurrentContext enumeration does not cover ManageAccessRules) and the untouched CurrentContext.SetOrganizationPermissionsFromClaims parser are both explicitly documented in the PR description with rationale and follow-up scope. Both fail closed today since nothing consumes ManageAccessRules until PM-40211.
  • PermissionsModelTests.ToData_RoundTripsEveryPermission is a good guard against the silent-clear class of bug on PUT /public/members/{id}; it will catch future drift automatically.

Comment thread src/Core/Utilities/CoreHelpers.cs Fixed
@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.06%. Comparing base (73ed2f6) to head (76f8d09).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main    #8160       +/-   ##
===========================================
+ Coverage   15.10%   63.06%   +47.95%     
===========================================
  Files        1417     2315      +898     
  Lines       61422   100530    +39108     
  Branches     4901     9045     +4144     
===========================================
+ Hits         9279    63395    +54116     
+ Misses      51978    34945    -17033     
- Partials      165     2190     +2025     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

The identity/authorization spine for Privileged Access Manager, mirroring the
Secrets Manager shape throughout: an `accesspam` claim beside
`accesssecretsmanager`, and the one PAM custom permission, `ManageAccessRules`.

Holding AccessPam *is* the access grant — there is no separate "can access PAM
items" permission. ManageAccessRules only gates Access Rule authorship.

Claims.PamAccess is deliberately kept out of UserIdentityClaimTypes: it is an
authorization claim, so it must be rebuilt from the database on every token
issuance rather than carried across a refresh.

Consumption is left to the IOrganizationRequirement pattern (ADR-0022) in
PM-40211, so this change only touches claim emission and the claims-parsing path
the requirement handler reads. CurrentContext is untouched — no AccessPam(orgId)
or ManageAccessRules(orgId) helpers, and no changes to its hand-rolled claims
parsers — since that is the legacy path requirements replace.

Permissions.ManageAccessRules gains a ClaimsMap entry, which makes both
custom-permission claim emission in BuildIdentityClaims and the grant-elevation
check in OrganizationUserValidationService automatic. Note that
OrganizationService.ValidateCustomPermissionsGrant enumerates permissions
explicitly against ICurrentContext and therefore does not cover
ManageAccessRules; closing that gap needs the CurrentContext helpers this story
excludes.

Two additions beyond the strict claims spine:

- ApiResources declares Claims.PamAccess on the `api` resource, where
  SecretsManagerAccess already sits. Not load-bearing — ProfileService issues
  claims regardless of RequestedClaimTypes — but it keeps the declared resource
  claims honest.
- The public API's hand-rolled PermissionsModel gains ManageAccessRules. ToData()
  rebuilds the whole permissions object, so without it a PUT to
  /public/members/{id} would silently clear ManageAccessRules on a Custom member.
  ToData_RoundTripsEveryPermission is a reflection-driven guard that now fails
  whenever any permission goes missing from that mirror, rather than only fixing
  this one instance.

Tests cover the AccessPam/UsePam/Enabled gating in CurrentContextOrganization
(and the previously uncovered Secrets Manager equivalent), access-claim emission
for both products, and the claim round trip through OrganizationClaimsExtensions.
@Hinton
Hinton force-pushed the pam/claims-permission-plumbing branch from e0485bd to 76f8d09 Compare August 7, 2026 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t:feature Change Type - Feature Development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant