Skip to content
Snippets Groups Projects
Commit d1d140fb authored by Fredrik Jonsson's avatar Fredrik Jonsson
Browse files

Implement 2fa with django-two-factor-auth.

parent 81d3a568
No related branches found
No related tags found
No related merge requests found
Showing
with 148 additions and 10 deletions
from django.conf import settings
from django.urls import include, path
from two_factor.urls import urlpatterns as tf_urls
from .utils import views
from .users import urls as users_urls
from .dashboard import urls as dashboard_urls
......@@ -14,6 +16,7 @@ urlpatterns = [
path('', include(users_urls)),
path('dashboard/', include(dashboard_urls)),
path('hijack/', include('hijack.urls', 'hijack')),
path('', include(tf_urls, 'two_factor')),
]
if settings.DEBUG:
......
{% extends 'base-apply.html' %}
{% block content_wrapper %}
<div class="wrapper wrapper--small wrapper--inner-space-medium">
{% block content %}{% endblock %}
</div>
{% endblock %}
{% extends "two_factor/_base.html" %}
{% block content_wrapper %}
<div class="admin-bar">
<div class="admin-bar__inner admin-bar__inner--with-button">
<h3 class="admin-bar__heading">Welcome {{ user }}</h3>
<a href="{% url 'dashboard:dashboard' %}" class="button button--primary button--arrow-pixels-white">
Go to dashboard
<svg><use xlink:href="#arrow-head-pixels--solid"></use></svg>
</a>
</div>
</div>
<div class="wrapper wrapper--small wrapper--inner-space-medium">
{% block content %}{% endblock %}
</div>
{% endblock %}
{% load i18n %}
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit"
value="{{ wizard.steps.prev }}"
class="button button--primary">{% trans "Back" %}</button>
{% else %}
<button disabled name="" type="button"
class="button button--primary">{% trans "Back" %}</button>
{% endif %}
<button type="submit" class="button button--primary">{% trans "Next" %}</button>
{% if cancel_url %}
<a href="{% url 'users:account' %}"
class="link link--bold link--left-space">{% trans "Cancel" %}</a>
{% endif %}
......@@ -29,7 +29,10 @@
{% if show_change_password and user.has_usable_password and not backends.associated %}
<div class="profile__column">
<h3>Change password</h3>
<a class="button button--primary" href="{% url 'users:password_change' %}">{% trans "Update password" %}</a>
<p><a class="button button--primary" href="{% url 'users:password_change' %}">{% trans "Update password" %}</a></p>
<h3>Account Security</h3>
<p><a class="link link--button link--button--narrow" href="{% url 'two_factor:profile' %}">Two-factor authentication settings</a></p>
</div>
{% endif %}
......
{% extends 'base.html' %}
{% load i18n two_factor %}
{% block header_modifier %}header--light-bg{% endblock %}
{% block page_title %}Login{% endblock %}
{% block title %}Login{% endblock %}
{% block content %}
<div class="wrapper wrapper--small">
{% if wizard.steps.current == 'auth' %}
<p>{% blocktrans %}Enter your credentials.{% endblocktrans %}</p>
{% elif wizard.steps.current == 'token' %}
{% if device.method == 'call' %}
<p>{% blocktrans %}We are calling your phone right now, please enter the
digits you hear.{% endblocktrans %}</p>
{% elif device.method == 'sms' %}
<p>{% blocktrans %}We sent you a text message, please enter the tokens we
sent.{% endblocktrans %}</p>
{% else %}
<p>{% blocktrans %}Please enter the tokens generated by your token
generator.{% endblocktrans %}</p>
{% endif %}
{% elif wizard.steps.current == 'backup' %}
<p>{% blocktrans %}Use this form for entering backup tokens for logging in.
These tokens have been generated for you to print and keep safe. Please
enter one of these backup tokens to login to your account.{% endblocktrans %}</p>
{% endif %}
<form class="form form--with-p-tags" method="post">
{% csrf_token %}
{{ form.as_p }}
<p><a class="link link--small" href="{% url 'users:password_reset' %}">Forgot your password?</a></p>
<button class="link link--button-secondary" type="submit">Login</button>
{{ wizard.management_form }}
{% if wizard.steps.current == 'auth' %}
{{ form.as_p }}
<p><a class="link link--small" href="{% url 'users:password_reset' %}">Forgot your password?</a></p>
<button class="link link--button-secondary" type="submit">Login</button>
{% else %}
{{ wizard.form }}
{# hidden submit button to enable [enter] key #}
<div style="margin-left: -9999px"><input type="submit" value=""/></div>
{% if other_devices %}
<p>{% trans "Or, alternatively, use one of your backup phones:" %}</p>
<p>
{% for other in other_devices %}
<button name="challenge_device" value="{{ other.persistent_id }}"
class="btn btn-default btn-block" type="submit">
{{ other|device_action }}
</button>
{% endfor %}</p>
{% endif %}
{% 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 btn-default btn-block">{% trans "Use Backup Token" %}</button>
</p>
{% endif %}
{% include "two_factor/_wizard_actions.html" %}
{% endif %}
</form>
<div class="wrapper wrapper--inner-space-large">
......
......@@ -2,6 +2,8 @@ from django.urls import path, include
from django.contrib.auth import views as auth_views
from django.urls import reverse_lazy
from two_factor.views import LoginView
from opentech.apply.users.views import AccountView, become, oauth, ActivationView, create_password
......@@ -11,9 +13,8 @@ app_name = 'users'
public_urlpatterns = [
path(
'login/',
auth_views.LoginView.as_view(
template_name='users/login.html',
redirect_authenticated_user=True
LoginView.as_view(
template_name='users/login.html'
),
name='login'
),
......@@ -73,5 +74,5 @@ urlpatterns = [
),
path('activate/', create_password, name="activate_password"),
path('oauth', oauth, name='oauth'),
]))
])),
]
......@@ -117,6 +117,10 @@ INSTALLED_APPS = [
'django_bleach',
'django_fsm',
'django_pwned_passwords',
'django_otp',
'django_otp.plugins.otp_totp',
'django_otp.plugins.otp_static',
'two_factor',
'rest_framework',
'wagtailcache',
......@@ -147,6 +151,7 @@ MIDDLEWARE = [
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django_referrer_policy.middleware.ReferrerPolicyMiddleware',
'django_otp.middleware.OTPMiddleware',
'opentech.apply.users.middleware.SocialAuthExceptionMiddleware',
......
.btn,
.button {
padding: 0;
background-color: transparent;
......@@ -15,6 +16,8 @@
opacity: .5;
}
&-default,
&-primary,
&--primary {
@include button($color--light-blue, $color--dark-blue);
display: inline-block;
......@@ -65,6 +68,7 @@
}
}
&-danger,
&--warning {
@include button($color--error, $color--error);
......
......@@ -9,7 +9,6 @@
@include button($color--light-blue, $color--dark-blue);
display: inline-block;
&--narrow {
@include button--narrow;
}
......@@ -27,6 +26,10 @@
font-weight: $weight--bold;
}
&--left-space {
margin-left: 20px;
}
&--download {
display: flex;
align-items: center;
......@@ -91,6 +94,14 @@
}
}
&--button-long-text {
padding: 10px;
@include media-query(tablet-portrait) {
padding: 10px 60px;
}
}
&--open-feed {
position: fixed;
right: 20px;
......
......@@ -9,6 +9,23 @@
cursor: pointer;
}
&:disabled,
&.is-disabled {
pointer-events: none;
opacity: .5;
}
&--primary {
@include button($color--light-blue, $color--dark-blue);
display: inline-block;
.form--filters & {
width: 100%;
text-align: center;
height: 45px;
}
}
&--left-space {
margin-left: 20px;
}
......@@ -111,4 +128,3 @@
}
}
}
......@@ -36,6 +36,7 @@
@include button(transparent, $color--darkest-blue);
color: $color--white;
&:focus,
&:hover {
border: 1px solid transparent;
}
......
......@@ -95,7 +95,9 @@
</header>
<main class="wrapper wrapper--large wrapper--main">
{% block content_wrapper %}
{% block content %}{% endblock %}
{% endblock %}
</main>
<footer class="footer"></footer>
......
......@@ -33,6 +33,7 @@ django-referrer-policy==1.0
django-storages==1.6.6
django-tables2==1.21.1
django-tinymce4-lite==1.7.0
django-two-factor-auth==1.8.0
django-webpack-loader==0.6.0
django_select2==6.0.1
djangorestframework==3.9.0
......
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