feat: OIDC account management page (MSC2965) + UIA bypass for SSO/OIDC users#407
Open
shaba wants to merge 3 commits intomatrix-construct:mainfrom
Open
feat: OIDC account management page (MSC2965) + UIA bypass for SSO/OIDC users#407shaba wants to merge 3 commits intomatrix-construct:mainfrom
shaba wants to merge 3 commits intomatrix-construct:mainfrom
Conversation
Identity provider IDs may contain characters that are invalid in URL path segments (e.g. colons, slashes). Percent-encode the idp_id before interpolating it into the SSO redirect URL to avoid a 404 or broken redirect when the IDP ID is not a plain alphanumeric string. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the simple IdP redirect in account_route with a self-hosted account management UI: - GET /_tuwunel/oidc/account: redirects through SSO to authenticate the user, then dispatches to the requested action page. - GET/POST /_tuwunel/oidc/account_callback: handles the login-token callback and renders HTML pages for sessions list, session detail, session sign-out (with CSRF-safe POST confirmation), and profile editing. - GET /_tuwunel/oidc/account.js: tiny inline JS to localise timestamps client-side; served separately for CSP compatibility. - GET /_tuwunel/oidc/account.css: shared stylesheet for all pages, enabling style-src 'self' in the Content-Security-Policy. For actions that require a POST confirmation (session_end, profile), the GET handler peeks at the SSO login token without consuming it and embeds it directly in the form. The token is consumed once on POST, so no secondary token is ever created and repeated GETs do not accumulate orphaned tokens. Per-route CSP overrides the global form-action 'none' and sandbox directives so HTML forms can submit, using style-src 'self' instead of 'unsafe-inline' (styles are in account.css). Advertises org.matrix.sessions_list, org.matrix.session_view, org.matrix.session_end, and org.matrix.profile actions in the OIDC discovery document (account_management_actions_supported). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SSO and native OIDC users are created with PASSWORD_SENTINEL ("*") as
their password hash. has_password() returns false for them, so no UIA
flows were advertised, and Matrix clients (e.g. FluffyChat) showed
"no permissions" when trying to delete devices via the direct Matrix API.
Per MSC3861 the possession of a valid OIDC access token is itself
sufficient proof of identity, so UIA should not be required for these
users. Short-circuit auth_uiaa() early when has_password is false:
the caller has already verified the access token, and there is no
additional credential to present.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Member
|
Sorry, I didn't mean to hit close. I think we just have to decide whether to go ahead with 1.6.0 or delay until we can work this in. The delay will be significant and I'm leaning toward going ahead and working this into the main branch afterward unless there's reason otherwise. |
Author
|
No worries, please go ahead with 1.6.0 — this can be worked in afterward without any rush. For context: all three changes in this PR have been running in production on our ALT Linux packaging of Tuwunel for a few days without issues. The UIA bypass in particular fixed a real user-facing problem (FluffyChat showing "no permissions" when deleting devices for OIDC users), and the account management page has been tested with both Fractal and FluffyChat. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR contains three changes related to native OIDC authentication:
1. fix: url-encode
idp_idin OIDC authorize SSO redirect pathIdentity provider IDs may contain characters invalid in URL path segments
(e.g. colons, slashes). The
idp_idis now percent-encoded before beinginterpolated into
/_matrix/client/v3/login/sso/redirect/{idp_id}.A
url_encodehelper implementing the RFC 3986 unreserved character setis added to
src/api/oidc/mod.rs.2. feat: self-hosted OIDC account management page (MSC2965)
Replaces the simple IdP redirect in
account_routewith a fullyserver-hosted account management UI, so
account_management_uriin theOIDC discovery document points to a functional page.
New endpoints:
GET /_tuwunel/oidc/accountGET /_tuwunel/oidc/account_callbackPOST /_tuwunel/oidc/account_callbackGET /_tuwunel/oidc/account.jsGET /_tuwunel/oidc/account.cssstyle-src 'self'in CSP)Supported actions (advertised in
account_management_actions_supported):org.matrix.sessions_list— list all active sessions, sorted newest-firstorg.matrix.session_view— view details of a single sessionorg.matrix.session_end— sign out a session (CSRF-safe POST confirmation)org.matrix.profile— view and edit display nameSecurity notes:
form-action 'none'andsandbox. Account pages set aper-route CSP (
form-action 'self', nosandbox,style-src 'self') thattakes precedence via
SetResponseHeaderLayer::if_not_present.protection). GET handlers peek at the token without consuming it so it can
be embedded in the confirmation form; the token is consumed once on POST.
This avoids creating a secondary token on every GET and prevents accumulation
of orphaned tokens if the user navigates back.
peek_login_token()method is added to the users service alongside theexisting destructive
find_from_login_token().html_escape().3. fix: bypass UIA for SSO/OIDC users without a local password
SSO and native OIDC users are created with
PASSWORD_SENTINEL("*") astheir password hash.
has_password()returnsfalsefor them, so no UIAflows were advertised, and Matrix clients (e.g. FluffyChat) showed
"no permissions" when attempting to delete devices via the standard Matrix API.
Per MSC3861,
possession of a valid OIDC access token is itself sufficient proof of identity.
auth_uiaa()now returns early whenhas_passwordis false: the access tokenhas already been verified by the middleware, and there is no additional
credential to present. This covers both traditional SSO users and native OIDC
users (who may not have an OAuth session entry from
exists_for_user()).Test plan
/_tuwunel/oidc/accountin a browser — redirects through SSO and shows the sessions listContent-Security-Policyheader on account pages allows form submission:) do not break the SSO redirect🤖 Generated with Claude Code