Skip to content

feat: DSPX-2416 add subject mapping guide#182

Open
marythought wants to merge 17 commits intomainfrom
feat/dspx-2416
Open

feat: DSPX-2416 add subject mapping guide#182
marythought wants to merge 17 commits intomainfrom
feat/dspx-2416

Conversation

@marythought
Copy link
Contributor

Summary

Creates comprehensive Subject Mapping guide to resolve the top recurring documentation gap identified across community discussions.

Changes

New: Subject Mapping Comprehensive Guide

Created /docs/guides/subject-mapping-guide.md - a complete tutorial addressing the most frequently misunderstood concept in OpenTDF.

What It Covers:

  • Why Subject Mappings exist: Addresses the core misconception that IdP attributes directly map to OpenTDF attributes
  • Complete authentication flow: Sequence diagrams showing IdP → Entity Resolution → Subject Mapping → Authorization
  • Entity types explained: Clarifies PE/NPE, Subject/Environment categories, and the common jwtentity-0 vs jwtentity-1 confusion
  • Subject Condition Sets: 5 progressively complex examples from simple role matching to multi-group logic
  • Enumerated vs. Dynamic attributes: Most frequently asked question - when to use fixed values vs. freeform strings
  • Real IdP integration examples: Keycloak, Auth0, and Okta with actual token structures and JMESPath selectors
  • Step-by-step creation guide: Complete workflow using otdfctl commands
  • Comprehensive troubleshooting: Solutions for "resource relation invalid", missing entitlements, and entity type issues
  • Best practices & FAQ: Reusable condition sets, hierarchical attributes, pattern-based mappings

Documentation Structure

  • Created new "Guides" section (/docs/guides/) for comprehensive tutorials and deep-dives
  • Added cross-reference in /docs/components/policy/subject_mappings.md pointing to the comprehensive guide
  • Established pattern for future comprehensive guides

Preview

https://opentdf-docs-preview-dspx-2416.surge.sh/guides/subject-mapping-guide

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @marythought, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the OpenTDF documentation by introducing a comprehensive guide on Subject Mapping. This guide aims to resolve common misunderstandings by clearly explaining how identity provider attributes are translated into OpenTDF access entitlements, detailing the full authentication and authorization flow, and providing practical examples and troubleshooting steps. The addition of a new 'Guides' section also improves the overall organization and discoverability of in-depth tutorials.

Highlights

  • New Comprehensive Subject Mapping Guide: A detailed tutorial has been added at /docs/guides/subject-mapping-guide.md to clarify core concepts, authentication flow, entity types, condition sets, attribute types, IdP integration examples (Keycloak, Auth0, Okta), creation steps, troubleshooting, and best practices for Subject Mappings.
  • Documentation Structure Enhancement: A new 'Guides' section (/docs/guides/) has been introduced in the documentation to organize comprehensive tutorials and deep-dives, improving content discoverability.
  • Cross-referencing Existing Documentation: The existing docs/components/policy/subject_mappings.md file now includes a prominent tip box that links directly to the new comprehensive Subject Mapping guide, ensuring users are directed to the most complete resource.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • docs/components/policy/subject_mappings.md
    • Added a Docusaurus tip block at the beginning of the file, directing users to the new comprehensive Subject Mapping guide.
  • docs/guides/category.json
    • Created a new JSON file to define the 'Guides' category in the documentation sidebar, including its label, position, and description.
  • docs/guides/subject-mapping-guide.md
    • Added a new Markdown file containing the extensive 'Subject Mapping: Comprehensive Guide'. This guide covers the core problem, architecture, entity types, condition sets with examples, enumerated vs. dynamic attributes, IdP integration examples (Keycloak, Auth0, Okta), step-by-step creation, troubleshooting, best practices, and FAQs.
Activity
  • The author, marythought, has created a new comprehensive guide for Subject Mapping.
  • The documentation structure has been updated to include a new 'Guides' section.
  • An existing documentation page now cross-references the newly created guide.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive guide for Subject Mappings, a frequently misunderstood concept in OpenTDF. The new guide is well-structured, detailed, and covers the topic from core concepts to IdP integration and troubleshooting. The changes also include creating a new 'Guides' section in the documentation and linking to the new guide from the existing subject mappings page. Overall, this is an excellent addition to the documentation that will be very helpful for the community. I have one suggestion to improve the clarity of the section on dynamic attributes to avoid potential confusion for users.

@marythought marythought marked this pull request as ready for review February 9, 2026 22:13
@marythought marythought requested a review from a team as a code owner February 9, 2026 22:13
@jp-ayyappan
Copy link
Contributor

You and I, we are working on the same stuff; we should sync up and I should hand over my branch to you before you re-write everything.

https://github.com/opentdf/docs/blob/docs/update_policy_docs/docs/explanation/platform-architecture/components/policy/subject_mappings.md

Copy link
Contributor

@jp-ayyappan jp-ayyappan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check my comment on the PR; we should sync up

@marythought
Copy link
Contributor Author

marythought commented Feb 12, 2026

You and I, we are working on the same stuff; we should sync up and I should hand over my branch to you before you re-write everything.

https://github.com/opentdf/docs/blob/docs/update_policy_docs/docs/explanation/platform-architecture/components/policy/subject_mappings.md

@jp-ayyappan It looks like your changes are to the component page about subject mappings, which is great. This one is built as a guide/deep dive that references that page, so I don't think there is any conflict here.

@marythought marythought force-pushed the feat/dspx-2416 branch 3 times, most recently from 5ec83fe to d13dfd0 Compare February 17, 2026 19:24
@marythought
Copy link
Contributor Author

This PR introduces the concept of a "Guide", which may or may not be aligned with the Diataxis definition: https://diataxis.fr/how-to-guides/ . I am open to moving this to an alternative section or re-writing it to be more of a "guide" based on that link.

Signed-off-by: Mary Dickson <mary.dickson@virtru.com>
Signed-off-by: Mary Dickson <mary.dickson@virtru.com>
Signed-off-by: Mary Dickson <mary.dickson@virtru.com>
Signed-off-by: Mary Dickson <mary.dickson@virtru.com>
Signed-off-by: Mary Dickson <mary.dickson@virtru.com>
marythought and others added 2 commits February 18, 2026 09:25
Signed-off-by: Mary Dickson <mary.dickson@virtru.com>
@jp-ayyappan
Copy link
Contributor

We should get rid of the Vale check and introduce something else that is better

jp-ayyappan
jp-ayyappan previously approved these changes Feb 20, 2026
Copy link
Contributor

@jp-ayyappan jp-ayyappan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -1,5 +1,9 @@
# Subject Mappings

:::tip New to Subject Mappings?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure the best way to do this, but we will want to make it clearer that Subject Mappings are actually logically checking the Entity Resolution Service response (entity representation). The source of truth for the ERS to build an entity representation can be:

  1. access token claims (the actual JWT)
  2. idP user info (keycloak, okta, etc)
  3. LDAP (active directory, etc)
  4. SQL (a relational database)

The multi-strategy ERS still in experimental status, but there is a need to productionize it to support entity attributes from diverse sources. Mature organizations keep user/entity information across several kinds of systems, and as a platform we should support these.

Practically that means a subject mapping relating a condition set to an attribute value where the condition set finds jake@acme.org IN .emailAddress, depending on the ERS running with the platform and its mode, that could be:

  1. a JWT payload claim emailAddress in my access token
  2. an attribute in my idP emailAddress
  3. a directory attribute emailAddress in my LDAP system
  4. a column value in my row in a SQL-compatible database, where a query results in a JSON object with a key emailAddress

TLDR: we should find a clear way to communicate that entity attributes are stored in diverse systems, organized/resolved by ERS, conditionally resolved to platform Attribute Values via Subject Mappings with Subject Condition Sets.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in commit 930f394 — added a :::note block immediately after the :::tip in subject_mappings.md that explains:

  • Subject Mappings evaluate against the Entity Representation produced by ERS, not directly against IdP tokens
  • Lists the four sources (JWT claims, IdP user info, LDAP/AD, SQL) explicitly
  • Notes that the same .emailAddress selector works regardless of which source ERS resolves it from
  • Links to the Entity Resolution docs for multi-source ERS details
  • Added a note that multi-source support is available (left the experimental status callout to the ERS docs page rather than flagging it as experimental here, since that status may change)

"conditions": [{
"subject_external_selector_value": ".groups",
"operator": 3,
"subject_external_values": ["/finance/"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if these pre and post-fixed slashes are typical. If not, they look a little confusing given our FQN structure, so maybe we could remove them?

Copy link
Contributor Author

@marythought marythought Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakedoublev ok, I spiraled with Claude on this for a good amount of time. It insists that they are needed specifically for a Keycloak group due to the "contains" lookup to prevent false matches. Does this make sense to you? It makes sense to me (based on the underlying code), and if it checks out we can add a comment explaining why the slashes are needed here and not elsewhere.

Why /finance/ has slashes:

Keycloak's "Full Group Path" mapper — when enabled, Keycloak includes group paths in tokens as slash-prefixed hierarchical paths: /finance/senior, not finance. The guide says "User 'bob' is in Keycloak group: /finance/senior" — that IS the literal token value when Full Group Path is on.

Operator 3 is IN_CONTAINS — from [subject_mapping_builtin.go:252](vscode-webview://1p4elejgd9vcld7v92e8m83vnphukfjrb0fjgesrann251okld6r/code/opentdf/platform/service/internal/subjectmappingbuiltin/subject_mapping_builtin.go#L252), this does strings.Contains(mappedValue, possibleValue). So it checks whether the group string /finance/senior contains the substring /finance/.

The trailing slash is intentional precision — /finance/ prevents false matches against /finance-external or /financeops. Without it, IN_CONTAINS with /finance would match any group starting with those characters.

- `jwtentity-0`: The **client application** (NPE - Non-Person Entity)
- `jwtentity-1`: The **user** (PE - Person Entity)

**Both need Subject Mappings** if both need attribute access. For SDK decryption, typically the client (`jwtentity-0`) needs mappings based on `.clientId`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more reliable field to check in logs is environment vs subject entity. In GetEntitlements flows, both subject and environment category entities are considered. In GetDecision flows, only subject category entities are considered, so only they need subject mappings. All users authenticate to an idP through an OIDC Client, which is what causes two chained entities to be present in the authorization logs, but the client (environment) and user (subject) are only identical when using client credentials authentication flows as service accounts for NPEs. Otherwise, the user and client will each correspond to the subject and environment entities in the logs and decisioning flows respectively.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed!

marythought and others added 3 commits February 24, 2026 08:38
…d content and deprecated APIs

- Replace deprecated STANDARD_ACTION_DECRYPT with `read` throughout (objects.proto)
- Fix selector syntax: was incorrectly described as JMESPath; platform uses custom
  flattening library (platform/lib/flattening/flatten.go)
- Correct entity category explanation: only CATEGORY_SUBJECT entities are evaluated
  in GetDecision flows; CATEGORY_ENVIRONMENT (OIDC client) is excluded (authorization.go:653-666)
- Rewrite "Dynamic Attribute Values" section — feature does not exist; all values
  must be explicitly created (attributes.proto CreateAttributeValueRequest)
- Remove Auth0 IdP section (untested)
- Remove nonexistent "order" key from HIERARCHY attribute JSON (objects.proto Value message)
- Fix troubleshooting DENY advice: client entity does not need Subject Mappings in
  user-auth flows; clarify service account (client credentials) exception
- Add otdfctl dev selectors generate/test examples to troubleshooting
- Add ERS multi-source note to subject_mappings.md (JWT, LDAP, SQL, IdP user info)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…2930, #1877, #1483, #1021

- Add --subject-sets-file-json alternative for complex condition sets (#1483)
- Add --allow-traversal flag explanation for encrypt-before-value-exists pattern (#2930, #1877)
- Link to ADR #1181 (typed entities) to explain SUBJECT/ENVIRONMENT design intent (#1021)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
marythought and others added 2 commits February 24, 2026 12:11
… Keycloak group paths

- .groups → .groups[] for Keycloak and Okta group examples
- .realm_access.roles → .realm_access.roles[] for Keycloak role examples
- Add scalar vs array selector reference table with explanation
- Fix troubleshooting array example with explanatory comment
- Add note on Keycloak Full Group Path mapper and why values include slashes

Evidence: lib/flattening/flatten.go produces .key[], .key[0] for arrays —
there is no .key key. Confirmed by subject_mapping_builtin_actions_test.go:85
which uses SubjectExternalSelectorValue: ".groups[]"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Scope (?i)tdf → (?i:tdf) to prevent Go regexp from applying
  case-insensitive flag to all subsequent vocab entries (root cause
  of spurious Vale.Terms errors like "Use 'JWT' instead of 'IdP'")
- Fix invalid PCRE conditionals: rewrap(?(s)) → rewraps? and
  requester(?('s)) → requester('s)?
- Add CI, [Ss]hellcheck, and Okta to suppress false spelling errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
marythought and others added 3 commits February 24, 2026 15:53
… and accuracy

- Add NIST roles table with actionable "How to use it" links
- Update high-level diagram to use full service names
- Move NIST table below the diagram
- Add per-step-group intro sentences explaining each phase
- Fix JWT claims note: clarify email/role/groups are configured, not standard
- Remove duplicate prose in steps 3-5 and 6-9
- Add plain-language intro to Subject Mapping JSON example
- Fix ERS description: called by KAS, not Authorization Service

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…or codes, fix fake IDs

- Add inline explanation of boolean_operator and operator enum values in Step 1 with link to reference section
- Add otdfctl policy attributes list command to Step 2 so users can find their attribute ID
- Add substitution reminder in Step 3 (IDs shown are from previous steps)
- Fix sm-789xyz fake placeholder to a proper UUID format in Steps 3 and 4
- Link prerequisites (platform running, otdfctl) to /quickstart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Explain .email selector syntax and link to Selectors section
- Clarify subject_external_values are matched against JWT claim values
- Show attributes list first in Step 2; explain UUID format and clearance/secret display label
- Explain --action read is the standard decrypt action
- Add payoff sentence in Step 3 explaining what the mapping does at runtime
- Add Step 4 guidance on what a correct mapping looks like and what null subject_condition_set means
- Add Next Steps section pointing to TDF SDK and troubleshooting
- Fix diagram box border cutoff with mirrorActors: false
- Fix intro sentence for step-by-step section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants