Skip to content

Commit

Permalink
Override LoginView to provide an SSO button
Browse files Browse the repository at this point in the history
This change moves our login template override to the `login` app, adds a subclass of Wagtail's `LoginView` to provide extra SSO context, and then adds a "Sign-in with SSO" button if SSO is enabled.

This simplifies some of our URLs around SSO (always having /admin/login respond), and moves one of our override templates out of `wagtailadmin_overrides` and justifies its existence a little bit more.

Co-authored-by: Andy Chosak <andy.chosak@cfpb.gov>
  • Loading branch information
willbarton and chosak committed May 23, 2024
1 parent 4f9d7f1 commit 3950e8e
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 36 deletions.
2 changes: 1 addition & 1 deletion cfgov/cfgov/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@

# Configure login/out URLs for OIDC
LOGIN_REDIRECT_URL = reverse_lazy("wagtailadmin_home")
LOGOUT_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = reverse_lazy("cfgov_login")
ALLOW_LOGOUT_GET_METHOD = True

# This OIDC client's id and secret
Expand Down
1 change: 1 addition & 0 deletions cfgov/cfgov/tests/test_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"^django-admin/",
"^login",
"^logout",
"^oidc/",
"^password/",
"^tasks/",
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{% extends "wagtailadmin/login.html" %}
{% load wagtailadmin_tags %}

{% block below_login %}
{% if sso_enabled %}
<hr>
<p><a href="{% url 'oidc_authentication_init' %}" class="button" style="text-align: center;">Sign in with Single Sign-On</a></p>
<hr>
{% endif %}
<p>This is a Consumer Financial Protection Bureau (CFPB) information system. The CFPB is an independent agency of the United States Government. CFPB information systems are provided for the processing of official information only. Unauthorized or improper use of this system may result in administrative action, as well as civil and criminal penalties.</p>
<p>Because this is a CFPB information system, you have no reasonable expectation of privacy regarding any communication or data, transiting or stored, on this information system. All data contained in CFPB information systems is owned by the CFPB, and your use of the CFPB information system serves as your consent to your usage being monitored, intercepted, recorded, read, copied, captured, or otherwise audited in any manner by authorized personnel, including, but not limited to, employees, contractors, and/or agents of the United States Government.</p>
{% endblock %}
2 changes: 1 addition & 1 deletion cfgov/login/tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,5 +209,5 @@ def test_create_user_already_exists(self):
self.assertEqual(len(messages), 1)
self.assertEqual(
messages[0].message,
"Unable to create a user for test@example.com",
"There was an error creating a user for test@example.com",
)
16 changes: 16 additions & 0 deletions cfgov/login/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from django.test import TestCase, override_settings
from django.urls import reverse


class LoginViewTestCase(TestCase):

@override_settings(ENABLE_SSO=True)
def test_view_gets_sso_enabled_context(self):
response = self.client.get(reverse("cfgov_login"))
self.assertTrue(response.context["sso_enabled"])
pass

@override_settings(ENABLE_SSO=False)
def test_view_gets_sso_disabled_context(self):
response = self.client.get(reverse("cfgov_login"))
self.assertFalse(response.context["sso_enabled"])
62 changes: 29 additions & 33 deletions cfgov/login/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,32 @@
from django.urls import include, re_path, reverse_lazy
from django.views.generic.base import RedirectView

from login.views import LoginView

if settings.ENABLE_SSO: # pragma: no cover
urlpatterns = [
# If SSO auth is enabled, /login will redirect to /oidc/login,
# which in turn will redirect to the configured identity provider.
re_path(r"^oidc/", include("mozilla_django_oidc.urls")),
re_path(
r"^admin/login/$",
RedirectView.as_view(
url=reverse_lazy("oidc_authentication_init"), query_string=True
),
),
re_path(
r"^admin/logout/$",
RedirectView.as_view(
url=reverse_lazy("oidc_logout"),
query_string=True,
),
),
]
else:
urlpatterns = [
# When SSO is not enabled, the Django login should redirect to Wagtail
re_path(
r"^django-admin/login/$",
RedirectView.as_view(
url=reverse_lazy("wagtailadmin_login"), query_string=True
),
),
]

urlpatterns = urlpatterns + [
# Redirect root-level /login and /logout to Wagtail's URLs
urlpatterns = [
# Include OIDC URLs
re_path(r"^oidc/", include("mozilla_django_oidc.urls")),
# Override Wagtail's login URL with our subclass
re_path(r"^admin/login/", LoginView.as_view(), name="cfgov_login"),
# Redirect root-level /login and /logout
re_path(
r"^login/$",
RedirectView.as_view(
url=reverse_lazy("wagtailadmin_login"), query_string=True
url=reverse_lazy("cfgov_login"), query_string=True
),
),
re_path(
r"^logout/$",
RedirectView.as_view(
url=reverse_lazy("wagtailadmin_logout"), query_string=True
url=reverse_lazy("cfgov_login"), query_string=True
),
),
# Redirect the Django admin login to Wagtail
re_path(
r"^django-admin/login/$",
RedirectView.as_view(
url=reverse_lazy("cfgov_login"), query_string=True
),
),
# Redirect Django's password change view to Wagtail's
Expand All @@ -55,3 +38,16 @@
),
),
]

if settings.ENABLE_SSO: # pragma: no cover
urlpatterns = urlpatterns + [
# Redirect logout to the OIDC logout to make sure we clear our OIDC
# session information
re_path(
r"^admin/logout/$",
RedirectView.as_view(
url=reverse_lazy("oidc_logout"),
query_string=True,
),
),
]
12 changes: 12 additions & 0 deletions cfgov/login/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.conf import settings

from wagtail.admin.views.account import LoginView as WagtailLoginView


class LoginView(WagtailLoginView):
template_name = "login/login.html"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["sso_enabled"] = settings.ENABLE_SSO
return context
2 changes: 1 addition & 1 deletion docs/sso.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ source .env

### Run consumerfinance.gov and log in

Start or restart your local consumerfinance.gov instance, then visit http://localhost:8000/admin.
Start or restart your local consumerfinance.gov instance, then visit http://localhost:8000/admin. Click "Sign in with Single Sign-On".

This should redirect you to the test OIDC provider at http://localhost:8080/openid/authorize with a prompt to authorize "Wagtail (Local HS256)" (the name of the client application as configured in the test provider) to access the OIDC user's address.

Expand Down

0 comments on commit 3950e8e

Please sign in to comment.