Skip to content

fix: handle dot-containing claim names in nested claim resolution#1375

Merged
julien-nc merged 1 commit intonextcloud:mainfrom
strobelpierre:fix/dotted-claim-names
Mar 12, 2026
Merged

fix: handle dot-containing claim names in nested claim resolution#1375
julien-nc merged 1 commit intonextcloud:mainfrom
strobelpierre:fix/dotted-claim-names

Conversation

@strobelpierre
Copy link
Contributor

@strobelpierre strobelpierre commented Mar 12, 2026

Summary

When --resolve-nested-claims=1 is enabled, getClaimValues() uses explode('.') to split claim paths. This breaks for:

  1. URL-based claim names (valid per OIDC Core §5.1.2): https://idp.example.com/claims/groups gets split at hostname dots
  2. Object keys with literal dots: {"user.role": "admin"} gets interpreted as nested navigation

Approach: greedy longest-prefix matching

Replace explode('.') with a recursive resolver (resolveNestedClaim()) that:

  1. Tries the full remaining path as a literal key first
  2. Then tries progressively shorter dot-prefixed segments (longest first)
  3. Recurses into the remainder when a prefix matches a nested object/array

This preserves full backward compatibility — existing dot-separated nested paths resolve identically since the algorithm falls through to the same splits.

Examples

Claim path Token payload Result
https://idp.example.com/claims/groups {"https://...groups": ["admin"]} ["admin"]
https://idp.example.com/attrs.role {"https://...attrs": {"role": "admin"}} "admin"
https://idp.example.com/attrs.user.role {"https://...attrs": {"user.role": "admin"}} "admin"
custom.nickname {"custom": {"nickname": "alice"}} "alice" (backward compat)
a.b {"a.b": "flat", "a": {"b": "nested"}} "flat" (literal key precedence)

Fixes #1373
Related: #1100

Test plan

  • Added 13 data-provider test cases covering: flat keys, nested keys, URL claim names, URL + nested navigation, URL + dotted sub-keys, deep nesting, pipe fallbacks, non-existent paths, empty paths, literal dot key precedence, array payloads
  • Added regression test for flat mode (nested resolution disabled)
  • CI phpunit pass

Replace explode('.') with greedy longest-prefix matching that tries the
full remaining path as a literal key first, then progressively shorter
dot-prefixed segments. This correctly handles URL-based claim names
(e.g. "https://idp.example.com/claims/groups") and object keys with
literal dots (e.g. "user.role") as permitted by OIDC Core §5.1.2.

Backward compatible: existing dot-separated nested paths resolve
identically since the algorithm falls through to the same splits.

Fixes nextcloud#1373
Related: nextcloud#1100

Signed-off-by: Strobel Pierre <strobelpierre@gmail.com>
@strobelpierre strobelpierre force-pushed the fix/dotted-claim-names branch from adbf700 to 06b4715 Compare March 12, 2026 15:41
@julien-nc
Copy link
Member

julien-nc commented Mar 12, 2026

@strobelpierre Lgtm. Thank you (and Claude 😁)

@andreblanke @dragonpil Can you confirm the backward compatibility is preserved in this PR for all your use cases?

@strobelpierre
Copy link
Contributor Author

@strobelpierre Lgtm. Thank you (and Claude 😁)

@andreblanke @dragonpil Can you confirm the backward compatibility is preserved in this PR for all your use cases?

Claude and I thank you too, haha 🤝❤️

@julien-nc
Copy link
Member

@strobelpierre I don't know what's gonna become the standard but here is my advice: Keep the "generated with AI/whatever you use" footer in PR comments and in issues. This is more honest and has less chances to trigger readers that don't like AI and will immediately detect AI generated content from the style and the length.

@strobelpierre
Copy link
Contributor Author

@strobelpierre I don't know what's gonna become the standard but here is my advice: Keep the "generated with AI/whatever you use" footer in PR comments and in issues. This is more honest and has less chances to trigger readers that don't like AI and will immediately detect AI generated content from the style and the length.

I completely agree with you, but on another project I had a PR that was fine and added a real feature, and I left the mention claude code that I use to formalize the PR format and also to code. The PR was rejected on the grounds that they don't accept code generated by AI, even though all the tests were fine. There are gatekeepers who automatically reject it.

@andreblanke
Copy link
Contributor

@julien-nc Looks good to me as well. Thanks for the ping.

@julien-nc
Copy link
Member

There are gatekeepers who automatically reject it

I hope this does not turn into a war between AI supporters and detractors.
Honestly your PR is readable, tested, commented, scoped. IMO, good combination of a powerful model and your ability to guide the model wisely.

@julien-nc
Copy link
Member

@andreblanke Thanks a lot for the super fast feedback!

@julien-nc julien-nc merged commit b26e927 into nextcloud:main Mar 12, 2026
45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nested claim resolution breaks when claim name is a URL containing dots

3 participants