Initial mfa support (for internal users) #93591
@ -18,7 +18,7 @@ import qrcode
|
|||||||
|
|
||||||
from . import mixins
|
from . import mixins
|
||||||
from mfa.fido2 import register_begin
|
from mfa.fido2 import register_begin
|
||||||
from mfa.forms import DisableMfaForm, TotpMfaForm, U2fMfaForm
|
from mfa.forms import DisableMfaForm, TotpRegisterForm, U2fRegisterForm
|
||||||
from mfa.models import EncryptedRecoveryDevice, EncryptedTOTPDevice, U2fDevice, devices_for_user
|
from mfa.models import EncryptedRecoveryDevice, EncryptedTOTPDevice, U2fDevice, devices_for_user
|
||||||
import bid_main.tasks
|
import bid_main.tasks
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ class InvalidateRecoveryView(mixins.MfaRequiredIfConfiguredMixin, View):
|
|||||||
|
|
||||||
Oleg-Komarov marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
class TotpView(mixins.MfaRequiredIfConfiguredMixin, FormView):
|
class TotpView(mixins.MfaRequiredIfConfiguredMixin, FormView):
|
||||||
form_class = TotpMfaForm
|
form_class = TotpRegisterForm
|
||||||
success_url = reverse_lazy('bid_main:mfa')
|
success_url = reverse_lazy('bid_main:mfa')
|
||||||
template_name = "bid_main/mfa/totp.html"
|
template_name = "bid_main/mfa/totp.html"
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ class TotpView(mixins.MfaRequiredIfConfiguredMixin, FormView):
|
|||||||
|
|
||||||
|
|
||||||
class U2fView(mixins.MfaRequiredIfConfiguredMixin, FormView):
|
class U2fView(mixins.MfaRequiredIfConfiguredMixin, FormView):
|
||||||
form_class = U2fMfaForm
|
form_class = U2fRegisterForm
|
||||||
success_url = reverse_lazy('bid_main:mfa')
|
success_url = reverse_lazy('bid_main:mfa')
|
||||||
template_name = "bid_main/mfa/u2f.html"
|
template_name = "bid_main/mfa/u2f.html"
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ from .. import forms, email
|
|||||||
from . import mixins
|
from . import mixins
|
||||||
from bid_main.email import send_verify_address
|
from bid_main.email import send_verify_address
|
||||||
from mfa.fido2 import authenticate_begin
|
from mfa.fido2 import authenticate_begin
|
||||||
from mfa.forms import MfaForm, U2fForm
|
from mfa.forms import MfaAuthenticateForm, U2fAuthenticateForm
|
||||||
import bid_main.file_utils
|
import bid_main.file_utils
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
@ -78,7 +78,7 @@ class LoginView(mixins.RedirectToPrivacyAgreeMixin, mixins.PageIdMixin, otp_agen
|
|||||||
"""Shows the login view."""
|
"""Shows the login view."""
|
||||||
|
|
||||||
otp_authentication_form = forms.AuthenticationForm
|
otp_authentication_form = forms.AuthenticationForm
|
||||||
otp_token_form = MfaForm
|
otp_token_form = MfaAuthenticateForm
|
||||||
page_id = "login"
|
page_id = "login"
|
||||||
redirect_authenticated_user = False
|
redirect_authenticated_user = False
|
||||||
success_url_allowed_hosts = settings.NEXT_REDIR_AFTER_LOGIN_ALLOWED_HOSTS
|
success_url_allowed_hosts = settings.NEXT_REDIR_AFTER_LOGIN_ALLOWED_HOSTS
|
||||||
@ -96,10 +96,10 @@ class LoginView(mixins.RedirectToPrivacyAgreeMixin, mixins.PageIdMixin, otp_agen
|
|||||||
ctx = super().get_context_data(**kwargs)
|
ctx = super().get_context_data(**kwargs)
|
||||||
self.find_oauth_flow(ctx)
|
self.find_oauth_flow(ctx)
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
if isinstance(form, U2fForm):
|
if isinstance(form, U2fAuthenticateForm):
|
||||||
ctx["devices"] = self.request.user.mfa_devices_per_category()
|
ctx["devices"] = self.request.user.mfa_devices_per_category()
|
||||||
ctx["is_u2f_form"] = True
|
ctx["is_u2f_form"] = True
|
||||||
elif isinstance(form, MfaForm):
|
elif isinstance(form, MfaAuthenticateForm):
|
||||||
ctx["devices"] = self.request.user.mfa_devices_per_category()
|
ctx["devices"] = self.request.user.mfa_devices_per_category()
|
||||||
ctx["is_mfa_form"] = True
|
ctx["is_mfa_form"] = True
|
||||||
ctx["use_recovery"] = self._use_recovery()
|
ctx["use_recovery"] = self._use_recovery()
|
||||||
@ -119,7 +119,7 @@ class LoginView(mixins.RedirectToPrivacyAgreeMixin, mixins.PageIdMixin, otp_agen
|
|||||||
kwargs['request_options'] = json.dumps(dict(request_options))
|
kwargs['request_options'] = json.dumps(dict(request_options))
|
||||||
kwargs['rp_id'] = rp_id
|
kwargs['rp_id'] = rp_id
|
||||||
kwargs['state'] = dict(state)
|
kwargs['state'] = dict(state)
|
||||||
return U2fForm(**kwargs)
|
return U2fAuthenticateForm(**kwargs)
|
||||||
# this will switch between MfaForm and AuthenticationForm
|
# this will switch between MfaForm and AuthenticationForm
|
||||||
return super().get_form()
|
return super().get_form()
|
||||||
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
default_app_config = "%s.apps.MfaConfig" % __name__
|
@ -27,7 +27,7 @@ def _verify_signature(payload, signature, max_age=3600):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class MfaForm(OTPTokenForm):
|
class MfaAuthenticateForm(OTPTokenForm):
|
||||||
"""Restyle the form widgets to do less work in the template."""
|
"""Restyle the form widgets to do less work in the template."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -73,7 +73,7 @@ class MfaForm(OTPTokenForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class U2fForm(OTPAgentFormMixin, forms.Form):
|
class U2fAuthenticateForm(OTPAgentFormMixin, forms.Form):
|
||||||
otp_trust_agent = forms.BooleanField(
|
otp_trust_agent = forms.BooleanField(
|
||||||
help_text=_(
|
help_text=_(
|
||||||
f"We won't ask for MFA on this device in the next {settings.AGENT_TRUST_DAYS} days. "
|
f"We won't ask for MFA on this device in the next {settings.AGENT_TRUST_DAYS} days. "
|
||||||
@ -145,7 +145,7 @@ class DisableMfaForm(forms.Form):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TotpMfaForm(forms.Form):
|
class TotpRegisterForm(forms.Form):
|
||||||
code = forms.CharField(
|
code = forms.CharField(
|
||||||
validators=[RegexValidator(r'^[0-9]{6}$')],
|
validators=[RegexValidator(r'^[0-9]{6}$')],
|
||||||
widget=forms.TextInput(
|
widget=forms.TextInput(
|
||||||
@ -190,7 +190,7 @@ class TotpMfaForm(forms.Form):
|
|||||||
EncryptedTOTPDevice.objects.create(encrypted_key=key, key='', name=name, user=self.user)
|
EncryptedTOTPDevice.objects.create(encrypted_key=key, key='', name=name, user=self.user)
|
||||||
|
|
||||||
|
|
||||||
class U2fMfaForm(forms.Form):
|
class U2fRegisterForm(forms.Form):
|
||||||
credential = forms.JSONField(widget=forms.HiddenInput)
|
credential = forms.JSONField(widget=forms.HiddenInput)
|
||||||
name = forms.CharField(
|
name = forms.CharField(
|
||||||
max_length=U2fDevice._meta.get_field('name').max_length,
|
max_length=U2fDevice._meta.get_field('name').max_length,
|
||||||
|
Loading…
Reference in New Issue
Block a user
same as above