Skip to content
Snippets Groups Projects
Verified Commit aca802ef authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

[2FA] Allow adding multiple authentication methods

parent 6bfa41c5
No related branches found
No related tags found
1 merge request!1099Activate WebAuthn and redesign 2FA profile page
{# -*- engine:django -*- #}
{% extends "two_factor/_base_focus.html" %}
{% load i18n phonenumber account socialaccount %}
{% load i18n phonenumber account socialaccount two_factor_tags %}
{% block browser_title %}
{% trans "Login" %}
......@@ -72,13 +72,19 @@
{% endblocktrans %}
{% elif device.method == 'sms' %}
{% blocktrans %}
We sent you a text message, please enter the tokens we
sent.
We sent you a text message, please enter the code we sent.
{% endblocktrans %}
{% elif device.method == 'email' %}
{% blocktrans %}
We sent you an email, please enter the code we sent.
{% endblocktrans %}
{% elif device.method == 'webauthn' %}
{% blocktrans %}
Please use your Webauthn-compatible device to authenticate.
{% endblocktrans %}
{% else %}
{% blocktrans %}
Please enter the tokens generated by your token
generator.
Please enter the code generated by your code generator.
{% endblocktrans %}
{% endif %}
{% elif wizard.steps.current == 'backup' %}
......@@ -112,12 +118,13 @@
<div class="card-content">
<div class="card-title">{% trans "Device currently not available?" %}</div>
{% if other_devices %}
<p>{% trans "Or, alternatively, use one of your backup phones:" %}</p>
<p>{% trans "Alternatively, use one of your other authentication methods:" %}</p>
<p>
{% for other in other_devices %}
<button name="challenge_device" value="{{ other.persistent_id }}" class="btn margin-bottom"
<button name="challenge_device" value="{{ other.persistent_id }}"
class="btn waves-effect waves-light margin-bottom"
type="submit">
{{ other|device_action }}
{{ other|as_action }}
</button>
{% endfor %}
</p>
......@@ -125,7 +132,7 @@
{% if backup_tokens %}
<p>{% trans "As a last resort, you can use a backup token:" %}</p>
<p>
<button name="wizard_goto_step" type="submit" value="backup" class="btn">
<button name="wizard_goto_step" type="submit" value="backup" class="btn waves-effect waves-light">
{% trans "Use Backup Token" %}
</button>
</p>
......
......@@ -7,18 +7,15 @@
<div class="card-content white-text">
<i class="material-icons small left">error_outline</i>
<span class="card-title">{% blocktrans %}Permission Denied{% endblocktrans %}</span>
<p>{% blocktrans %}The page you requested, enforces users to verify using
two-factor authentication for security reasons. You need to enable these
security features in order to access this page.{% endblocktrans %}</p>
<p>{% blocktrans %}The page you requested enforces users to verify using
two-factor authentication for security reasons. You need to enable this
security feature in order to access this page.{% endblocktrans %}</p>
<p>{% blocktrans %}Two-factor authentication is not enabled for your
account. Enable two-factor authentication for enhanced account
security.{% endblocktrans %}</p>
<p>
<a href="javascript:history.go(-1)" class="pull-right btn waves-effect waves-light">
{% trans "Go back" %}
</a>
<a href="{% url 'two_factor:setup' %}" class="btn green waves-effect waves-light">
<a href="{% url 'setup_two_factor_auth' %}" class="btn green waves-effect waves-light">
{% trans "Enable Two-Factor Authentication" %}</a>
</p>
</div>
......
......@@ -6,14 +6,14 @@
{% endblock %}
{% block content %}
<h1>{% block title %}{% trans "Enable Two-Factor Authentication" %}{% endblock %}</h1>
<h1>{% block title %}{% trans "Add Two-Factor Authentication Method" %}{% endblock %}</h1>
{% if wizard.steps.current == 'welcome' %}
<p class="flow-text">
{% blocktrans %}
You are about to take your account security to the
next level. Follow the steps in this wizard to enable two-factor
authentication.
next level. Follow the steps in this wizard to add
a two-factor authentication method to your account.
{% endblocktrans %}
</p>
{% elif wizard.steps.current == 'method' %}
......@@ -25,9 +25,9 @@
{% elif wizard.steps.current == 'generator' %}
<p>
{% blocktrans %}
To start using a token generator, please use your
favourite two factor authentication (TOTP) app to scan the QR code below.
Then, enter the token generated by the app.
To start using a code generator, please use your
favourite two-factor authentication (TOTP) app to scan the QR code below.
Then enter the token generated by the app.
{% endblocktrans %}
</p>
<p>
......@@ -64,19 +64,19 @@
{% elif device.method == 'sms' %}
<p>
{% blocktrans %}
We sent you a text message, please enter the tokens we sent.
We sent you a text message, please enter the code we sent.
{% endblocktrans %}
</p>
{% endif %}
{% else %}
<p class="alert warning" role="alert">
<figure class="alert warning">
{% blocktrans %}
We've encountered an issue with the selected authentication method. Please
go back and verify that you entered your information correctly, try
again, or use a different authentication method instead. If the issue
persists, contact the site administrator.
{% endblocktrans %}
</p>
</figure>
{% endif %}
{% elif wizard.steps.current == 'yubikey' %}
<p>
......
......@@ -8,14 +8,12 @@
{% block content %}
<h1>{% block title %}{% trans "Two-Factor Authentication successfully enabled" %}{% endblock %}</h1>
<div class="alert success">
<p>
<figure class="alert success">
<i class="material-icons iconify left" data-icon="mdi:check-circle-outline"></i>
{% blocktrans %}
Congratulations, you've successfully enabled two-factor authentication.
{% endblocktrans %}
</p>
</div>
</figure>
{% if not phone_methods %}
<a href="{% url 'two_factor:profile' %}"
......@@ -28,16 +26,14 @@
{% trans "Generate backup codes" %}
</a>
{% else %}
<div class="warning">
<p>
<figure class="alert warning">
<i class="material-icons iconify left" data-icon="mdi:alert-outline"></i>
{% blocktrans %}
However, it might happen that you don't have access to
your primary token device. To enable account recovery, generate backup codes
or add a phone number.
your primary device. To enable account recovery, generate backup codes
or add other authentication methods.
{% endblocktrans %}
</p>
</div>
</figure>
<a href="{% url 'two_factor:profile' %}"
class="btn btn-primary waves-effect waves-light">
<i class="material-icons iconify left" data-icon="mdi:arrow-left"></i>
......@@ -47,9 +43,9 @@
<i class="material-icons iconify left" data-icon="mdi:key-outline"></i>
{% trans "Generate backup codes" %}
</a>
<a href="{% url 'two_factor:phone_create' %}" class="btn green waves-effect waves-light">
<i class="material-icons iconify left" data-icon="mdi:phone-plus"></i>
{% trans "Add Phone Number" %}
<a href="{% url 'setup_two_factor_auth' %}" class="btn green waves-effect waves-light">
<i class="material-icons iconify left" data-icon="mdi:key-plus"></i>
{% trans "Add Another Authentication Method" %}
</a>
{% endif %}
......
......@@ -74,6 +74,12 @@ urlpatterns = [
path("invitations/", include("invitations.urls")),
path("status/", views.SystemStatus.as_view(), name="system_status"),
path("", include(tf_urls)),
path("account/login/", views.TwoFactorLoginView.as_view()),
path(
"account/two_factor/add/",
views.TwoFactorSetupView.as_view(),
name="setup_two_factor_auth",
),
path("school_terms/", views.SchoolTermListView.as_view(), name="school_terms"),
path(
"school_terms/create/",
......
......@@ -58,6 +58,8 @@ from oauth2_provider.views import AuthorizationView
from reversion import set_user
from reversion.views import RevisionMixin
from rules.contrib.views import PermissionRequiredMixin, permission_required
from two_factor import views as two_factor_views
from two_factor.utils import devices_for_user
from two_factor.views.core import LoginView as AllAuthLoginView
from aleksis.core.data_checks import DataCheck, check_data
......@@ -1513,3 +1515,21 @@ class CustomAuthorizationView(AuthorizationView):
context = super().get_context_data(**kwargs)
context["no_menu"] = True
return context
class TwoFactorSetupView(two_factor_views.SetupView):
def get(self, request, *args, **kwargs):
return super(two_factor_views.SetupView, self).get(request, *args, **kwargs)
class TwoFactorLoginView(two_factor_views.LoginView):
def get_devices(self):
user = self.get_user()
return devices_for_user(user)
def get_other_devices(self, main_device):
other_devices = self.get_devices()
other_devices = list(filter(lambda x: not isinstance(x, type(main_device)), other_devices))
return other_devices
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment