Feature #4601

[SSO] Migrate OpenId users to OAuth/Google+

Added by Peter Amstutz over 5 years ago. Updated over 5 years ago.

Status:
Resolved
Priority:
Normal
Assigned To:
Category:
SSO
Target version:
Start date:
11/05/2014
Due date:
% Done:

100%

Estimated time:
(Total: 0.00 h)
Story points:
3.0

Subtasks

Task #5286: Review 4601-openid-migrate-to-oauth2 (sso-provider)ResolvedWard Vandewege

Task #4421: API server can migrate users from OpenID to OpenID ConnectResolvedPeter Amstutz


Related issues

Related to Arvados - Feature #4570: [SSO] Implement Google OAuth2 for new SSO installationsResolved11/05/2014

Related to Arvados - Story #4927: [SSO] Decide overall single sign-on strategyResolved01/12/2015

Related to Arvados - Feature #4637: [SSO] Use "authentications" table and support account linkingRejected11/06/2017

Associated revisions

Revision 08542a17
Added by Peter Amstutz over 5 years ago

Merge branch '4601-openid-migrate-to-oauth2' closes #4601

History

#1 Updated by Peter Amstutz over 5 years ago

  • Target version changed from Arvados Future Sprints to 2014-12-10 sprint

#2 Updated by Peter Amstutz over 5 years ago

  • Target version changed from 2014-12-10 sprint to Arvados Future Sprints

#3 Updated by Peter Amstutz over 5 years ago

Proposed migration strategy:

  1. Add &openid_shutdown_ack=2015-04-20 to existing OpenID request to temporarily disable warning message (https://developers.google.com/accounts/docs/OpenID)
  2. Migrate SSO database and leverage existing feature supporting multiple providers tied to the same SSO user identity
  3. API server uses SSO user ID (e.g. http://auth.curoverse.com/users/99) for identity_url (instead of deprecated Google OpenId identity URL)
  4. Batch migrate identity_url column in API server users table from deprecated Google OpenId identity URL to SSO server user ID
  5. Start sending users to Google OAuth2 page
  6. OAuth2 response includes deprecated OpenID identity_url
  7. If OAuth2 ID is not found, look up OpenID record. If found, associate OAuth2 identity with existing user record, if not, create new user.

#4 Updated by Peter Amstutz over 5 years ago

Some other ideas:

  1. Collect user id on the workbench page. Pass this as login_hint in the OAuth2 request. When we support multiple authentication providers, we can look up the user id and/or pattern match the domain to determine the correct provider for the log in redirect.
  2. Only when the user (and provider domain) are not recognized do we send them to a "choose your provider log in" page. This page can be hosted by the SSO server. Then the SSO server doesn't need to advertise available providers to workbench or whatever.

#5 Updated by Tom Clegg over 5 years ago

  • Target version changed from Arvados Future Sprints to 2015-01-28 Sprint

#6 Updated by Tom Clegg over 5 years ago

  • Target version changed from 2015-01-28 Sprint to Arvados Future Sprints

#7 Updated by Peter Amstutz over 5 years ago

  • Story points set to 3.0

#8 Updated by Tom Clegg over 5 years ago

  • Target version changed from Arvados Future Sprints to 2015-02-18 sprint

#9 Updated by Peter Amstutz over 5 years ago

  • Assigned To set to Peter Amstutz

#10 Updated by Peter Amstutz over 5 years ago

2. Instead of a URL to identify users, SSO server should assign user ids that are compatible with existing arvados user id format.

4. Instead of doing batch migration, migrate incrementally by including both legacy OpenID and new Arvados uuid when responding to API server request.

#11 Updated by Tom Clegg over 5 years ago

Priorities for this story, in order:
  1. allow existing users (who signed up using Google OpenID) to log in after login.curoverse.com changes its strategy to Google OAuth2, and continue using their accounts without interruption
  2. minimize scope beyond that
  3. minimize "bad investment" changes that will be thrown out when we make further progress on the longer term Authentication strategy
Suggestion:
  • SSO provider should continue to provide a unique ID in identity_url
    • Optionally, it should also provide that ID in a field with a better name (user_uuid?)
  • When it detects the OpenID migration case (i.e., OAuth2 callback says user has OAuth2 ID "currentID" and OpenID "oldID" and there is no user in its database with ID "currentID" and there is a user in its database with ID "oldID")
    • Use "oldID" instead of "currentID" and continue.
  • If the user is brand new, assign an Arvados-format UUID, associate that with the subscriber ID returned by Google, and return the UUID as identity_url

This way, API server will always see either an OpenID or a UUID. All it cares about (for now) is that it's unique across users, and stable for a given user.

#12 Updated by Peter Amstutz over 5 years ago

  • Category set to SSO

Some thoughts:

  • SSO migration: Start Using multiple authorizations feature of SSO server in order to support notion of multiple providers. Migrate OpenId auth info to authorizations table. Add uuid column to users table. Batch allocate uuids to users during migration.
  • Google OAuth2 response to SSO: if there is no OAuth2 provider record in authorizations table, check for OpenId provider with old OpenId user and associate user with that. Add OAuth2 authorization.

When SSO server responds to API server, it returns both the new UUID and the "legacy" OpenId (if it exists). API server will first check if there is a user with the same id; then checks if there is a user with the OpenId in the identity_url field.

  1. If the user matches uuid, log them in with that id.
  2. If the user matches OpenId in the identity_url field, log them in with the mapped api server uuid.
  3. If the user doesn't exist, they are created with the uuid assigned by the SSO.

Longer term plan (not this story):

  1. Once above work goes live, we know that there won't be any new OpenId signups.
  2. Dump OpenId to identity_url to an offline table.
  3. On API, use offline table to migrate legacy identity_url users to SSO-assigned uuids across all tables.
  4. Eliminate identity_url column and related logic.

#13 Updated by Tom Clegg over 5 years ago

Updated strategy
  1. Change API server:
    • If SSO provider gives us an identity_url field, log in the same way we've done it before.
    • Otherwise, use the user_uuid provided: log in as (and create if needed) a user with that UUID
  2. Deploy API server everywhere
  3. Change SSO provider as above, making use of sso-provider's authorizations table.
    • Always provide a locally assigned user_uuid
    • If the user has a legacy OpenID, also pass that back to API server as identity_url

#14 Updated by Tom Clegg over 5 years ago

Related work from wikifarm
  • Google login button
    • openid.realm has to be the same realm the OpenID code has been using, likely "https://sso-provider.example.com/"
  • Callback handler (the URI where this lives has to be specified as an allowed callback URI on the Google developer console)
    • Callback receives a ?code=XXX
    • GET a discovery doc to find the right token_endpoint
    • POST the XXX code to that token_endpoint (along with the client_id and client_secret that you made on the Google developer console, along with the openid.realm again, the redirect_uri again, and grant_type=authorization_code)
    • token_endpoint's response is JSON: {"id_token":"YYY",...}
    • YYY is a JWT. Decode it (OK to skip JWT key verification because it came straight from Google over TLS).
    • "sub" field of the JWT is the Google subscriber ID (a big decimal number)
    • "openid_id" field of the JWT is the OpenID this user would have looked like if you had done OpenID login.

#15 Updated by Tom Clegg over 5 years ago

  • Target version changed from 2015-02-18 sprint to 2015-03-11 sprint

#16 Updated by Peter Amstutz over 5 years ago

  • Status changed from New to In Progress

#17 Updated by Peter Amstutz over 5 years ago

4601-openid-migrate-to-oauth2

  • To support multiple providers, start using the "authentications" table.
    • Migrate identity_url attached to user records to authentication records with the "google" (OpenId 2.0) provider. Remove identity_url column from users table.
  • Every user record also gets a new Arvados user uuid assigned by the SSO server
  • When a user logs in via Google OAuth2, it first checks for authentication record with provider "google_oauth2"; if that fails but there is a user record with the same email address it falls back to checking for an authentication record with provider "google" (OpenId 2.0)
    • If a OpenId 2.0 authentication record is found it creates a authentication record for the "google_oauth2" provider associated with the existing user. When the API server requests user info from SSO, it searches for provider "google" (OpenId 2.0) authentication records and sends the legacy identity_url to the API server.
    • If there is no legacy OpenId 2.0 identity, it sends the SSO-assigned Arvados user uuid in the identity_url field instead.
  • This approach is backwards compatible with the current API server in master!

This is the logic written up in #note-11. I advise we disregard #note-13

Eventually we do want to use the SSO-assigned user uuid directly, which will involve a big-bang migration of the user table for each API server instance. At that point it will also make sense to adjust the API server's behavior regarding how we assign the primary UUID for user records.

#18 Updated by Peter Amstutz over 5 years ago

  • Status changed from In Progress to Resolved
  • % Done changed from 50 to 100

Applied in changeset sso-provider|commit:08542a178c1bc11c222dee6b4202c731f96ade77.

Also available in: Atom PDF