From ed764987edb2b3b99564ff8dd4ef03345c6c4738 Mon Sep 17 00:00:00 2001 From: Steve Jalim Date: Fri, 7 Jun 2024 11:47:33 +0100 Subject: [PATCH] Add SSO auth to Wagtail and Django admins (#14649) * Add mozilla-django-oidc to the project dependencies * Add SSO support to Bedrock for accessing Wagtail and Django admins * Plumbs in mozilla-django-oidc * Add custom login pages for Wagtail and Django admins that show an SSO button instead of form fields * Retain support for username + password login (for local development) * Tests * Add custom CSRF page to help explain SSO-related session loss, if it occurs Because a renewed/cycled OIDC/SSO session can zap a CSRF token and block a user from submitting a CMS edit, we need to provide a bit more information about what's happened. This changeset adds that, via a new template and a tiny view to serve it, plugged in as Django's default CSRF view Logged out users (who are very unlikely to see this anyway) get a simple version of the message, while logged in users get more detail/context. * Bump SSO lease time to 18 hours - trying to balance awkward signouts with wanting re-checks * Update test.env so that Wagtail and Django admins are available by default when urlconf is generated. Oddly the reload trick didn't work here * Update bedrock/base/templates/403_csrf.html Co-authored-by: Alex Gibson * Make translation tagging consistent on new login templates * Move new CSRF view to use a CSS bundle, not inline CSS * Remove old, redundant CSRF view It looks like this was no longer in use. It wasn't specified as settings.CSRF_FAILURE_VIEW so wouldn't have been used/found by Django I believe * Drop translation markup from login templates to simplify * Don't count the test 404 and 500 views as nonlocaled, because we do localize them * Update bedrock/admin/templates/wagtailadmin/login.html * Tweak wording re SSO for login pages --------- Co-authored-by: Alex Gibson --- .env-dist | 9 + bedrock/admin/templates/admin/login.html | 63 +++++++ .../admin/templates/wagtailadmin/login.html | 39 ++++ bedrock/base/templates/403_csrf.html | 34 ++++ bedrock/base/templatetags/auth_tags.py | 13 ++ bedrock/base/tests/test_auth_tags.py | 22 +++ bedrock/base/tests/test_views.py | 6 + bedrock/base/views.py | 4 + bedrock/cms/tests/test_auth.py | 171 ++++++++++++++++++ .../mozorg/templates/mozorg/csrf-failure.html | 28 --- bedrock/mozorg/views.py | 5 - bedrock/settings/base.py | 70 +++++++ bedrock/urls/mozorg_mode.py | 5 + docker/envfiles/test.env | 1 + docs/cms.rst | 16 +- media/css/csrf-failure.scss | 6 +- requirements/dev.txt | 96 ++++++---- requirements/prod.in | 1 + requirements/prod.txt | 88 +++++---- 19 files changed, 565 insertions(+), 112 deletions(-) create mode 100644 bedrock/admin/templates/admin/login.html create mode 100644 bedrock/admin/templates/wagtailadmin/login.html create mode 100644 bedrock/base/templates/403_csrf.html create mode 100644 bedrock/base/templatetags/auth_tags.py create mode 100644 bedrock/base/tests/test_auth_tags.py create mode 100644 bedrock/cms/tests/test_auth.py delete mode 100644 bedrock/mozorg/templates/mozorg/csrf-failure.html diff --git a/.env-dist b/.env-dist index 4a189a8522..fee944146b 100644 --- a/.env-dist +++ b/.env-dist @@ -17,3 +17,12 @@ WAGTAIL_ENABLE_ADMIN=True # GS_PROJECT_ID="meao-stevejalim-dev-sandbox" # # export this before starting the django runserver: # # GOOGLE_APPLICATION_CREDENTIALS="./local-credentials/name-of-credentials-file.json" + +# Change to True if you want to use SSO locally, else you'll use username+password auth +USE_SSO_AUTH=False + +# If USE_SSO_AUTH is True, you'll be using Mozilla OpenID Connect via Auth0 +# Get from IAM creentials from an appropriate person within the org to set here +# in your .env +OIDC_RP_CLIENT_ID=setme +OIDC_RP_CLIENT_SECRET=setme diff --git a/bedrock/admin/templates/admin/login.html b/bedrock/admin/templates/admin/login.html new file mode 100644 index 0000000000..ffdf2f027c --- /dev/null +++ b/bedrock/admin/templates/admin/login.html @@ -0,0 +1,63 @@ +{% extends "admin/login.html" %} +{% comment %} SKIP LICENSE INSERTION {% endcomment %} +{% comment %} + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. +{% endcomment %} + +{% load auth_tags %} + +{% block content %} + + {% should_use_sso_auth as sso_auth_enabled %} + + {% if sso_auth_enabled %} + + {% if form.errors and not form.non_field_errors %} +

+ Please correct the error{{form.errors.items|length|pluralize}} below. +

+ {% endif %} + + {% if form.non_field_errors %} + {% for error in form.non_field_errors %} +

+ {{ error }} +

+ {% endfor %} + {% endif %} + +
+ + {% if user.is_authenticated %} +

+ You are authenticated as {{ username }}, but are not authorized to + access this page. Would you like to login to a different account? +

+ {% endif %} + +

+ + Sign in with Mozilla SSO + +

+

+ {% url 'admin:index' as admin_url %} + Note that after sign-in, you will be sent back to the CMS admin. Please re-access {{admin_url}} manually. +

+

+ + If you lack SSO access to this site, please ask your manager or in #www. + +

+ +
+ + {% else %} + + {{block.super}} + + {% endif %} + +{% endblock content %} diff --git a/bedrock/admin/templates/wagtailadmin/login.html b/bedrock/admin/templates/wagtailadmin/login.html new file mode 100644 index 0000000000..e364992f3a --- /dev/null +++ b/bedrock/admin/templates/wagtailadmin/login.html @@ -0,0 +1,39 @@ +{% extends "wagtailadmin/login.html" %} +{% comment %} SKIP LICENSE INSERTION {% endcomment %} +{% comment %} +This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. +{% endcomment %} + +{% load auth_tags %} + +{% block login_form %} + {% should_use_sso_auth as sso_auth_enabled %} + + {% if sso_auth_enabled %} + + + + Sign in with Mozilla SSO + + +

If you lack SSO access to this site, please ask your manager or in #www

+ + {% else %} + {{block.super}} + {% endif %} + +{% endblock login_form %} + + +{% block submit_buttons %} + {% should_use_sso_auth as sso_auth_enabled %} + + {% if sso_auth_enabled %} + {# No need to show the button content if SSO is enabled#} + {% else %} + {{block.super}} + {% endif %} + +{% endblock submit_buttons %} diff --git a/bedrock/base/templates/403_csrf.html b/bedrock/base/templates/403_csrf.html new file mode 100644 index 0000000000..b2d97628a9 --- /dev/null +++ b/bedrock/base/templates/403_csrf.html @@ -0,0 +1,34 @@ +{# + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. +#} + + + + + + CSRF mismatch detected. + + {{ css_bundle('csrf-failure') }} + + +

Access denied

+

+ Cross-site request forgery (CSRF) mismatch detected. +

+ {% if request.user.is_staff %} +

+ This is most likely because your SSO session expired or had to be renewed. +

+

+ It's likely and regrettable that you have lost work since your last save. +
+ If this is happening a lot, please open a bug report. +

+ {% endif %} +

+ Please go back using your browser's back button and try again. Reloading this page will not fix the problem. +

+ + diff --git a/bedrock/base/templatetags/auth_tags.py b/bedrock/base/templatetags/auth_tags.py new file mode 100644 index 0000000000..918e66f7f8 --- /dev/null +++ b/bedrock/base/templatetags/auth_tags.py @@ -0,0 +1,13 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +from django.conf import settings +from django.template import Library + +register = Library() + + +@register.simple_tag +def should_use_sso_auth(): + return settings.USE_SSO_AUTH is True diff --git a/bedrock/base/tests/test_auth_tags.py b/bedrock/base/tests/test_auth_tags.py new file mode 100644 index 0000000000..03c3f7999c --- /dev/null +++ b/bedrock/base/tests/test_auth_tags.py @@ -0,0 +1,22 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +from django.test import override_settings + +import pytest + +from bedrock.base.templatetags.auth_tags import should_use_sso_auth + + +@pytest.mark.parametrize( + "settings_val, expected", + ( + (True, True), + (False, False), + (None, False), + ), +) +def test_should_use_simple_auth(settings_val, expected): + with override_settings(USE_SSO_AUTH=settings_val): + assert should_use_sso_auth() == expected diff --git a/bedrock/base/tests/test_views.py b/bedrock/base/tests/test_views.py index aac0dcfdba..3a31561998 100644 --- a/bedrock/base/tests/test_views.py +++ b/bedrock/base/tests/test_views.py @@ -5,6 +5,7 @@ import datetime from unittest.mock import patch +from django.conf import settings from django.test import RequestFactory, TestCase from django.utils.timezone import now as tz_now @@ -73,3 +74,8 @@ def test_get_contentful_sync_info(mock_timeago_format, mock_tz_now): # Also check the no-data context dict: ContentfulEntry.objects.all().delete() assert get_contentful_sync_info() == {} + + +@pytest.mark.django_db +def test_csrf_view_is_custom_one(): + assert settings.CSRF_FAILURE_VIEW == "bedrock.base.views.csrf_failure" diff --git a/bedrock/base/views.py b/bedrock/base/views.py index a28ff63eb7..3fe795bb1d 100644 --- a/bedrock/base/views.py +++ b/bedrock/base/views.py @@ -172,3 +172,7 @@ def server_error_view(request, template_name="500.html"): def page_not_found_view(request, exception=None, template_name="404.html"): """404 error handler that runs context processors.""" return l10n_utils.render(request, template_name, ftl_files=["404", "500"], status=404) + + +def csrf_failure(request, reason="CSRF failure", template_name="403_csrf.html"): + return render(request, template_name, status=403) diff --git a/bedrock/cms/tests/test_auth.py b/bedrock/cms/tests/test_auth.py new file mode 100644 index 0000000000..9954473162 --- /dev/null +++ b/bedrock/cms/tests/test_auth.py @@ -0,0 +1,171 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +from importlib import reload +from unittest import mock + +from django.contrib.auth.models import User +from django.test import TestCase, override_settings +from django.urls import reverse + + +class LoginTestBase(TestCase): + TEST_ADMIN_PASSWORD = "admin12345" + + def setUp(self): + self.wagtail_login_url = reverse("wagtailadmin_login") + self.django_admin_login_url = reverse("admin:login") + + def _create_admin(self): + # create an admin user + admin = User.objects.create_superuser( + username="admin", + email="admin@example.com", + password=self.TEST_ADMIN_PASSWORD, + ) + assert admin.is_active is True + assert admin.has_usable_password() is True + assert admin.check_password(self.TEST_ADMIN_PASSWORD) is True + assert admin.is_staff is True + assert admin.is_superuser is True + + return admin + + +class ConventionalLoginDeniedTest(LoginTestBase): + """Tests to show that the standard way to sign in to Wagtail and the Django + Admin just do not work (which is good, because everyone should use SSO + in production)""" + + @override_settings( + WAGTAIL_ENABLE_ADMIN=True, + USE_SSO_AUTH=True, + AUTHENTICATION_BACKENDS=("mozilla_django_oidc.auth.OIDCAuthenticationBackend",), + ) + def test_login_page_contains_no_form(self): + for url in (self.wagtail_login_url, self.django_admin_login_url): + with self.subTest(url=url): + response = self.client.get(url) + assert response.status_code == 200 + # Check for the form field attrs that would normally be present + self.assertNotContains(response, b'name="username"') + self.assertNotContains(response, b'name="password"') + # No CSRF token == no go, anyway + self.assertNotContains(response, b"csrfmiddlewaretoken") + # Confirm SSO link + self.assertContains(response, b"Sign in with Mozilla SSO") + + @override_settings( + WAGTAIL_ENABLE_ADMIN=True, + USE_SSO_AUTH=True, + AUTHENTICATION_BACKENDS=("mozilla_django_oidc.auth.OIDCAuthenticationBackend",), + ) + def test_posting_to_login_denied(self): + admin = self._create_admin() + + for url, error_message, expected_template in ( + ( + self.wagtail_login_url, + b"Your username and password didn't match.", + "wagtailadmin/login.html", + ), + ( + self.django_admin_login_url, + b"Please enter the correct username and password for a staff account.", + "admin/login.html", + ), + ): + payload = { + "username": admin.username, + "password": self.TEST_ADMIN_PASSWORD, + } + with self.subTest( + url=url, + error_message=error_message, + expected_template=expected_template, + ): + response = self.client.post(url, data=payload, follow=True) + self.assertEqual( + response.status_code, + 200, # 200 is what comes back after the redirect + ) + # Show that while we provided valid credentials, we still get + # treated as if they are not the correct ones. + self.assertContains(response, error_message) + self.assertContains(response, b"Sign in with Mozilla SSO") + self.assertTemplateUsed(response, expected_template) + + +class AuthenticationBackendSelectionTests(TestCase): + # We have to force the USE_SSO_AUTH to True at the environment level + # then import the settings to trigger the appropriate if/else branch + # that sets the right auth backend. + + @mock.patch.dict("os.environ", {"USE_SSO_AUTH": "True"}) + def test_only_sso_backend_enabled_if_USE_SSO_AUTH_is_True(self): + from bedrock.settings import base as base_settings + + reloaded_settings = reload(base_settings) + + self.assertEqual( + reloaded_settings.AUTHENTICATION_BACKENDS, + ("mozilla_django_oidc.auth.OIDCAuthenticationBackend",), + ) + + @mock.patch.dict("os.environ", {"USE_SSO_AUTH": "False"}) + def test_only_model_backend_enabled_if_USE_SSO_AUTH_is_False(self): + from bedrock.settings import base as base_settings + + reloaded_settings = reload(base_settings) + + self.assertEqual( + reloaded_settings.AUTHENTICATION_BACKENDS, + ("django.contrib.auth.backends.ModelBackend",), + ) + + +class ConventionalLoginAllowedTest(LoginTestBase): + """If certain settings are set in settings.local, regular + username + password sign-in functionality is restored + """ + + @override_settings(WAGTAIL_ENABLE_ADMIN=True, USE_SSO_AUTH=False) + def test_login_page_contains_form(self): + for url in (self.wagtail_login_url, self.django_admin_login_url): + with self.subTest(url=url): + response = self.client.get(url) + assert response.status_code == 200 + # Check for the form field attrs that would normally be present + self.assertContains(response, b'name="username"', 1) + self.assertContains(response, b'name="password"', 1) + self.assertContains(response, b"csrfmiddlewaretoken", 1) + self.assertNotContains(response, b"Sign in with Mozilla SSO") + + @override_settings( + AUTHENTICATION_BACKENDS=("django.contrib.auth.backends.ModelBackend",), + WAGTAIL_ENABLE_ADMIN=True, + USE_SSO_AUTH=False, + ) + def test_posting_to_login_works_if_the_modelbackend_is_configured(self): + # Only relevant to local usage, but good to confirm + admin = self._create_admin() + for url, expected_template in ( + (self.wagtail_login_url, "wagtailadmin/home.html"), + ( + self.django_admin_login_url, + "wagtailadmin/home.html", + # That expected template is correct. Signing in to Django Admin + # redirects to Wagtail's Admin, because that's what + # LOGIN_REDIRECT_URL points to + ), + ): + payload = { + "username": admin.username, + "password": self.TEST_ADMIN_PASSWORD, + } + with self.subTest(url=url, expected_template=expected_template): + response = self.client.post(url, data=payload, follow=True) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, b"Sign in") + self.assertTemplateUsed(response, expected_template) diff --git a/bedrock/mozorg/templates/mozorg/csrf-failure.html b/bedrock/mozorg/templates/mozorg/csrf-failure.html deleted file mode 100644 index 3b98f79062..0000000000 --- a/bedrock/mozorg/templates/mozorg/csrf-failure.html +++ /dev/null @@ -1,28 +0,0 @@ -{# - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at https://mozilla.org/MPL/2.0/. -#} - -{% extends "base-protocol-mozilla.html" %} - -{% block page_title %}Invalid Request{% endblock %} - -{% block page_css %} - {{ css_bundle('csrf-failure') }} -{% endblock %} - -{% block body_id %}csrf-failure{% endblock %} - -{% block content %} - -
-
-

Invalid Request

- -

- We could not process your request. -

-
-
-{% endblock %} diff --git a/bedrock/mozorg/views.py b/bedrock/mozorg/views.py index 178e92bb4d..17c4b0b800 100644 --- a/bedrock/mozorg/views.py +++ b/bedrock/mozorg/views.py @@ -32,11 +32,6 @@ credits_file = CreditsFile("credits") TECH_BLOG_SLUGS = ["hacks", "cd", "futurereleases"] -def csrf_failure(request, reason=""): - template_vars = {"reason": reason} - return l10n_utils.render(request, "mozorg/csrf-failure.html", template_vars, status=403) - - @xframe_allow def hacks_newsletter(request): return l10n_utils.render(request, "mozorg/newsletter/hacks.mozilla.org.html") diff --git a/bedrock/settings/base.py b/bedrock/settings/base.py index 7a3c40681c..f1ffd2784a 100644 --- a/bedrock/settings/base.py +++ b/bedrock/settings/base.py @@ -485,7 +485,9 @@ SUPPORTED_NONLOCALES = [ "xbl", # in mozorg urls "revision.txt", # from root_files "locales", # in mozorg urls + "csrf_403", ] + # Paths that can exist either with or without a locale code in the URL. # Matches the whole URL path SUPPORTED_LOCALE_IGNORE = [ @@ -717,6 +719,7 @@ INSTALLED_APPS = [ "django_extensions", "lib.l10n_utils", "django_rq", + "mozilla_django_oidc", # needs to be loaded after django.contrib.auth ] # Must match the list at CloudFlare if the @@ -1083,6 +1086,10 @@ LOGGING = { "handlers": ["console"], "propagate": False, }, + "mozilla_django_oidc": { + "handlers": ["console"], + "level": "DEBUG", + }, }, } @@ -1907,6 +1914,67 @@ RELAY_PRODUCT_URL = config( "RELAY_PRODUCT_URL", default="https://stage.fxprivaterelay.nonprod.cloudops.mozgcp.net/" if DEV else "https://relay.firefox.com/" ) + +# Authentication with Mozilla OpenID Connect / Auth0 ============================================ + +LOGIN_ERROR_URL = "/cms-admin/" +LOGIN_REDIRECT_URL_FAILURE = "/cms-admin/" +LOGIN_REDIRECT_URL = "/cms-admin/" +LOGOUT_REDIRECT_URL = "/cms-admin/" + +OIDC_RP_SIGN_ALGO = "RS256" + +# How frequently do we check with the provider that the user still exists and is authorised? +OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS = config( + "OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS", + default="64800", # 18 hours + parser=int, +) + +OIDC_CREATE_USER = False # We don't want drive-by signups + +OIDC_RP_CLIENT_ID = config("OIDC_RP_CLIENT_ID", default="", parser=str) +OIDC_RP_CLIENT_SECRET = config("OIDC_RP_CLIENT_SECRET", default="", parser=str) + +OIDC_OP_AUTHORIZATION_ENDPOINT = "https://auth.mozilla.auth0.com/authorize" +OIDC_OP_TOKEN_ENDPOINT = "https://auth.mozilla.auth0.com/oauth/token" +OIDC_OP_USER_ENDPOINT = "https://auth.mozilla.auth0.com/userinfo" +OIDC_OP_DOMAIN = "auth.mozilla.auth0.com" +OIDC_OP_JWKS_ENDPOINT = "https://auth.mozilla.auth0.com/.well-known/jwks.json" + +# If True (which should only be for local work in your .env), then show +# username and password fields when signing up, not the SSO button +USE_SSO_AUTH = config("USE_SSO_AUTH", default="True", parser=bool) + +if USE_SSO_AUTH: + AUTHENTICATION_BACKENDS = ( + # Deliberately OIDC only, else no entry by any other means + "mozilla_django_oidc.auth.OIDCAuthenticationBackend", + ) +else: + AUTHENTICATION_BACKENDS = ( + # Regular username + password auth + "django.contrib.auth.backends.ModelBackend", + ) + +# Note that AUTHENTICATION_BACKENDS is overridden in tests, so take care +# to check/amend those if you add additional auth backends + +# Extra Wagtail config to disable password usage (SSO should be the only route) +# https://docs.wagtail.org/en/v4.2.4/reference/settings.html#wagtail-password-management-enabled +# Don't let users change or reset their password +if USE_SSO_AUTH: + WAGTAIL_PASSWORD_MANAGEMENT_ENABLED = False + WAGTAIL_PASSWORD_RESET_ENABLED = False + + # Don't require a password when creating a user, + # and blank password means cannot log in unless via SSO + WAGTAILUSERS_PASSWORD_ENABLED = False + +# Custom CSRF failure view to show custom CSRF messaging, which is +# more likely to appear with SSO auth enabled, when sessions expire +CSRF_FAILURE_VIEW = "bedrock.base.views.csrf_failure" + # WAGTAIL ======================================================================================= WAGTAIL_SITE_NAME = config( @@ -1944,6 +2012,7 @@ if WAGTAIL_ENABLE_ADMIN: ] for midddleware_spec in [ + "mozilla_django_oidc.middleware.SessionRefresh", # In case someone has their Auth0 revoked while logged in, revalidate it "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", @@ -1955,6 +2024,7 @@ if WAGTAIL_ENABLE_ADMIN: "cms-admin", "django-admin", "django-rq", + "oidc", ] ) diff --git a/bedrock/urls/mozorg_mode.py b/bedrock/urls/mozorg_mode.py index 7b3ff3ed46..e5411d7dff 100644 --- a/bedrock/urls/mozorg_mode.py +++ b/bedrock/urls/mozorg_mode.py @@ -57,9 +57,14 @@ if settings.DEBUG: path("404/", import_string(handler404)), path("500/", import_string(handler500)), ) + urlpatterns += (path("csrf_403/", base_views.csrf_failure, {}),) if settings.WAGTAIL_ENABLE_ADMIN: + # If adding new a new path here, you must also add an entry to + # settings.SUPPORTED_NONLOCALES in the `if WAGTAIL_ENABLE_ADMIN` block so + # that bedrock doesn't try to prepend a locale onto requests for the path urlpatterns += ( + path("oidc/", include("mozilla_django_oidc.urls")), path("cms-admin/", include(wagtailadmin_urls)), path("django-admin/", admin.site.urls), # needed to show django-rq UI path("django-rq/", include("django_rq.urls")), # task queue management diff --git a/docker/envfiles/test.env b/docker/envfiles/test.env index db698a2209..d175f7666b 100644 --- a/docker/envfiles/test.env +++ b/docker/envfiles/test.env @@ -2,3 +2,4 @@ DEBUG=False DEV=False ALLOWED_HOSTS=* ADMINS=["thedude@example.com"] +WAGTAIL_ENABLE_ADMIN=True diff --git a/docs/cms.rst b/docs/cms.rst index 7285302b2c..04a6ee0202 100644 --- a/docs/cms.rst +++ b/docs/cms.rst @@ -115,8 +115,22 @@ we need to. Infrastructure notes -------------------- -To come +SSO setup +~~~~~~~~~ + +When the env vars `OIDC_RP_CLIENT_ID` and `OIDC_RP_CLIENT_SECRET` are present and +`USE_SSO_AUTH` is set to True in settings, Bedrock will use Mozilla SSO instead of +username + password to sign in. The deployed sites will have these set, but we +also have credentials available for using SSO locally if you need to develop something +that needs it - see our password vault. + +Note that Bedrock in SSO mode will not support 'drive by' user creation even if +they have an @mozilla.com identity. Only users who already exist in the Wagtail +admin as a User will be allowed to log in. You can create new users using Django's +`createsuperuser`_ command, setting both the username and email do be your +``flast@mozilla.com`` LDAP address .. _wagtail: https://wagtail.org/ .. _Editor Guide: https://guide.wagtail.org/en-latest/ .. _Wagtail Images docs: https://docs.wagtail.org/en/stable/topics/images.html +.. _createsuperuser: https://docs.djangoproject.com/en/5.0/ref/django-admin/#createsuperuser diff --git a/media/css/csrf-failure.scss b/media/css/csrf-failure.scss index 273b629557..8426c2c82a 100644 --- a/media/css/csrf-failure.scss +++ b/media/css/csrf-failure.scss @@ -4,6 +4,10 @@ @import '~@mozilla-protocol/core/protocol/css/includes/lib'; -main { +body { min-height: 350px; + color: #000; + background-color: #fff; + font: 100%/1.5 sans-serif; + padding: 40px; } diff --git a/requirements/dev.txt b/requirements/dev.txt index f5741c59be..2b5bf1125c 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -69,9 +69,9 @@ boto3==1.34.101 \ --hash=sha256:1d854b5880e185db546b4c759fcb664bf3326275064d2b44229cc217e8be9d7e \ --hash=sha256:79b93f3370ea96ce838042bc2eac0c996aee204b01e7e6452eb77abcbe697d6a # via -r requirements/prod.txt -botocore==1.34.118 \ - --hash=sha256:0a3d1ec0186f8b516deb39474de3d226d531f77f92a0f56ad79b80219db3ae9e \ - --hash=sha256:e3f6c5636a4394768e81e33a16f5c6ae7f364f512415d423f9b9dc67fc638df4 +botocore==1.34.119 \ + --hash=sha256:4bdf7926a1290b2650d62899ceba65073dd2693e61c35f5cdeb3a286a0aaa27b \ + --hash=sha256:b253f15b24b87b070e176af48e8ef146516090429d30a7d8b136a4c079b28008 # via # -r requirements/prod.txt # boto3 @@ -336,41 +336,43 @@ coverage[toml]==7.5.3 \ --hash=sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9 \ --hash=sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35 # via pytest-cov -cryptography==42.0.7 \ - --hash=sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55 \ - --hash=sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785 \ - --hash=sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b \ - --hash=sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886 \ - --hash=sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82 \ - --hash=sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1 \ - --hash=sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda \ - --hash=sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f \ - --hash=sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68 \ - --hash=sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60 \ - --hash=sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7 \ - --hash=sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd \ - --hash=sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582 \ - --hash=sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc \ - --hash=sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858 \ - --hash=sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b \ - --hash=sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2 \ - --hash=sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678 \ - --hash=sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13 \ - --hash=sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4 \ - --hash=sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8 \ - --hash=sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604 \ - --hash=sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477 \ - --hash=sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e \ - --hash=sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a \ - --hash=sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9 \ - --hash=sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14 \ - --hash=sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda \ - --hash=sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da \ - --hash=sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562 \ - --hash=sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2 \ - --hash=sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9 +cryptography==42.0.8 \ + --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ + --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ + --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ + --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ + --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ + --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ + --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ + --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ + --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ + --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ + --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ + --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ + --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ + --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ + --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ + --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ + --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ + --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ + --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ + --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ + --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ + --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ + --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ + --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ + --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ + --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ + --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ + --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ + --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ + --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ + --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ + --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e # via # -r requirements/prod.txt + # josepy + # mozilla-django-oidc # pyjwt # pyopenssl cssselect==1.2.0 \ @@ -475,6 +477,7 @@ django==4.2.11 \ # django-treebeard # django-watchman # djangorestframework + # mozilla-django-oidc # wagtail # wagtail-localize django-allow-cidr==0.7.1 \ @@ -596,9 +599,9 @@ factory-boy==3.3.0 \ # via # -r requirements/dev.in # wagtail-factories -faker==25.4.0 \ - --hash=sha256:2baf32ca8a9e6870445f2248c99b210e5d0e5eadaba5936b407f6eb9d63cb96a \ - --hash=sha256:c6c2a937c59f12ee9878434c6ad3d6eca5d429d50a9b7c5923d99aa1a7ba5fba +faker==25.5.0 \ + --hash=sha256:84d454fc9fef0b73428e00bdf45a36c04568c75f22727e990071580840cfbb84 \ + --hash=sha256:edb85040a47ef1b30ccd8c4b6f07ee3cb4bd64aab1483be4efe75816ee2e2e36 # via factory-boy filetype==1.2.0 \ --hash=sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb \ @@ -888,6 +891,12 @@ jmespath==1.0.1 \ # -r requirements/prod.txt # boto3 # botocore +josepy==1.14.0 \ + --hash=sha256:308b3bf9ce825ad4d4bba76372cf19b5dc1c2ce96a9d298f9642975e64bd13dd \ + --hash=sha256:d2b36a30f316269f3242f4c2e45e15890784178af5ec54fa3e49cf9234ee22e0 + # via + # -r requirements/prod.txt + # mozilla-django-oidc jq==1.7.0 \ --hash=sha256:0137445eb67c43eb0eb46933aff7e8afbbd6c5aaf8574efd5df536dc9d177d1d \ --hash=sha256:05ebdaa868f068967d9e7cbf76e59e61fbdafa565dbc3579c387fb1f248592bb \ @@ -1215,6 +1224,10 @@ mdurl==0.1.2 \ mdx-outline @ https://github.com/mozmeao/mdx_outline/archive/refs/tags/markdown-3.4-compatibility.tar.gz \ --hash=sha256:a78e112f80628246dd45858fe18404aaa8efb8dc81949bb1fbb87e91f9654afa # via -r requirements/prod.txt +mozilla-django-oidc==4.0.1 \ + --hash=sha256:04ef58759be69f22cdc402d082480aaebf193466cad385dc9e4f8df2a0b187ca \ + --hash=sha256:4ff8c64069e3e05c539cecf9345e73225a99641a25e13b7a5f933ec897b58918 + # via -r requirements/prod.txt newrelic==9.10.0 \ --hash=sha256:02db25b0fd2fc835efe4a7f1c92dbc5bbb95125341aba07152041aa6a5666cda \ --hash=sha256:09912303e04bee6aa1fe1c671e87b4e8e55461081a96210895828798f5ba8c3f \ @@ -1568,7 +1581,9 @@ pynacl==1.5.0 \ pyopenssl==24.1.0 \ --hash=sha256:17ed5be5936449c5418d1cd269a1a9e9081bc54c17aed272b45856a3d3dc86ad \ --hash=sha256:cabed4bfaa5df9f1a16c0ef64a0cb65318b5cd077a7eda7d6970131ca2f41a6f - # via -r requirements/prod.txt + # via + # -r requirements/prod.txt + # josepy pypng==0.20220715.0 \ --hash=sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c \ --hash=sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1 @@ -1840,6 +1855,7 @@ requests==2.32.3 \ # django-mozilla-product-details # google-api-core # google-cloud-storage + # mozilla-django-oidc # pygithub # pytest-base-url # pytest-selenium diff --git a/requirements/prod.in b/requirements/prod.in index f9935824c8..8a7193bd2b 100644 --- a/requirements/prod.in +++ b/requirements/prod.in @@ -41,6 +41,7 @@ lxml==5.2.2 # Needed as a top-level dep so that it's available for BeautifulSou Markdown==3.6 markus[datadog]==4.2.0 https://github.com/mozmeao/mdx_outline/archive/refs/tags/markdown-3.4-compatibility.tar.gz#egg=mdx_outline +mozilla-django-oidc==4.0.1 newrelic==9.10.0 Pillow==10.3.0 psycopg2-binary==2.9.9 diff --git a/requirements/prod.txt b/requirements/prod.txt index a1d625834a..018e3cb2cd 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -53,9 +53,9 @@ boto3==1.34.101 \ --hash=sha256:1d854b5880e185db546b4c759fcb664bf3326275064d2b44229cc217e8be9d7e \ --hash=sha256:79b93f3370ea96ce838042bc2eac0c996aee204b01e7e6452eb77abcbe697d6a # via -r requirements/prod.in -botocore==1.34.118 \ - --hash=sha256:0a3d1ec0186f8b516deb39474de3d226d531f77f92a0f56ad79b80219db3ae9e \ - --hash=sha256:e3f6c5636a4394768e81e33a16f5c6ae7f364f512415d423f9b9dc67fc638df4 +botocore==1.34.119 \ + --hash=sha256:4bdf7926a1290b2650d62899ceba65073dd2693e61c35f5cdeb3a286a0aaa27b \ + --hash=sha256:b253f15b24b87b070e176af48e8ef146516090429d30a7d8b136a4c079b28008 # via # boto3 # s3transfer @@ -240,40 +240,42 @@ contextlib2==21.6.0 \ --hash=sha256:3fbdb64466afd23abaf6c977627b75b6139a5a3e8ce38405c5b413aed7a0471f \ --hash=sha256:ab1e2bfe1d01d968e1b7e8d9023bc51ef3509bba217bb730cee3827e1ee82869 # via -r requirements/prod.in -cryptography==42.0.7 \ - --hash=sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55 \ - --hash=sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785 \ - --hash=sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b \ - --hash=sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886 \ - --hash=sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82 \ - --hash=sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1 \ - --hash=sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda \ - --hash=sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f \ - --hash=sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68 \ - --hash=sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60 \ - --hash=sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7 \ - --hash=sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd \ - --hash=sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582 \ - --hash=sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc \ - --hash=sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858 \ - --hash=sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b \ - --hash=sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2 \ - --hash=sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678 \ - --hash=sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13 \ - --hash=sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4 \ - --hash=sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8 \ - --hash=sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604 \ - --hash=sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477 \ - --hash=sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e \ - --hash=sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a \ - --hash=sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9 \ - --hash=sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14 \ - --hash=sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda \ - --hash=sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da \ - --hash=sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562 \ - --hash=sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2 \ - --hash=sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9 +cryptography==42.0.8 \ + --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ + --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ + --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ + --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ + --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ + --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ + --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ + --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ + --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ + --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ + --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ + --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ + --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ + --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ + --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ + --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ + --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ + --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ + --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ + --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ + --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ + --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ + --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ + --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ + --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ + --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ + --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ + --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ + --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ + --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ + --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ + --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e # via + # josepy + # mozilla-django-oidc # pyjwt # pyopenssl datadog==0.49.1 \ @@ -322,6 +324,7 @@ django==4.2.11 \ # django-treebeard # django-watchman # djangorestframework + # mozilla-django-oidc # wagtail # wagtail-localize django-allow-cidr==0.7.1 \ @@ -677,6 +680,10 @@ jmespath==1.0.1 \ # via # boto3 # botocore +josepy==1.14.0 \ + --hash=sha256:308b3bf9ce825ad4d4bba76372cf19b5dc1c2ce96a9d298f9642975e64bd13dd \ + --hash=sha256:d2b36a30f316269f3242f4c2e45e15890784178af5ec54fa3e49cf9234ee22e0 + # via mozilla-django-oidc jq==1.7.0 \ --hash=sha256:0137445eb67c43eb0eb46933aff7e8afbbd6c5aaf8574efd5df536dc9d177d1d \ --hash=sha256:05ebdaa868f068967d9e7cbf76e59e61fbdafa565dbc3579c387fb1f248592bb \ @@ -986,6 +993,10 @@ markus[datadog]==4.2.0 \ mdx-outline @ https://github.com/mozmeao/mdx_outline/archive/refs/tags/markdown-3.4-compatibility.tar.gz \ --hash=sha256:a78e112f80628246dd45858fe18404aaa8efb8dc81949bb1fbb87e91f9654afa # via -r requirements/prod.in +mozilla-django-oidc==4.0.1 \ + --hash=sha256:04ef58759be69f22cdc402d082480aaebf193466cad385dc9e4f8df2a0b187ca \ + --hash=sha256:4ff8c64069e3e05c539cecf9345e73225a99641a25e13b7a5f933ec897b58918 + # via -r requirements/prod.in newrelic==9.10.0 \ --hash=sha256:02db25b0fd2fc835efe4a7f1c92dbc5bbb95125341aba07152041aa6a5666cda \ --hash=sha256:09912303e04bee6aa1fe1c671e87b4e8e55461081a96210895828798f5ba8c3f \ @@ -1289,7 +1300,9 @@ pynacl==1.5.0 \ pyopenssl==24.1.0 \ --hash=sha256:17ed5be5936449c5418d1cd269a1a9e9081bc54c17aed272b45856a3d3dc86ad \ --hash=sha256:cabed4bfaa5df9f1a16c0ef64a0cb65318b5cd077a7eda7d6970131ca2f41a6f - # via -r requirements/prod.in + # via + # -r requirements/prod.in + # josepy pypng==0.20220715.0 \ --hash=sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c \ --hash=sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1 @@ -1393,6 +1406,7 @@ requests==2.32.3 \ # django-mozilla-product-details # google-api-core # google-cloud-storage + # mozilla-django-oidc # pygithub # wagtail rich-text-renderer==0.2.8 \