Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support requiring 2FA for authentication, check isEnrolledIn2Sv #204

Merged
merged 1 commit into from
Nov 30, 2023

Conversation

rtyley
Copy link
Member

@rtyley rtyley commented Nov 24, 2023

see also the Decommissioning 2fa_enforce Google Group doc

Checking users have 2FA enabled before they access internal Guardian tools is very important (good security practice, required by GDPR, etc), but in the past it's not been possible to directly check if a user has 2FA enabled - as a proxy, we've checked the user for membership of the 2fa_enforce@guardian.co.uk Google Group. The Google Group was manually administered, so suffered from reconciliation issues, and Patrick Simkins reports the group does not correspond well with our onboarding process.

Recently, in discussion about this, @andrew-nowak pointed out that we can use Google's Admin SDK Directory API and retrieve the Directory API User entity, giving access to the isEnrolledIn2Sv field which accurately gives the 2FA status of a user.

This PR introduces TwoFactorAuthChecker, a class that can read the isEnrolledIn2Sv field for a given user. If you supply a TwoFactorAuthChecker to the GoogleAuthConfig, the 2FA status of the user will be checked at authentication time, and rejected if isEnrolledIn2Sv is false - only users with 2FA will be allowed to authenticate, and it's no longer necessary, or advisable, to check the 2fa_enforce@guardian.co.uk Google Group.

Required permissions to access the User entity

Note that this new call requires the https://www.googleapis.com/auth/admin.directory.user.readonly scope, and the Google Service Account used by TwoFactorAuthChecker will need to have the corresponding user-read permission set in order for this call to succeed. You can adapt the code in TwoFactorAuthCheckerCLITester to double-check permissions are setup correctly.

Example PR using this change

Similar changes for other Guardian libraries

@rtyley rtyley force-pushed the use-isEnrolledIn2Sv-to-check-2FA branch 12 times, most recently from eb191bd to c920ab6 Compare November 24, 2023 19:41
@rtyley rtyley changed the title WIP IsEnrolledIn2Sv Support requiring 2FA for authentication, checked with isEnrolledIn2Sv Nov 24, 2023
@rtyley rtyley force-pushed the use-isEnrolledIn2Sv-to-check-2FA branch from c920ab6 to 4611032 Compare November 24, 2023 19:50
Using Google's Admin SDK Directory API we can check the `isEnrolledIn2Sv`
field on the Directory API User entity (https://developers.google.com/admin-sdk/directory/reference/rest/v1/users)
to accurately obtain the 2FA status of a user.

At the Guardian, in the past, we've checked the user for membership of the
`2fa_enforce@guardian.co.uk` Google Group, as a proxy for being able to
directly check the 2FA status of the user. The Google Group was manually
administered, so suffered from reconciliation issues, and no longer
corresponds to our onboarding process.

Now, if you supply a `TwoFactorAuthChecker` to the `GoogleAuthConfig`,
the 2FA status of the user will be checked at the point of authentication,
and rejected if `isEnrolledIn2Sv` is false - only users with 2FA will be
allowed to authenticate.
@rtyley rtyley force-pushed the use-isEnrolledIn2Sv-to-check-2FA branch from 4611032 to e6cef99 Compare November 24, 2023 19:52
@rtyley rtyley changed the title Support requiring 2FA for authentication, checked with isEnrolledIn2Sv Support requiring 2FA for authentication, check isEnrolledIn2Sv Nov 28, 2023
@@ -41,6 +41,7 @@ def projectWithPlayVersion(playVersion: PlayVersion) =
"org.typelevel" %% "cats-core" % "2.9.0",
commonsCodec,
"org.scalatest" %% "scalatest" % "3.2.16" % Test,
"software.amazon.awssdk" % "ssm" % "2.21.7" % Test
Copy link
Member Author

@rtyley rtyley Nov 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new dependency is only for the test scope, as it's only needed for the new TwoFactorAuthCheckerCLITester, only used for double-checking Google Credentials are correctly setup.

): EitherT[Future, Result, UserIdentity] = EitherT {
checker.check(userIdentity.email).map(userHas2FA => if (userHas2FA) Right(userIdentity) else {
logger.warn(s"failed-oauth-callback : user-does-not-have-2fa")
Left(redirectWithError(failureRedirectTarget, "You do not have 2FA enabled"))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message will be displayed to the user if they don't have 2FA - as in this Ophan PR here:

image

@rtyley rtyley marked this pull request as ready for review November 28, 2023 14:40
@rtyley rtyley merged commit 08c10f2 into main Nov 30, 2023
1 check passed
@rtyley rtyley deleted the use-isEnrolledIn2Sv-to-check-2FA branch November 30, 2023 10:29
gu-scala-steward-public-repos bot pushed a commit that referenced this pull request Nov 30, 2023
…code

Tidying up code in preparation for #204 which
adds support for requiring 2FA.

Both `GoogleGroupChecker` (which will soon have a smaller role, as it was
previously crucial for checking membership of `2fa_enforce@guardian.co.uk`)
and the new `TwoFactorAuthChecker` (introduced by PR #204), require an
Admin SDK `Directory` API client (but with different scopes), so
`DirectoryService` is introduced to make creating one a little simpler.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant