stages/authenticator_validate: fix stage not working without pending user (#5096)

closes #5094

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-03-27 23:08:55 +02:00 committed by GitHub
parent 0d6481c4d5
commit 4218ece2a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 7 deletions

View file

@ -377,9 +377,7 @@ class AuthenticatorValidateStageView(ChallengeStageView):
def challenge_valid(self, response: AuthenticatorValidationChallengeResponse) -> HttpResponse: def challenge_valid(self, response: AuthenticatorValidationChallengeResponse) -> HttpResponse:
# All validation is done by the serializer # All validation is done by the serializer
user = self.executor.plan.context.get(PLAN_CONTEXT_PENDING_USER) user = self.executor.plan.context.get(PLAN_CONTEXT_PENDING_USER)
if not user: if not user and "webauthn" in response.data:
if "webauthn" not in response.data:
return self.executor.stage_invalid()
webauthn_device: WebAuthnDevice = response.device webauthn_device: WebAuthnDevice = response.device
self.logger.debug("Set user from user-less flow", user=webauthn_device.user) self.logger.debug("Set user from user-less flow", user=webauthn_device.user)
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = webauthn_device.user self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = webauthn_device.user

View file

@ -1,18 +1,22 @@
"""Test validator stage""" """Test validator stage"""
from unittest.mock import MagicMock, patch
from django.contrib.sessions.middleware import SessionMiddleware from django.contrib.sessions.middleware import SessionMiddleware
from django.test.client import RequestFactory from django.test.client import RequestFactory
from django.urls.base import reverse from django.urls.base import reverse
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.models import FlowStageBinding, NotConfiguredAction from authentik.flows.models import FlowDesignation, FlowStageBinding, NotConfiguredAction
from authentik.flows.planner import FlowPlan
from authentik.flows.stage import StageView from authentik.flows.stage import StageView
from authentik.flows.tests import FlowTestCase from authentik.flows.tests import FlowTestCase
from authentik.flows.views.executor import FlowExecutorView from authentik.flows.views.executor import SESSION_KEY_PLAN, FlowExecutorView
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id, generate_key
from authentik.lib.tests.utils import dummy_get_response from authentik.lib.tests.utils import dummy_get_response
from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice
from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageSerializer from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageSerializer
from authentik.stages.authenticator_validate.models import AuthenticatorValidateStage from authentik.stages.authenticator_validate.models import AuthenticatorValidateStage, DeviceClasses
from authentik.stages.authenticator_validate.stage import ( from authentik.stages.authenticator_validate.stage import (
SESSION_KEY_DEVICE_CHALLENGES, SESSION_KEY_DEVICE_CHALLENGES,
AuthenticatorValidationChallengeResponse, AuthenticatorValidationChallengeResponse,
@ -115,3 +119,57 @@ class AuthenticatorValidateStageTests(FlowTestCase):
"device_uid": "1", "device_uid": "1",
} }
) )
@patch(
"authentik.stages.authenticator_duo.models.AuthenticatorDuoStage.auth_client",
MagicMock(
return_value=MagicMock(
auth=MagicMock(
return_value={
"result": "allow",
"status": "allow",
"status_msg": "Success. Logging you in...",
}
)
)
),
)
def test_non_authentication_flow(self):
"""Test full in an authorization flow (no pending user)"""
self.client.force_login(self.user)
duo_stage = AuthenticatorDuoStage.objects.create(
name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
api_hostname="",
)
duo_device = DuoDevice.objects.create(
user=self.user,
stage=duo_stage,
)
flow = create_test_flow(FlowDesignation.AUTHORIZATION)
stage = AuthenticatorValidateStage.objects.create(
name=generate_id(),
device_classes=[DeviceClasses.DUO],
)
plan = FlowPlan(flow_pk=flow.pk.hex)
plan.append(FlowStageBinding.objects.create(target=flow, stage=stage, order=2))
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
self.assertEqual(response.status_code, 200)
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
{"duo": duo_device.pk},
follow=True,
)
self.assertEqual(response.status_code, 200)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))