flows: add invalidation designation, use as default logout action

This commit is contained in:
Jens Langhammer 2020-05-11 01:12:57 +02:00
parent 9dec13c225
commit e12780f78f
13 changed files with 75 additions and 77 deletions

View File

@ -40,7 +40,7 @@
</div> </div>
<div class="pf-c-page__header-tools"> <div class="pf-c-page__header-tools">
<div class="pf-c-page__header-tools-group pf-m-icons"> <div class="pf-c-page__header-tools-group pf-m-icons">
<a href="{% url 'passbook_core:auth-logout' %}" class="pf-c-button pf-m-plain" type="button"> <a href="{% url 'passbook_flows:default-invalidation' %}" class="pf-c-button pf-m-plain" type="button">
<i class="fas fa-sign-out-alt" aria-hidden="true"></i> <i class="fas fa-sign-out-alt" aria-hidden="true"></i>
</a> </a>
</div> </div>

View File

@ -1,45 +0,0 @@
"""passbook Core Account Test"""
import string
from random import SystemRandom
from django.test import TestCase
from django.urls import reverse
from passbook.core.models import User
class TestAuthenticationViews(TestCase):
"""passbook Core Account Test"""
def setUp(self):
super().setUp()
self.sign_up_data = {
"name": "Test",
"username": "beryjuorg",
"email": "unittest@passbook.beryju.org",
"password": "B3ryju0rg!",
"password_repeat": "B3ryju0rg!",
}
self.login_data = {
"uid_field": "unittest@example.com",
}
self.user = User.objects.create_superuser(
username="unittest user",
email="unittest@example.com",
password="".join(
SystemRandom().choice(string.ascii_uppercase + string.digits)
for _ in range(8)
),
)
def test_logout_view(self):
"""Test account.logout view"""
self.client.force_login(self.user)
response = self.client.get(reverse("passbook_core:auth-logout"))
self.assertEqual(response.status_code, 302)
def test_sign_up_view_auth(self):
"""Test account.sign_up view (Authenticated)"""
self.client.force_login(self.user)
response = self.client.get(reverse("passbook_core:auth-logout"))
self.assertEqual(response.status_code, 302)

View File

@ -1,11 +1,9 @@
"""passbook URL Configuration""" """passbook URL Configuration"""
from django.urls import path from django.urls import path
from passbook.core.views import authentication, overview, user from passbook.core.views import overview, user
urlpatterns = [ urlpatterns = [
# Authentication views
path("auth/logout/", authentication.LogoutView.as_view(), name="auth-logout"),
# User views # User views
path("-/user/", user.UserSettingsView.as_view(), name="user-settings"), path("-/user/", user.UserSettingsView.as_view(), name="user-settings"),
path("-/user/delete/", user.UserDeleteView.as_view(), name="user-delete"), path("-/user/delete/", user.UserDeleteView.as_view(), name="user-delete"),

View File

@ -1,21 +0,0 @@
"""passbook core authentication views"""
from django.contrib import messages
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpRequest, HttpResponse
from django.shortcuts import redirect, reverse
from django.utils.translation import ugettext as _
from django.views import View
from structlog import get_logger
LOGGER = get_logger()
class LogoutView(LoginRequiredMixin, View):
"""Log current user out"""
def dispatch(self, request: HttpRequest) -> HttpResponse:
"""Log current user out"""
logout(request)
messages.success(request, _("You've successfully been logged out."))
return redirect(reverse("passbook_flows:default-auth"))

View File

@ -8,7 +8,9 @@ from passbook.flows.models import FlowDesignation
from passbook.stages.identification.models import Templates, UserFields from passbook.stages.identification.models import Templates, UserFields
def create_default_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): def create_default_authentication_flow(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
Flow = apps.get_model("passbook_flows", "Flow") Flow = apps.get_model("passbook_flows", "Flow")
FlowStageBinding = apps.get_model("passbook_flows", "FlowStageBinding") FlowStageBinding = apps.get_model("passbook_flows", "FlowStageBinding")
PasswordStage = apps.get_model("passbook_stages_password", "PasswordStage") PasswordStage = apps.get_model("passbook_stages_password", "PasswordStage")
@ -18,7 +20,11 @@ def create_default_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
) )
db_alias = schema_editor.connection.alias db_alias = schema_editor.connection.alias
if Flow.objects.using(db_alias).all().exists(): if (
Flow.objects.using(db_alias)
.filter(designation=FlowDesignation.AUTHENTICATION)
.exists()
):
# Only create default flow when none exist # Only create default flow when none exist
return return
@ -53,13 +59,46 @@ def create_default_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
) )
def create_default_invalidation_flow(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
Flow = apps.get_model("passbook_flows", "Flow")
FlowStageBinding = apps.get_model("passbook_flows", "FlowStageBinding")
UserLogoutStage = apps.get_model("passbook_stages_user_logout", "UserLogoutStage")
db_alias = schema_editor.connection.alias
if (
Flow.objects.using(db_alias)
.filter(designation=FlowDesignation.INVALIDATION)
.exists()
):
# Only create default flow when none exist
return
if not UserLogoutStage.objects.using(db_alias).exists():
UserLogoutStage.objects.using(db_alias).create(name="authentication")
flow = Flow.objects.using(db_alias).create(
name="default-invalidation-flow",
slug="default-invalidation-flow",
designation=FlowDesignation.INVALIDATION,
)
FlowStageBinding.objects.using(db_alias).create(
flow=flow, stage=UserLogoutStage.objects.using(db_alias).first(), order=0,
)
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("passbook_flows", "0001_initial"), ("passbook_flows", "0001_initial"),
("passbook_stages_user_login", "0001_initial"), ("passbook_stages_user_login", "0001_initial"),
("passbook_stages_user_logout", "0001_initial"),
("passbook_stages_password", "0001_initial"), ("passbook_stages_password", "0001_initial"),
("passbook_stages_identification", "0001_initial"), ("passbook_stages_identification", "0001_initial"),
] ]
operations = [migrations.RunPython(create_default_flow)] operations = [
migrations.RunPython(create_default_authentication_flow),
migrations.RunPython(create_default_invalidation_flow),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.5 on 2020-05-10 23:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('passbook_flows', '0003_auto_20200509_1258'),
]
operations = [
migrations.AlterField(
model_name='flow',
name='designation',
field=models.CharField(choices=[('authentication', 'Authentication'), ('enrollment', 'Enrollment'), ('recovery', 'Recovery'), ('password_change', 'Password Change'), ('invalidation', 'Invalidation')], max_length=100),
),
]

View File

@ -18,6 +18,7 @@ class FlowDesignation(models.TextChoices):
ENROLLMENT = "enrollment" ENROLLMENT = "enrollment"
RECOVERY = "recovery" RECOVERY = "recovery"
PASSWORD_CHANGE = "password_change" # nosec # noqa PASSWORD_CHANGE = "password_change" # nosec # noqa
INVALIDATION = "invalidation"
class Stage(UUIDModel): class Stage(UUIDModel):

View File

@ -15,6 +15,11 @@ urlpatterns = [
ToDefaultFlow.as_view(designation=FlowDesignation.AUTHENTICATION), ToDefaultFlow.as_view(designation=FlowDesignation.AUTHENTICATION),
name="default-auth", name="default-auth",
), ),
path(
"-/default/invalidation/",
ToDefaultFlow.as_view(designation=FlowDesignation.INVALIDATION),
name="default-invalidation",
),
path( path(
"-/default/recovery/", "-/default/recovery/",
ToDefaultFlow.as_view(designation=FlowDesignation.RECOVERY), ToDefaultFlow.as_view(designation=FlowDesignation.RECOVERY),

View File

@ -37,7 +37,7 @@
{% blocktrans with user=user %} {% blocktrans with user=user %}
You are logged in as {{ user }}. Not you? You are logged in as {{ user }}. Not you?
{% endblocktrans %} {% endblocktrans %}
<a href="{% url 'passbook_core:auth-logout' %}">{% trans 'Logout' %}</a> <a href="{% url 'passbook_flows:default-invalidation' %}">{% trans 'Logout' %}</a>
</p> </p>
</div> </div>
<div class="pf-c-form__group pf-m-action"> <div class="pf-c-form__group pf-m-action">

View File

@ -38,7 +38,7 @@
{% blocktrans with user=user %} {% blocktrans with user=user %}
You are logged in as {{ user }}. Not you? You are logged in as {{ user }}. Not you?
{% endblocktrans %} {% endblocktrans %}
<a href="{% url 'passbook_core:auth-logout' %}">{% trans 'Logout' %}</a> <a href="{% url 'passbook_flows:default-invalidation' %}">{% trans 'Logout' %}</a>
</p> </p>
</div> </div>
<div class="pf-c-form__group pf-m-action"> <div class="pf-c-form__group pf-m-action">

View File

@ -18,7 +18,7 @@
{% blocktrans with user=user %} {% blocktrans with user=user %}
You are logged in as {{ user }}. You are logged in as {{ user }}.
{% endblocktrans %} {% endblocktrans %}
<a href="{% url 'passbook_core:auth-logout' %}">{% trans 'Not you?' %}</a> <a href="{% url 'passbook_flows:default-invalidation' %}">{% trans 'Not you?' %}</a>
</p> </p>
<input class="btn btn-primary btn-block btn-lg" type="submit" value="{% trans 'Continue' %}" /> <input class="btn btn-primary btn-block btn-lg" type="submit" value="{% trans 'Continue' %}" />
</div> </div>

View File

@ -16,7 +16,7 @@
{% blocktrans with user=user %} {% blocktrans with user=user %}
You are logged in as {{ user }}. You are logged in as {{ user }}.
{% endblocktrans %} {% endblocktrans %}
<a href="{% url 'passbook_core:auth-logout' %}">{% trans 'Not you?' %}</a> <a href="{% url 'passbook_flows:default-invalidation' %}">{% trans 'Not you?' %}</a>
</p> </p>
</div> </div>
<div class="pf-c-form__group pf-m-action"> <div class="pf-c-form__group pf-m-action">

View File

@ -12,6 +12,9 @@ from passbook.root.monitoring import MetricsView
LOGGER = get_logger() LOGGER = get_logger()
admin.autodiscover() admin.autodiscover()
admin.site.login = RedirectView.as_view(pattern_name="passbook_flows:default-auth") admin.site.login = RedirectView.as_view(pattern_name="passbook_flows:default-auth")
admin.site.logout = RedirectView.as_view(
pattern_name="passbook_flows:default-invalidate"
)
handler400 = error.BadRequestView.as_view() handler400 = error.BadRequestView.as_view()
handler403 = error.ForbiddenView.as_view() handler403 = error.ForbiddenView.as_view()