Skip to content

Commit

Permalink
Add documentation about the pipeline for One Login updates
Browse files Browse the repository at this point in the history
  • Loading branch information
KludgeKML committed Sep 18, 2023
1 parent 7260d7b commit 3930d73
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 24 deletions.
61 changes: 61 additions & 0 deletions docs/one-login-pipeline.md
@@ -0,0 +1,61 @@
# One Login to GOV.UK pipeline

One Login is an OpenID Connect (OIDC) provider, which GOV.UK accounts are based on. Currently the only thing that a GOV.UK account handles is email alert subscriptions. Subscriptions are handled in two ways, one that requires a GOV.UK account, one that does not. (As of time of writing, there are 2.5 million subscribers using the old no-account method, 211,000 using the new account-based method).

So a user who has subscribed to email alerts will create records in 3 places if an account is required:

- A One Login account record in One Login
- An account record in account-api
- A subscriber record in email-alert-api

…but only one (a subscriber record in email-alert-api) if an account is not required (this is the magic-email path)

Therefore not all Subscriber records in email-alert-api will have a corresponding account record in account-api, but currently all account-api records have a corresponding subscriber record in email-alert-api.

## How Email Alert records are created

There are a series of paths in email-alert-frontend which end up with an email subscription being made. The exact path depends on the component used for signup, and how that component is configured.

### Single Page Notification Button Component

This component is the more complicated, and renders as a box with a bell icon and text inside. It’s progressively enhanced with the ability to query whether the user already has a subscription (in which case it allows them to cancel it).

If the user is logged in, this component calls the account api endpoint /api/personalisation/check-email-subscription from the browser, passing it the base path of the current page. If the logged-in user already has a subscription to that page, it will alter the action of the button to unsubscribe.

The behaviour of the button when pressed depends on the skip_account parameter passed to the component. If true, the button acts to create a subscription by POSTing to the email-alert-frontend endpoint /email-signup with the details of the subscription to be created in the request body. This causes a magic-email subscription to be created (ie one with no account-api record)

If skip_account is false, though, the button POSTs to the email-alert frontend endpoint /email/subscriptions/single-page/new . This endpoint requires the user to be logged in with a One Login account. If they are not logged in, it will redirect them to a login/create account page (after which they’ll be directed back). If logged in, it calls the email-alert-api methods “authenticate_subscriber_by_govuk_account” and “get_subscriptions” to get the existing subscriptions for that account holder for that page, then toggles that subscription (if it doesn’t exist, it will make one. If it already exists, it will end it).

### Subscription Links Gem Component

This component is a simple link that creates a subscription with a GET to /email-signup passing the link as a query parameter. This causes a magic-email subscription to be created (ie one with no account-api record)

### Application-specified Subscription Links

These links aren’t in a component, and are generated by Collections and Finder Frontend. They GET the email-alert-frontend endpoint /email/subscriptions/new, which again requires the user to be logged in with a One Login account, and will redirect them to login/create an account if they do not already have one. It then calls the email-alert-api methods “link_subscriber_to_govuk_account” and “subscribe” to create the subscription. This is not a toggle, as with the single page notification button - it will not unsubscribe an existing subscription.

## How Account records are created

When one of the email alert paths above requires an account but doesn’t find it, it redirects the user to the One Login endpoint “https://signin.account.gov.uk/sign-in-or-create”. The One Login account is logged into or created at that point, and then the user is redirected back to the /callback endpoint on account-api that creates the account-api record and then redirects to the subscription path with the user already logged in.

## How Email Alert / Account records are updated

When a user is logged into their One Login account (at home.account.gov.uk/your-services), they can see a list of services attached to that account. If one of them is GOV.UK email subscriptions, there is a link to https://www.gov.uk/email/manage?from=your-services, which is the email management page on email-alert-frontend. This is a simple link, but the query parameter tells email-alert-frontend that the user is already logged in.

Moving to the security tab, the user gets the option to change their email address, their password, and to delete their account.

- Email address changes should affect Account API / Email Alerts (they should change where the email alerts go to)
- Password changes **should not** affect GOV.UK (as an OIDC relying party, we shouldn't be privy to password information from the provider)
- Deleting the account should affect Account API / Email Alerts (they should remove both the account and the subscriber record, and any subscriptions attached to the subscriber)

### Email Address Changes:

When the user changes the email address in One Login a direct call is made to the account api PUT /api/oidc_users, which causes the user to be looked up by the OneLogin subject_identifier field (or created, if it doesn’t exist). Then the email and verified email fields are updated (these appear to be the only fields that _can_ be updated by this call). Problems can occur if the subject_identifier for a user has changed in One Login - then we’ll try to create a new account api record with the new subject_identifier, but it will fail to create because the email field has to be unique. Emails also have to be unique in One Login, so theoretically this shouldn’t happen, but if a user is deleted in One Login but not in Account API, it can.

Once the account API record has been changed, a call is made from account API to email alert API to update the attached email alert api subscriber record (if one exists).

### One Login Account Deletions:

When an account is deleted (either by user or support agent) in One Login, a pub/sub message is created, then picked up by a service which makes the call to the account api DELETE /api/oidc_users/. This causes the user to be looked up by the OneLogin subject_identifier. If it exists, a call is made to email alert api to unsubscribe the subscriber record (making it eligible for historic account deletion). After that, the Account API account record is destroyed.

If the service call to Account API fails, the message goes into a Dead Letter Queue, which causes the One Login team to get an alert by email (they then go and manually investigate the problem). If the call between Account API and Email Alert API fails, we are notified by Sentry.
52 changes: 28 additions & 24 deletions docs/one-login.md
@@ -1,66 +1,70 @@
# Digital Identity
# One Login

This document gets into some of the details of the integration with
Digital Identity, and where it can go wrong. For a high-level
One Login, and where it can go wrong. For a high-level
overview, see [the developer docs][].

[the developer docs]: https://docs.publishing.service.gov.uk/manual/govuk-account.html

## Big picture

The [`OidcUser` model][], which represents a user who has
authenticated via Digital Identity, holds four special pieces of data:
authenticated via One Login, holds four special pieces of data:

- The `sub`, or "subject identifier", is a unique identifier assigned
by Digital Identity when the account is created, and never changes.
by One Login when the account is created, and never changes.
Other data, like an email address, can change: so this is what we
use to identify users.

- The `legacy_sub` is the user's subject identifier from the old
[account manager prototype][]. Only accounts which were created
before the Digital Identity migration have this set. We use this to
before the One Login migration have this set. We use this to
join up old data.

- The `email` is the user's current email address. It is set by
Digital Identity calling the `/api/oidc-users/:subject_identifier`
One Login calling the `/api/oidc-users/:subject_identifier`
endpoint.

- The `email_verified` is a boolean denoting whether the user's email
address is verified. It is set by Digital Identity calling the
`/api/oidc-users/:subject_identifier` endpoint. As Digital Identity
address is verified. It is set by One Login calling the
`/api/oidc-users/:subject_identifier` endpoint. As One Login
require immediate verification of email addresses, this is always
true.

Communication flows in both directions between account-api and Digital
Identity:

- When a user is updated or deleted, Digital Identity call the
- When a user is updated or deleted, One Login call the
endpoints in [`Internal::OidcUsersController`][].

- When a user logs in, we call Digital Identity from the
- When a user logs in, we call One Login from the
[`Internal::AuthenticationController`][].

These calls can affect both Account API and Email Alert API, read
more about the [One Login to GOV.UK pipeline][one-login-pipeline].

[`OidcUser` model]: https://github.com/alphagov/account-api/blob/main/app/models/oidc_user.rb
[`Internal::OidcUsersController`]: https://github.com/alphagov/account-api/blob/main/app/controllers/internal/oidc_users_controller.rb
[`Internal::AuthenticationController`]: https://github.com/alphagov/account-api/blob/main/app/controllers/internal/authentication_controller.rb
[account manager prototype]: https://github.com/alphagov/govuk-account-manager-prototype/
[One Login to GOV.UK pipeline]: /

## Errors

This is a non-exhaustive list of problems that could be due to
something breaking with the Digital Identity integration.
something breaking with the One Login integration.

Firstly, check if the problem is on the Digital Identity side:
Firstly, check if the problem is on the One Login side:

- If the user got the problem on `https://account.gov.uk` (or some
subdomain of that), then it's Digital Identity.
subdomain of that), then it's One Login.
- If account-api is persistently unable to connect to
`https://oidc.account.gov.uk`, then it's Digital Identity.
`https://oidc.account.gov.uk`, then it's One Login.

If the problem is on the Digital Identity side, or if you need support
If the problem is on the One Login side, or if you need support
from them, ask for help in `#di-authentication` on Slack.

If the problem is not clearly to do with Digital Identity, read on.
If the problem is not clearly to do with One Login, read on.

### Email address out of date

Expand All @@ -80,7 +84,7 @@ trying to change to:
other_user = OidcUser.find_by(email: "desired new email address")
```

Digital Identity enforces that email addresses are unique, so we
One Login enforces that email addresses are unique, so we
shouldn't ever have two users with the same email address.

If there is another user with the desired email address, something may
Expand Down Expand Up @@ -118,12 +122,12 @@ DETAIL: Key (email)=(email@example.com) already exists.
#### There is no relevant error

If a user has the wrong email address and there is no relevant error,
then Digital Identity may not have called the
then One Login may not have called the
`/api/oidc-users/:subject_identifier` endpoint, or their call may have
failed due to some error which wasn't reported.

Check Kibana to see if the call was made and what the response code
was. If the call wasn't made at all, contact Digital Identity for
was. If the call wasn't made at all, contact One Login for
support.

### Can't log in
Expand All @@ -140,7 +144,7 @@ user = OidcUser.find_by(email: "address")
#### Can't log in for the first time

When a user first logs in, we create an `OidcUser` record just holding
their subject identifier, and query Digital Identity for their email
their subject identifier, and query One Login for their email
address.

So if there is no `OidcUser` record with the email address, this
Expand All @@ -158,7 +162,7 @@ DETAIL: Key (sub)=(foo) already exists.

This should never happen in production.

As subject identifiers come from Digital Identity, contact them for
As subject identifiers come from One Login, contact them for
support and give the duplicate subject identifier (`foo` in the
example above).

Expand Down Expand Up @@ -187,7 +191,7 @@ destroyed. This record holds the subject identifier, and we use it to
end any active sessions that user still has.

If a user logs into an account that has a subject identifier with a
corresponding `Tombstone` record, Digital Identity have re-used a
corresponding `Tombstone` record, One Login have re-used a
subject identifier, or un-deleted the account. We currently assume
this does not happen.

Expand All @@ -201,12 +205,12 @@ Ask the `#di-authentication` channel in Slack whether their service is
up, and ask if they are seeing an elevated rate of invalid
authorization codes or access tokens from GOV.UK.

If Digital Identity are experiencing a problem, we just have to wait
If One Login are experiencing a problem, we just have to wait
for them to fix it.

Otherwise, we have a bug in account-api, or perhaps elsewhere in the
GOV.UK stack. One thing to try would be to clear our cached copy of
the Digital Identity OIDC configuration:
the One Login OIDC configuration:

```ruby
Rails.cache.clear
Expand Down

0 comments on commit 3930d73

Please sign in to comment.