Skip to content

multi-ingress: cross-IdP SSO#5212

Open
supersven wants to merge 4 commits into
developfrom
sventennie/multi-ingress-sso_cross_idp
Open

multi-ingress: cross-IdP SSO#5212
supersven wants to merge 4 commits into
developfrom
sventennie/multi-ingress-sso_cross_idp

Conversation

@supersven
Copy link
Copy Markdown
Contributor

@supersven supersven commented May 1, 2026

I've covered this usecase in the documentation. To avoid duplication, please look at the docs in this PR.

Ticket: https://wearezeta.atlassian.net/browse/WPB-25161

Security notes:

  • This requires a final sign off by @wireapp/security
  • The algorithm for multi-ingress SSO cross-IdP logins has been discussed with @emil-wire
  • This PR also lowers the condition to be found by /sso/get-by-email from SCIM SSO to SSO user

Further reading:

Checklist

  • Add a new entry in an appropriate subdirectory of changelog.d
  • Read and follow the PR guidelines

@zebot zebot added the ok-to-test Approved for running tests in CI, overrides not-ok-to-test if both labels exist label May 1, 2026
@supersven supersven force-pushed the sventennie/multi-ingress-sso_cross_idp branch 3 times, most recently from 70c63ab to 63c5b7d Compare May 5, 2026 17:18
@supersven supersven force-pushed the sventennie/multi-ingress-sso_cross_idp branch 3 times, most recently from c70220c to e7f3bf2 Compare May 12, 2026 08:33
@supersven supersven changed the title POC: multi ingress sso cross idp multi-ingress: cross-IdP SSO May 12, 2026
supersven added 3 commits May 12, 2026 11:32
Allow users to login with all team IdPs.

This is required because there's usually one IdP per ingress in a team
and users should be able to login on all ingresses.
@supersven supersven force-pushed the sventennie/multi-ingress-sso_cross_idp branch from e7f3bf2 to d27326c Compare May 12, 2026 09:37
@supersven supersven requested review from Copilot and sanojwr May 12, 2026 10:06
@supersven supersven marked this pull request as ready for review May 12, 2026 10:07
@supersven supersven requested review from a team as code owners May 12, 2026 10:07
@supersven supersven requested a review from emil-wire May 12, 2026 10:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for multi-ingress “cross-IdP” SSO logins in Spar by falling back to a team-wide lookup (by email NameID) when the primary (issuer, NameID) lookup fails, and updates /sso/get-by-email discovery to work for any SSO user (not only SCIM-managed).

Changes:

  • Extend Spar SAML finalize-login handling to support cross-IdP migration in multi-ingress mode (and add a dedicated config error for non-email NameIDs).
  • Relax /sso/get-by-email lookup condition from “SCIM+SSO” to “SSO user”.
  • Add integration and unit tests plus documentation/changelog updates covering the new behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
services/spar/test-integration/Test/Spar/AppSpec.hs Updates integration test helper to call updated verdictHandler signature with SAML config.
services/spar/src/Spar/Error.hs Adds and renders a new error for invalid multi-ingress cross-IdP configuration (non-email NameID).
services/spar/src/Spar/App.hs Implements multi-ingress cross-IdP fallback flow + structured logging changes.
services/spar/src/Spar/API.hs Plumbs SAML config/host info into finalize-login handling and updates logger constraints.
libs/wire-subsystems/test/unit/Wire/IdPSubsystem/InterpreterSpec.hs Adjusts unit test expectation to “non SSO user” behavior for get-by-email.
libs/wire-subsystems/src/Wire/IdPSubsystem/Interpreter.hs Changes /sso/get-by-email eligibility check from SCIM+SSO to SSO.
integration/test/Test/Spar/MultiIngressCrossIdpSso.hs Adds new integration test suite for cross-IdP migration and related error cases.
integration/integration.cabal Registers new integration test module.
docs/src/developer/reference/config-options.md Documents cross-IdP fallback algorithm and updates get-by-email criteria.
changelog.d/2-features/multi-ingress-cross-IdP-SSO Adds changelog entry describing cross-IdP SSO behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread services/spar/src/Spar/App.hs
Comment thread docs/src/developer/reference/config-options.md Outdated
Comment thread docs/src/developer/reference/config-options.md Outdated
Comment thread changelog.d/2-features/multi-ingress-cross-IdP-SSO Outdated
Simple spelling issues.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Comment on lines +124 to +128
-- This used to check if the user is SCIM AND SSO! The RFC ("2025-05-12
-- RFC: Default SSO flow for team by host domain") is not really
-- unambiguous about this. The customer currently provisions non-SCIM.
isSsoUser :: User -> Bool
isSsoUser = isJust . userSSOId
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This might be subject to change in case the customer decides to go for SCIM. Then, we could make this condition stricter (requiring SSO AND SCIM).

Copy link
Copy Markdown
Contributor

@fisx fisx left a comment

Choose a reason for hiding this comment

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

I read the docs and have some questions, more feedback coming up!

Comment on lines +1522 to +1524
`(issuer, NameID)` lookup finds nothing. Using a shared static issuer across
all domains is not an option because each external identity provider has its
own issuer URI that spar cannot control.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm confused by this sentence. How about:

Suggested change
`(issuer, NameID)` lookup finds nothing. Using a shared static issuer across
all domains is not an option because each external identity provider has its
own issuer URI that spar cannot control.
`(issuer, NameID)` lookup finds nothing. Two IdPs can't have the same Issuer ID because those must be globally unique. Sharing the IdP for all multi-ingress domains is not an option because that would reveal the connection between the domains to the attacker.

If yours is more correct, I want to understand how.

Comment on lines +1529 to +1530
1. **NameID must be an email address.** Username-based `NameID`s are rejected
to avoid ambiguity across authenticating IdPs.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[nit] admins need to manually guarantee that email addresses are unique, so why can't they do the same thing here?

Comment on lines +1533 to +1535
assertion's issuer and the incoming `Z-Host` header (exact match). If no exact
match is found and the team has exactly one IdP configuration, that one is used
unconditionally (no issuer or domain check). If neither condition is met, the
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why pick a non-matching IdP, and not just reject right away?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ok-to-test Approved for running tests in CI, overrides not-ok-to-test if both labels exist

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants