Initial mfa support (for internal users) #93591
@ -96,7 +96,6 @@ class TotpView(mixins.MfaRequiredIfConfiguredMixin, FormView):
|
|||||||
kwargs = self.get_form_kwargs()
|
kwargs = self.get_form_kwargs()
|
||||||
key = self.request.POST.get('key', random_hex(20))
|
key = self.request.POST.get('key', random_hex(20))
|
||||||
kwargs['initial']['key'] = key
|
kwargs['initial']['key'] = key
|
||||||
kwargs['initial']['signature'] = TotpMfaForm.sign(kwargs['user'], key)
|
|
||||||
return TotpMfaForm(**kwargs)
|
return TotpMfaForm(**kwargs)
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
|
14
mfa/forms.py
14
mfa/forms.py
@ -95,6 +95,9 @@ class TotpMfaForm(forms.Form):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.user = kwargs.pop('user', None)
|
self.user = kwargs.pop('user', None)
|
||||||
|
kwargs['initial']['signature'] = self.sign(
|
||||||
|
f"{self.user.email}_{kwargs['initial']['key']}"
|
||||||
|
)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
@ -102,7 +105,7 @@ class TotpMfaForm(forms.Form):
|
|||||||
code = self.data.get('code')
|
code = self.data.get('code')
|
||||||
key = self.data.get('key')
|
key = self.data.get('key')
|
||||||
signature = self.cleaned_data.get('signature')
|
signature = self.cleaned_data.get('signature')
|
||||||
if not self.verify_signature(self.user, key, signature):
|
if not self.verify_signature(f'{self.user.email}_{key}', signature):
|
||||||
raise forms.ValidationError(_('Invalid signature'))
|
raise forms.ValidationError(_('Invalid signature'))
|
||||||
self.cleaned_data['key'] = key
|
self.cleaned_data['key'] = key
|
||||||
if not TOTP(unhexlify(key)).verify(int(code), tolerance=1):
|
if not TOTP(unhexlify(key)).verify(int(code), tolerance=1):
|
||||||
@ -115,14 +118,15 @@ 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)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def sign(cls, user, key):
|
def sign(cls, payload):
|
||||||
signer = TimestampSigner()
|
signer = TimestampSigner()
|
||||||
return signer.sign(f'{user.email}_{key}')
|
return signer.sign(payload)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def verify_signature(cls, user, key, signature, max_age=3600):
|
def verify_signature(cls, payload, signature, max_age=3600):
|
||||||
|
|
||||||
signer = TimestampSigner()
|
signer = TimestampSigner()
|
||||||
try:
|
try:
|
||||||
return f'{user.email}_{key}' == signer.unsign(signature, max_age=max_age)
|
return payload == signer.unsign(signature, max_age=max_age)
|
||||||
except BadSignature:
|
except BadSignature:
|
||||||
return False
|
return False
|
||||||
|
Loading…
Reference in New Issue
Block a user