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