Repository navigation
Conversation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SamDP1AS8ybBhCc1CWBWWk
tamassoltesz
left a comment
There was a problem hiding this comment.
Checked against core #1506 (base: 12.4 tip), plugin-interface #239, and core 12.3.1 / 12.4 for acsURLs. Nothing blocking; the only v5_8 use in #1506 src/main is the required-once-set flag, so nothing gated is missing. Inline comments are precision fixes. As the PR body says, worth re-checking against #1506 once it merges.
Verified correct:
attributeMappingkeys are exactlyuserId,email,firstName,lastName; unknown keys, wrong counts (1-10), non-strings, empty, padded and > 512 names are all 400s naming the key (SAMLAttributeMapping.java:82-114);null/{}mean no mapping; names match exactly and case-sensitively.- The default lists match
DEFAULT_USER_ID/DEFAULT_EMAIL(:53-56), including NameID counting for email only with an@; fields a mapping leaves out use the defaults. acsURLs: when set, the loginacsURLmust be a member (INVALID_CLIENT_ERROR); IdP-initiated responses are pinned to it; required whenallowIDPInitiatedLoginis true (400 "acsURLs must contain at least one URL when allowIDPInitiatedLogin is true"); IdP-initiated login without a list is refused.null/[]clearing it is correct for 5.8 (on 12.4acsURLs: nullwas a 400).- Required-once-set: gated exactly on
SemVer.v5_8(CreateOrUpdateSamlClientAPI.java:117); the 400 names the field; below 5.8 the stored value is kept; new clients (including generated ids) are exempt; JSONnullcounts as sent. samlClientcarriesacsURLs/attributeMappingonly when set (PI #239toJson), on both PUT and/clients/list./recipe/saml/user: mapping read at call time;sub/emailalways present and nullable;firstName/lastNameonly when mapped and found.info.version5.8.0, thecdi-versionexample, the CHANGELOG entry; #1506 declares 5.8 and returns it as the latest version.
| Exchange the single-use `code` returned by `/recipe/saml/callback` (passed as `accessToken`) for the authenticated user's SAML claims. | ||
| The code is removed on first use; a second call returns `INVALID_TOKEN_ERROR`. | ||
|
|
||
| For a client with an `attributeMapping`, `sub`, `email`, `firstName` and `lastName` are resolved through it at the time of this call (using the client's current mapping, with the default lists for fields it leaves out). A client without a mapping uses the built-in rules described on each field. |
There was a problem hiding this comment.
The built-in rules for clients without a mapping aren't the default lists, and the sub / email descriptions below now only describe the lists. Without a mapping, the first claim present wins and its value is taken as is (SAML.java:989-994 @ #1506: if (claims.has("NameID")) { sub = …get(0).getAsString(); }, same pattern for emailaddress / mail / email at :1008-1016). With a mapping, blank values are skipped (SAMLAttributeMapping.java:134).
So a blank NameID gives sub: "" without a mapping and falls through with one (core's CHANGELOG states this difference). Suggest describing the built-in chain separately on sub / email, or noting the blank-value difference here.
There was a problem hiding this comment.
Fixed in 6ff90b4: sub / email now describe the built-in chain (first present claim, taken as is, so a blank NameID gives an empty sub) separately from the mapping resolution (blank values fall through); the schema description and CHANGELOG note the difference.
| type: object | ||
| nullable: true | ||
| description: | | ||
| Which assertion claims supply the user's id, email, first name and last name, as ordered fallback lists of claim names (attribute `Name`s; `NameID` is the Subject NameID). For each field the first listed claim with a non-blank value wins. For `email`, `NameID` only counts if it contains an `@`. |
There was a problem hiding this comment.
Only each claim's first value is considered: SAMLAttributeMapping.java:189-193 takes array.get(0) and skips the claim if that is blank, even if a later value isn't. Suggest "the first listed claim whose first value is non-blank wins" (matches the core CHANGELOG wording).
There was a problem hiding this comment.
Fixed in 6ff90b4: "first listed claim whose first value is non-blank wins (only a claim's first value is considered)".
| description: | | ||
| Optional allow-list of Assertion Consumer Service URLs. When set, the `acsURL` given to `/recipe/saml/login` must be a member, and the `Destination` / `SubjectConfirmationData.Recipient` of an IdP-initiated response must be a member. | ||
| Required (at least one URL) when `allowIDPInitiatedLogin` is true; IdP-initiated logins for a client without one are refused. | ||
| Required once set (see above). `null` and `[]` clear it. Entries must be non-empty strings. |
There was a problem hiding this comment.
Core also rejects whitespace-only and non-string entries (SAML.java:500: !a.isJsonPrimitive() || !…isString() || a.getAsString().trim().isEmpty(), 400 "acsURLs must only contain non-empty strings"). Suggest "Entries must be strings that are not empty or whitespace-only".
There was a problem hiding this comment.
Fixed in 6ff90b4: "strings that are not empty or whitespace-only".
| type: array | ||
| nullable: true | ||
| description: | | ||
| Optional allow-list of Assertion Consumer Service URLs. When set, the `acsURL` given to `/recipe/saml/login` must be a member, and the `Destination` / `SubjectConfirmationData.Recipient` of an IdP-initiated response must be a member. |
There was a problem hiding this comment.
Destination and SubjectConfirmationData.Recipient are only checked when present (SAML.java:548-549, :562-563: if (destination != null && !allowedAcs.contains(destination))). Suggest "…must be a member when present".
There was a problem hiding this comment.
Fixed in 6ff90b4: "must be a member when present".
| - `email`: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`, `mail`, `email`, `NameID` | ||
| - `firstName`, `lastName`: none | ||
|
|
||
| Each list has 1 to 10 names; each name is a non-empty string of at most 512 characters with no leading or trailing whitespace (names match claims exactly and case-sensitively). Unknown keys are rejected. Invalid mappings return a 400 naming the key. |
There was a problem hiding this comment.
Nit: the limit is s.length() > 512, i.e. UTF-16 code units, and the whitespace check is String.trim(), which only strips characters up to U+0020 (SAMLAttributeMapping.java:107-111). Only matters for non-BMP or Unicode-whitespace claim names; mention it only if you want the spec exact.
There was a problem hiding this comment.
Took the UTF-16 code units part in 6ff90b4; left trim() semantics out to keep it readable.
- built-in rules (no mapping) take the first present claim as is; a mapping skips blank values - described separately on sub/email - only a claim's first value is considered - acsURLs entries: strings, not empty or whitespace-only; Destination/Recipient checked when present - 512 is UTF-16 code units Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SamDP1AS8ybBhCc1CWBWWk
- built-in rules (no mapping) take the first present claim as is; a mapping skips blank values - described separately on sub/email - only a claim's first value is considered - acsURLs entries: strings, not empty or whitespace-only; Destination/Recipient checked when present - 512 is UTF-16 code units - CHANGELOG: acsURLs itself is documented in 5.4.1; 5.8 adds null-clearing Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SamDP1AS8ybBhCc1CWBWWk
593a6dc to
240a07e
Compare
|
Restructured: this branch now carries only its own version's changes (the earlier push had duplicated the 5.4.1 / 5.5 wording fixes as extra commits). Those arrive by merging the base branches forward — #105 → |
CDI 5.8 — SAML client
attributeMappingandacsURLs(PLAN-M-016)Core: supertokens-core#1506 (draft, 12.5.0), supertokens-plugin-interface#239, supertokens-postgresql-plugin#429. Keep this PR in draft until core#1506 merges, and re-check the field validation against the merged version.
Spec changes
PUT /appid-<appId>/<tenantId>/recipe/saml/clientsattributeMapping(userId,email,firstName,lastName, each 1–10 claim names ≤ 512 chars, no surrounding whitespace, unknown keys rejected;null/{}= no mapping). NewsamlAttributeMappingschema with the default lists.acsURLs(accepted by core since 12.3.1 but never in a spec): allow-list for the loginacsURLand for IdP-initiatedDestination/Recipient; required whenallowIDPInitiatedLoginis true;null/[]clear it.nullclears); omitting it is a 400 naming the field. Below 5.8 the stored value is kept instead.samlClient(PUT response and/recipe/saml/clients/list) carriesacsURLsandattributeMappingwhen set.POST /appid-<appId>/<tenantId>/recipe/saml/usersub/emailare resolved through the client's mapping (defaults for fields it leaves out);firstName/lastNameare returned when mapped and found.Follow-ups
refs/heads/5.8/api_spec.yaml, so the5.8branch must exist on origin before they can run.Stacked on
5.7; base branch5.8was cut from the tip offeat/5.7-users-count-ledger.