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

Admin: Add Google SSO for Compiler users #1855

Merged
merged 23 commits into from
Feb 8, 2024
Merged

Conversation

machikoyasuda
Copy link
Member

@machikoyasuda machikoyasuda commented Jan 17, 2024

closes #1817

After merging this PR and ensuring the proper secrets are set up in Terraform, anyone with a compiler.la email address will be able to log into the Benefits Admin application. When the user is authenticated, the application will create a user with their Google first name, last name and e-mail address in Benefits.

What this PR does

  • Uses https://megalus.github.io/django-google-sso/ library for Google single-sign on. Also uses https://github.com/encode/httpx/ for simple HTTP requests, to fetch Google API data.
  • Set up Google SSO log in to allow for compiler.la domains, if the users email address is in the correct secret (see below)
  • Set up Google SSO secrets with Terraform
  • Fixes issue where Django JS files were not being allowed on Admin site
  • Set user's username as their Google email address, and also save their profile icon URL, first and last name from Google.
  • Outside of this PR, the necessary secrets have been set up. These secrets allow us to control exactly which compiler.la addresses can log in and get staff or superuser status:
GOOGLE_SSO_STAFF_LIST - [email protected]
GOOGLE_SSO_SUPERUSER_LIST - [email protected],[email protected],[email protected]
image image

Done

  • Set up Google Cloud SSO new project for Benefits Admin
  • Set up OAuth page
  • Set up OAuth credentials per environment (Localhost, Dev, Test, Prod). Put in LastPass.
  • Set up Terraform with info from above
  • Fix test failures
  • Host Google image locally
  • Make Allowed Domain (compiler.la, mst.org) an environment variable (similar to Allowed Hosts - split by comma and filter empties)
  • Create username as your Google email address, save user's first name, last name and email address.
  • Create Allowable Staff list + env var
  • Create Allowable Admin list + env var
  • Add spec

About django-google-sso

How to test

  • Engineers: Try to log in via your Compiler email address. Should be able to log in successfully.
  • Engineers: Try to log in via a personal Gmail address. Should not be able to log in.

@github-actions github-actions bot added back-end Django views, sessions, middleware, models, migrations etc. infrastructure Terraform, Azure, etc. deployment-dev [auto] Changes that will trigger a deploy if merged to dev and removed back-end Django views, sessions, middleware, models, migrations etc. infrastructure Terraform, Azure, etc. labels Jan 17, 2024
benefits/settings.py Outdated Show resolved Hide resolved
@machikoyasuda machikoyasuda changed the title Feat/1817 admin google sso Admin: Add Google SSO Jan 17, 2024
@machikoyasuda machikoyasuda changed the title Admin: Add Google SSO Admin: Add Google SSO for Compiler users Jan 17, 2024
benefits/settings.py Outdated Show resolved Hide resolved
@machikoyasuda machikoyasuda self-assigned this Jan 17, 2024
@machikoyasuda machikoyasuda added this to the Admin tool: foundation milestone Jan 17, 2024
@machikoyasuda
Copy link
Member Author

To test this locally so far:

    # GOOGLE_SSO_CLIENT_ID = "XXXX"
    # GOOGLE_SSO_PROJECT_ID = "XXXX"
    # GOOGLE_SSO_CLIENT_SECRET = "XXXX"
  • Recreate devcontainer. Make sure it downloaded the Django-Google-SSO library. Running a ./bin/init.sh runs migrate - and that should work successfully.
  • Go to localhost:8000/admin
  • Try logging in with a Compiler and a non-Compiler Google account. Should be able to log in and not log in, respectively.

@machikoyasuda
Copy link
Member Author

Not sure why GitHub Actions pytest/Cypress are failing here: https://github.com/cal-itp/benefits/actions/runs/7549568812/job/20553782925?pr=1855#step:7:22

I am able to run migrate locally and run all the tests locally, too.

cc @angela-tran @thekaveman

@angela-tran
Copy link
Member

angela-tran commented Jan 17, 2024

Not sure why GitHub Actions pytest/Cypress are failing here: https://github.com/cal-itp/benefits/actions/runs/7549568812/job/20553782925?pr=1855#step:7:22

I am able to run migrate locally and run all the tests locally, too.

cc @angela-tran @thekaveman

It's failing because when the tests run, DJANGO_ADMIN is false, so django.contrib.auth is not installed. This is the problem I was running into while trying to write tests for #1851.

From the workflow logs, it looks like django-google-sso depends on django.contrib.auth and tries to call get_user_model.

  File "/opt/hostedtoolcache/Python/3.11.7/x64/lib/python3.11/site-packages/django_google_sso/models.py", line 6, in <module>
    User = get_user_model()
           ^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.11.7/x64/lib/python3.11/site-packages/django/contrib/auth/__init__.py", line 194, in get_user_model
    raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'auth.User' that has not been installed

@angela-tran
Copy link
Member

@machikoyasuda I think if you were to run locally with DJANGO_ADMIN set to false, you would see the same issue when running migrations.

This can probably be resolved by moving line 32 to go after line 49.

Copy link

github-actions bot commented Jan 17, 2024

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  benefits
  settings.py 40-49
  urls.py 42
  benefits/core
  admin.py 5-7, 26-44
Project Total  

This report was generated by python-coverage-comment-action

@machikoyasuda
Copy link
Member Author

@thekaveman @angela-tran Google SSO credential information for Localhost, Dev, Test and Prod are now saved in LastPass, Shared-Compiler Engineering.

@machikoyasuda
Copy link
Member Author

Terraform updated for 4 Google SSO env vars for Dev, Test and Prod.

@machikoyasuda machikoyasuda marked this pull request as ready for review January 29, 2024 20:42
@machikoyasuda machikoyasuda requested a review from a team as a code owner January 29, 2024 20:42
@thekaveman
Copy link
Member

@machikoyasuda I'm taking a look at this now. One quick question, you mentioned:

Also uses https://github.com/encode/httpx/ for simple HTTP requests

Is it possible to use requests here, which was already listed as a requirement? Rather than adding a new package that essentially does the same thing?

Copy link
Member

@thekaveman thekaveman left a comment

Choose a reason for hiding this comment

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

This is looking fantastic so far!! 👏 👏

Steps I took for local setup

Created the following environment variables in my local .env file:

DJANGO_ADMIN=true
DJANGO_SUPERUSER_EMAIL=[email protected]
DJANGO_SUPERUSER_PASSWORD=password1234!
DJANGO_SUPERUSER_USERNAME=benefits-admin

DJANGO_LOCAL_PORT=11369

GOOGLE_SSO_CLIENT_ID=<value from https://console.cloud.google.com/apis/credentials/oauthclient/415252694921-b03mul9832970e54gbkj4ae8l4f6fu4q.apps.googleusercontent.com?project=benefits-admin-411518>
GOOGLE_SSO_PROJECT_ID=benefits-admin-411518
GOOGLE_SSO_CLIENT_SECRET=<https://console.cloud.google.com/apis/credentials/oauthclient/415252694921-b03mul9832970e54gbkj4ae8l4f6fu4q.apps.googleusercontent.com?project=benefits-admin-411518>
GOOGLE_SSO_ALLOWABLE_DOMAINS=compiler.la
GOOGLE_SSO_STAFF_LIST=[email protected]
GOOGLE_SSO_SUPERUSER_LIST=[email protected]

Rebuild and Reopen devcontainer

Confirm in log output that Admin is enabled and setup:

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, core, django_google_sso, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
...

Login with the standard superuser

☑️ Using the username/password as shown above

Login with my personal compiler.la Google account

☑️ A user was created for my Google account
☑️ That user is marked as a superuser

Login with the [email protected] Google account

☑️ A user was created for this Google account
☑️ That user is marked as a normal staff user

Attempt login with a non-compiler.la Google account

☑️ Access is blocked due to non-matching domain

A couple of questions

  • Asked in another comment: do we need to use httpx here when we already have requests?
  • Do we need the user's Google profile pic? I don't see that showing up anywhere in the Admin interface. Should I?
  • Slightly off-topic for this PR, but related: I think we can remove 127.0.0.1 from the default ALLOWED_HOSTS list -- since the Google integration is setup for localhost redirects only, we can simplify that setting a bit.
  • Can we get some quick unit tests written for benefits/admin.py, the pre_login_user function? Skip these for now, it's complicated to test models/database type stuff.

@machikoyasuda
Copy link
Member Author

machikoyasuda commented Jan 30, 2024

@thekaveman Re: The icon - shows up here: http://localhost:11369/admin/django_google_sso/googlessouser/1/change/

image

and the URL is used here: http://localhost:11369/admin/auth/user/1/change/

image

The GoogleSSOUser model comes with the picture_url attribute baked in (https://megalus.github.io/django-google-sso/model/#the-googlessouser-model), so I recommend just keeping it - even if we don't use it in the admin app.

benefits/admin.py Outdated Show resolved Hide resolved
@thekaveman
Copy link
Member

thekaveman commented Feb 1, 2024

@machikoyasuda any updates on adding some basic unit tests here? Any blockers / questions?

Copy link
Member

@angela-tran angela-tran left a comment

Choose a reason for hiding this comment

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

I was able to test out setting all the environment variables up and logging in with my Compiler Google account today. I got through successfully too 👍

benefits/admin.py Outdated Show resolved Hide resolved
angela-tran
angela-tran previously approved these changes Feb 6, 2024
@thekaveman
Copy link
Member

thekaveman commented Feb 6, 2024

I'm looking at this again now 👀

EDIT (12pm Pacific): OK I am actually looking at this RIGHT NOW 😅

@machikoyasuda
Copy link
Member Author

Terraform dev has been updated to include:

GOOGLE_SSO_STAFF_LIST - x
GOOGLE_SSO_SUPERUSER_LIST - x,x,x

Thank you @angela-tran

Copy link
Member

@thekaveman thekaveman left a comment

Choose a reason for hiding this comment

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

I'm a little confused as to if this is totally done?

  • It seems like ADMIN checks were removed but the setting is still around.
  • Locally I'm seeing this test failing, should probably be deleted if we aren't using this setting anymore.
  • The code in benefits/admin.py is now duplicated in benefits/core/admin.py.
  • There is still code that checks for the DJANGO_ADMIN environment variable, e.g. in bin/init.sh -- if we are now saying in this PR that admin is always on, that code should probably be cleaned up as well.

This PR doesn't feel quite ready / cleaned up.

benefits/settings.py Show resolved Hide resolved
benefits/admin.py Outdated Show resolved Hide resolved
@angela-tran angela-tran dismissed their stale review February 6, 2024 21:10

Duplicate code needs to be removed, and need to agree on what to do about unit test

@machikoyasuda
Copy link
Member Author

@thekaveman @angela-tran Sorry for the delay --- I removed the test, un-did the settings.py changes, removed extra admin file, updated the function call setting ( "benefits.core.admin.pre_login_user" - has to add core in there ). And re-tested it all locally.

Copy link
Member

@angela-tran angela-tran left a comment

Choose a reason for hiding this comment

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

This looks good to me

Copy link
Member

@thekaveman thekaveman left a comment

Choose a reason for hiding this comment

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

Yep, me too! I went through all 4 scenarios again:

  • I can login with the DJANGO_SUPERUSER_USERNAME and password
  • I can login with my own compiler.la email configured in the superuser list
  • I can login with a different compiler.la email configured in the user list
  • I cannot login with a personal Gmail email not in the compiler.la domain

@machikoyasuda machikoyasuda merged commit 8faf1a7 into dev Feb 8, 2024
13 checks passed
@machikoyasuda machikoyasuda deleted the feat/1817-admin-google-sso branch February 8, 2024 00:18
thekaveman added a commit that referenced this pull request Feb 23, 2024
quick follow-up to #1855 that was missed in review
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
back-end Django views, sessions, middleware, models, migrations etc. deployment-dev [auto] Changes that will trigger a deploy if merged to dev
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enable Google SSO login for Admin
3 participants