Initial mfa support (for internal users) #93591
@ -1,9 +1,58 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
{% load pipeline static %}
|
{% load pipeline static %}
|
||||||
{% block page_title %}
|
{% block page_title %}
|
||||||
MFA Setup
|
Multi-factor Authentication Setup
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% for d in devices %}{{d}}{% endfor %}
|
<div class="bid box">
|
||||||
|
<h2>Multi-factor Authentication (MFA) Setup</h2>
|
||||||
|
{% if user_has_mfa_configured %}
|
||||||
|
<p>
|
||||||
|
You have configured MFA for your account.
|
||||||
|
You can disable MFA at any time, but you have to sign-in using your authentication device or a recovery code.
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<button class="btn-danger">Disable</btn>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p>TODO Explain why and how</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bid box mt-3">
|
||||||
|
<h3>Time-based one-time password (TOTP)</h3>
|
||||||
|
<p>TODO Explain how to use TOTP, <a href="https://en.wikipedia.org/wiki/Comparison_of_OTP_applications">TOTP applications</a></p>
|
||||||
|
{% with devices=devices_per_category.totp %}
|
||||||
|
{% if devices %}
|
||||||
|
<ul>
|
||||||
|
{% for d in devices %}
|
||||||
|
<li>{{ d.name }} <button class="btn-danger"><i class="i-trash"></i></button></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
<button>Configure a new TOTP device</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bid box mt-3">
|
||||||
|
<h3>Recovery codes</h3>
|
||||||
|
<p>
|
||||||
|
Store your recovery codes safely (e.g. in a password manager) and don't share them.
|
||||||
|
Each code can be used only once.
|
||||||
|
You can generate a new set of recovery codes at any time, any remaining old codes will become invalidated.
|
||||||
|
</p>
|
||||||
|
{% with devices=devices_per_category.recovery %}
|
||||||
|
{% for d in devices %}
|
||||||
|
<div class="mb-3">
|
||||||
|
{% with code_count=d.token_set.count %}
|
||||||
|
{{ code_count }} recovery code{{ code_count|pluralize }} remaining
|
||||||
|
<button>Download</button>
|
||||||
|
<button class="btn-danger">Invalidate</button>
|
||||||
|
{% endwith %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
<button>{% if devices %}Regenerate{% else %}Generate{% endif %} recovery codes</button>
|
||||||
|
{% endwith %}
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -4,6 +4,7 @@ No error handlers, no usually-one-off things like registration and
|
|||||||
email confirmation.
|
email confirmation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
import logging
|
import logging
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ from django.views.generic import TemplateView, FormView
|
|||||||
from django.views.generic.base import View
|
from django.views.generic.base import View
|
||||||
from django.views.generic.edit import UpdateView
|
from django.views.generic.edit import UpdateView
|
||||||
from django_otp import devices_for_user
|
from django_otp import devices_for_user
|
||||||
|
from django_otp.plugins.otp_static.models import StaticDevice
|
||||||
|
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||||
from otp_agents.forms import OTPTokenForm
|
from otp_agents.forms import OTPTokenForm
|
||||||
import loginas.utils
|
import loginas.utils
|
||||||
import oauth2_provider.models as oauth2_models
|
import oauth2_provider.models as oauth2_models
|
||||||
@ -455,6 +458,14 @@ class MfaView(mixins.MfaRequiredIfConfiguredMixin, TemplateView):
|
|||||||
template_name = "bid_main/mfa_setup.html"
|
template_name = "bid_main/mfa_setup.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
devices = list(devices_for_user(self.request.user))
|
||||||
|
devices_per_category = defaultdict(list)
|
||||||
|
for device in devices:
|
||||||
|
if isinstance(device, StaticDevice):
|
||||||
|
devices_per_category['recovery'].append(device)
|
||||||
|
if isinstance(device, TOTPDevice):
|
||||||
|
devices_per_category['totp'].append(device)
|
||||||
return {
|
return {
|
||||||
'devices': list(devices_for_user(self.request.user)),
|
'devices_per_category': devices_per_category,
|
||||||
|
'user_has_mfa_configured': len(devices) > 0,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user