[18.0][ADD] auth_oauth_autolink: link OAuth logins to existing users by verified email - #997
[18.0][ADD] auth_oauth_autolink: link OAuth logins to existing users by verified email#997nimarosa wants to merge 1 commit into
Conversation
3ee297d to
40c06a1
Compare
40c06a1 to
4b183ff
Compare
|
Force-pushed a fix: the first version passed when the addon was installed on its own, but failed the all-addons CI job because of two interactions with sibling addons in this repo. Both are now handled, and the design is better for it. 1. The link now happens in 2. 3. Log levels. The refusal messages were logged at WARNING, which trips Test suite is 17 tests (15 running in the all-addons job, 2 skipped as above), including one that drives the real entry point with only All test jobs and pre-commit are green. |
What it does
Stock
auth_oauthrecognises a user only by theoauth_uidstored on the user record. A user created by an administrator has neitheroauth_uidnoroauth_provider_id, so the very first OAuth login misses, falls through to the signup path and — on a B2B database, where signup is disabled — is refused with "You do not have access to this database…". The only stock workarounds are enabling public signup or writing the provider's opaqueoauth_uidonto every user by hand.This module performs that first link automatically: when the
oauth_uidlookup misses, the login is linked to the existing user whose login is the e-mail address the provider verified. From then on the stock path takes over and nothing else changes.Security model
The trust anchor is the provider's verified-email claim, and every guard around it is deliberate. A link happens only when all of these hold:
auth.oauth.provider.autolink_by_email, off by default, opt-in per provider).email_verified(OpenID Connect) orverified_email(legacy Google tokeninfo). An absent claim counts as not verified.login == email, compared through Odoo's ownemail_normalize(case-insensitive, unlike Odoo's case-sensitive login).oauth_uidyet.Consequences, spelled out:
searchexcludes archived records), so deactivating a user still ends their access.Anything that does not pass every guard behaves exactly like stock
auth_oauth: the sameAccessDenied, with no hint about which condition refused. The reason is written to the server log only.On a successful link the module writes
oauth_provider_id,oauth_uidandoauth_access_token(so the session behaves like any other OAuth login), logs at INFO and posts a note on the user's partner chatter —res.usersis not amail.thread.Implementation note
The override runs before
super()rather than catching itsAccessDenied. On a signup-enabled (B2C) databasesuper()would first try to create a user with the very login we are about to link, which fails on theloginunique index and poisons the transaction. Behaviour is unchanged: an existingoauth_uidmatch always wins, and everything not linked is handed tosuper()untouched.Test coverage
12 tests in
tests/test_auth_oauth_autolink.py, driving_auth_oauth_signinwith controlled validation dictionaries (exactly what_auth_oauth_validatereturns after a real round-trip — no network needed), with signup forced tob2b:AccessDeniedand that nothing was written: provider flag off,email_verified: False, missing verified claim, missingemailclaim, no matching user, already-linked user (never overwritten), archived user, ambiguous e-mail (two logins differing only in case)verified_emailspelling is acceptedPrior art
Related to #941 (
[17.0][ADD] auth_oauth_link_by_email, still open). Same problem, deliberately stricter design:autolink_by_email, default off)logincomparisonemail_normalizeon both sidesoauth_uid+ provideroauth_access_tokenWithout the verified-email requirement and the per-provider opt-in, any provider that lets a user assert an arbitrary e-mail address can be used to take over the matching Odoo account on every database that installs the module. Making the claim mandatory and the behaviour opt-in is what makes this safe to ship as a generic addon.
Runbat/manual check: used in production against a Google Workspace provider.
@OCA/server-auth-maintainers