Compare commits

...

4 Commits

Author SHA1 Message Date
Jens Langhammer
4470fcba1d fix more
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-05-14 02:31:03 +02:00
Jens Langhammer
253d1532da update email stage
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-05-14 02:28:24 +02:00
Jens Langhammer
c91139fd89 Merge branch 'main' into flows/correct-result-code 2026-05-14 02:09:17 +02:00
Jens Langhammer
1db6104bef flows: return correct status code on error
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-18 13:23:24 +01:00
7 changed files with 39 additions and 15 deletions

View File

@@ -255,7 +255,7 @@ class ChallengeStageView(StageView):
"f(ch): invalid challenge response",
errors=challenge_response.errors,
)
return HttpChallengeResponse(challenge_response)
return HttpChallengeResponse(challenge_response, status=400)
class AccessDeniedStage(ChallengeStageView):

View File

@@ -2,6 +2,7 @@
from collections.abc import Callable, Generator
from contextlib import contextmanager
from http import HTTPStatus
from json import loads
from typing import Any
from unittest.mock import MagicMock, patch
@@ -27,7 +28,7 @@ class FlowTestCase(APITestCase):
**kwargs,
) -> dict[str, Any]:
"""Assert various attributes of a stage response"""
self.assertEqual(response.status_code, 200)
self.assertIn(response.status_code, [HTTPStatus.OK, HTTPStatus.BAD_REQUEST])
raw_response = loads(response.content.decode())
self.assertIsNotNone(raw_response["component"])
if flow:

View File

@@ -259,6 +259,11 @@ class FlowExecutorView(APIView):
serializers=challenge_types,
resource_type_field_name="component",
),
400: PolymorphicProxySerializer(
component_name="ChallengeTypes",
serializers=challenge_types,
resource_type_field_name="component",
),
},
request=OpenApiTypes.NONE,
parameters=[
@@ -306,6 +311,11 @@ class FlowExecutorView(APIView):
serializers=challenge_types,
resource_type_field_name="component",
),
400: PolymorphicProxySerializer(
component_name="ChallengeTypes",
serializers=challenge_types,
resource_type_field_name="component",
),
},
request=PolymorphicProxySerializer(
component_name="FlowChallengeResponse",

View File

@@ -8,6 +8,7 @@ from authentik.flows.models import FlowStageBinding, NotConfiguredAction
from authentik.flows.tests import FlowTestCase
from authentik.lib.generators import generate_id
from authentik.lib.utils.email import mask_email
from authentik.stages.authenticator.models import Device
from authentik.stages.authenticator_email.models import AuthenticatorEmailStage, EmailDevice
from authentik.stages.authenticator_validate.models import AuthenticatorValidateStage, DeviceClasses
from authentik.stages.identification.models import IdentificationStage, UserFields
@@ -50,7 +51,7 @@ class AuthenticatorValidateStageEmailTests(FlowTestCase):
self.assertEqual(response.status_code, 200)
return response
def _send_challenge(self, device):
def _send_challenge(self, device: Device):
"""Helper to send challenge for device"""
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
@@ -64,7 +65,7 @@ class AuthenticatorValidateStageEmailTests(FlowTestCase):
},
},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, 400)
return response
def test_happy_path(self):
@@ -125,7 +126,6 @@ class AuthenticatorValidateStageEmailTests(FlowTestCase):
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
{"component": "ak-stage-authenticator-validate"},
)
self.assertEqual(response.status_code, 200)
response_data = self.assertStageResponse(
response,
flow=flow,

View File

@@ -501,7 +501,6 @@ class AuthenticatorValidateStageWebAuthnTests(FlowTestCase):
SERVER_NAME="localhost",
SERVER_PORT="9000",
)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
flow,

View File

@@ -47,7 +47,6 @@ class TestEmailStageSending(FlowTestCase):
PropertyMock(return_value=EmailBackend),
):
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
@@ -85,7 +84,6 @@ class TestEmailStageSending(FlowTestCase):
PropertyMock(return_value=EmailBackend),
):
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
@@ -116,10 +114,10 @@ class TestEmailStageSending(FlowTestCase):
PropertyMock(return_value=EmailBackend),
):
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
component="ak-stage-email",
response_errors={
"non_field_errors": [{"string": "email-sent", "code": "email-sent"}]
},
@@ -144,10 +142,10 @@ class TestEmailStageSending(FlowTestCase):
PropertyMock(return_value=EmailBackend),
):
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
component="ak-stage-email",
response_errors={
"non_field_errors": [{"string": "email-sent", "code": "email-sent"}]
},
@@ -173,6 +171,13 @@ class TestEmailStageSending(FlowTestCase):
):
response = self.client.post(url)
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
component="ak-stage-email",
response_errors={
"non_field_errors": [{"string": "email-sent", "code": "email-sent"}]
},
)
self.assertGreaterEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "authentik")

View File

@@ -99,7 +99,11 @@ class TestEmailStage(FlowTestCase):
url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
response_errors={"non_field_errors": [{"string": "email-sent", "code": "email-sent"}]},
)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "authentik")
self.assertEqual(mail.outbox[0].to, [f"{self.user.name} <{self.user.email}>"])
@@ -119,7 +123,12 @@ class TestEmailStage(FlowTestCase):
url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
component="ak-stage-email",
response_errors={"non_field_errors": [{"string": "email-sent", "code": "email-sent"}]},
)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "authentik")
self.assertEqual(mail.outbox[0].to, [f"{self.user.name} <foo@bar.baz>"])
@@ -430,7 +439,7 @@ class TestEmailStage(FlowTestCase):
with patch.object(stage_view, "send_email") as mock_send_email:
result = stage_view.challenge_invalid(challenge_response)
self.assertEqual(result.status_code, 200)
self.assertEqual(result.status_code, 400)
mock_send_email.assert_called_once()
@@ -453,7 +462,7 @@ class TestEmailStage(FlowTestCase):
# This next request should be rate limited
result = stage_view.challenge_invalid(challenge_response)
self.assertEqual(result.status_code, 200)
self.assertEqual(result.status_code, 400)
mock_send_email.assert_not_called()