Repository navigation
OIDC resource server: never link a back-office account by e-mail - #901
Merged
Merged
Conversation
A verified e-mail in an access token linked an existing administrator, vendor or store staff account without its password. A provider where someone can mark an address as verified without owning it (an administrator of another organization or realm) would hand over the Web API with admin rights, and the stored link then also signed the account in through the browser plugin, skipping the password step that plugin requires for staff. Staff now connect once through the browser sign-in (password and two-factor code); tokens use that link. Ordinary customers are linked by e-mail as before, and an account linked while ordinary keeps its link when an administrator grants back-office access. The guide also stops claiming that switching Authority only refuses old links: a sub is unique per provider, so the links must be removed.
A link is now marked when it was made by the e-mail address alone (by an access token, or by the browser sign-in without a password). Such a link is held to the rules of a first link on every use: it does not serve an account that has back-office access or two-factor authentication, and the browser sign-in asks for the password when the provider does not report the e-mail as verified. Linking with the password (LinkIdentity) clears the mark. The access-token path applies the two-factor rule of the browser sign-in when linking, and checks an existing link to another subject before the back-office rule, so the answer names the actual conflict. Documentation of RequireEmailVerified, IOidcCustomerResolver and the guide follow; the back-office tests are merged into data rows that also check the refusal reason.
The constant holds the fixed refusal text logged when an account has to be connected with its password first. Its name made code scanning read it as a stored password (cs/cleartext-storage-of-sensitive-information); no password is logged. No behaviour change.
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.
Resolves: no issue (found while reviewing the OpenID Connect work merged in #891-#897)
Type: bugfix
Issue
An access token on a protected resource (by default
/api) linked an existing back-office account (admin panel access, vendor, store staff) to the provider identity by a verified e-mail, without the account's password.With a provider where someone can mark an address as verified without owning it (for example an administrator of another organization in Zitadel, or a realm administrator in Keycloak creating a user), that person got the Web API with the administrator's rights. The stored link is shared with the browser sign-in plugin, so the same account could then also sign in to the store without its password. That skipped the password and two-factor step the plugin requires for the first link of a staff account (#896).
Two related gaps:
To reproduce on
develop: enable the resource server, have an administrator accountadmin@shop.testwithout an OIDC link, issue a token for a provider user withemail = admin@shop.test,email_verified = trueand thegrandnode.apiscope, then call/api/.... The account is linked and the call succeeds.Solution
ExternalAuthentication.LinkedByEmailmarks a link made by the e-mail alone, whether by an access token or by the browser sign-in without a password. Such a link is re-checked on every use:LinkIdentity: plugin "Connect your account", registration) clears the mark. A link made by a token registration (AutoRegister) is not marked, because the identity created that account.AutoRegister = true) and grant that account the access.docs/oidc-resource-server.md, sections 3.1, 3.3, 11.2, 11.6) updated. The guide also no longer claims that after switchingAuthoritythe old links are only refused: asubis unique per provider, so those links must be removed before switching.Breaking changes
Behaviour change against unreleased
developonly; the resource server is not in any release.ExternalAuthenticationgets the bool fieldLinkedByEmail. No migration is needed: links stored before this change read asfalse(made with the password).Testing
dotnet testonsrc/Tests/Grand.Business.Authentication.Tests(168/168),Grand.Web.Common.Tests(385/385),Grand.Modules.Tests(246/246),Grand.Web.Tests(77/77),Grand.Module.Api.Tests(47/47) andGrand.Mapping.Tests(236/236).docs/oidc/docker-compose.yml(remove existingExternalAuth.OpenIdConnectlinks first):/api/...with a token of a user whose verified e-mail belongs to an unlinked administrator. Expect 403 and noExternalAuthenticationrecord./api/...with a token of a plain registered customer (verified e-mail). Expect 403 (no admin panel access) and a link withLinkedByEmail = true. Grant the customer an admin group and repeat. Expect 403 "must be connected ... with its password first". Connect through the plugin and repeat. Expect 200 andLinkedByEmail = false.AutoRegister = true, call/api/...with a token of a new user. The account is registered with an unmarked link. Grant it an admin group and repeat. Expect 200.