authentik.flows.markers

Stage Markers

 1"""Stage Markers"""
 2
 3from dataclasses import dataclass
 4from typing import TYPE_CHECKING
 5
 6from django.contrib.messages import INFO, add_message
 7from django.http.request import HttpRequest
 8from structlog.stdlib import get_logger
 9
10from authentik.flows.models import FlowStageBinding
11from authentik.policies.engine import PolicyEngine
12from authentik.policies.models import PolicyBinding
13
14if TYPE_CHECKING:
15    from authentik.flows.planner import FlowPlan
16
17LOGGER = get_logger()
18
19
20@dataclass
21class StageMarker:
22    """Base stage marker class, no extra attributes, and has no special handler."""
23
24    def process(
25        self,
26        plan: FlowPlan,
27        binding: FlowStageBinding,
28        http_request: HttpRequest,
29    ) -> FlowStageBinding | None:
30        """Process callback for this marker. This should be overridden by sub-classes.
31        If a stage should be removed, return None."""
32        return binding
33
34
35@dataclass(slots=True)
36class ReevaluateMarker(StageMarker):
37    """Reevaluate Marker, forces stage's policies to be evaluated again."""
38
39    binding: PolicyBinding
40
41    def process(
42        self,
43        plan: FlowPlan,
44        binding: FlowStageBinding,
45        http_request: HttpRequest,
46    ) -> FlowStageBinding | None:
47        """Re-evaluate policies bound to stage, and if they fail, remove from plan"""
48        from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
49
50        LOGGER.debug(
51            "f(plan_inst): running re-evaluation",
52            marker="ReevaluateMarker",
53            binding=binding,
54            policy_binding=self.binding,
55        )
56        engine = PolicyEngine(
57            self.binding, plan.context.get(PLAN_CONTEXT_PENDING_USER, http_request.user)
58        )
59        engine.use_cache = False
60        engine.request.set_http_request(http_request)
61        engine.request.context["flow_plan"] = plan
62        engine.request.context.update(plan.context)
63        engine.build()
64        result = engine.result
65        for message in result.messages:
66            add_message(http_request, INFO, message)
67        if result.passing:
68            return binding
69        LOGGER.warning(
70            "f(plan_inst): binding failed re-evaluation",
71            marker="ReevaluateMarker",
72            binding=binding,
73            messages=result.messages,
74        )
75        return None
LOGGER = <BoundLoggerLazyProxy(logger=None, wrapper_class=None, processors=None, context_class=None, initial_values={}, logger_factory_args=())>
@dataclass
class StageMarker:
21@dataclass
22class StageMarker:
23    """Base stage marker class, no extra attributes, and has no special handler."""
24
25    def process(
26        self,
27        plan: FlowPlan,
28        binding: FlowStageBinding,
29        http_request: HttpRequest,
30    ) -> FlowStageBinding | None:
31        """Process callback for this marker. This should be overridden by sub-classes.
32        If a stage should be removed, return None."""
33        return binding

Base stage marker class, no extra attributes, and has no special handler.

def process(unknown):
25    def process(
26        self,
27        plan: FlowPlan,
28        binding: FlowStageBinding,
29        http_request: HttpRequest,
30    ) -> FlowStageBinding | None:
31        """Process callback for this marker. This should be overridden by sub-classes.
32        If a stage should be removed, return None."""
33        return binding

Process callback for this marker. This should be overridden by sub-classes. If a stage should be removed, return None.

@dataclass(slots=True)
class ReevaluateMarker(StageMarker):
36@dataclass(slots=True)
37class ReevaluateMarker(StageMarker):
38    """Reevaluate Marker, forces stage's policies to be evaluated again."""
39
40    binding: PolicyBinding
41
42    def process(
43        self,
44        plan: FlowPlan,
45        binding: FlowStageBinding,
46        http_request: HttpRequest,
47    ) -> FlowStageBinding | None:
48        """Re-evaluate policies bound to stage, and if they fail, remove from plan"""
49        from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
50
51        LOGGER.debug(
52            "f(plan_inst): running re-evaluation",
53            marker="ReevaluateMarker",
54            binding=binding,
55            policy_binding=self.binding,
56        )
57        engine = PolicyEngine(
58            self.binding, plan.context.get(PLAN_CONTEXT_PENDING_USER, http_request.user)
59        )
60        engine.use_cache = False
61        engine.request.set_http_request(http_request)
62        engine.request.context["flow_plan"] = plan
63        engine.request.context.update(plan.context)
64        engine.build()
65        result = engine.result
66        for message in result.messages:
67            add_message(http_request, INFO, message)
68        if result.passing:
69            return binding
70        LOGGER.warning(
71            "f(plan_inst): binding failed re-evaluation",
72            marker="ReevaluateMarker",
73            binding=binding,
74            messages=result.messages,
75        )
76        return None

Reevaluate Marker, forces stage's policies to be evaluated again.

ReevaluateMarker(binding: authentik.policies.models.PolicyBinding)
def process(unknown):
42    def process(
43        self,
44        plan: FlowPlan,
45        binding: FlowStageBinding,
46        http_request: HttpRequest,
47    ) -> FlowStageBinding | None:
48        """Re-evaluate policies bound to stage, and if they fail, remove from plan"""
49        from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
50
51        LOGGER.debug(
52            "f(plan_inst): running re-evaluation",
53            marker="ReevaluateMarker",
54            binding=binding,
55            policy_binding=self.binding,
56        )
57        engine = PolicyEngine(
58            self.binding, plan.context.get(PLAN_CONTEXT_PENDING_USER, http_request.user)
59        )
60        engine.use_cache = False
61        engine.request.set_http_request(http_request)
62        engine.request.context["flow_plan"] = plan
63        engine.request.context.update(plan.context)
64        engine.build()
65        result = engine.result
66        for message in result.messages:
67            add_message(http_request, INFO, message)
68        if result.passing:
69            return binding
70        LOGGER.warning(
71            "f(plan_inst): binding failed re-evaluation",
72            marker="ReevaluateMarker",
73            binding=binding,
74            messages=result.messages,
75        )
76        return None

Re-evaluate policies bound to stage, and if they fail, remove from plan