Skip to content

Commit 14d93df

Browse files
committed
Add 2FA using allauth
Most of the work here is templating and ensuring the settings are correct. There's no 2FA mandate and this doesn't enable webauthn/passkeys for now, strictly TOTP and recovery codes.
1 parent 3998a00 commit 14d93df

23 files changed

+459
-9
lines changed

.coveragerc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ omit =
1818

1919
*/migrations/*.py
2020
templates/admin/*.html
21-
templates/account/*.html
21+
22+
# Skip allauth templates
23+
templates/allauth/*
24+
templates/account/*
25+
templates/mfa/*
26+
2227
templates/includes/*.html
2328
adserver/templatetags/metabase.py
2429
adserver/regiontopics.py # Just data/constants

adserver/templates/adserver/base.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
<span class="fa fa-key fa-fw mr-2 text-muted" aria-hidden="true"></span>
4343
<span>{% trans 'Change password' %}</span>
4444
</a>
45+
<a class="dropdown-item" href="{% url 'mfa_index' %}">
46+
<span class="fa fa-unlock-alt fa-fw mr-2 text-muted" aria-hidden="true"></span>
47+
<span>{% trans 'MFA' %}</span>
48+
</a>
4549
<div class="dropdown-divider"></div>
4650
<a class="dropdown-item" href="{% url 'support' %}">
4751
<span class="fa fa-envelope fa-fw mr-2 text-muted" aria-hidden="true"></span>

config/settings/base.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"django.contrib.humanize",
7171
"allauth",
7272
"allauth.account",
73-
"allauth.socialaccount",
73+
"allauth.mfa",
7474
"crispy_forms",
7575
"crispy_bootstrap4",
7676
"rest_framework",
@@ -382,14 +382,18 @@
382382

383383

384384
# Django allauth
385-
# https://django-allauth.readthedocs.io
385+
# https://docs.allauth.org
386+
# https://docs.allauth.org/en/latest/account/advanced.html#custom-user-models
387+
# https://docs.allauth.org/en/latest/mfa/introduction.html
386388
# --------------------------------------------------------------------------
387389
ACCOUNT_ADAPTER = "adserver.auth.adapters.AdServerAccountAdapter"
388390
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
389391
ACCOUNT_EMAIL_REQUIRED = True
390392
ACCOUNT_USERNAME_REQUIRED = False
391-
ACCOUNT_AUTHENTICATION_METHOD = "email"
392393
ACCOUNT_LOGIN_ON_PASSWORD_RESET = True
394+
ACCOUNT_MAX_EMAIL_ADDRESSES = 1
395+
ACCOUNT_LOGIN_METHODS = {"email"}
396+
393397

394398
# Celery settings for asynchronous tasks
395399
# http://docs.celeryproject.org/en/latest/userguide/configuration.html

config/settings/production.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@
8989
if not socket.gethostname().startswith("ethicalads-extra"):
9090
ENFORCE_HOST = env("ENFORCE_HOST", default=None)
9191

92-
9392
# Email settings
9493
# See: https://anymail.readthedocs.io
9594
# --------------------------------------------------------------------------

config/urls.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from django.urls import include
77
from django.urls import path
88
from django.views import defaults as default_views
9+
from django.views.generic import RedirectView
910

1011

1112
urlpatterns = []
@@ -56,6 +57,12 @@
5657
]
5758

5859
urlpatterns += [
60+
# Allauth overrides
61+
# Disable managing emails for now
62+
path(
63+
r"accounts/email/",
64+
RedirectView.as_view(pattern_name="dashboard-home", permanent=False),
65+
),
5966
path(r"accounts/", include("allauth.urls")),
6067
path(r"stripe/", include("djstripe.urls", namespace="djstripe")),
6168
path(r"", include("adserver.urls")),

requirements/base.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ crispy-bootstrap4
2424
django-crispy-forms
2525

2626
# Authentication
27-
django-allauth
27+
django-allauth[mfa]
2828

2929
# Reading Django settings environment variables
3030
django-environ

requirements/base.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ django==5.0.12
6363
# django-slack
6464
# djangorestframework
6565
# jsonfield
66-
django-allauth==65.4.1
66+
django-allauth[mfa]==65.4.1
6767
# via -r base.in
6868
django-cors-headers==4.7.0
6969
# via -r base.in

requirements/development.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ django==5.0.12
9696
# django-slack
9797
# djangorestframework
9898
# jsonfield
99-
django-allauth==65.4.1
99+
django-allauth[mfa]==65.4.1
100100
# via -r /home/david/ReadTheDocs/ethical-ad-server/requirements/base.in
101101
django-cors-headers==4.7.0
102102
# via -r /home/david/ReadTheDocs/ethical-ad-server/requirements/base.in

requirements/production.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ django==5.0.12
7878
# django-storages
7979
# djangorestframework
8080
# jsonfield
81-
django-allauth==65.4.1
81+
django-allauth[mfa]==65.4.1
8282
# via -r /home/david/ReadTheDocs/ethical-ad-server/requirements/base.in
8383
django-anymail==12.0
8484
# via -r production.in
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{% extends "account/base_entrance.html" %}
2+
3+
{# https://github.com/pennersr/django-allauth/blob/main/allauth/templates/account/base_reauthenticate.html #}
4+
5+
6+
{% load allauth %}
7+
{% load i18n %}
8+
9+
10+
{% block title %}{% trans 'Confirm Access' %}{% endblock title %}
11+
12+
13+
{% block content %}
14+
15+
{% block reauthenticate_content %}
16+
{% endblock reauthenticate_content %}
17+
18+
{% if reauthentication_alternatives %}
19+
<hr>
20+
21+
<h3>{% translate "Alternative options" %}</h3>
22+
23+
{% for alt in reauthentication_alternatives %}
24+
<a href="{{ alt.url }}">{{ alt.description }}</a>
25+
{% endfor %}
26+
{% endif %}
27+
{% endblock content %}

0 commit comments

Comments
 (0)