1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
from allauth.account import app_settings as account_settings
from allauth.account.internal.decorators import login_stage_required
from allauth.account.views import BaseReauthenticateView
from allauth.mfa import app_settings
from allauth.mfa.base.forms import AuthenticateForm, ReauthenticateForm
from allauth.mfa.models import Authenticator
from allauth.mfa.stages import AuthenticateStage
from allauth.mfa.utils import is_mfa_enabled
from allauth.mfa.webauthn.forms import AuthenticateWebAuthnForm
from allauth.mfa.webauthn.internal.flows import auth as webauthn_auth
from allauth.utils import get_form_class
@method_decorator(
login_stage_required(stage=AuthenticateStage.key, redirect_urlname="account_login"),
name="dispatch",
)
class AuthenticateView(TemplateView):
form_class = AuthenticateForm
webauthn_form_class = AuthenticateWebAuthnForm
template_name = "mfa/authenticate." + account_settings.TEMPLATE_EXTENSION
def dispatch(self, request, *args, **kwargs):
self.stage = request._login_stage
if not is_mfa_enabled(
self.stage.login.user,
[Authenticator.Type.TOTP, Authenticator.Type.WEBAUTHN],
):
return HttpResponseRedirect(reverse("account_login"))
self.form = self._build_forms()
return super().dispatch(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
if self.form.is_valid():
return self.form_valid(self.form)
else:
return self.form_invalid(self.form)
def _build_forms(self):
posted_form = None
AuthenticateFormClass = self.get_form_class()
AuthenticateWebAuthnFormClass = self.get_webauthn_form_class()
user = self.stage.login.user
support_webauthn = "webauthn" in app_settings.SUPPORTED_TYPES
if self.request.method == "POST":
if "code" in self.request.POST:
posted_form = self.auth_form = AuthenticateFormClass(
user=user, data=self.request.POST
)
self.webauthn_form = (
AuthenticateWebAuthnFormClass(user=user)
if support_webauthn
else None
)
else:
self.auth_form = (
AuthenticateFormClass(user=user) if support_webauthn else None
)
posted_form = self.webauthn_form = AuthenticateWebAuthnFormClass(
user=user, data=self.request.POST
)
else:
self.auth_form = AuthenticateFormClass(user=user)
self.webauthn_form = (
AuthenticateWebAuthnFormClass(user=user) if support_webauthn else None
)
return posted_form
def get_form_class(self):
return get_form_class(app_settings.FORMS, "authenticate", self.form_class)
def get_webauthn_form_class(self):
return get_form_class(
app_settings.FORMS, "authenticate_webauthn", self.webauthn_form_class
)
def form_valid(self, form):
form.save()
return self.stage.exit()
def form_invalid(self, form):
return super().get(self.request)
def get_context_data(self, **kwargs):
ret = super().get_context_data()
ret.update(
{
"form": self.auth_form,
"MFA_SUPPORTED_TYPES": app_settings.SUPPORTED_TYPES,
}
)
if self.webauthn_form:
request_options = webauthn_auth.begin_authentication(self.stage.login.user)
ret.update(
{
"webauthn_form": self.webauthn_form,
"js_data": {"request_options": request_options},
}
)
return ret
authenticate = AuthenticateView.as_view()
@method_decorator(login_required, name="dispatch")
class ReauthenticateView(BaseReauthenticateView):
form_class = ReauthenticateForm
template_name = "mfa/reauthenticate." + account_settings.TEMPLATE_EXTENSION
def get_form_kwargs(self):
ret = super().get_form_kwargs()
ret["user"] = self.request.user
return ret
def get_form_class(self):
return get_form_class(app_settings.FORMS, "reauthenticate", self.form_class)
def form_valid(self, form):
form.save()
return super().form_valid(form)
reauthenticate = ReauthenticateView.as_view()
@method_decorator(login_required, name="dispatch")
class IndexView(TemplateView):
template_name = "mfa/index." + account_settings.TEMPLATE_EXTENSION
def get_context_data(self, **kwargs):
ret = super().get_context_data(**kwargs)
authenticators = {}
for auth in Authenticator.objects.filter(user=self.request.user):
if auth.type == Authenticator.Type.WEBAUTHN:
auths = authenticators.setdefault(auth.type, [])
auths.append(auth.wrap())
else:
authenticators[auth.type] = auth.wrap()
ret["authenticators"] = authenticators
ret["MFA_SUPPORTED_TYPES"] = app_settings.SUPPORTED_TYPES
ret["is_mfa_enabled"] = is_mfa_enabled(self.request.user)
return ret
index = IndexView.as_view()
|