Skip to content

Release 1.14.0

Choose a tag to compare

@github-actions github-actions released this 09 Jul 23:15
· 2 commits to main since this release
e4db54f
feat(mapper): email-domain-guard — update-path email domain guard (#14)

* feat(mapper): email-domain-guard update-path email guard

Adds email-domain-guard-idp-mapper, a broker-time guard that stops an
already-linked identity provider from rewriting an account's email onto a
domain it is not authoritative for.

Companion to idp-asserted-domain-matches (#13): that condition guards the
first-broker-login create/link path; this mapper guards the *update* path,
which no authentication flow runs on. A returning brokered login (existing
(idp, brokerUserId) link) skips first-broker-login entirely — Keycloak calls
updateBrokeredUser and, under FORCE sync, rewrites email + re-derives
emailVerified from the provider's trustEmail, with no flow to intercept.

preprocessFederatedIdentity runs in IdentityBrokerService.authenticated
before that write. When a federated link already exists (update path only)
and the provider has domains configured, an out-of-domain asserted email is
nulled — Keycloak's updateEmail early-returns on a null email, so the account
keeps its existing verified address. First broker login and domain-less
providers pass through untouched (the auth flow owns the former; the latter
has no basis to judge domain membership).

Runs on all providers (reads the normalized context email + provider domain
list, neither protocol-specific). Suppression decision extracted to a pure
shouldSuppressEmail() and unit-tested; domain matching reuses EmailDomainMatcher.
Bumps version to 1.14.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* perf(mapper): gate update-path link lookup behind the domain check

preprocessFederatedIdentity runs on every brokered login. Move the cheap
in-memory domain parse + match ahead of the getUserByFederatedIdentity DB
lookup, and skip the lookup entirely for the common in-domain (or no-domains)
case — only an out-of-domain email on a domains-configured provider can ever
be suppressed. No behavior change; shouldSuppressEmail stays the authoritative
decision.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(mapper): use Keycloak's "Preprocessor" display category

The mapper adjusts the brokered context via preprocessFederatedIdentity
before the user is written; it does not import an attribute. "Preprocessor"
is Keycloak's built-in category for exactly this kind of mapper (its own
Username Template mapper uses it), so the guard groups correctly in the admin
UI's mapper-type dropdown instead of appearing under "Attribute Importer".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Jared Gibson <jared@gibson.run>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>