Compare commits
1 Commits
version-20
...
flows/conc
Author | SHA1 | Date | |
---|---|---|---|
5797a51993 |
@ -54,6 +54,7 @@ class Challenge(PassiveSerializer):
|
|||||||
|
|
||||||
flow_info = ContextualFlowInfo(required=False)
|
flow_info = ContextualFlowInfo(required=False)
|
||||||
component = CharField(default="")
|
component = CharField(default="")
|
||||||
|
xid = CharField(required=False)
|
||||||
|
|
||||||
response_errors = DictField(
|
response_errors = DictField(
|
||||||
child=ErrorDetailSerializer(many=True), allow_empty=True, required=False
|
child=ErrorDetailSerializer(many=True), allow_empty=True, required=False
|
||||||
|
@ -143,10 +143,12 @@ class FlowPlan:
|
|||||||
request: HttpRequest,
|
request: HttpRequest,
|
||||||
flow: Flow,
|
flow: Flow,
|
||||||
allowed_silent_types: list["StageView"] | None = None,
|
allowed_silent_types: list["StageView"] | None = None,
|
||||||
|
**get_params,
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
"""Redirect to the flow executor for this flow plan"""
|
"""Redirect to the flow executor for this flow plan"""
|
||||||
from authentik.flows.views.executor import (
|
from authentik.flows.views.executor import (
|
||||||
SESSION_KEY_PLAN,
|
SESSION_KEY_PLAN,
|
||||||
|
FlowContainer,
|
||||||
FlowExecutorView,
|
FlowExecutorView,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -157,6 +159,7 @@ class FlowPlan:
|
|||||||
# No unskippable stages found, so we can directly return the response of the last stage
|
# No unskippable stages found, so we can directly return the response of the last stage
|
||||||
final_stage: type[StageView] = self.bindings[-1].stage.view
|
final_stage: type[StageView] = self.bindings[-1].stage.view
|
||||||
temp_exec = FlowExecutorView(flow=flow, request=request, plan=self)
|
temp_exec = FlowExecutorView(flow=flow, request=request, plan=self)
|
||||||
|
temp_exec.container = FlowContainer(request)
|
||||||
temp_exec.current_stage = self.bindings[-1].stage
|
temp_exec.current_stage = self.bindings[-1].stage
|
||||||
temp_exec.current_stage_view = final_stage
|
temp_exec.current_stage_view = final_stage
|
||||||
temp_exec.setup(request, flow.slug)
|
temp_exec.setup(request, flow.slug)
|
||||||
@ -174,6 +177,9 @@ class FlowPlan:
|
|||||||
):
|
):
|
||||||
get_qs["inspector"] = "available"
|
get_qs["inspector"] = "available"
|
||||||
|
|
||||||
|
for key, value in get_params:
|
||||||
|
get_qs[key] = value
|
||||||
|
|
||||||
return redirect_with_qs(
|
return redirect_with_qs(
|
||||||
"authentik_core:if-flow",
|
"authentik_core:if-flow",
|
||||||
get_qs,
|
get_qs,
|
||||||
|
@ -191,6 +191,7 @@ class ChallengeStageView(StageView):
|
|||||||
)
|
)
|
||||||
flow_info.is_valid()
|
flow_info.is_valid()
|
||||||
challenge.initial_data["flow_info"] = flow_info.data
|
challenge.initial_data["flow_info"] = flow_info.data
|
||||||
|
challenge.initial_data["xid"] = self.executor.container.exec_id
|
||||||
if isinstance(challenge, WithUserInfoChallenge):
|
if isinstance(challenge, WithUserInfoChallenge):
|
||||||
# If there's a pending user, update the `username` field
|
# If there's a pending user, update the `username` field
|
||||||
# this field is only used by password managers.
|
# this field is only used by password managers.
|
||||||
|
@ -28,7 +28,7 @@ window.authentik.flow = {
|
|||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<ak-message-container></ak-message-container>
|
<ak-message-container></ak-message-container>
|
||||||
<ak-flow-executor flowSlug="{{ flow.slug }}">
|
<ak-flow-executor flowSlug="{{ flow.slug }}" xid="{{ xid }}">
|
||||||
<ak-loading></ak-loading>
|
<ak-loading></ak-loading>
|
||||||
</ak-flow-executor>
|
</ak-flow-executor>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""authentik multi-stage authentication engine"""
|
"""authentik multi-stage authentication engine"""
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
@ -64,6 +65,7 @@ from authentik.policies.engine import PolicyEngine
|
|||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
# Argument used to redirect user after login
|
# Argument used to redirect user after login
|
||||||
NEXT_ARG_NAME = "next"
|
NEXT_ARG_NAME = "next"
|
||||||
|
SESSION_KEY_PLAN_CONTAINER = "authentik/flows/plan_container/%s"
|
||||||
SESSION_KEY_PLAN = "authentik/flows/plan"
|
SESSION_KEY_PLAN = "authentik/flows/plan"
|
||||||
SESSION_KEY_APPLICATION_PRE = "authentik/flows/application_pre"
|
SESSION_KEY_APPLICATION_PRE = "authentik/flows/application_pre"
|
||||||
SESSION_KEY_GET = "authentik/flows/get"
|
SESSION_KEY_GET = "authentik/flows/get"
|
||||||
@ -71,6 +73,7 @@ SESSION_KEY_POST = "authentik/flows/post"
|
|||||||
SESSION_KEY_HISTORY = "authentik/flows/history"
|
SESSION_KEY_HISTORY = "authentik/flows/history"
|
||||||
QS_KEY_TOKEN = "flow_token" # nosec
|
QS_KEY_TOKEN = "flow_token" # nosec
|
||||||
QS_QUERY = "query"
|
QS_QUERY = "query"
|
||||||
|
QS_EXEC_ID = "xid"
|
||||||
|
|
||||||
|
|
||||||
def challenge_types():
|
def challenge_types():
|
||||||
@ -97,6 +100,88 @@ class InvalidStageError(SentryIgnoredException):
|
|||||||
"""Error raised when a challenge from a stage is not valid"""
|
"""Error raised when a challenge from a stage is not valid"""
|
||||||
|
|
||||||
|
|
||||||
|
class FlowContainer:
|
||||||
|
"""Allow for multiple concurrent flow executions in the same session"""
|
||||||
|
|
||||||
|
def __init__(self, request: HttpRequest, exec_id: str | None = None) -> None:
|
||||||
|
self.request = request
|
||||||
|
self.exec_id = exec_id
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def new(request: HttpRequest):
|
||||||
|
exec_id = str(uuid4())
|
||||||
|
request.session[SESSION_KEY_PLAN_CONTAINER % exec_id] = {}
|
||||||
|
return FlowContainer(request, exec_id)
|
||||||
|
|
||||||
|
def exists(self) -> bool:
|
||||||
|
"""Check if flow exists in container/session"""
|
||||||
|
return SESSION_KEY_PLAN in self.session
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
self.request.session.modified = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def session(self):
|
||||||
|
# Backwards compatibility: store session plan/etc directly in session
|
||||||
|
if not self.exec_id:
|
||||||
|
return self.request.session
|
||||||
|
self.request.session.setdefault(SESSION_KEY_PLAN_CONTAINER % self.exec_id, {})
|
||||||
|
return self.request.session.get(SESSION_KEY_PLAN_CONTAINER % self.exec_id, {})
|
||||||
|
|
||||||
|
@property
|
||||||
|
def plan(self) -> FlowPlan:
|
||||||
|
return self.session.get(SESSION_KEY_PLAN)
|
||||||
|
|
||||||
|
def to_redirect(
|
||||||
|
self,
|
||||||
|
request: HttpRequest,
|
||||||
|
flow: Flow,
|
||||||
|
allowed_silent_types: list[StageView] | None = None,
|
||||||
|
**get_params,
|
||||||
|
) -> HttpResponse:
|
||||||
|
get_params[QS_EXEC_ID] = self.exec_id
|
||||||
|
return self.plan.to_redirect(
|
||||||
|
request, flow, allowed_silent_types=allowed_silent_types, **get_params
|
||||||
|
)
|
||||||
|
|
||||||
|
@plan.setter
|
||||||
|
def plan(self, value: FlowPlan):
|
||||||
|
self.session[SESSION_KEY_PLAN] = value
|
||||||
|
self.request.session.modified = True
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def application_pre(self):
|
||||||
|
return self.session.get(SESSION_KEY_APPLICATION_PRE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get(self) -> QueryDict:
|
||||||
|
return self.session.get(SESSION_KEY_GET)
|
||||||
|
|
||||||
|
@get.setter
|
||||||
|
def get(self, value: QueryDict):
|
||||||
|
self.session[SESSION_KEY_GET] = value
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def post(self) -> QueryDict:
|
||||||
|
return self.session.get(SESSION_KEY_POST)
|
||||||
|
|
||||||
|
@post.setter
|
||||||
|
def post(self, value: QueryDict):
|
||||||
|
self.session[SESSION_KEY_POST] = value
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def history(self) -> list[FlowPlan]:
|
||||||
|
return self.session.get(SESSION_KEY_HISTORY)
|
||||||
|
|
||||||
|
@history.setter
|
||||||
|
def history(self, value: list[FlowPlan]):
|
||||||
|
self.session[SESSION_KEY_HISTORY] = value
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
||||||
class FlowExecutorView(APIView):
|
class FlowExecutorView(APIView):
|
||||||
"""Flow executor, passing requests to Stage Views"""
|
"""Flow executor, passing requests to Stage Views"""
|
||||||
@ -104,8 +189,9 @@ class FlowExecutorView(APIView):
|
|||||||
permission_classes = [AllowAny]
|
permission_classes = [AllowAny]
|
||||||
|
|
||||||
flow: Flow = None
|
flow: Flow = None
|
||||||
|
|
||||||
plan: FlowPlan | None = None
|
plan: FlowPlan | None = None
|
||||||
|
container: FlowContainer
|
||||||
|
|
||||||
current_binding: FlowStageBinding | None = None
|
current_binding: FlowStageBinding | None = None
|
||||||
current_stage: Stage
|
current_stage: Stage
|
||||||
current_stage_view: View
|
current_stage_view: View
|
||||||
@ -160,10 +246,12 @@ class FlowExecutorView(APIView):
|
|||||||
if QS_KEY_TOKEN in get_params:
|
if QS_KEY_TOKEN in get_params:
|
||||||
plan = self._check_flow_token(get_params[QS_KEY_TOKEN])
|
plan = self._check_flow_token(get_params[QS_KEY_TOKEN])
|
||||||
if plan:
|
if plan:
|
||||||
self.request.session[SESSION_KEY_PLAN] = plan
|
container = FlowContainer.new(request)
|
||||||
|
container.plan = plan
|
||||||
# Early check if there's an active Plan for the current session
|
# Early check if there's an active Plan for the current session
|
||||||
if SESSION_KEY_PLAN in self.request.session:
|
self.container = FlowContainer(request, request.GET.get(QS_EXEC_ID))
|
||||||
self.plan: FlowPlan = self.request.session[SESSION_KEY_PLAN]
|
if self.container.exists():
|
||||||
|
self.plan: FlowPlan = self.container.plan
|
||||||
if self.plan.flow_pk != self.flow.pk.hex:
|
if self.plan.flow_pk != self.flow.pk.hex:
|
||||||
self._logger.warning(
|
self._logger.warning(
|
||||||
"f(exec): Found existing plan for other flow, deleting plan",
|
"f(exec): Found existing plan for other flow, deleting plan",
|
||||||
@ -176,13 +264,14 @@ class FlowExecutorView(APIView):
|
|||||||
self._logger.debug("f(exec): Continuing existing plan")
|
self._logger.debug("f(exec): Continuing existing plan")
|
||||||
|
|
||||||
# Initial flow request, check if we have an upstream query string passed in
|
# Initial flow request, check if we have an upstream query string passed in
|
||||||
request.session[SESSION_KEY_GET] = get_params
|
self.container.get = get_params
|
||||||
# Don't check session again as we've either already loaded the plan or we need to plan
|
# Don't check session again as we've either already loaded the plan or we need to plan
|
||||||
if not self.plan:
|
if not self.plan:
|
||||||
request.session[SESSION_KEY_HISTORY] = []
|
self.container.history = []
|
||||||
self._logger.debug("f(exec): No active Plan found, initiating planner")
|
self._logger.debug("f(exec): No active Plan found, initiating planner")
|
||||||
try:
|
try:
|
||||||
self.plan = self._initiate_plan()
|
self.plan = self._initiate_plan()
|
||||||
|
self.container.plan = self.plan
|
||||||
except FlowNonApplicableException as exc:
|
except FlowNonApplicableException as exc:
|
||||||
self._logger.warning("f(exec): Flow not applicable to current user", exc=exc)
|
self._logger.warning("f(exec): Flow not applicable to current user", exc=exc)
|
||||||
return self.handle_invalid_flow(exc)
|
return self.handle_invalid_flow(exc)
|
||||||
@ -254,12 +343,19 @@ class FlowExecutorView(APIView):
|
|||||||
request=OpenApiTypes.NONE,
|
request=OpenApiTypes.NONE,
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="query",
|
name=QS_QUERY,
|
||||||
location=OpenApiParameter.QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
required=True,
|
required=True,
|
||||||
description="Querystring as received",
|
description="Querystring as received",
|
||||||
type=OpenApiTypes.STR,
|
type=OpenApiTypes.STR,
|
||||||
)
|
),
|
||||||
|
OpenApiParameter(
|
||||||
|
name=QS_EXEC_ID,
|
||||||
|
location=OpenApiParameter.QUERY,
|
||||||
|
required=False,
|
||||||
|
description="Flow execution ID",
|
||||||
|
type=OpenApiTypes.STR,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
operation_id="flows_executor_get",
|
operation_id="flows_executor_get",
|
||||||
)
|
)
|
||||||
@ -286,7 +382,7 @@ class FlowExecutorView(APIView):
|
|||||||
span.set_data("authentik Stage", self.current_stage_view)
|
span.set_data("authentik Stage", self.current_stage_view)
|
||||||
span.set_data("authentik Flow", self.flow.slug)
|
span.set_data("authentik Flow", self.flow.slug)
|
||||||
stage_response = self.current_stage_view.dispatch(request)
|
stage_response = self.current_stage_view.dispatch(request)
|
||||||
return to_stage_response(request, stage_response)
|
return to_stage_response(request, stage_response, self.container.exec_id)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return self.handle_exception(exc)
|
return self.handle_exception(exc)
|
||||||
|
|
||||||
@ -305,12 +401,19 @@ class FlowExecutorView(APIView):
|
|||||||
),
|
),
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="query",
|
name=QS_QUERY,
|
||||||
location=OpenApiParameter.QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
required=True,
|
required=True,
|
||||||
description="Querystring as received",
|
description="Querystring as received",
|
||||||
type=OpenApiTypes.STR,
|
type=OpenApiTypes.STR,
|
||||||
)
|
),
|
||||||
|
OpenApiParameter(
|
||||||
|
name=QS_EXEC_ID,
|
||||||
|
location=OpenApiParameter.QUERY,
|
||||||
|
required=True,
|
||||||
|
description="Flow execution ID",
|
||||||
|
type=OpenApiTypes.STR,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
operation_id="flows_executor_solve",
|
operation_id="flows_executor_solve",
|
||||||
)
|
)
|
||||||
@ -337,14 +440,15 @@ class FlowExecutorView(APIView):
|
|||||||
span.set_data("authentik Stage", self.current_stage_view)
|
span.set_data("authentik Stage", self.current_stage_view)
|
||||||
span.set_data("authentik Flow", self.flow.slug)
|
span.set_data("authentik Flow", self.flow.slug)
|
||||||
stage_response = self.current_stage_view.dispatch(request)
|
stage_response = self.current_stage_view.dispatch(request)
|
||||||
return to_stage_response(request, stage_response)
|
return to_stage_response(request, stage_response, self.container.exec_id)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return self.handle_exception(exc)
|
return self.handle_exception(exc)
|
||||||
|
|
||||||
def _initiate_plan(self) -> FlowPlan:
|
def _initiate_plan(self) -> FlowPlan:
|
||||||
planner = FlowPlanner(self.flow)
|
planner = FlowPlanner(self.flow)
|
||||||
plan = planner.plan(self.request)
|
plan = planner.plan(self.request)
|
||||||
self.request.session[SESSION_KEY_PLAN] = plan
|
container = FlowContainer.new(self.request)
|
||||||
|
container.plan = plan
|
||||||
try:
|
try:
|
||||||
# Call the has_stages getter to check that
|
# Call the has_stages getter to check that
|
||||||
# there are no issues with the class we might've gotten
|
# there are no issues with the class we might've gotten
|
||||||
@ -368,7 +472,7 @@ class FlowExecutorView(APIView):
|
|||||||
except FlowNonApplicableException as exc:
|
except FlowNonApplicableException as exc:
|
||||||
self._logger.warning("f(exec): Flow restart not applicable to current user", exc=exc)
|
self._logger.warning("f(exec): Flow restart not applicable to current user", exc=exc)
|
||||||
return self.handle_invalid_flow(exc)
|
return self.handle_invalid_flow(exc)
|
||||||
self.request.session[SESSION_KEY_PLAN] = plan
|
self.container.plan = plan
|
||||||
kwargs = self.kwargs
|
kwargs = self.kwargs
|
||||||
kwargs.update({"flow_slug": self.flow.slug})
|
kwargs.update({"flow_slug": self.flow.slug})
|
||||||
return redirect_with_qs("authentik_api:flow-executor", self.request.GET, **kwargs)
|
return redirect_with_qs("authentik_api:flow-executor", self.request.GET, **kwargs)
|
||||||
@ -390,9 +494,13 @@ class FlowExecutorView(APIView):
|
|||||||
)
|
)
|
||||||
self.cancel()
|
self.cancel()
|
||||||
if next_param and not is_url_absolute(next_param):
|
if next_param and not is_url_absolute(next_param):
|
||||||
return to_stage_response(self.request, redirect_with_qs(next_param))
|
return to_stage_response(
|
||||||
|
self.request, redirect_with_qs(next_param), self.container.exec_id
|
||||||
|
)
|
||||||
return to_stage_response(
|
return to_stage_response(
|
||||||
self.request, self.stage_invalid(error_message=_("Invalid next URL"))
|
self.request,
|
||||||
|
self.stage_invalid(error_message=_("Invalid next URL")),
|
||||||
|
self.container.exec_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
def stage_ok(self) -> HttpResponse:
|
def stage_ok(self) -> HttpResponse:
|
||||||
@ -406,7 +514,7 @@ class FlowExecutorView(APIView):
|
|||||||
self.current_stage_view.cleanup()
|
self.current_stage_view.cleanup()
|
||||||
self.request.session.get(SESSION_KEY_HISTORY, []).append(deepcopy(self.plan))
|
self.request.session.get(SESSION_KEY_HISTORY, []).append(deepcopy(self.plan))
|
||||||
self.plan.pop()
|
self.plan.pop()
|
||||||
self.request.session[SESSION_KEY_PLAN] = self.plan
|
self.container.plan = self.plan
|
||||||
if self.plan.bindings:
|
if self.plan.bindings:
|
||||||
self._logger.debug(
|
self._logger.debug(
|
||||||
"f(exec): Continuing with next stage",
|
"f(exec): Continuing with next stage",
|
||||||
@ -449,6 +557,7 @@ class FlowExecutorView(APIView):
|
|||||||
|
|
||||||
def cancel(self):
|
def cancel(self):
|
||||||
"""Cancel current flow execution"""
|
"""Cancel current flow execution"""
|
||||||
|
# TODO: Clean up container
|
||||||
keys_to_delete = [
|
keys_to_delete = [
|
||||||
SESSION_KEY_APPLICATION_PRE,
|
SESSION_KEY_APPLICATION_PRE,
|
||||||
SESSION_KEY_PLAN,
|
SESSION_KEY_PLAN,
|
||||||
@ -471,8 +580,8 @@ class CancelView(View):
|
|||||||
|
|
||||||
def get(self, request: HttpRequest) -> HttpResponse:
|
def get(self, request: HttpRequest) -> HttpResponse:
|
||||||
"""View which canels the currently active plan"""
|
"""View which canels the currently active plan"""
|
||||||
if SESSION_KEY_PLAN in request.session:
|
if FlowContainer(request, request.GET.get(QS_EXEC_ID)).exists():
|
||||||
del request.session[SESSION_KEY_PLAN]
|
del request.session[SESSION_KEY_PLAN_CONTAINER % request.GET.get(QS_EXEC_ID)]
|
||||||
LOGGER.debug("Canceled current plan")
|
LOGGER.debug("Canceled current plan")
|
||||||
return redirect("authentik_flows:default-invalidation")
|
return redirect("authentik_flows:default-invalidation")
|
||||||
|
|
||||||
@ -520,19 +629,12 @@ class ToDefaultFlow(View):
|
|||||||
|
|
||||||
def dispatch(self, request: HttpRequest) -> HttpResponse:
|
def dispatch(self, request: HttpRequest) -> HttpResponse:
|
||||||
flow = self.get_flow()
|
flow = self.get_flow()
|
||||||
# If user already has a pending plan, clear it so we don't have to later.
|
get_qs = request.GET.copy()
|
||||||
if SESSION_KEY_PLAN in self.request.session:
|
get_qs[QS_EXEC_ID] = str(uuid4())
|
||||||
plan: FlowPlan = self.request.session[SESSION_KEY_PLAN]
|
return redirect_with_qs("authentik_core:if-flow", get_qs, flow_slug=flow.slug)
|
||||||
if plan.flow_pk != flow.pk.hex:
|
|
||||||
LOGGER.warning(
|
|
||||||
"f(def): Found existing plan for other flow, deleting plan",
|
|
||||||
flow_slug=flow.slug,
|
|
||||||
)
|
|
||||||
del self.request.session[SESSION_KEY_PLAN]
|
|
||||||
return redirect_with_qs("authentik_core:if-flow", request.GET, flow_slug=flow.slug)
|
|
||||||
|
|
||||||
|
|
||||||
def to_stage_response(request: HttpRequest, source: HttpResponse) -> HttpResponse:
|
def to_stage_response(request: HttpRequest, source: HttpResponse, xid: str) -> HttpResponse:
|
||||||
"""Convert normal HttpResponse into JSON Response"""
|
"""Convert normal HttpResponse into JSON Response"""
|
||||||
if (
|
if (
|
||||||
isinstance(source, HttpResponseRedirect)
|
isinstance(source, HttpResponseRedirect)
|
||||||
@ -551,6 +653,7 @@ def to_stage_response(request: HttpRequest, source: HttpResponse) -> HttpRespons
|
|||||||
RedirectChallenge(
|
RedirectChallenge(
|
||||||
{
|
{
|
||||||
"to": str(redirect_url),
|
"to": str(redirect_url),
|
||||||
|
"xid": xid,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -559,6 +662,7 @@ def to_stage_response(request: HttpRequest, source: HttpResponse) -> HttpRespons
|
|||||||
ShellChallenge(
|
ShellChallenge(
|
||||||
{
|
{
|
||||||
"body": source.render().content.decode("utf-8"),
|
"body": source.render().content.decode("utf-8"),
|
||||||
|
"xid": xid,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -568,6 +672,7 @@ def to_stage_response(request: HttpRequest, source: HttpResponse) -> HttpRespons
|
|||||||
ShellChallenge(
|
ShellChallenge(
|
||||||
{
|
{
|
||||||
"body": source.content.decode("utf-8"),
|
"body": source.content.decode("utf-8"),
|
||||||
|
"xid": xid,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -599,4 +704,6 @@ class ConfigureFlowInitView(LoginRequiredMixin, View):
|
|||||||
except FlowNonApplicableException:
|
except FlowNonApplicableException:
|
||||||
LOGGER.warning("Flow not applicable to user")
|
LOGGER.warning("Flow not applicable to user")
|
||||||
raise Http404 from None
|
raise Http404 from None
|
||||||
return plan.to_redirect(request, stage.configure_flow)
|
container = FlowContainer.new(request)
|
||||||
|
container.plan = plan
|
||||||
|
return container.to_redirect(request, stage.configure_flow)
|
||||||
|
@ -7,6 +7,7 @@ from ua_parser.user_agent_parser import Parse
|
|||||||
|
|
||||||
from authentik.core.views.interface import InterfaceView
|
from authentik.core.views.interface import InterfaceView
|
||||||
from authentik.flows.models import Flow
|
from authentik.flows.models import Flow
|
||||||
|
from authentik.flows.views.executor import QS_EXEC_ID
|
||||||
|
|
||||||
|
|
||||||
class FlowInterfaceView(InterfaceView):
|
class FlowInterfaceView(InterfaceView):
|
||||||
@ -15,6 +16,7 @@ class FlowInterfaceView(InterfaceView):
|
|||||||
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
||||||
kwargs["flow"] = get_object_or_404(Flow, slug=self.kwargs.get("flow_slug"))
|
kwargs["flow"] = get_object_or_404(Flow, slug=self.kwargs.get("flow_slug"))
|
||||||
kwargs["inspector"] = "inspector" in self.request.GET
|
kwargs["inspector"] = "inspector" in self.request.GET
|
||||||
|
kwargs["xid"] = self.request.GET.get(QS_EXEC_ID)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def compat_needs_sfe(self) -> bool:
|
def compat_needs_sfe(self) -> bool:
|
||||||
|
2
go.mod
2
go.mod
@ -82,3 +82,5 @@ require (
|
|||||||
google.golang.org/protobuf v1.36.1 // indirect
|
google.golang.org/protobuf v1.36.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace goauthentik.io/api/v3 => ./gen-go-api
|
||||||
|
92
schema.yml
92
schema.yml
@ -8917,6 +8917,11 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
description: Querystring as received
|
description: Querystring as received
|
||||||
required: true
|
required: true
|
||||||
|
- in: query
|
||||||
|
name: xid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Flow execution ID
|
||||||
tags:
|
tags:
|
||||||
- flows
|
- flows
|
||||||
security:
|
security:
|
||||||
@ -8957,6 +8962,12 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
description: Querystring as received
|
description: Querystring as received
|
||||||
required: true
|
required: true
|
||||||
|
- in: query
|
||||||
|
name: xid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Flow execution ID
|
||||||
|
required: true
|
||||||
tags:
|
tags:
|
||||||
- flows
|
- flows
|
||||||
requestBody:
|
requestBody:
|
||||||
@ -39437,6 +39448,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-access-denied
|
default: ak-stage-access-denied
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -39452,6 +39465,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
|
- xid
|
||||||
AlgEnum:
|
AlgEnum:
|
||||||
enum:
|
enum:
|
||||||
- rsa
|
- rsa
|
||||||
@ -39551,6 +39565,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-source-oauth-apple
|
default: ak-source-oauth-apple
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -39570,6 +39586,7 @@ components:
|
|||||||
- redirect_uri
|
- redirect_uri
|
||||||
- scope
|
- scope
|
||||||
- state
|
- state
|
||||||
|
- xid
|
||||||
Application:
|
Application:
|
||||||
type: object
|
type: object
|
||||||
description: Application Serializer
|
description: Application Serializer
|
||||||
@ -39878,6 +39895,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-authenticator-duo
|
default: ak-stage-authenticator-duo
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -39900,6 +39919,7 @@ components:
|
|||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
- stage_uuid
|
- stage_uuid
|
||||||
|
- xid
|
||||||
AuthenticatorDuoChallengeResponseRequest:
|
AuthenticatorDuoChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Pseudo class for duo response
|
description: Pseudo class for duo response
|
||||||
@ -40037,6 +40057,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-authenticator-email
|
default: ak-stage-authenticator-email
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -40056,6 +40078,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
|
- xid
|
||||||
AuthenticatorEmailChallengeResponseRequest:
|
AuthenticatorEmailChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Authenticator Email Challenge response, device is set by get_response_instance
|
description: Authenticator Email Challenge response, device is set by get_response_instance
|
||||||
@ -40293,6 +40316,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-authenticator-sms
|
default: ak-stage-authenticator-sms
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -40309,6 +40334,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
|
- xid
|
||||||
AuthenticatorSMSChallengeResponseRequest:
|
AuthenticatorSMSChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: SMS Challenge response, device is set by get_response_instance
|
description: SMS Challenge response, device is set by get_response_instance
|
||||||
@ -40456,6 +40482,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-authenticator-static
|
default: ak-stage-authenticator-static
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -40474,6 +40502,7 @@ components:
|
|||||||
- codes
|
- codes
|
||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
|
- xid
|
||||||
AuthenticatorStaticChallengeResponseRequest:
|
AuthenticatorStaticChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Pseudo class for static response
|
description: Pseudo class for static response
|
||||||
@ -40577,6 +40606,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-authenticator-totp
|
default: ak-stage-authenticator-totp
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -40593,6 +40624,7 @@ components:
|
|||||||
- config_url
|
- config_url
|
||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
|
- xid
|
||||||
AuthenticatorTOTPChallengeResponseRequest:
|
AuthenticatorTOTPChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: TOTP Challenge response, device is set by get_response_instance
|
description: TOTP Challenge response, device is set by get_response_instance
|
||||||
@ -40804,6 +40836,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-authenticator-validate
|
default: ak-stage-authenticator-validate
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -40827,6 +40861,7 @@ components:
|
|||||||
- device_challenges
|
- device_challenges
|
||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
|
- xid
|
||||||
AuthenticatorValidationChallengeResponseRequest:
|
AuthenticatorValidationChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Challenge used for Code-based and WebAuthn authenticators
|
description: Challenge used for Code-based and WebAuthn authenticators
|
||||||
@ -40857,6 +40892,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-authenticator-webauthn
|
default: ak-stage-authenticator-webauthn
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -40874,6 +40911,7 @@ components:
|
|||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
- registration
|
- registration
|
||||||
|
- xid
|
||||||
AuthenticatorWebAuthnChallengeResponseRequest:
|
AuthenticatorWebAuthnChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: WebAuthn Challenge response
|
description: WebAuthn Challenge response
|
||||||
@ -41006,6 +41044,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-autosubmit
|
default: ak-stage-autosubmit
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -41023,6 +41063,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- attrs
|
- attrs
|
||||||
- url
|
- url
|
||||||
|
- xid
|
||||||
BackendsEnum:
|
BackendsEnum:
|
||||||
enum:
|
enum:
|
||||||
- authentik.core.auth.InbuiltBackend
|
- authentik.core.auth.InbuiltBackend
|
||||||
@ -41269,6 +41310,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-captcha
|
default: ak-stage-captcha
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -41291,6 +41334,7 @@ components:
|
|||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
- site_key
|
- site_key
|
||||||
|
- xid
|
||||||
CaptchaChallengeResponseRequest:
|
CaptchaChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Validate captcha token
|
description: Validate captcha token
|
||||||
@ -41674,6 +41718,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-consent
|
default: ak-stage-consent
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -41702,6 +41748,7 @@ components:
|
|||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
- permissions
|
- permissions
|
||||||
- token
|
- token
|
||||||
|
- xid
|
||||||
ConsentChallengeResponseRequest:
|
ConsentChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Consent challenge response, any valid response request is valid
|
description: Consent challenge response, any valid response request is valid
|
||||||
@ -42475,6 +42522,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-dummy
|
default: ak-stage-dummy
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -42485,6 +42534,7 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
- xid
|
||||||
DummyChallengeResponseRequest:
|
DummyChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Dummy challenge response
|
description: Dummy challenge response
|
||||||
@ -42677,12 +42727,16 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-email
|
default: ak-stage-email
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/ErrorDetail'
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
required:
|
||||||
|
- xid
|
||||||
EmailChallengeResponseRequest:
|
EmailChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: |-
|
description: |-
|
||||||
@ -43601,6 +43655,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-flow-error
|
default: ak-stage-flow-error
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -43615,6 +43671,7 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- request_id
|
- request_id
|
||||||
|
- xid
|
||||||
FlowImportResult:
|
FlowImportResult:
|
||||||
type: object
|
type: object
|
||||||
description: Logs of an attempted flow import
|
description: Logs of an attempted flow import
|
||||||
@ -43929,6 +43986,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: xak-flow-frame
|
default: xak-flow-frame
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -43945,6 +44004,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- loading_text
|
- loading_text
|
||||||
- url
|
- url
|
||||||
|
- xid
|
||||||
FrameChallengeResponseRequest:
|
FrameChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Base class for all challenge responses
|
description: Base class for all challenge responses
|
||||||
@ -44747,6 +44807,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-identification
|
default: ak-stage-identification
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -44791,6 +44853,7 @@ components:
|
|||||||
- primary_action
|
- primary_action
|
||||||
- show_source_labels
|
- show_source_labels
|
||||||
- user_fields
|
- user_fields
|
||||||
|
- xid
|
||||||
IdentificationChallengeResponseRequest:
|
IdentificationChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Identification challenge
|
description: Identification challenge
|
||||||
@ -47233,12 +47296,16 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-provider-oauth2-device-code
|
default: ak-provider-oauth2-device-code
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/ErrorDetail'
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
required:
|
||||||
|
- xid
|
||||||
OAuthDeviceCodeChallengeResponseRequest:
|
OAuthDeviceCodeChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Response that includes the user-entered device code
|
description: Response that includes the user-entered device code
|
||||||
@ -47261,12 +47328,16 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-provider-oauth2-device-code-finish
|
default: ak-provider-oauth2-device-code-finish
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/ErrorDetail'
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
required:
|
||||||
|
- xid
|
||||||
OAuthDeviceCodeFinishChallengeResponseRequest:
|
OAuthDeviceCodeFinishChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Response that device has been authenticated and tab can be closed
|
description: Response that device has been authenticated and tab can be closed
|
||||||
@ -49411,6 +49482,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-password
|
default: ak-stage-password
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -49429,6 +49502,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
|
- xid
|
||||||
PasswordChallengeResponseRequest:
|
PasswordChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Password challenge response
|
description: Password challenge response
|
||||||
@ -52990,6 +53064,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-source-plex
|
default: ak-source-plex
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -53003,6 +53079,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- client_id
|
- client_id
|
||||||
- slug
|
- slug
|
||||||
|
- xid
|
||||||
PlexAuthenticationChallengeResponseRequest:
|
PlexAuthenticationChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Pseudo class for plex response
|
description: Pseudo class for plex response
|
||||||
@ -53515,6 +53592,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-prompt
|
default: ak-stage-prompt
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -53527,6 +53606,7 @@ components:
|
|||||||
$ref: '#/components/schemas/StagePrompt'
|
$ref: '#/components/schemas/StagePrompt'
|
||||||
required:
|
required:
|
||||||
- fields
|
- fields
|
||||||
|
- xid
|
||||||
PromptChallengeResponseRequest:
|
PromptChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: |-
|
description: |-
|
||||||
@ -54711,6 +54791,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: xak-flow-redirect
|
default: xak-flow-redirect
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -54721,6 +54803,7 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- to
|
- to
|
||||||
|
- xid
|
||||||
RedirectChallengeResponseRequest:
|
RedirectChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Redirect challenge response
|
description: Redirect challenge response
|
||||||
@ -56616,6 +56699,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-session-end
|
default: ak-stage-session-end
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -56638,6 +56723,7 @@ components:
|
|||||||
- brand_name
|
- brand_name
|
||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
|
- xid
|
||||||
SessionUser:
|
SessionUser:
|
||||||
type: object
|
type: object
|
||||||
description: |-
|
description: |-
|
||||||
@ -56750,6 +56836,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: xak-flow-shell
|
default: xak-flow-shell
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -56760,6 +56848,7 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- body
|
- body
|
||||||
|
- xid
|
||||||
SignatureAlgorithmEnum:
|
SignatureAlgorithmEnum:
|
||||||
enum:
|
enum:
|
||||||
- http://www.w3.org/2000/09/xmldsig#rsa-sha1
|
- http://www.w3.org/2000/09/xmldsig#rsa-sha1
|
||||||
@ -58034,6 +58123,8 @@ components:
|
|||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-user-login
|
default: ak-stage-user-login
|
||||||
|
xid:
|
||||||
|
type: string
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
@ -58047,6 +58138,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- pending_user
|
- pending_user
|
||||||
- pending_user_avatar
|
- pending_user_avatar
|
||||||
|
- xid
|
||||||
UserLoginChallengeResponseRequest:
|
UserLoginChallengeResponseRequest:
|
||||||
type: object
|
type: object
|
||||||
description: User login challenge
|
description: User login challenge
|
||||||
|
@ -85,6 +85,9 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
|
|
||||||
ws: WebsocketClient;
|
ws: WebsocketClient;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
xid?: string;
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [PFBase, PFLogin, PFDrawer, PFButton, PFTitle, PFList, PFBackgroundImage].concat(css`
|
return [PFBase, PFLogin, PFDrawer, PFButton, PFTitle, PFList, PFBackgroundImage].concat(css`
|
||||||
:host {
|
:host {
|
||||||
@ -219,6 +222,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
const challenge = await new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolve({
|
const challenge = await new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolve({
|
||||||
flowSlug: this.flowSlug,
|
flowSlug: this.flowSlug,
|
||||||
query: window.location.search.substring(1),
|
query: window.location.search.substring(1),
|
||||||
|
xid: this.xid || "",
|
||||||
flowChallengeResponseRequest: payload,
|
flowChallengeResponseRequest: payload,
|
||||||
});
|
});
|
||||||
if (this.inspectorOpen) {
|
if (this.inspectorOpen) {
|
||||||
@ -252,6 +256,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
const challenge = await new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
|
const challenge = await new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
|
||||||
flowSlug: this.flowSlug,
|
flowSlug: this.flowSlug,
|
||||||
query: window.location.search.substring(1),
|
query: window.location.search.substring(1),
|
||||||
|
xid: this.xid,
|
||||||
});
|
});
|
||||||
if (this.inspectorOpen) {
|
if (this.inspectorOpen) {
|
||||||
window.dispatchEvent(
|
window.dispatchEvent(
|
||||||
@ -262,6 +267,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.challenge = challenge;
|
this.challenge = challenge;
|
||||||
|
this.xid = challenge.xid ?? undefined;
|
||||||
if (this.challenge.flowInfo) {
|
if (this.challenge.flowInfo) {
|
||||||
this.flowInfo = this.challenge.flowInfo;
|
this.flowInfo = this.challenge.flowInfo;
|
||||||
}
|
}
|
||||||
@ -286,6 +292,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
component: "ak-stage-flow-error",
|
component: "ak-stage-flow-error",
|
||||||
error: body,
|
error: body,
|
||||||
requestId: "",
|
requestId: "",
|
||||||
|
xid: "",
|
||||||
};
|
};
|
||||||
this.challenge = challenge as ChallengeTypes;
|
this.challenge = challenge as ChallengeTypes;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user