stages/authenticator_validate: fix error when using not_configured_action=configure

closes #1048

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-06-22 20:07:23 +02:00
parent 5ff5edf769
commit b69248dd55
2 changed files with 55 additions and 3 deletions

View File

@ -10,7 +10,7 @@ from authentik.flows.challenge import (
ChallengeTypes,
WithUserInfoChallenge,
)
from authentik.flows.models import NotConfiguredAction
from authentik.flows.models import NotConfiguredAction, Stage
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
from authentik.flows.stage import ChallengeStageView
from authentik.stages.authenticator_validate.challenge import (
@ -143,9 +143,12 @@ class AuthenticatorValidateStageView(ChallengeStageView):
return self.executor.stage_invalid()
if stage.not_configured_action == NotConfiguredAction.CONFIGURE:
LOGGER.debug("Authenticator not configured, sending user to configure")
# Because the foreign key to stage.configuration_stage points to
# a base stage class, we need to do another lookup
stage = Stage.objects.get_subclass(pk=stage.configuration_stage.pk)
# plan.insert inserts at 1 index, so when stage_ok pops 0,
# the configuration stage is next
self.executor.plan.insert(stage.configuration_stage)
self.executor.plan.insert(stage)
return self.executor.stage_ok()
return super().get(request, *args, **kwargs)

View File

@ -4,11 +4,14 @@ from unittest.mock import MagicMock, patch
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import TestCase
from django.test.client import RequestFactory
from django.urls.base import reverse
from django.utils.encoding import force_str
from django_otp.plugins.otp_totp.models import TOTPDevice
from rest_framework.exceptions import ValidationError
from authentik.core.models import User
from authentik.flows.models import NotConfiguredAction
from authentik.flows.challenge import ChallengeTypes
from authentik.flows.models import Flow, FlowStageBinding, NotConfiguredAction
from authentik.flows.tests.test_planner import dummy_get_response
from authentik.providers.oauth2.generators import (
generate_client_id,
@ -24,7 +27,9 @@ from authentik.stages.authenticator_validate.challenge import (
validate_challenge_duo,
validate_challenge_webauthn,
)
from authentik.stages.authenticator_validate.models import AuthenticatorValidateStage
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
from authentik.stages.identification.models import IdentificationStage, UserFields
class AuthenticatorValidateStageTests(TestCase):
@ -34,6 +39,50 @@ class AuthenticatorValidateStageTests(TestCase):
self.user = User.objects.get(username="akadmin")
self.request_factory = RequestFactory()
def test_not_configured_action(self):
"""Test not_configured_action"""
conf_stage = IdentificationStage.objects.create(
name="conf",
user_fields=[
UserFields.USERNAME,
],
)
stage = AuthenticatorValidateStage.objects.create(
name="foo",
not_configured_action=NotConfiguredAction.CONFIGURE,
configuration_stage=conf_stage,
)
flow = Flow.objects.create(name="test", slug="test", title="test")
FlowStageBinding.objects.create(target=flow, stage=conf_stage, order=0)
FlowStageBinding.objects.create(target=flow, stage=stage, order=1)
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
{"uid_field": "akadmin"},
)
self.assertEqual(response.status_code, 302)
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
follow=True,
)
self.assertEqual(response.status_code, 200)
self.assertJSONEqual(
force_str(response.content),
{
"type": ChallengeTypes.NATIVE.value,
"component": "ak-stage-identification",
"password_fields": False,
"primary_action": "Log in",
"flow_info": {
"background": flow.background_url,
"cancel_url": reverse("authentik_flows:cancel"),
"title": flow.title,
},
"user_fields": ["username"],
"sources": [],
},
)
def test_stage_validation(self):
"""Test serializer validation"""
self.client.force_login(self.user)