flows: show messages from ak_message when flow is denied
fallback to same generic message closes #3197 Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
23c1e22a04
commit
14a4047bdd
|
@ -165,7 +165,7 @@ class SourceFlowManager:
|
||||||
self._logger.debug("Handling enrollment of new user")
|
self._logger.debug("Handling enrollment of new user")
|
||||||
return self.handle_enroll(connection)
|
return self.handle_enroll(connection)
|
||||||
except FlowNonApplicableException as exc:
|
except FlowNonApplicableException as exc:
|
||||||
self._logger.warning("Flow non applicable", exc=exc)
|
self._logger.warning("Flow non applicable", exc=exc, result=exc.policy_result)
|
||||||
return self.error_handler(exc, exc.policy_result)
|
return self.error_handler(exc, exc.policy_result)
|
||||||
# Default case, assume deny
|
# Default case, assume deny
|
||||||
error = (
|
error = (
|
||||||
|
|
|
@ -372,7 +372,7 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
|
||||||
request,
|
request,
|
||||||
_(
|
_(
|
||||||
"Flow not applicable to current user/request: %(messages)s"
|
"Flow not applicable to current user/request: %(messages)s"
|
||||||
% {"messages": str(exc)}
|
% {"messages": exc.messages}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return Response(
|
return Response(
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""flow exceptions"""
|
"""flow exceptions"""
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from authentik.lib.sentry import SentryIgnoredException
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
from authentik.policies.types import PolicyResult
|
from authentik.policies.types import PolicyResult
|
||||||
|
@ -9,6 +10,13 @@ class FlowNonApplicableException(SentryIgnoredException):
|
||||||
|
|
||||||
policy_result: PolicyResult
|
policy_result: PolicyResult
|
||||||
|
|
||||||
|
@property
|
||||||
|
def messages(self) -> str:
|
||||||
|
"""Get messages from policy result, fallback to generic reason"""
|
||||||
|
if len(self.policy_result.messages) < 1:
|
||||||
|
return _("Flow does not apply to current user (denied by policy).")
|
||||||
|
return "\n".join(self.policy_result.messages)
|
||||||
|
|
||||||
|
|
||||||
class EmptyFlowException(SentryIgnoredException):
|
class EmptyFlowException(SentryIgnoredException):
|
||||||
"""Flow has no stages."""
|
"""Flow has no stages."""
|
||||||
|
|
|
@ -147,7 +147,7 @@ class FlowPlanner:
|
||||||
engine.build()
|
engine.build()
|
||||||
result = engine.result
|
result = engine.result
|
||||||
if not result.passing:
|
if not result.passing:
|
||||||
exc = FlowNonApplicableException(",".join(result.messages))
|
exc = FlowNonApplicableException()
|
||||||
exc.policy_result = result
|
exc.policy_result = result
|
||||||
raise exc
|
raise exc
|
||||||
# User is passing so far, check if we have a cached plan
|
# User is passing so far, check if we have a cached plan
|
||||||
|
|
|
@ -7,7 +7,6 @@ from django.urls import reverse
|
||||||
|
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
from authentik.core.tests.utils import create_test_flow
|
from authentik.core.tests.utils import create_test_flow
|
||||||
from authentik.flows.exceptions import FlowNonApplicableException
|
|
||||||
from authentik.flows.markers import ReevaluateMarker, StageMarker
|
from authentik.flows.markers import ReevaluateMarker, StageMarker
|
||||||
from authentik.flows.models import (
|
from authentik.flows.models import (
|
||||||
FlowDeniedAction,
|
FlowDeniedAction,
|
||||||
|
@ -29,7 +28,7 @@ from authentik.stages.deny.models import DenyStage
|
||||||
from authentik.stages.dummy.models import DummyStage
|
from authentik.stages.dummy.models import DummyStage
|
||||||
from authentik.stages.identification.models import IdentificationStage, UserFields
|
from authentik.stages.identification.models import IdentificationStage, UserFields
|
||||||
|
|
||||||
POLICY_RETURN_FALSE = PropertyMock(return_value=PolicyResult(False))
|
POLICY_RETURN_FALSE = PropertyMock(return_value=PolicyResult(False, "foo"))
|
||||||
POLICY_RETURN_TRUE = MagicMock(return_value=PolicyResult(True))
|
POLICY_RETURN_TRUE = MagicMock(return_value=PolicyResult(True))
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,7 +92,7 @@ class TestFlowExecutor(FlowTestCase):
|
||||||
self.assertStageResponse(
|
self.assertStageResponse(
|
||||||
response,
|
response,
|
||||||
flow=flow,
|
flow=flow,
|
||||||
error_message=FlowNonApplicableException.__doc__,
|
error_message="foo",
|
||||||
component="ak-stage-access-denied",
|
component="ak-stage-access-denied",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ class FlowExecutorView(APIView):
|
||||||
self._logger = get_logger().bind(flow_slug=flow_slug)
|
self._logger = get_logger().bind(flow_slug=flow_slug)
|
||||||
set_tag("authentik.flow", self.flow.slug)
|
set_tag("authentik.flow", self.flow.slug)
|
||||||
|
|
||||||
def handle_invalid_flow(self, exc: BaseException) -> HttpResponse:
|
def handle_invalid_flow(self, exc: FlowNonApplicableException) -> HttpResponse:
|
||||||
"""When a flow is non-applicable check if user is on the correct domain"""
|
"""When a flow is non-applicable check if user is on the correct domain"""
|
||||||
if self.flow.denied_action in [
|
if self.flow.denied_action in [
|
||||||
FlowDeniedAction.CONTINUE,
|
FlowDeniedAction.CONTINUE,
|
||||||
|
@ -146,8 +146,7 @@ class FlowExecutorView(APIView):
|
||||||
return to_stage_response(
|
return to_stage_response(
|
||||||
self.request, redirect(reverse("authentik_core:root-redirect"))
|
self.request, redirect(reverse("authentik_core:root-redirect"))
|
||||||
)
|
)
|
||||||
message = exc.__doc__ if exc.__doc__ else str(exc)
|
return to_stage_response(self.request, self.stage_invalid(error_message=exc.messages))
|
||||||
return to_stage_response(self.request, self.stage_invalid(error_message=message))
|
|
||||||
|
|
||||||
def _check_flow_token(self, key: str) -> Optional[FlowPlan]:
|
def _check_flow_token(self, key: str) -> Optional[FlowPlan]:
|
||||||
"""Check if the user is using a flow token to restore a plan"""
|
"""Check if the user is using a flow token to restore a plan"""
|
||||||
|
|
|
@ -143,7 +143,10 @@ class OAuth2Provider(Provider):
|
||||||
choices=ClientTypes.choices,
|
choices=ClientTypes.choices,
|
||||||
default=ClientTypes.CONFIDENTIAL,
|
default=ClientTypes.CONFIDENTIAL,
|
||||||
verbose_name=_("Client Type"),
|
verbose_name=_("Client Type"),
|
||||||
help_text=_(ClientTypes.__doc__),
|
help_text=_(
|
||||||
|
"Confidential clients are capable of maintaining the confidentiality "
|
||||||
|
"of their credentials. Public clients are incapable"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
client_id = models.CharField(
|
client_id = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
|
|
Reference in New Issue