flows: make use of oneOf OpenAPI to annotate all challenge types
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
3b41c662ed
commit
6f6ae7831e
|
@ -2,6 +2,9 @@
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.db.utils import ProgrammingError
|
||||||
|
|
||||||
|
from authentik.lib.utils.reflection import all_subclasses
|
||||||
|
|
||||||
|
|
||||||
class AuthentikFlowsConfig(AppConfig):
|
class AuthentikFlowsConfig(AppConfig):
|
||||||
|
@ -14,3 +17,10 @@ class AuthentikFlowsConfig(AppConfig):
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
import_module("authentik.flows.signals")
|
import_module("authentik.flows.signals")
|
||||||
|
try:
|
||||||
|
from authentik.flows.models import Stage
|
||||||
|
|
||||||
|
for stage in all_subclasses(Stage):
|
||||||
|
_ = stage().type
|
||||||
|
except ProgrammingError:
|
||||||
|
pass
|
||||||
|
|
|
@ -35,9 +35,9 @@ class Challenge(PassiveSerializer):
|
||||||
type = ChoiceField(
|
type = ChoiceField(
|
||||||
choices=[(x.value, x.name) for x in ChallengeTypes],
|
choices=[(x.value, x.name) for x in ChallengeTypes],
|
||||||
)
|
)
|
||||||
component = CharField(required=False)
|
|
||||||
title = CharField(required=False)
|
title = CharField(required=False)
|
||||||
background = CharField(required=False)
|
background = CharField(required=False)
|
||||||
|
component = CharField(default="")
|
||||||
|
|
||||||
response_errors = DictField(
|
response_errors = DictField(
|
||||||
child=ErrorDetailSerializer(many=True), allow_empty=True, required=False
|
child=ErrorDetailSerializer(many=True), allow_empty=True, required=False
|
||||||
|
@ -48,12 +48,14 @@ class RedirectChallenge(Challenge):
|
||||||
"""Challenge type to redirect the client"""
|
"""Challenge type to redirect the client"""
|
||||||
|
|
||||||
to = CharField()
|
to = CharField()
|
||||||
|
component = CharField(default="xak-flow-redirect")
|
||||||
|
|
||||||
|
|
||||||
class ShellChallenge(Challenge):
|
class ShellChallenge(Challenge):
|
||||||
"""Legacy challenge type to render HTML as-is"""
|
"""challenge type to render HTML as-is"""
|
||||||
|
|
||||||
body = CharField()
|
body = CharField()
|
||||||
|
component = CharField(default="xak-flow-shell")
|
||||||
|
|
||||||
|
|
||||||
class WithUserInfoChallenge(Challenge):
|
class WithUserInfoChallenge(Challenge):
|
||||||
|
@ -67,6 +69,7 @@ class AccessDeniedChallenge(Challenge):
|
||||||
"""Challenge when a flow's active stage calls `stage_invalid()`."""
|
"""Challenge when a flow's active stage calls `stage_invalid()`."""
|
||||||
|
|
||||||
error_message = CharField(required=False)
|
error_message = CharField(required=False)
|
||||||
|
component = CharField(default="ak-stage-access-denied")
|
||||||
|
|
||||||
|
|
||||||
class PermissionSerializer(PassiveSerializer):
|
class PermissionSerializer(PassiveSerializer):
|
||||||
|
@ -80,6 +83,7 @@ class ChallengeResponse(PassiveSerializer):
|
||||||
"""Base class for all challenge responses"""
|
"""Base class for all challenge responses"""
|
||||||
|
|
||||||
stage: Optional["StageView"]
|
stage: Optional["StageView"]
|
||||||
|
component = CharField(default="")
|
||||||
|
|
||||||
def __init__(self, instance=None, data=None, **kwargs):
|
def __init__(self, instance=None, data=None, **kwargs):
|
||||||
self.stage = kwargs.pop("stage", None)
|
self.stage = kwargs.pop("stage", None)
|
||||||
|
|
|
@ -11,7 +11,12 @@ from django.utils.decorators import method_decorator
|
||||||
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
from drf_spectacular.types import OpenApiTypes
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
from drf_spectacular.utils import (
|
||||||
|
OpenApiParameter,
|
||||||
|
OpenApiResponse,
|
||||||
|
PolymorphicProxySerializer,
|
||||||
|
extend_schema,
|
||||||
|
)
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from sentry_sdk import capture_exception
|
from sentry_sdk import capture_exception
|
||||||
|
@ -22,10 +27,12 @@ from authentik.events.models import cleanse_dict
|
||||||
from authentik.flows.challenge import (
|
from authentik.flows.challenge import (
|
||||||
AccessDeniedChallenge,
|
AccessDeniedChallenge,
|
||||||
Challenge,
|
Challenge,
|
||||||
|
ChallengeResponse,
|
||||||
ChallengeTypes,
|
ChallengeTypes,
|
||||||
HttpChallengeResponse,
|
HttpChallengeResponse,
|
||||||
RedirectChallenge,
|
RedirectChallenge,
|
||||||
ShellChallenge,
|
ShellChallenge,
|
||||||
|
WithUserInfoChallenge,
|
||||||
)
|
)
|
||||||
from authentik.flows.exceptions import EmptyFlowException, FlowNonApplicableException
|
from authentik.flows.exceptions import EmptyFlowException, FlowNonApplicableException
|
||||||
from authentik.flows.models import ConfigurableStage, Flow, FlowDesignation, Stage
|
from authentik.flows.models import ConfigurableStage, Flow, FlowDesignation, Stage
|
||||||
|
@ -35,7 +42,7 @@ from authentik.flows.planner import (
|
||||||
FlowPlan,
|
FlowPlan,
|
||||||
FlowPlanner,
|
FlowPlanner,
|
||||||
)
|
)
|
||||||
from authentik.lib.utils.reflection import class_to_path
|
from authentik.lib.utils.reflection import all_subclasses, class_to_path
|
||||||
from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs
|
from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
@ -46,6 +53,43 @@ SESSION_KEY_APPLICATION_PRE = "authentik_flows_application_pre"
|
||||||
SESSION_KEY_GET = "authentik_flows_get"
|
SESSION_KEY_GET = "authentik_flows_get"
|
||||||
|
|
||||||
|
|
||||||
|
def challenge_types():
|
||||||
|
"""This is a workaround for PolymorphicProxySerializer not accepting a callable for
|
||||||
|
`serializers`. This function returns a class which is an iterator, which returns the
|
||||||
|
subclasses of Challenge, and Challenge itself."""
|
||||||
|
|
||||||
|
class Inner(dict):
|
||||||
|
"""dummy class with custom callback on .items()"""
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
mapping = {}
|
||||||
|
classes = all_subclasses(Challenge)
|
||||||
|
classes.remove(WithUserInfoChallenge)
|
||||||
|
for cls in classes:
|
||||||
|
mapping[cls().fields["component"].default] = cls
|
||||||
|
return mapping.items()
|
||||||
|
|
||||||
|
return Inner()
|
||||||
|
|
||||||
|
|
||||||
|
def challenge_response_types():
|
||||||
|
"""This is a workaround for PolymorphicProxySerializer not accepting a callable for
|
||||||
|
`serializers`. This function returns a class which is an iterator, which returns the
|
||||||
|
subclasses of Challenge, and Challenge itself."""
|
||||||
|
|
||||||
|
class Inner(dict):
|
||||||
|
"""dummy class with custom callback on .items()"""
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
mapping = {}
|
||||||
|
classes = all_subclasses(ChallengeResponse)
|
||||||
|
for cls in classes:
|
||||||
|
mapping[cls(stage=None).fields["component"].default] = cls
|
||||||
|
return mapping.items()
|
||||||
|
|
||||||
|
return Inner()
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
||||||
class FlowExecutorView(APIView):
|
class FlowExecutorView(APIView):
|
||||||
"""Stage 1 Flow executor, passing requests to Stage Views"""
|
"""Stage 1 Flow executor, passing requests to Stage Views"""
|
||||||
|
@ -126,7 +170,11 @@ class FlowExecutorView(APIView):
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
responses={
|
responses={
|
||||||
200: Challenge(),
|
200: PolymorphicProxySerializer(
|
||||||
|
component_name="Challenge",
|
||||||
|
serializers=challenge_types(),
|
||||||
|
resource_type_field_name="component",
|
||||||
|
),
|
||||||
404: OpenApiResponse(
|
404: OpenApiResponse(
|
||||||
description="No Token found"
|
description="No Token found"
|
||||||
), # This error can be raised by the email stage
|
), # This error can be raised by the email stage
|
||||||
|
@ -159,8 +207,18 @@ class FlowExecutorView(APIView):
|
||||||
return to_stage_response(request, FlowErrorResponse(request, exc))
|
return to_stage_response(request, FlowErrorResponse(request, exc))
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
responses={200: Challenge()},
|
responses={
|
||||||
request=OpenApiTypes.OBJECT,
|
200: PolymorphicProxySerializer(
|
||||||
|
component_name="Challenge",
|
||||||
|
serializers=challenge_types(),
|
||||||
|
resource_type_field_name="component",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
request=PolymorphicProxySerializer(
|
||||||
|
component_name="ChallengeResponse",
|
||||||
|
serializers=challenge_response_types(),
|
||||||
|
resource_type_field_name="component",
|
||||||
|
),
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="query",
|
name="query",
|
||||||
|
|
|
@ -34,6 +34,7 @@ class AutosubmitChallenge(Challenge):
|
||||||
|
|
||||||
url = CharField()
|
url = CharField()
|
||||||
attrs = DictField(child=CharField())
|
attrs = DictField(child=CharField())
|
||||||
|
component = CharField(default="ak-stage-autosubmit")
|
||||||
|
|
||||||
|
|
||||||
# This View doesn't have a URL on purpose, as its called by the FlowExecutor
|
# This View doesn't have a URL on purpose, as its called by the FlowExecutor
|
||||||
|
|
|
@ -17,6 +17,7 @@ class PlexAuthenticationChallenge(Challenge):
|
||||||
|
|
||||||
client_id = CharField()
|
client_id = CharField()
|
||||||
slug = CharField()
|
slug = CharField()
|
||||||
|
component = CharField(default="ak-flow-sources-plex")
|
||||||
|
|
||||||
|
|
||||||
class PlexSource(Source):
|
class PlexSource(Source):
|
||||||
|
|
|
@ -25,6 +25,7 @@ class AuthenticatorDuoChallenge(WithUserInfoChallenge):
|
||||||
activation_barcode = CharField()
|
activation_barcode = CharField()
|
||||||
activation_code = CharField()
|
activation_code = CharField()
|
||||||
stage_uuid = CharField()
|
stage_uuid = CharField()
|
||||||
|
component = CharField(default="ak-stage-authenticator-duo")
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorDuoStageView(ChallengeStageView):
|
class AuthenticatorDuoStageView(ChallengeStageView):
|
||||||
|
@ -42,7 +43,6 @@ class AuthenticatorDuoStageView(ChallengeStageView):
|
||||||
return AuthenticatorDuoChallenge(
|
return AuthenticatorDuoChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-authenticator-duo",
|
|
||||||
"activation_barcode": enroll["activation_barcode"],
|
"activation_barcode": enroll["activation_barcode"],
|
||||||
"activation_code": enroll["activation_code"],
|
"activation_code": enroll["activation_code"],
|
||||||
"stage_uuid": stage.stage_uuid,
|
"stage_uuid": stage.stage_uuid,
|
||||||
|
|
|
@ -22,6 +22,7 @@ class AuthenticatorStaticChallenge(WithUserInfoChallenge):
|
||||||
"""Static authenticator challenge"""
|
"""Static authenticator challenge"""
|
||||||
|
|
||||||
codes = ListField(child=CharField())
|
codes = ListField(child=CharField())
|
||||||
|
component = CharField(default="ak-stage-authenticator-static")
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorStaticStageView(ChallengeStageView):
|
class AuthenticatorStaticStageView(ChallengeStageView):
|
||||||
|
@ -32,7 +33,6 @@ class AuthenticatorStaticStageView(ChallengeStageView):
|
||||||
return AuthenticatorStaticChallenge(
|
return AuthenticatorStaticChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-authenticator-static",
|
|
||||||
"codes": [token.token for token in tokens],
|
"codes": [token.token for token in tokens],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,6 +25,7 @@ class AuthenticatorTOTPChallenge(WithUserInfoChallenge):
|
||||||
"""TOTP Setup challenge"""
|
"""TOTP Setup challenge"""
|
||||||
|
|
||||||
config_url = CharField()
|
config_url = CharField()
|
||||||
|
component = CharField(default="ak-stage-authenticator-totp")
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorTOTPChallengeResponse(ChallengeResponse):
|
class AuthenticatorTOTPChallengeResponse(ChallengeResponse):
|
||||||
|
@ -33,6 +34,7 @@ class AuthenticatorTOTPChallengeResponse(ChallengeResponse):
|
||||||
device: TOTPDevice
|
device: TOTPDevice
|
||||||
|
|
||||||
code = IntegerField()
|
code = IntegerField()
|
||||||
|
component = CharField(default="ak-stage-authenticator-totp")
|
||||||
|
|
||||||
def validate_code(self, code: int) -> int:
|
def validate_code(self, code: int) -> int:
|
||||||
"""Validate totp code"""
|
"""Validate totp code"""
|
||||||
|
@ -52,7 +54,6 @@ class AuthenticatorTOTPStageView(ChallengeStageView):
|
||||||
return AuthenticatorTOTPChallenge(
|
return AuthenticatorTOTPChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-authenticator-totp",
|
|
||||||
"config_url": device.config_url,
|
"config_url": device.config_url,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -30,18 +30,20 @@ LOGGER = get_logger()
|
||||||
PER_DEVICE_CLASSES = [DeviceClasses.WEBAUTHN]
|
PER_DEVICE_CLASSES = [DeviceClasses.WEBAUTHN]
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorChallenge(WithUserInfoChallenge):
|
class AuthenticatorValidationChallenge(WithUserInfoChallenge):
|
||||||
"""Authenticator challenge"""
|
"""Authenticator challenge"""
|
||||||
|
|
||||||
device_challenges = ListField(child=DeviceChallenge())
|
device_challenges = ListField(child=DeviceChallenge())
|
||||||
|
component = CharField(default="ak-stage-authenticator-validate")
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorChallengeResponse(ChallengeResponse):
|
class AuthenticatorValidationChallengeResponse(ChallengeResponse):
|
||||||
"""Challenge used for Code-based and WebAuthn authenticators"""
|
"""Challenge used for Code-based and WebAuthn authenticators"""
|
||||||
|
|
||||||
code = CharField(required=False)
|
code = CharField(required=False)
|
||||||
webauthn = JSONField(required=False)
|
webauthn = JSONField(required=False)
|
||||||
duo = IntegerField(required=False)
|
duo = IntegerField(required=False)
|
||||||
|
component = CharField(default="ak-stage-authenticator-validate")
|
||||||
|
|
||||||
def _challenge_allowed(self, classes: list):
|
def _challenge_allowed(self, classes: list):
|
||||||
device_challenges: list[dict] = self.stage.request.session.get(
|
device_challenges: list[dict] = self.stage.request.session.get(
|
||||||
|
@ -83,7 +85,7 @@ class AuthenticatorChallengeResponse(ChallengeResponse):
|
||||||
class AuthenticatorValidateStageView(ChallengeStageView):
|
class AuthenticatorValidateStageView(ChallengeStageView):
|
||||||
"""Authenticator Validation"""
|
"""Authenticator Validation"""
|
||||||
|
|
||||||
response_class = AuthenticatorChallengeResponse
|
response_class = AuthenticatorValidationChallengeResponse
|
||||||
|
|
||||||
def get_device_challenges(self) -> list[dict]:
|
def get_device_challenges(self) -> list[dict]:
|
||||||
"""Get a list of all device challenges applicable for the current stage"""
|
"""Get a list of all device challenges applicable for the current stage"""
|
||||||
|
@ -144,19 +146,18 @@ class AuthenticatorValidateStageView(ChallengeStageView):
|
||||||
return self.executor.stage_ok()
|
return self.executor.stage_ok()
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_challenge(self) -> AuthenticatorChallenge:
|
def get_challenge(self) -> AuthenticatorValidationChallenge:
|
||||||
challenges = self.request.session["device_challenges"]
|
challenges = self.request.session["device_challenges"]
|
||||||
return AuthenticatorChallenge(
|
return AuthenticatorValidationChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-authenticator-validate",
|
|
||||||
"device_challenges": challenges,
|
"device_challenges": challenges,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def challenge_valid(
|
def challenge_valid(
|
||||||
self, challenge: AuthenticatorChallengeResponse
|
self, challenge: AuthenticatorValidationChallengeResponse
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
# All validation is done by the serializer
|
# All validation is done by the serializer
|
||||||
return self.executor.stage_ok()
|
return self.executor.stage_ok()
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.http.request import QueryDict
|
from django.http.request import QueryDict
|
||||||
from rest_framework.fields import JSONField
|
from rest_framework.fields import CharField, JSONField
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
from webauthn.webauthn import (
|
from webauthn.webauthn import (
|
||||||
|
@ -41,12 +41,14 @@ class AuthenticatorWebAuthnChallenge(WithUserInfoChallenge):
|
||||||
"""WebAuthn Challenge"""
|
"""WebAuthn Challenge"""
|
||||||
|
|
||||||
registration = JSONField()
|
registration = JSONField()
|
||||||
|
component = CharField(default="ak-stage-authenticator-webauthn")
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse):
|
class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse):
|
||||||
"""WebAuthn Challenge response"""
|
"""WebAuthn Challenge response"""
|
||||||
|
|
||||||
response = JSONField()
|
response = JSONField()
|
||||||
|
component = CharField(default="ak-stage-authenticator-webauthn")
|
||||||
|
|
||||||
request: HttpRequest
|
request: HttpRequest
|
||||||
user: User
|
user: User
|
||||||
|
@ -134,7 +136,6 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
||||||
return AuthenticatorWebAuthnChallenge(
|
return AuthenticatorWebAuthnChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-authenticator-webauthn",
|
|
||||||
"registration": registration_dict,
|
"registration": registration_dict,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,12 +21,14 @@ class CaptchaChallenge(WithUserInfoChallenge):
|
||||||
"""Site public key"""
|
"""Site public key"""
|
||||||
|
|
||||||
site_key = CharField()
|
site_key = CharField()
|
||||||
|
component = CharField(default="ak-stage-captcha")
|
||||||
|
|
||||||
|
|
||||||
class CaptchaChallengeResponse(ChallengeResponse):
|
class CaptchaChallengeResponse(ChallengeResponse):
|
||||||
"""Validate captcha token"""
|
"""Validate captcha token"""
|
||||||
|
|
||||||
token = CharField()
|
token = CharField()
|
||||||
|
component = CharField(default="ak-stage-captcha")
|
||||||
|
|
||||||
def validate_token(self, token: str) -> str:
|
def validate_token(self, token: str) -> str:
|
||||||
"""Validate captcha token"""
|
"""Validate captcha token"""
|
||||||
|
@ -64,7 +66,6 @@ class CaptchaStageView(ChallengeStageView):
|
||||||
return CaptchaChallenge(
|
return CaptchaChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-captcha",
|
|
||||||
"site_key": self.executor.current_stage.public_key,
|
"site_key": self.executor.current_stage.public_key,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,11 +25,14 @@ class ConsentChallenge(WithUserInfoChallenge):
|
||||||
|
|
||||||
header_text = CharField()
|
header_text = CharField()
|
||||||
permissions = PermissionSerializer(many=True)
|
permissions = PermissionSerializer(many=True)
|
||||||
|
component = CharField(default="ak-stage-consent")
|
||||||
|
|
||||||
|
|
||||||
class ConsentChallengeResponse(ChallengeResponse):
|
class ConsentChallengeResponse(ChallengeResponse):
|
||||||
"""Consent challenge response, any valid response request is valid"""
|
"""Consent challenge response, any valid response request is valid"""
|
||||||
|
|
||||||
|
component = CharField(default="ak-stage-consent")
|
||||||
|
|
||||||
|
|
||||||
class ConsentStageView(ChallengeStageView):
|
class ConsentStageView(ChallengeStageView):
|
||||||
"""Simple consent checker."""
|
"""Simple consent checker."""
|
||||||
|
@ -40,7 +43,6 @@ class ConsentStageView(ChallengeStageView):
|
||||||
challenge = ConsentChallenge(
|
challenge = ConsentChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-consent",
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if PLAN_CONTEXT_CONSENT_TITLE in self.executor.plan.context:
|
if PLAN_CONTEXT_CONSENT_TITLE in self.executor.plan.context:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""authentik multi-stage authentication engine"""
|
"""authentik multi-stage authentication engine"""
|
||||||
from django.http.response import HttpResponse
|
from django.http.response import HttpResponse
|
||||||
|
from rest_framework.fields import CharField
|
||||||
|
|
||||||
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
|
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
|
||||||
from authentik.flows.stage import ChallengeStageView
|
from authentik.flows.stage import ChallengeStageView
|
||||||
|
@ -8,10 +9,14 @@ from authentik.flows.stage import ChallengeStageView
|
||||||
class DummyChallenge(Challenge):
|
class DummyChallenge(Challenge):
|
||||||
"""Dummy challenge"""
|
"""Dummy challenge"""
|
||||||
|
|
||||||
|
component = CharField(default="ak-stage-dummy")
|
||||||
|
|
||||||
|
|
||||||
class DummyChallengeResponse(ChallengeResponse):
|
class DummyChallengeResponse(ChallengeResponse):
|
||||||
"""Dummy challenge response"""
|
"""Dummy challenge response"""
|
||||||
|
|
||||||
|
component = CharField(default="ak-stage-dummy")
|
||||||
|
|
||||||
|
|
||||||
class DummyStageView(ChallengeStageView):
|
class DummyStageView(ChallengeStageView):
|
||||||
"""Dummy stage for testing with multiple stages"""
|
"""Dummy stage for testing with multiple stages"""
|
||||||
|
@ -25,7 +30,6 @@ class DummyStageView(ChallengeStageView):
|
||||||
return DummyChallenge(
|
return DummyChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-dummy",
|
|
||||||
"title": self.executor.current_stage.name,
|
"title": self.executor.current_stage.name,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,6 +8,7 @@ from django.urls import reverse
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
from rest_framework.fields import CharField
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
@ -28,11 +29,15 @@ PLAN_CONTEXT_EMAIL_SENT = "email_sent"
|
||||||
class EmailChallenge(Challenge):
|
class EmailChallenge(Challenge):
|
||||||
"""Email challenge"""
|
"""Email challenge"""
|
||||||
|
|
||||||
|
component = CharField(default="ak-stage-email")
|
||||||
|
|
||||||
|
|
||||||
class EmailChallengeResponse(ChallengeResponse):
|
class EmailChallengeResponse(ChallengeResponse):
|
||||||
"""Email challenge resposen. No fields. This challenge is
|
"""Email challenge resposen. No fields. This challenge is
|
||||||
always declared invalid to give the user a chance to retry"""
|
always declared invalid to give the user a chance to retry"""
|
||||||
|
|
||||||
|
component = CharField(default="ak-stage-email")
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
raise ValidationError("")
|
raise ValidationError("")
|
||||||
|
|
||||||
|
@ -97,7 +102,6 @@ class EmailStageView(ChallengeStageView):
|
||||||
challenge = EmailChallenge(
|
challenge = EmailChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-email",
|
|
||||||
"title": "Email sent.",
|
"title": "Email sent.",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -36,11 +36,15 @@ class IdentificationChallenge(Challenge):
|
||||||
primary_action = CharField()
|
primary_action = CharField()
|
||||||
sources = UILoginButtonSerializer(many=True, required=False)
|
sources = UILoginButtonSerializer(many=True, required=False)
|
||||||
|
|
||||||
|
component = CharField(default="ak-stage-identification")
|
||||||
|
|
||||||
|
|
||||||
class IdentificationChallengeResponse(ChallengeResponse):
|
class IdentificationChallengeResponse(ChallengeResponse):
|
||||||
"""Identification challenge"""
|
"""Identification challenge"""
|
||||||
|
|
||||||
uid_field = CharField()
|
uid_field = CharField()
|
||||||
|
component = CharField(default="ak-stage-identification")
|
||||||
|
|
||||||
pre_user: Optional[User] = None
|
pre_user: Optional[User] = None
|
||||||
|
|
||||||
def validate_uid_field(self, value: str) -> str:
|
def validate_uid_field(self, value: str) -> str:
|
||||||
|
@ -81,7 +85,6 @@ class IdentificationStageView(ChallengeStageView):
|
||||||
challenge = IdentificationChallenge(
|
challenge = IdentificationChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-identification",
|
|
||||||
"primary_action": _("Log in"),
|
"primary_action": _("Log in"),
|
||||||
"user_fields": current_stage.user_fields,
|
"user_fields": current_stage.user_fields,
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,12 +63,16 @@ class PasswordChallenge(WithUserInfoChallenge):
|
||||||
|
|
||||||
recovery_url = CharField(required=False)
|
recovery_url = CharField(required=False)
|
||||||
|
|
||||||
|
component = CharField(default="ak-stage-password")
|
||||||
|
|
||||||
|
|
||||||
class PasswordChallengeResponse(ChallengeResponse):
|
class PasswordChallengeResponse(ChallengeResponse):
|
||||||
"""Password challenge response"""
|
"""Password challenge response"""
|
||||||
|
|
||||||
password = CharField()
|
password = CharField()
|
||||||
|
|
||||||
|
component = CharField(default="ak-stage-password")
|
||||||
|
|
||||||
|
|
||||||
class PasswordStageView(ChallengeStageView):
|
class PasswordStageView(ChallengeStageView):
|
||||||
"""Authentication stage which authenticates against django's AuthBackend"""
|
"""Authentication stage which authenticates against django's AuthBackend"""
|
||||||
|
@ -79,7 +83,6 @@ class PasswordStageView(ChallengeStageView):
|
||||||
challenge = PasswordChallenge(
|
challenge = PasswordChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-password",
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
recovery_flow = Flow.objects.filter(designation=FlowDesignation.RECOVERY)
|
recovery_flow = Flow.objects.filter(designation=FlowDesignation.RECOVERY)
|
||||||
|
|
|
@ -26,7 +26,7 @@ LOGGER = get_logger()
|
||||||
PLAN_CONTEXT_PROMPT = "prompt_data"
|
PLAN_CONTEXT_PROMPT = "prompt_data"
|
||||||
|
|
||||||
|
|
||||||
class PromptSerializer(PassiveSerializer):
|
class StagePromptSerializer(PassiveSerializer):
|
||||||
"""Serializer for a single Prompt field"""
|
"""Serializer for a single Prompt field"""
|
||||||
|
|
||||||
field_key = CharField()
|
field_key = CharField()
|
||||||
|
@ -40,17 +40,22 @@ class PromptSerializer(PassiveSerializer):
|
||||||
class PromptChallenge(Challenge):
|
class PromptChallenge(Challenge):
|
||||||
"""Initial challenge being sent, define fields"""
|
"""Initial challenge being sent, define fields"""
|
||||||
|
|
||||||
fields = PromptSerializer(many=True)
|
fields = StagePromptSerializer(many=True)
|
||||||
|
component = CharField(default="ak-stage-prompt")
|
||||||
|
|
||||||
|
|
||||||
class PromptResponseChallenge(ChallengeResponse):
|
class PromptResponseChallenge(ChallengeResponse):
|
||||||
"""Validate response, fields are dynamically created based
|
"""Validate response, fields are dynamically created based
|
||||||
on the stage"""
|
on the stage"""
|
||||||
|
|
||||||
def __init__(self, *args, stage: PromptStage, plan: FlowPlan, **kwargs):
|
component = CharField(default="ak-stage-prompt")
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.stage = stage
|
self.stage: PromptStage = kwargs.pop("stage", None)
|
||||||
self.plan = plan
|
self.plan: FlowPlan = kwargs.pop("plan", None)
|
||||||
|
if not self.stage:
|
||||||
|
return
|
||||||
# list() is called so we only load the fields once
|
# list() is called so we only load the fields once
|
||||||
fields = list(self.stage.fields.all())
|
fields = list(self.stage.fields.all())
|
||||||
for field in fields:
|
for field in fields:
|
||||||
|
@ -159,8 +164,7 @@ class PromptStageView(ChallengeStageView):
|
||||||
challenge = PromptChallenge(
|
challenge = PromptChallenge(
|
||||||
data={
|
data={
|
||||||
"type": ChallengeTypes.NATIVE.value,
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
"component": "ak-stage-prompt",
|
"fields": [StagePromptSerializer(field).data for field in fields],
|
||||||
"fields": [PromptSerializer(field).data for field in fields],
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return challenge
|
return challenge
|
||||||
|
|
730
schema.yml
730
schema.yml
|
@ -3550,16 +3550,13 @@ paths:
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
$ref: '#/components/schemas/ChallengeResponseRequest'
|
||||||
additionalProperties: {}
|
|
||||||
application/x-www-form-urlencoded:
|
application/x-www-form-urlencoded:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
$ref: '#/components/schemas/ChallengeResponseRequest'
|
||||||
additionalProperties: {}
|
|
||||||
multipart/form-data:
|
multipart/form-data:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
$ref: '#/components/schemas/ChallengeResponseRequest'
|
||||||
additionalProperties: {}
|
|
||||||
security:
|
security:
|
||||||
- authentik: []
|
- authentik: []
|
||||||
- cookieAuth: []
|
- cookieAuth: []
|
||||||
|
@ -14924,6 +14921,29 @@ paths:
|
||||||
$ref: '#/components/schemas/GenericError'
|
$ref: '#/components/schemas/GenericError'
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
|
AccessDeniedChallenge:
|
||||||
|
type: object
|
||||||
|
description: Challenge when a flow's active stage calls `stage_invalid()`.
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-access-denied
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
error_message:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
ActionEnum:
|
ActionEnum:
|
||||||
enum:
|
enum:
|
||||||
- login
|
- login
|
||||||
|
@ -15138,6 +15158,42 @@ components:
|
||||||
If empty, user will not be able to configure this stage.
|
If empty, user will not be able to configure this stage.
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
AuthenticatorDuoChallenge:
|
||||||
|
type: object
|
||||||
|
description: Duo Challenge
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-duo
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
pending_user:
|
||||||
|
type: string
|
||||||
|
pending_user_avatar:
|
||||||
|
type: string
|
||||||
|
activation_barcode:
|
||||||
|
type: string
|
||||||
|
activation_code:
|
||||||
|
type: string
|
||||||
|
stage_uuid:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- activation_barcode
|
||||||
|
- activation_code
|
||||||
|
- pending_user
|
||||||
|
- pending_user_avatar
|
||||||
|
- stage_uuid
|
||||||
|
- type
|
||||||
AuthenticatorDuoStage:
|
AuthenticatorDuoStage:
|
||||||
type: object
|
type: object
|
||||||
description: AuthenticatorDuoStage Serializer
|
description: AuthenticatorDuoStage Serializer
|
||||||
|
@ -15208,6 +15264,38 @@ components:
|
||||||
- client_id
|
- client_id
|
||||||
- client_secret
|
- client_secret
|
||||||
- name
|
- name
|
||||||
|
AuthenticatorStaticChallenge:
|
||||||
|
type: object
|
||||||
|
description: Static authenticator challenge
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-static
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
pending_user:
|
||||||
|
type: string
|
||||||
|
pending_user_avatar:
|
||||||
|
type: string
|
||||||
|
codes:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- codes
|
||||||
|
- pending_user
|
||||||
|
- pending_user_avatar
|
||||||
|
- type
|
||||||
AuthenticatorStaticStage:
|
AuthenticatorStaticStage:
|
||||||
type: object
|
type: object
|
||||||
description: AuthenticatorStaticStage Serializer
|
description: AuthenticatorStaticStage Serializer
|
||||||
|
@ -15270,6 +15358,47 @@ components:
|
||||||
minimum: -2147483648
|
minimum: -2147483648
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
AuthenticatorTOTPChallenge:
|
||||||
|
type: object
|
||||||
|
description: TOTP Setup challenge
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-totp
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
pending_user:
|
||||||
|
type: string
|
||||||
|
pending_user_avatar:
|
||||||
|
type: string
|
||||||
|
config_url:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- config_url
|
||||||
|
- pending_user
|
||||||
|
- pending_user_avatar
|
||||||
|
- type
|
||||||
|
AuthenticatorTOTPChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: TOTP Challenge response, device is set by get_response_instance
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-totp
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
required:
|
||||||
|
- code
|
||||||
AuthenticatorTOTPStage:
|
AuthenticatorTOTPStage:
|
||||||
type: object
|
type: object
|
||||||
description: AuthenticatorTOTPStage Serializer
|
description: AuthenticatorTOTPStage Serializer
|
||||||
|
@ -15406,6 +15535,124 @@ components:
|
||||||
is not prompted again.
|
is not prompted again.
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
AuthenticatorValidationChallenge:
|
||||||
|
type: object
|
||||||
|
description: Authenticator challenge
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-validate
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
pending_user:
|
||||||
|
type: string
|
||||||
|
pending_user_avatar:
|
||||||
|
type: string
|
||||||
|
device_challenges:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/DeviceChallenge'
|
||||||
|
required:
|
||||||
|
- device_challenges
|
||||||
|
- pending_user
|
||||||
|
- pending_user_avatar
|
||||||
|
- type
|
||||||
|
AuthenticatorValidationChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: Challenge used for Code-based and WebAuthn authenticators
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-validate
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
webauthn:
|
||||||
|
type: object
|
||||||
|
additionalProperties: {}
|
||||||
|
duo:
|
||||||
|
type: integer
|
||||||
|
AuthenticatorWebAuthnChallenge:
|
||||||
|
type: object
|
||||||
|
description: WebAuthn Challenge
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-webauthn
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
pending_user:
|
||||||
|
type: string
|
||||||
|
pending_user_avatar:
|
||||||
|
type: string
|
||||||
|
registration:
|
||||||
|
type: object
|
||||||
|
additionalProperties: {}
|
||||||
|
required:
|
||||||
|
- pending_user
|
||||||
|
- pending_user_avatar
|
||||||
|
- registration
|
||||||
|
- type
|
||||||
|
AuthenticatorWebAuthnChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: WebAuthn Challenge response
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-webauthn
|
||||||
|
response:
|
||||||
|
type: object
|
||||||
|
additionalProperties: {}
|
||||||
|
required:
|
||||||
|
- response
|
||||||
|
AutosubmitChallenge:
|
||||||
|
type: object
|
||||||
|
description: Autosubmit challenge used to send and navigate a POST request
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-autosubmit
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
url:
|
||||||
|
type: string
|
||||||
|
attrs:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- attrs
|
||||||
|
- type
|
||||||
|
- url
|
||||||
BackendsEnum:
|
BackendsEnum:
|
||||||
enum:
|
enum:
|
||||||
- django.contrib.auth.backends.ModelBackend
|
- django.contrib.auth.backends.ModelBackend
|
||||||
|
@ -15430,6 +15677,47 @@ components:
|
||||||
enum:
|
enum:
|
||||||
- can_save_media
|
- can_save_media
|
||||||
type: string
|
type: string
|
||||||
|
CaptchaChallenge:
|
||||||
|
type: object
|
||||||
|
description: Site public key
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-captcha
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
pending_user:
|
||||||
|
type: string
|
||||||
|
pending_user_avatar:
|
||||||
|
type: string
|
||||||
|
site_key:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- pending_user
|
||||||
|
- pending_user_avatar
|
||||||
|
- site_key
|
||||||
|
- type
|
||||||
|
CaptchaChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: Validate captcha token
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-captcha
|
||||||
|
token:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- token
|
||||||
CaptchaStage:
|
CaptchaStage:
|
||||||
type: object
|
type: object
|
||||||
description: CaptchaStage Serializer
|
description: CaptchaStage Serializer
|
||||||
|
@ -15557,33 +15845,75 @@ components:
|
||||||
- certificate_data
|
- certificate_data
|
||||||
- name
|
- name
|
||||||
Challenge:
|
Challenge:
|
||||||
type: object
|
oneOf:
|
||||||
description: |-
|
- $ref: '#/components/schemas/AccessDeniedChallenge'
|
||||||
Challenge that gets sent to the client based on which stage
|
- $ref: '#/components/schemas/AuthenticatorDuoChallenge'
|
||||||
is currently active
|
- $ref: '#/components/schemas/AuthenticatorStaticChallenge'
|
||||||
properties:
|
- $ref: '#/components/schemas/AuthenticatorTOTPChallenge'
|
||||||
type:
|
- $ref: '#/components/schemas/AuthenticatorValidationChallenge'
|
||||||
$ref: '#/components/schemas/ChallengeChoices'
|
- $ref: '#/components/schemas/AuthenticatorWebAuthnChallenge'
|
||||||
component:
|
- $ref: '#/components/schemas/AutosubmitChallenge'
|
||||||
type: string
|
- $ref: '#/components/schemas/CaptchaChallenge'
|
||||||
title:
|
- $ref: '#/components/schemas/ConsentChallenge'
|
||||||
type: string
|
- $ref: '#/components/schemas/DummyChallenge'
|
||||||
background:
|
- $ref: '#/components/schemas/EmailChallenge'
|
||||||
type: string
|
- $ref: '#/components/schemas/IdentificationChallenge'
|
||||||
response_errors:
|
- $ref: '#/components/schemas/PasswordChallenge'
|
||||||
type: object
|
- $ref: '#/components/schemas/PlexAuthenticationChallenge'
|
||||||
additionalProperties:
|
- $ref: '#/components/schemas/PromptChallenge'
|
||||||
type: array
|
- $ref: '#/components/schemas/RedirectChallenge'
|
||||||
items:
|
- $ref: '#/components/schemas/ShellChallenge'
|
||||||
$ref: '#/components/schemas/ErrorDetail'
|
discriminator:
|
||||||
required:
|
propertyName: component
|
||||||
- type
|
mapping:
|
||||||
|
ak-stage-access-denied: '#/components/schemas/AccessDeniedChallenge'
|
||||||
|
ak-stage-authenticator-duo: '#/components/schemas/AuthenticatorDuoChallenge'
|
||||||
|
ak-stage-authenticator-static: '#/components/schemas/AuthenticatorStaticChallenge'
|
||||||
|
ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallenge'
|
||||||
|
ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallenge'
|
||||||
|
ak-stage-authenticator-webauthn: '#/components/schemas/AuthenticatorWebAuthnChallenge'
|
||||||
|
ak-stage-autosubmit: '#/components/schemas/AutosubmitChallenge'
|
||||||
|
ak-stage-captcha: '#/components/schemas/CaptchaChallenge'
|
||||||
|
ak-stage-consent: '#/components/schemas/ConsentChallenge'
|
||||||
|
ak-stage-dummy: '#/components/schemas/DummyChallenge'
|
||||||
|
ak-stage-email: '#/components/schemas/EmailChallenge'
|
||||||
|
ak-stage-identification: '#/components/schemas/IdentificationChallenge'
|
||||||
|
ak-stage-password: '#/components/schemas/PasswordChallenge'
|
||||||
|
ak-flow-sources-plex: '#/components/schemas/PlexAuthenticationChallenge'
|
||||||
|
ak-stage-prompt: '#/components/schemas/PromptChallenge'
|
||||||
|
xak-flow-redirect: '#/components/schemas/RedirectChallenge'
|
||||||
|
xak-flow-shell: '#/components/schemas/ShellChallenge'
|
||||||
ChallengeChoices:
|
ChallengeChoices:
|
||||||
enum:
|
enum:
|
||||||
- native
|
- native
|
||||||
- shell
|
- shell
|
||||||
- redirect
|
- redirect
|
||||||
type: string
|
type: string
|
||||||
|
ChallengeResponseRequest:
|
||||||
|
oneOf:
|
||||||
|
- $ref: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/AuthenticatorWebAuthnChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/CaptchaChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/ConsentChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/DummyChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/EmailChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/IdentificationChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/PasswordChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/PromptResponseChallengeRequest'
|
||||||
|
discriminator:
|
||||||
|
propertyName: component
|
||||||
|
mapping:
|
||||||
|
ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest'
|
||||||
|
ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest'
|
||||||
|
ak-stage-authenticator-webauthn: '#/components/schemas/AuthenticatorWebAuthnChallengeResponseRequest'
|
||||||
|
ak-stage-captcha: '#/components/schemas/CaptchaChallengeResponseRequest'
|
||||||
|
ak-stage-consent: '#/components/schemas/ConsentChallengeResponseRequest'
|
||||||
|
ak-stage-dummy: '#/components/schemas/DummyChallengeResponseRequest'
|
||||||
|
ak-stage-email: '#/components/schemas/EmailChallengeResponseRequest'
|
||||||
|
ak-stage-identification: '#/components/schemas/IdentificationChallengeResponseRequest'
|
||||||
|
ak-stage-password: '#/components/schemas/PasswordChallengeResponseRequest'
|
||||||
|
ak-stage-prompt: '#/components/schemas/PromptResponseChallengeRequest'
|
||||||
ClientTypeEnum:
|
ClientTypeEnum:
|
||||||
enum:
|
enum:
|
||||||
- confidential
|
- confidential
|
||||||
|
@ -15625,6 +15955,48 @@ components:
|
||||||
- error_reporting_environment
|
- error_reporting_environment
|
||||||
- error_reporting_send_pii
|
- error_reporting_send_pii
|
||||||
- ui_footer_links
|
- ui_footer_links
|
||||||
|
ConsentChallenge:
|
||||||
|
type: object
|
||||||
|
description: Challenge info for consent screens
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-consent
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
pending_user:
|
||||||
|
type: string
|
||||||
|
pending_user_avatar:
|
||||||
|
type: string
|
||||||
|
header_text:
|
||||||
|
type: string
|
||||||
|
permissions:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Permission'
|
||||||
|
required:
|
||||||
|
- header_text
|
||||||
|
- pending_user
|
||||||
|
- pending_user_avatar
|
||||||
|
- permissions
|
||||||
|
- type
|
||||||
|
ConsentChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: Consent challenge response, any valid response request is valid
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-consent
|
||||||
ConsentStage:
|
ConsentStage:
|
||||||
type: object
|
type: object
|
||||||
description: ConsentStage Serializer
|
description: ConsentStage Serializer
|
||||||
|
@ -15740,6 +16112,21 @@ components:
|
||||||
$ref: '#/components/schemas/FlowRequest'
|
$ref: '#/components/schemas/FlowRequest'
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
DeviceChallenge:
|
||||||
|
type: object
|
||||||
|
description: Single device challenge
|
||||||
|
properties:
|
||||||
|
device_class:
|
||||||
|
type: string
|
||||||
|
device_uid:
|
||||||
|
type: string
|
||||||
|
challenge:
|
||||||
|
type: object
|
||||||
|
additionalProperties: {}
|
||||||
|
required:
|
||||||
|
- challenge
|
||||||
|
- device_class
|
||||||
|
- device_uid
|
||||||
DeviceClassesEnum:
|
DeviceClassesEnum:
|
||||||
enum:
|
enum:
|
||||||
- static
|
- static
|
||||||
|
@ -15837,6 +16224,34 @@ components:
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- url
|
- url
|
||||||
|
DummyChallenge:
|
||||||
|
type: object
|
||||||
|
description: Dummy challenge
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-dummy
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
DummyChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: Dummy challenge response
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-dummy
|
||||||
DummyPolicy:
|
DummyPolicy:
|
||||||
type: object
|
type: object
|
||||||
description: Dummy Policy Serializer
|
description: Dummy Policy Serializer
|
||||||
|
@ -15944,6 +16359,36 @@ components:
|
||||||
$ref: '#/components/schemas/FlowRequest'
|
$ref: '#/components/schemas/FlowRequest'
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
EmailChallenge:
|
||||||
|
type: object
|
||||||
|
description: Email challenge
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-email
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
EmailChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: |-
|
||||||
|
Email challenge resposen. No fields. This challenge is
|
||||||
|
always declared invalid to give the user a chance to retry
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-email
|
||||||
EmailStage:
|
EmailStage:
|
||||||
type: object
|
type: object
|
||||||
description: EmailStage Serializer
|
description: EmailStage Serializer
|
||||||
|
@ -16640,6 +17085,57 @@ components:
|
||||||
minimum: -2147483648
|
minimum: -2147483648
|
||||||
required:
|
required:
|
||||||
- ip
|
- ip
|
||||||
|
IdentificationChallenge:
|
||||||
|
type: object
|
||||||
|
description: Identification challenges with all UI elements
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-identification
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
user_fields:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
application_pre:
|
||||||
|
type: string
|
||||||
|
enroll_url:
|
||||||
|
type: string
|
||||||
|
recovery_url:
|
||||||
|
type: string
|
||||||
|
primary_action:
|
||||||
|
type: string
|
||||||
|
sources:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/UILoginButton'
|
||||||
|
required:
|
||||||
|
- primary_action
|
||||||
|
- type
|
||||||
|
- user_fields
|
||||||
|
IdentificationChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: Identification challenge
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-identification
|
||||||
|
uid_field:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- uid_field
|
||||||
IdentificationStage:
|
IdentificationStage:
|
||||||
type: object
|
type: object
|
||||||
description: IdentificationStage Serializer
|
description: IdentificationStage Serializer
|
||||||
|
@ -20375,6 +20871,46 @@ components:
|
||||||
required:
|
required:
|
||||||
- pagination
|
- pagination
|
||||||
- results
|
- results
|
||||||
|
PasswordChallenge:
|
||||||
|
type: object
|
||||||
|
description: Password challenge UI fields
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-password
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
pending_user:
|
||||||
|
type: string
|
||||||
|
pending_user_avatar:
|
||||||
|
type: string
|
||||||
|
recovery_url:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- pending_user
|
||||||
|
- pending_user_avatar
|
||||||
|
- type
|
||||||
|
PasswordChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: Password challenge response
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-password
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- password
|
||||||
PasswordExpiryPolicy:
|
PasswordExpiryPolicy:
|
||||||
type: object
|
type: object
|
||||||
description: Password Expiry Policy Serializer
|
description: Password Expiry Policy Serializer
|
||||||
|
@ -22038,6 +22574,44 @@ components:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
maxLength: 200
|
maxLength: 200
|
||||||
|
Permission:
|
||||||
|
type: object
|
||||||
|
description: Permission used for consent
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
PlexAuthenticationChallenge:
|
||||||
|
type: object
|
||||||
|
description: Challenge shown to the user in identification stage
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-flow-sources-plex
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
client_id:
|
||||||
|
type: string
|
||||||
|
slug:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- client_id
|
||||||
|
- slug
|
||||||
|
- type
|
||||||
PlexSource:
|
PlexSource:
|
||||||
type: object
|
type: object
|
||||||
description: Plex Source Serializer
|
description: Plex Source Serializer
|
||||||
|
@ -22359,6 +22933,32 @@ components:
|
||||||
- label
|
- label
|
||||||
- pk
|
- pk
|
||||||
- type
|
- type
|
||||||
|
PromptChallenge:
|
||||||
|
type: object
|
||||||
|
description: Initial challenge being sent, define fields
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-prompt
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
fields:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/StagePrompt'
|
||||||
|
required:
|
||||||
|
- fields
|
||||||
|
- type
|
||||||
PromptRequest:
|
PromptRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Prompt Serializer
|
description: Prompt Serializer
|
||||||
|
@ -22388,6 +22988,15 @@ components:
|
||||||
- field_key
|
- field_key
|
||||||
- label
|
- label
|
||||||
- type
|
- type
|
||||||
|
PromptResponseChallengeRequest:
|
||||||
|
type: object
|
||||||
|
description: |-
|
||||||
|
Validate response, fields are dynamically created based
|
||||||
|
on the stage
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-prompt
|
||||||
PromptStage:
|
PromptStage:
|
||||||
type: object
|
type: object
|
||||||
description: PromptStage Serializer
|
description: PromptStage Serializer
|
||||||
|
@ -22789,12 +23398,13 @@ components:
|
||||||
properties:
|
properties:
|
||||||
type:
|
type:
|
||||||
$ref: '#/components/schemas/ChallengeChoices'
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
component:
|
|
||||||
type: string
|
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
background:
|
background:
|
||||||
type: string
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: xak-flow-redirect
|
||||||
response_errors:
|
response_errors:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
|
@ -23462,6 +24072,30 @@ components:
|
||||||
- warning
|
- warning
|
||||||
- alert
|
- alert
|
||||||
type: string
|
type: string
|
||||||
|
ShellChallenge:
|
||||||
|
type: object
|
||||||
|
description: challenge type to render HTML as-is
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: xak-flow-shell
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
body:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- body
|
||||||
|
- type
|
||||||
SignatureAlgorithmEnum:
|
SignatureAlgorithmEnum:
|
||||||
enum:
|
enum:
|
||||||
- http://www.w3.org/2000/09/xmldsig#rsa-sha1
|
- http://www.w3.org/2000/09/xmldsig#rsa-sha1
|
||||||
|
@ -23591,6 +24225,29 @@ components:
|
||||||
- pk
|
- pk
|
||||||
- verbose_name
|
- verbose_name
|
||||||
- verbose_name_plural
|
- verbose_name_plural
|
||||||
|
StagePrompt:
|
||||||
|
type: object
|
||||||
|
description: Serializer for a single Prompt field
|
||||||
|
properties:
|
||||||
|
field_key:
|
||||||
|
type: string
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
type: boolean
|
||||||
|
placeholder:
|
||||||
|
type: string
|
||||||
|
order:
|
||||||
|
type: integer
|
||||||
|
required:
|
||||||
|
- field_key
|
||||||
|
- label
|
||||||
|
- order
|
||||||
|
- placeholder
|
||||||
|
- required
|
||||||
|
- type
|
||||||
StageRequest:
|
StageRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Stage Serializer
|
description: Stage Serializer
|
||||||
|
@ -23818,6 +24475,21 @@ components:
|
||||||
- description
|
- description
|
||||||
- model_name
|
- model_name
|
||||||
- name
|
- name
|
||||||
|
UILoginButton:
|
||||||
|
type: object
|
||||||
|
description: Serializer for Login buttons of sources
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
challenge:
|
||||||
|
type: object
|
||||||
|
additionalProperties: {}
|
||||||
|
icon_url:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
required:
|
||||||
|
- challenge
|
||||||
|
- name
|
||||||
User:
|
User:
|
||||||
type: object
|
type: object
|
||||||
description: User Serializer
|
description: User Serializer
|
||||||
|
|
|
@ -8,23 +8,3 @@ export interface Error {
|
||||||
export interface ErrorDict {
|
export interface ErrorDict {
|
||||||
[key: string]: Error[];
|
[key: string]: Error[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Challenge {
|
|
||||||
type: ChallengeChoices;
|
|
||||||
component?: string;
|
|
||||||
title?: string;
|
|
||||||
response_errors?: ErrorDict;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WithUserInfoChallenge extends Challenge {
|
|
||||||
pending_user: string;
|
|
||||||
pending_user_avatar: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ShellChallenge extends Challenge {
|
|
||||||
body: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RedirectChallenge extends Challenge {
|
|
||||||
to: string;
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,29 +25,16 @@ import "./stages/identification/IdentificationStage";
|
||||||
import "./stages/password/PasswordStage";
|
import "./stages/password/PasswordStage";
|
||||||
import "./stages/prompt/PromptStage";
|
import "./stages/prompt/PromptStage";
|
||||||
import "./sources/plex/PlexLoginInit";
|
import "./sources/plex/PlexLoginInit";
|
||||||
import { ShellChallenge, RedirectChallenge } from "../api/Flows";
|
|
||||||
import { IdentificationChallenge } from "./stages/identification/IdentificationStage";
|
|
||||||
import { PasswordChallenge } from "./stages/password/PasswordStage";
|
|
||||||
import { ConsentChallenge } from "./stages/consent/ConsentStage";
|
|
||||||
import { EmailChallenge } from "./stages/email/EmailStage";
|
|
||||||
import { AutosubmitChallenge } from "./stages/autosubmit/AutosubmitStage";
|
|
||||||
import { PromptChallenge } from "./stages/prompt/PromptStage";
|
|
||||||
import { AuthenticatorTOTPChallenge } from "./stages/authenticator_totp/AuthenticatorTOTPStage";
|
|
||||||
import { AuthenticatorStaticChallenge } from "./stages/authenticator_static/AuthenticatorStaticStage";
|
|
||||||
import { AuthenticatorValidateStageChallenge } from "./stages/authenticator_validate/AuthenticatorValidateStage";
|
|
||||||
import { WebAuthnAuthenticatorRegisterChallenge } from "./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
|
|
||||||
import { CaptchaChallenge } from "./stages/captcha/CaptchaStage";
|
|
||||||
import { StageHost } from "./stages/base";
|
import { StageHost } from "./stages/base";
|
||||||
import { Challenge, ChallengeChoices, Config, FlowsApi } from "authentik-api";
|
import { Challenge, ChallengeChoices, Config, FlowsApi, RedirectChallenge, ShellChallenge } from "authentik-api";
|
||||||
import { config, DEFAULT_CONFIG } from "../api/Config";
|
import { config, DEFAULT_CONFIG } from "../api/Config";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import { until } from "lit-html/directives/until";
|
import { until } from "lit-html/directives/until";
|
||||||
import { AccessDeniedChallenge } from "./access_denied/FlowAccessDenied";
|
|
||||||
import { PFSize } from "../elements/Spinner";
|
import { PFSize } from "../elements/Spinner";
|
||||||
import { TITLE_DEFAULT } from "../constants";
|
import { TITLE_DEFAULT } from "../constants";
|
||||||
import { configureSentry } from "../api/Sentry";
|
import { configureSentry } from "../api/Sentry";
|
||||||
import { PlexAuthenticationChallenge } from "./sources/plex/PlexLoginInit";
|
import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest";
|
||||||
import { AuthenticatorDuoChallenge } from "./stages/authenticator_duo/AuthenticatorDuoStage";
|
|
||||||
|
|
||||||
@customElement("ak-flow-executor")
|
@customElement("ak-flow-executor")
|
||||||
export class FlowExecutor extends LitElement implements StageHost {
|
export class FlowExecutor extends LitElement implements StageHost {
|
||||||
|
@ -112,18 +99,18 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
submit<T>(formData?: T): Promise<void> {
|
submit(payload: ChallengeResponseRequest): Promise<void> {
|
||||||
|
payload.component = this.challenge.component;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolveRaw({
|
return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolve({
|
||||||
flowSlug: this.flowSlug,
|
flowSlug: this.flowSlug,
|
||||||
requestBody: formData || {},
|
|
||||||
query: window.location.search.substring(1),
|
query: window.location.search.substring(1),
|
||||||
}).then((challengeRaw) => {
|
challengeResponseRequest: payload,
|
||||||
return challengeRaw.raw.json();
|
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
this.challenge = data;
|
this.challenge = data;
|
||||||
this.postUpdate();
|
this.postUpdate();
|
||||||
}).catch((e: Response) => {
|
}).catch((e: Response) => {
|
||||||
|
console.debug(e);
|
||||||
this.errorMessage(e.statusText);
|
this.errorMessage(e.statusText);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
@ -135,19 +122,18 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
});
|
});
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
new FlowsApi(DEFAULT_CONFIG).flowsExecutorGetRaw({
|
new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
|
||||||
flowSlug: this.flowSlug,
|
flowSlug: this.flowSlug,
|
||||||
query: window.location.search.substring(1),
|
query: window.location.search.substring(1),
|
||||||
}).then((challengeRaw) => {
|
|
||||||
return challengeRaw.raw.json();
|
|
||||||
}).then((challenge) => {
|
}).then((challenge) => {
|
||||||
this.challenge = challenge as Challenge;
|
this.challenge = challenge;
|
||||||
// Only set background on first update, flow won't change throughout execution
|
// Only set background on first update, flow won't change throughout execution
|
||||||
if (this.challenge?.background) {
|
if (this.challenge?.background) {
|
||||||
this.setBackground(this.challenge.background);
|
this.setBackground(this.challenge.background);
|
||||||
}
|
}
|
||||||
this.postUpdate();
|
this.postUpdate();
|
||||||
}).catch((e: Response) => {
|
}).catch((e: Response) => {
|
||||||
|
console.debug(e);
|
||||||
// Catch JSON or Update errors
|
// Catch JSON or Update errors
|
||||||
this.errorMessage(e.statusText);
|
this.errorMessage(e.statusText);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
@ -202,35 +188,35 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
case ChallengeChoices.Native:
|
case ChallengeChoices.Native:
|
||||||
switch (this.challenge.component) {
|
switch (this.challenge.component) {
|
||||||
case "ak-stage-access-denied":
|
case "ak-stage-access-denied":
|
||||||
return html`<ak-stage-access-denied .host=${this} .challenge=${this.challenge as AccessDeniedChallenge}></ak-stage-access-denied>`;
|
return html`<ak-stage-access-denied .host=${this} .challenge=${this.challenge}></ak-stage-access-denied>`;
|
||||||
case "ak-stage-identification":
|
case "ak-stage-identification":
|
||||||
return html`<ak-stage-identification .host=${this} .challenge=${this.challenge as IdentificationChallenge}></ak-stage-identification>`;
|
return html`<ak-stage-identification .host=${this} .challenge=${this.challenge}></ak-stage-identification>`;
|
||||||
case "ak-stage-password":
|
case "ak-stage-password":
|
||||||
return html`<ak-stage-password .host=${this} .challenge=${this.challenge as PasswordChallenge}></ak-stage-password>`;
|
return html`<ak-stage-password .host=${this} .challenge=${this.challenge}></ak-stage-password>`;
|
||||||
case "ak-stage-captcha":
|
case "ak-stage-captcha":
|
||||||
return html`<ak-stage-captcha .host=${this} .challenge=${this.challenge as CaptchaChallenge}></ak-stage-captcha>`;
|
return html`<ak-stage-captcha .host=${this} .challenge=${this.challenge}></ak-stage-captcha>`;
|
||||||
case "ak-stage-consent":
|
case "ak-stage-consent":
|
||||||
return html`<ak-stage-consent .host=${this} .challenge=${this.challenge as ConsentChallenge}></ak-stage-consent>`;
|
return html`<ak-stage-consent .host=${this} .challenge=${this.challenge}></ak-stage-consent>`;
|
||||||
case "ak-stage-dummy":
|
case "ak-stage-dummy":
|
||||||
return html`<ak-stage-dummy .host=${this} .challenge=${this.challenge as Challenge}></ak-stage-dummy>`;
|
return html`<ak-stage-dummy .host=${this} .challenge=${this.challenge}></ak-stage-dummy>`;
|
||||||
case "ak-stage-email":
|
case "ak-stage-email":
|
||||||
return html`<ak-stage-email .host=${this} .challenge=${this.challenge as EmailChallenge}></ak-stage-email>`;
|
return html`<ak-stage-email .host=${this} .challenge=${this.challenge}></ak-stage-email>`;
|
||||||
case "ak-stage-autosubmit":
|
case "ak-stage-autosubmit":
|
||||||
return html`<ak-stage-autosubmit .host=${this} .challenge=${this.challenge as AutosubmitChallenge}></ak-stage-autosubmit>`;
|
return html`<ak-stage-autosubmit .host=${this} .challenge=${this.challenge}></ak-stage-autosubmit>`;
|
||||||
case "ak-stage-prompt":
|
case "ak-stage-prompt":
|
||||||
return html`<ak-stage-prompt .host=${this} .challenge=${this.challenge as PromptChallenge}></ak-stage-prompt>`;
|
return html`<ak-stage-prompt .host=${this} .challenge=${this.challenge}></ak-stage-prompt>`;
|
||||||
case "ak-stage-authenticator-totp":
|
case "ak-stage-authenticator-totp":
|
||||||
return html`<ak-stage-authenticator-totp .host=${this} .challenge=${this.challenge as AuthenticatorTOTPChallenge}></ak-stage-authenticator-totp>`;
|
return html`<ak-stage-authenticator-totp .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-totp>`;
|
||||||
case "ak-stage-authenticator-duo":
|
case "ak-stage-authenticator-duo":
|
||||||
return html`<ak-stage-authenticator-duo .host=${this} .challenge=${this.challenge as AuthenticatorDuoChallenge}></ak-stage-authenticator-duo>`;
|
return html`<ak-stage-authenticator-duo .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-duo>`;
|
||||||
case "ak-stage-authenticator-static":
|
case "ak-stage-authenticator-static":
|
||||||
return html`<ak-stage-authenticator-static .host=${this} .challenge=${this.challenge as AuthenticatorStaticChallenge}></ak-stage-authenticator-static>`;
|
return html`<ak-stage-authenticator-static .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-static>`;
|
||||||
case "ak-stage-authenticator-webauthn":
|
case "ak-stage-authenticator-webauthn":
|
||||||
return html`<ak-stage-authenticator-webauthn .host=${this} .challenge=${this.challenge as WebAuthnAuthenticatorRegisterChallenge}></ak-stage-authenticator-webauthn>`;
|
return html`<ak-stage-authenticator-webauthn .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-webauthn>`;
|
||||||
case "ak-stage-authenticator-validate":
|
case "ak-stage-authenticator-validate":
|
||||||
return html`<ak-stage-authenticator-validate .host=${this} .challenge=${this.challenge as AuthenticatorValidateStageChallenge}></ak-stage-authenticator-validate>`;
|
return html`<ak-stage-authenticator-validate .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-validate>`;
|
||||||
case "ak-flow-sources-plex":
|
case "ak-flow-sources-plex":
|
||||||
return html`<ak-flow-sources-plex .host=${this} .challenge=${this.challenge as PlexAuthenticationChallenge}></ak-flow-sources-plex>`;
|
return html`<ak-flow-sources-plex .host=${this} .challenge=${this.challenge}></ak-flow-sources-plex>`;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -288,8 +274,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
</li>`;
|
</li>`;
|
||||||
}))}
|
}))}
|
||||||
${this.config?.brandingTitle != "authentik" ? html`
|
${this.config?.brandingTitle != "authentik" ? html`
|
||||||
<li><a href="https://goauthentik.io">${t`Powered by authentik`}</a></li>
|
<li><a href="https://goauthentik.io">${t`Powered by authentik`}</a></li>` : html``}
|
||||||
` : html``}
|
|
||||||
</ul>
|
</ul>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Challenge } from "authentik-api";
|
import { AccessDeniedChallenge } from "authentik-api";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { BaseStage } from "../stages/base";
|
import { BaseStage } from "../stages/base";
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
|
@ -12,10 +12,6 @@ import { t } from "@lingui/macro";
|
||||||
|
|
||||||
import "../../elements/EmptyState";
|
import "../../elements/EmptyState";
|
||||||
|
|
||||||
export interface AccessDeniedChallenge extends Challenge {
|
|
||||||
error_message?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-access-denied")
|
@customElement("ak-stage-access-denied")
|
||||||
export class FlowAccessDenied extends BaseStage {
|
export class FlowAccessDenied extends BaseStage {
|
||||||
|
|
||||||
|
@ -45,9 +41,9 @@ export class FlowAccessDenied extends BaseStage {
|
||||||
<i class="pf-icon pf-icon-error-circle-o"></i>
|
<i class="pf-icon pf-icon-error-circle-o"></i>
|
||||||
${t`Request has been denied.`}
|
${t`Request has been denied.`}
|
||||||
</p>
|
</p>
|
||||||
${this.challenge?.error_message &&
|
${this.challenge?.errorMessage &&
|
||||||
html`<hr>
|
html`<hr>
|
||||||
<p>${this.challenge.error_message}</p>`}
|
<p>${this.challenge.errorMessage}</p>`}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { Challenge } from "authentik-api";
|
import { PlexAuthenticationChallenge } from "authentik-api";
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -16,12 +16,6 @@ import { SourcesApi } from "authentik-api";
|
||||||
import { showMessage } from "../../../elements/messages/MessageContainer";
|
import { showMessage } from "../../../elements/messages/MessageContainer";
|
||||||
import { MessageLevel } from "../../../elements/messages/Message";
|
import { MessageLevel } from "../../../elements/messages/Message";
|
||||||
|
|
||||||
export interface PlexAuthenticationChallenge extends Challenge {
|
|
||||||
|
|
||||||
client_id: string;
|
|
||||||
slug: string;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-flow-sources-plex")
|
@customElement("ak-flow-sources-plex")
|
||||||
export class PlexLoginInit extends BaseStage {
|
export class PlexLoginInit extends BaseStage {
|
||||||
|
@ -34,9 +28,9 @@ export class PlexLoginInit extends BaseStage {
|
||||||
}
|
}
|
||||||
|
|
||||||
async firstUpdated(): Promise<void> {
|
async firstUpdated(): Promise<void> {
|
||||||
const authInfo = await PlexAPIClient.getPin(this.challenge?.client_id || "");
|
const authInfo = await PlexAPIClient.getPin(this.challenge?.clientId || "");
|
||||||
const authWindow = popupCenterScreen(authInfo.authUrl, "plex auth", 550, 700);
|
const authWindow = popupCenterScreen(authInfo.authUrl, "plex auth", 550, 700);
|
||||||
PlexAPIClient.pinPoll(this.challenge?.client_id || "", authInfo.pin.id).then(token => {
|
PlexAPIClient.pinPoll(this.challenge?.clientId || "", authInfo.pin.id).then(token => {
|
||||||
authWindow?.close();
|
authWindow?.close();
|
||||||
new SourcesApi(DEFAULT_CONFIG).sourcesPlexRedeemTokenCreate({
|
new SourcesApi(DEFAULT_CONFIG).sourcesPlexRedeemTokenCreate({
|
||||||
plexTokenRedeemRequest: {
|
plexTokenRedeemRequest: {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { WithUserInfoChallenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -13,15 +12,9 @@ import "../../../elements/forms/FormElement";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import "../../FormStatic";
|
import "../../FormStatic";
|
||||||
import { FlowURLManager } from "../../../api/legacy";
|
import { FlowURLManager } from "../../../api/legacy";
|
||||||
import { StagesApi } from "authentik-api";
|
import { AuthenticatorDuoChallenge, StagesApi } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
|
|
||||||
export interface AuthenticatorDuoChallenge extends WithUserInfoChallenge {
|
|
||||||
activation_barcode: string;
|
|
||||||
activation_code: string;
|
|
||||||
stage_uuid: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-authenticator-duo")
|
@customElement("ak-stage-authenticator-duo")
|
||||||
export class AuthenticatorDuoStage extends BaseStage {
|
export class AuthenticatorDuoStage extends BaseStage {
|
||||||
|
|
||||||
|
@ -42,10 +35,11 @@ export class AuthenticatorDuoStage extends BaseStage {
|
||||||
|
|
||||||
checkEnrollStatus(): Promise<void> {
|
checkEnrollStatus(): Promise<void> {
|
||||||
return new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorDuoEnrollmentStatusCreate({
|
return new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorDuoEnrollmentStatusCreate({
|
||||||
stageUuid: this.challenge?.stage_uuid || "",
|
stageUuid: this.challenge?.stageUuid || "",
|
||||||
}).then(r => {
|
}).then(() => {
|
||||||
this.host?.submit({});
|
this.host?.submit({});
|
||||||
}).catch(e => {
|
}).catch(() => {
|
||||||
|
console.debug("authentik/flows/duo: Waiting for auth status");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,17 +59,17 @@ export class AuthenticatorDuoStage extends BaseStage {
|
||||||
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
||||||
<ak-form-static
|
<ak-form-static
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
userAvatar="${this.challenge.pending_user_avatar}"
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
user=${this.challenge.pending_user}>
|
user=${this.challenge.pendingUser}>
|
||||||
<div slot="link">
|
<div slot="link">
|
||||||
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-static>
|
</ak-form-static>
|
||||||
<img src=${this.challenge.activation_barcode} />
|
<img src=${this.challenge.activationBarcode} />
|
||||||
<p>
|
<p>
|
||||||
${t`Alternatively, if your current device has Duo installed, click on this link:`}
|
${t`Alternatively, if your current device has Duo installed, click on this link:`}
|
||||||
</p>
|
</p>
|
||||||
<a href=${this.challenge.activation_code}>${t`Duo activation`}</a>
|
<a href=${this.challenge.activationCode}>${t`Duo activation`}</a>
|
||||||
|
|
||||||
<div class="pf-c-form__group pf-m-action">
|
<div class="pf-c-form__group pf-m-action">
|
||||||
<button type="button" class="pf-c-button pf-m-primary pf-m-block" @click=${() => {
|
<button type="button" class="pf-c-button pf-m-primary pf-m-block" @click=${() => {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { WithUserInfoChallenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -13,6 +12,7 @@ import "../../../elements/forms/FormElement";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import "../../FormStatic";
|
import "../../FormStatic";
|
||||||
import { FlowURLManager } from "../../../api/legacy";
|
import { FlowURLManager } from "../../../api/legacy";
|
||||||
|
import { AuthenticatorStaticChallenge } from "authentik-api";
|
||||||
|
|
||||||
export const STATIC_TOKEN_STYLE = css`
|
export const STATIC_TOKEN_STYLE = css`
|
||||||
/* Static OTP Tokens */
|
/* Static OTP Tokens */
|
||||||
|
@ -29,9 +29,6 @@ export const STATIC_TOKEN_STYLE = css`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export interface AuthenticatorStaticChallenge extends WithUserInfoChallenge {
|
|
||||||
codes: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-authenticator-static")
|
@customElement("ak-stage-authenticator-static")
|
||||||
export class AuthenticatorStaticStage extends BaseStage {
|
export class AuthenticatorStaticStage extends BaseStage {
|
||||||
|
@ -59,8 +56,8 @@ export class AuthenticatorStaticStage extends BaseStage {
|
||||||
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
||||||
<ak-form-static
|
<ak-form-static
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
userAvatar="${this.challenge.pending_user_avatar}"
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
user=${this.challenge.pending_user}>
|
user=${this.challenge.pendingUser}>
|
||||||
<div slot="link">
|
<div slot="link">
|
||||||
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { WithUserInfoChallenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -16,10 +15,8 @@ import "../../../elements/EmptyState";
|
||||||
import "../../FormStatic";
|
import "../../FormStatic";
|
||||||
import { MessageLevel } from "../../../elements/messages/Message";
|
import { MessageLevel } from "../../../elements/messages/Message";
|
||||||
import { FlowURLManager } from "../../../api/legacy";
|
import { FlowURLManager } from "../../../api/legacy";
|
||||||
|
import { AuthenticatorTOTPChallenge } from "authentik-api";
|
||||||
|
|
||||||
export interface AuthenticatorTOTPChallenge extends WithUserInfoChallenge {
|
|
||||||
config_url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-authenticator-totp")
|
@customElement("ak-stage-authenticator-totp")
|
||||||
export class AuthenticatorTOTPStage extends BaseStage {
|
export class AuthenticatorTOTPStage extends BaseStage {
|
||||||
|
@ -47,20 +44,20 @@ export class AuthenticatorTOTPStage extends BaseStage {
|
||||||
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
||||||
<ak-form-static
|
<ak-form-static
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
userAvatar="${this.challenge.pending_user_avatar}"
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
user=${this.challenge.pending_user}>
|
user=${this.challenge.pendingUser}>
|
||||||
<div slot="link">
|
<div slot="link">
|
||||||
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-static>
|
</ak-form-static>
|
||||||
<input type="hidden" name="otp_uri" value=${this.challenge.config_url} />
|
<input type="hidden" name="otp_uri" value=${this.challenge.configUrl} />
|
||||||
<ak-form-element>
|
<ak-form-element>
|
||||||
<!-- @ts-ignore -->
|
<!-- @ts-ignore -->
|
||||||
<qr-code data="${this.challenge.config_url}"></qr-code>
|
<qr-code data="${this.challenge.configUrl}"></qr-code>
|
||||||
<button type="button" class="pf-c-button pf-m-secondary pf-m-progress pf-m-in-progress" @click=${(e: Event) => {
|
<button type="button" class="pf-c-button pf-m-secondary pf-m-progress pf-m-in-progress" @click=${(e: Event) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!this.challenge?.config_url) return;
|
if (!this.challenge?.configUrl) return;
|
||||||
navigator.clipboard.writeText(this.challenge?.config_url).then(() => {
|
navigator.clipboard.writeText(this.challenge?.configUrl).then(() => {
|
||||||
showMessage({
|
showMessage({
|
||||||
level: MessageLevel.success,
|
level: MessageLevel.success,
|
||||||
message: t`Successfully copied TOTP Config.`
|
message: t`Successfully copied TOTP Config.`
|
||||||
|
@ -75,7 +72,7 @@ export class AuthenticatorTOTPStage extends BaseStage {
|
||||||
label="${t`Code`}"
|
label="${t`Code`}"
|
||||||
?required="${true}"
|
?required="${true}"
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
.errors=${(this.challenge?.response_errors || {})["code"]}>
|
.errors=${(this.challenge?.responseErrors || {})["code"]}>
|
||||||
<!-- @ts-ignore -->
|
<!-- @ts-ignore -->
|
||||||
<input type="text"
|
<input type="text"
|
||||||
name="code"
|
name="code"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { WithUserInfoChallenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -13,6 +12,9 @@ import "./AuthenticatorValidateStageWebAuthn";
|
||||||
import "./AuthenticatorValidateStageCode";
|
import "./AuthenticatorValidateStageCode";
|
||||||
import "./AuthenticatorValidateStageDuo";
|
import "./AuthenticatorValidateStageDuo";
|
||||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
|
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
|
||||||
|
import { DeviceChallenge } from "authentik-api";
|
||||||
|
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
|
||||||
|
import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest";
|
||||||
|
|
||||||
export enum DeviceClasses {
|
export enum DeviceClasses {
|
||||||
STATIC = "static",
|
STATIC = "static",
|
||||||
|
@ -21,33 +23,17 @@ export enum DeviceClasses {
|
||||||
DUO = "duo",
|
DUO = "duo",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DeviceChallenge {
|
|
||||||
device_class: DeviceClasses;
|
|
||||||
device_uid: string;
|
|
||||||
challenge: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AuthenticatorValidateStageChallenge extends WithUserInfoChallenge {
|
|
||||||
device_challenges: DeviceChallenge[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AuthenticatorValidateStageChallengeResponse {
|
|
||||||
code?: string;
|
|
||||||
webauthn?: string;
|
|
||||||
duo?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-authenticator-validate")
|
@customElement("ak-stage-authenticator-validate")
|
||||||
export class AuthenticatorValidateStage extends BaseStage implements StageHost {
|
export class AuthenticatorValidateStage extends BaseStage implements StageHost {
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
challenge?: AuthenticatorValidateStageChallenge;
|
challenge?: AuthenticatorValidationChallenge;
|
||||||
|
|
||||||
@property({attribute: false})
|
@property({attribute: false})
|
||||||
selectedDeviceChallenge?: DeviceChallenge;
|
selectedDeviceChallenge?: DeviceChallenge;
|
||||||
|
|
||||||
submit<T>(formData?: T): Promise<void> {
|
submit(payload: ChallengeResponseRequest): Promise<void> {
|
||||||
return this.host?.submit<T>(formData) || Promise.resolve();
|
return this.host?.submit(payload) || Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
|
@ -79,7 +65,7 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderDevicePickerSingle(deviceChallenge: DeviceChallenge): TemplateResult {
|
renderDevicePickerSingle(deviceChallenge: DeviceChallenge): TemplateResult {
|
||||||
switch (deviceChallenge.device_class) {
|
switch (deviceChallenge.deviceClass) {
|
||||||
case DeviceClasses.DUO:
|
case DeviceClasses.DUO:
|
||||||
return html`<i class="fas fa-mobile-alt"></i>
|
return html`<i class="fas fa-mobile-alt"></i>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
|
@ -124,7 +110,7 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
|
||||||
renderDevicePicker(): TemplateResult {
|
renderDevicePicker(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ul>
|
<ul>
|
||||||
${this.challenge?.device_challenges.map((challenges) => {
|
${this.challenge?.deviceChallenges.map((challenges) => {
|
||||||
return html`<li>
|
return html`<li>
|
||||||
<button class="pf-c-button authenticator-button" type="button" @click=${() => {
|
<button class="pf-c-button authenticator-button" type="button" @click=${() => {
|
||||||
this.selectedDeviceChallenge = challenges;
|
this.selectedDeviceChallenge = challenges;
|
||||||
|
@ -140,30 +126,31 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
|
||||||
if (!this.selectedDeviceChallenge) {
|
if (!this.selectedDeviceChallenge) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
switch (this.selectedDeviceChallenge?.device_class) {
|
switch (this.selectedDeviceChallenge?.deviceClass) {
|
||||||
case DeviceClasses.STATIC:
|
case DeviceClasses.STATIC:
|
||||||
case DeviceClasses.TOTP:
|
case DeviceClasses.TOTP:
|
||||||
return html`<ak-stage-authenticator-validate-code
|
return html`<ak-stage-authenticator-validate-code
|
||||||
.host=${this}
|
.host=${this as StageHost}
|
||||||
.challenge=${this.challenge}
|
.challenge=${this.challenge}
|
||||||
.deviceChallenge=${this.selectedDeviceChallenge}
|
.deviceChallenge=${this.selectedDeviceChallenge}
|
||||||
.showBackButton=${(this.challenge?.device_challenges.length || []) > 1}>
|
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}>
|
||||||
</ak-stage-authenticator-validate-code>`;
|
</ak-stage-authenticator-validate-code>`;
|
||||||
case DeviceClasses.WEBAUTHN:
|
case DeviceClasses.WEBAUTHN:
|
||||||
return html`<ak-stage-authenticator-validate-webauthn
|
return html`<ak-stage-authenticator-validate-webauthn
|
||||||
.host=${this}
|
.host=${this as StageHost}
|
||||||
.challenge=${this.challenge}
|
.challenge=${this.challenge}
|
||||||
.deviceChallenge=${this.selectedDeviceChallenge}
|
.deviceChallenge=${this.selectedDeviceChallenge}
|
||||||
.showBackButton=${(this.challenge?.device_challenges.length || []) > 1}>
|
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}>
|
||||||
</ak-stage-authenticator-validate-webauthn>`;
|
</ak-stage-authenticator-validate-webauthn>`;
|
||||||
case DeviceClasses.DUO:
|
case DeviceClasses.DUO:
|
||||||
return html`<ak-stage-authenticator-validate-duo
|
return html`<ak-stage-authenticator-validate-duo
|
||||||
.host=${this}
|
.host=${this as StageHost}
|
||||||
.challenge=${this.challenge}
|
.challenge=${this.challenge}
|
||||||
.deviceChallenge=${this.selectedDeviceChallenge}
|
.deviceChallenge=${this.selectedDeviceChallenge}
|
||||||
.showBackButton=${(this.challenge?.device_challenges.length || []) > 1}>
|
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}>
|
||||||
</ak-stage-authenticator-validate-duo>`;
|
</ak-stage-authenticator-validate-duo>`;
|
||||||
}
|
}
|
||||||
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
|
@ -174,8 +161,8 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
|
||||||
</ak-empty-state>`;
|
</ak-empty-state>`;
|
||||||
}
|
}
|
||||||
// User only has a single device class, so we don't show a picker
|
// User only has a single device class, so we don't show a picker
|
||||||
if (this.challenge?.device_challenges.length === 1) {
|
if (this.challenge?.deviceChallenges.length === 1) {
|
||||||
this.selectedDeviceChallenge = this.challenge.device_challenges[0];
|
this.selectedDeviceChallenge = this.challenge.deviceChallenges[0];
|
||||||
}
|
}
|
||||||
return html`<header class="pf-c-login__main-header">
|
return html`<header class="pf-c-login__main-header">
|
||||||
<h1 class="pf-c-title pf-m-3xl">
|
<h1 class="pf-c-title pf-m-3xl">
|
||||||
|
|
|
@ -8,18 +8,20 @@ import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import AKGlobal from "../../../authentik.css";
|
import AKGlobal from "../../../authentik.css";
|
||||||
import { BaseStage } from "../base";
|
import { BaseStage } from "../base";
|
||||||
import { AuthenticatorValidateStage, AuthenticatorValidateStageChallenge, DeviceChallenge } from "./AuthenticatorValidateStage";
|
import { AuthenticatorValidateStage } from "./AuthenticatorValidateStage";
|
||||||
import "../../../elements/forms/FormElement";
|
import "../../../elements/forms/FormElement";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
|
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
|
||||||
import "../../FormStatic";
|
import "../../FormStatic";
|
||||||
import { FlowURLManager } from "../../../api/legacy";
|
import { FlowURLManager } from "../../../api/legacy";
|
||||||
|
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
|
||||||
|
import { DeviceChallenge } from "authentik-api";
|
||||||
|
|
||||||
@customElement("ak-stage-authenticator-validate-code")
|
@customElement("ak-stage-authenticator-validate-code")
|
||||||
export class AuthenticatorValidateStageWebCode extends BaseStage {
|
export class AuthenticatorValidateStageWebCode extends BaseStage {
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
challenge?: AuthenticatorValidateStageChallenge;
|
challenge?: AuthenticatorValidationChallenge;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
deviceChallenge?: DeviceChallenge;
|
deviceChallenge?: DeviceChallenge;
|
||||||
|
@ -42,8 +44,8 @@ export class AuthenticatorValidateStageWebCode extends BaseStage {
|
||||||
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
||||||
<ak-form-static
|
<ak-form-static
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
userAvatar="${this.challenge.pending_user_avatar}"
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
user=${this.challenge.pending_user}>
|
user=${this.challenge.pendingUser}>
|
||||||
<div slot="link">
|
<div slot="link">
|
||||||
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -52,7 +54,7 @@ export class AuthenticatorValidateStageWebCode extends BaseStage {
|
||||||
label="${t`Code`}"
|
label="${t`Code`}"
|
||||||
?required="${true}"
|
?required="${true}"
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
.errors=${(this.challenge?.response_errors || {})["code"]}>
|
.errors=${(this.challenge?.responseErrors || {})["code"]}>
|
||||||
<!-- @ts-ignore -->
|
<!-- @ts-ignore -->
|
||||||
<input type="text"
|
<input type="text"
|
||||||
name="code"
|
name="code"
|
||||||
|
|
|
@ -8,18 +8,19 @@ import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import AKGlobal from "../../../authentik.css";
|
import AKGlobal from "../../../authentik.css";
|
||||||
import { BaseStage } from "../base";
|
import { BaseStage } from "../base";
|
||||||
import { AuthenticatorValidateStage, AuthenticatorValidateStageChallenge, DeviceChallenge } from "./AuthenticatorValidateStage";
|
import { AuthenticatorValidateStage } from "./AuthenticatorValidateStage";
|
||||||
import "../../../elements/forms/FormElement";
|
import "../../../elements/forms/FormElement";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
|
|
||||||
import "../../FormStatic";
|
import "../../FormStatic";
|
||||||
import { FlowURLManager } from "../../../api/legacy";
|
import { FlowURLManager } from "../../../api/legacy";
|
||||||
|
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
|
||||||
|
import { DeviceChallenge } from "authentik-api";
|
||||||
|
|
||||||
@customElement("ak-stage-authenticator-validate-duo")
|
@customElement("ak-stage-authenticator-validate-duo")
|
||||||
export class AuthenticatorValidateStageWebDuo extends BaseStage {
|
export class AuthenticatorValidateStageWebDuo extends BaseStage {
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
challenge?: AuthenticatorValidateStageChallenge;
|
challenge?: AuthenticatorValidationChallenge;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
deviceChallenge?: DeviceChallenge;
|
deviceChallenge?: DeviceChallenge;
|
||||||
|
@ -33,7 +34,7 @@ export class AuthenticatorValidateStageWebDuo extends BaseStage {
|
||||||
|
|
||||||
firstUpdated(): void {
|
firstUpdated(): void {
|
||||||
this.host?.submit({
|
this.host?.submit({
|
||||||
"duo": this.deviceChallenge?.device_uid
|
"duo": this.deviceChallenge?.deviceUid
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +49,8 @@ export class AuthenticatorValidateStageWebDuo extends BaseStage {
|
||||||
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
||||||
<ak-form-static
|
<ak-form-static
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
userAvatar="${this.challenge.pending_user_avatar}"
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
user=${this.challenge.pending_user}>
|
user=${this.challenge.pendingUser}>
|
||||||
<div slot="link">
|
<div slot="link">
|
||||||
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,13 +10,15 @@ import AKGlobal from "../../../authentik.css";
|
||||||
import { PFSize } from "../../../elements/Spinner";
|
import { PFSize } from "../../../elements/Spinner";
|
||||||
import { transformAssertionForServer, transformCredentialRequestOptions } from "../authenticator_webauthn/utils";
|
import { transformAssertionForServer, transformCredentialRequestOptions } from "../authenticator_webauthn/utils";
|
||||||
import { BaseStage } from "../base";
|
import { BaseStage } from "../base";
|
||||||
import { AuthenticatorValidateStage, AuthenticatorValidateStageChallenge, DeviceChallenge } from "./AuthenticatorValidateStage";
|
import { AuthenticatorValidateStage } from "./AuthenticatorValidateStage";
|
||||||
|
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
|
||||||
|
import { DeviceChallenge } from "authentik-api";
|
||||||
|
|
||||||
@customElement("ak-stage-authenticator-validate-webauthn")
|
@customElement("ak-stage-authenticator-validate-webauthn")
|
||||||
export class AuthenticatorValidateStageWebAuthn extends BaseStage {
|
export class AuthenticatorValidateStageWebAuthn extends BaseStage {
|
||||||
|
|
||||||
@property({attribute: false})
|
@property({attribute: false})
|
||||||
challenge?: AuthenticatorValidateStageChallenge;
|
challenge?: AuthenticatorValidationChallenge;
|
||||||
|
|
||||||
@property({attribute: false})
|
@property({attribute: false})
|
||||||
deviceChallenge?: DeviceChallenge;
|
deviceChallenge?: DeviceChallenge;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { WithUserInfoChallenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -11,10 +10,7 @@ import AKGlobal from "../../../authentik.css";
|
||||||
import { PFSize } from "../../../elements/Spinner";
|
import { PFSize } from "../../../elements/Spinner";
|
||||||
import { BaseStage } from "../base";
|
import { BaseStage } from "../base";
|
||||||
import { Assertion, transformCredentialCreateOptions, transformNewAssertionForServer } from "./utils";
|
import { Assertion, transformCredentialCreateOptions, transformNewAssertionForServer } from "./utils";
|
||||||
|
import { AuthenticatorWebAuthnChallenge } from "authentik-api";
|
||||||
export interface WebAuthnAuthenticatorRegisterChallenge extends WithUserInfoChallenge {
|
|
||||||
registration: PublicKeyCredentialCreationOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebAuthnAuthenticatorRegisterChallengeResponse {
|
export interface WebAuthnAuthenticatorRegisterChallengeResponse {
|
||||||
response: Assertion;
|
response: Assertion;
|
||||||
|
@ -24,7 +20,7 @@ export interface WebAuthnAuthenticatorRegisterChallengeResponse {
|
||||||
export class WebAuthnAuthenticatorRegisterStage extends BaseStage {
|
export class WebAuthnAuthenticatorRegisterStage extends BaseStage {
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
challenge?: WebAuthnAuthenticatorRegisterChallenge;
|
challenge?: AuthenticatorWebAuthnChallenge;
|
||||||
|
|
||||||
@property({type: Boolean})
|
@property({type: Boolean})
|
||||||
registerRunning = false;
|
registerRunning = false;
|
||||||
|
@ -42,7 +38,7 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage {
|
||||||
}
|
}
|
||||||
// convert certain members of the PublicKeyCredentialCreateOptions into
|
// convert certain members of the PublicKeyCredentialCreateOptions into
|
||||||
// byte arrays as expected by the spec.
|
// byte arrays as expected by the spec.
|
||||||
const publicKeyCredentialCreateOptions = transformCredentialCreateOptions(this.challenge?.registration);
|
const publicKeyCredentialCreateOptions = transformCredentialCreateOptions(this.challenge?.registration as PublicKeyCredentialCreationOptions);
|
||||||
|
|
||||||
// request the authenticator(s) to create a new credential keypair.
|
// request the authenticator(s) to create a new credential keypair.
|
||||||
let credential;
|
let credential;
|
||||||
|
@ -106,8 +102,8 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage {
|
||||||
</div>`:
|
</div>`:
|
||||||
html`
|
html`
|
||||||
<div class="pf-c-form__group pf-m-action">
|
<div class="pf-c-form__group pf-m-action">
|
||||||
${this.challenge?.response_errors ?
|
${this.challenge?.responseErrors ?
|
||||||
html`<p class="pf-m-block">${this.challenge.response_errors["response"][0].string}</p>`:
|
html`<p class="pf-m-block">${this.challenge.responseErrors["response"][0].string}</p>`:
|
||||||
html``}
|
html``}
|
||||||
<p class="pf-m-block">${this.registerMessage}</p>
|
<p class="pf-m-block">${this.registerMessage}</p>
|
||||||
<button class="pf-c-button pf-m-primary pf-m-block" @click=${() => {
|
<button class="pf-c-button pf-m-primary pf-m-block" @click=${() => {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { WithUserInfoChallenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -10,11 +9,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import AKGlobal from "../../../authentik.css";
|
import AKGlobal from "../../../authentik.css";
|
||||||
import { BaseStage } from "../base";
|
import { BaseStage } from "../base";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
|
import { AutosubmitChallenge } from "authentik-api";
|
||||||
export interface AutosubmitChallenge extends WithUserInfoChallenge {
|
|
||||||
url: string;
|
|
||||||
attrs: { [key: string]: string };
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-autosubmit")
|
@customElement("ak-stage-autosubmit")
|
||||||
export class AutosubmitStage extends BaseStage {
|
export class AutosubmitStage extends BaseStage {
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
import { Challenge } from "authentik-api";
|
import { Challenge } from "authentik-api";
|
||||||
|
import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest";
|
||||||
import { LitElement } from "lit-element";
|
import { LitElement } from "lit-element";
|
||||||
|
|
||||||
export interface StageHost {
|
export interface StageHost {
|
||||||
challenge?: Challenge;
|
challenge?: Challenge;
|
||||||
submit<T>(formData?: T): Promise<void>;
|
submit(payload: ChallengeResponseRequest): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BaseStage extends LitElement {
|
export class BaseStage extends LitElement {
|
||||||
|
|
||||||
host?: StageHost;
|
host?: StageHost;
|
||||||
|
challenge?: Challenge;
|
||||||
|
|
||||||
submitForm(e: Event): void {
|
submitForm(e: Event): void {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const object: {
|
const object: {
|
||||||
|
component: string;
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
} = {};
|
} = {
|
||||||
|
component: this.challenge.component,
|
||||||
|
};
|
||||||
const form = new FormData(this.shadowRoot?.querySelector("form") || undefined);
|
const form = new FormData(this.shadowRoot?.querySelector("form") || undefined);
|
||||||
form.forEach((value, key) => object[key] = value);
|
form.forEach((value, key) => object[key] = value);
|
||||||
this.host?.submit(object);
|
this.host?.submit(object);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { WithUserInfoChallenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -14,10 +13,7 @@ import "../../../elements/forms/FormElement";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import "../../FormStatic";
|
import "../../FormStatic";
|
||||||
import { FlowURLManager } from "../../../api/legacy";
|
import { FlowURLManager } from "../../../api/legacy";
|
||||||
|
import { CaptchaChallenge } from "authentik-api";
|
||||||
export interface CaptchaChallenge extends WithUserInfoChallenge {
|
|
||||||
site_key: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-captcha")
|
@customElement("ak-stage-captcha")
|
||||||
export class CaptchaStage extends BaseStage {
|
export class CaptchaStage extends BaseStage {
|
||||||
|
@ -39,10 +35,10 @@ export class CaptchaStage extends BaseStage {
|
||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
console.debug("authentik/stages/captcha: script loaded");
|
console.debug("authentik/stages/captcha: script loaded");
|
||||||
grecaptcha.ready(() => {
|
grecaptcha.ready(() => {
|
||||||
if (!this.challenge?.site_key) return;
|
if (!this.challenge?.siteKey) return;
|
||||||
console.debug("authentik/stages/captcha: ready");
|
console.debug("authentik/stages/captcha: ready");
|
||||||
const captchaId = grecaptcha.render(captchaContainer, {
|
const captchaId = grecaptcha.render(captchaContainer, {
|
||||||
sitekey: this.challenge.site_key,
|
sitekey: this.challenge.siteKey,
|
||||||
callback: (token) => {
|
callback: (token) => {
|
||||||
this.host?.submit({
|
this.host?.submit({
|
||||||
"token": token,
|
"token": token,
|
||||||
|
@ -72,8 +68,8 @@ export class CaptchaStage extends BaseStage {
|
||||||
<form class="pf-c-form">
|
<form class="pf-c-form">
|
||||||
<ak-form-static
|
<ak-form-static
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
userAvatar="${this.challenge.pending_user_avatar}"
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
user=${this.challenge.pending_user}>
|
user=${this.challenge.pendingUser}>
|
||||||
<div slot="link">
|
<div slot="link">
|
||||||
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { WithUserInfoChallenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -12,18 +11,8 @@ import { BaseStage } from "../base";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import "../../FormStatic";
|
import "../../FormStatic";
|
||||||
import { FlowURLManager } from "../../../api/legacy";
|
import { FlowURLManager } from "../../../api/legacy";
|
||||||
|
import { ConsentChallenge } from "authentik-api";
|
||||||
|
|
||||||
export interface Permission {
|
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ConsentChallenge extends WithUserInfoChallenge {
|
|
||||||
|
|
||||||
header_text: string;
|
|
||||||
permissions?: Permission[];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-consent")
|
@customElement("ak-stage-consent")
|
||||||
export class ConsentStage extends BaseStage {
|
export class ConsentStage extends BaseStage {
|
||||||
|
@ -51,15 +40,15 @@ export class ConsentStage extends BaseStage {
|
||||||
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
<form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
|
||||||
<ak-form-static
|
<ak-form-static
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
userAvatar="${this.challenge.pending_user_avatar}"
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
user=${this.challenge.pending_user}>
|
user=${this.challenge.pendingUser}>
|
||||||
<div slot="link">
|
<div slot="link">
|
||||||
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-static>
|
</ak-form-static>
|
||||||
<div class="pf-c-form__group">
|
<div class="pf-c-form__group">
|
||||||
<p id="header-text">
|
<p id="header-text">
|
||||||
${this.challenge.header_text}
|
${this.challenge.headerText}
|
||||||
</p>
|
</p>
|
||||||
<p>${t`Application requires following permissions`}</p>
|
<p>${t`Application requires following permissions`}</p>
|
||||||
<ul class="pf-c-list" id="permmissions">
|
<ul class="pf-c-list" id="permmissions">
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { Challenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -11,12 +10,13 @@ import AKGlobal from "../../../authentik.css";
|
||||||
import { BaseStage } from "../base";
|
import { BaseStage } from "../base";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import "../../FormStatic";
|
import "../../FormStatic";
|
||||||
|
import { DummyChallenge } from "authentik-api";
|
||||||
|
|
||||||
@customElement("ak-stage-dummy")
|
@customElement("ak-stage-dummy")
|
||||||
export class DummyStage extends BaseStage {
|
export class DummyStage extends BaseStage {
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
challenge?: Challenge;
|
challenge?: DummyChallenge;
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];
|
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { Challenge } from "authentik-api";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -10,8 +9,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import AKGlobal from "../../../authentik.css";
|
import AKGlobal from "../../../authentik.css";
|
||||||
import { BaseStage } from "../base";
|
import { BaseStage } from "../base";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
|
import { EmailChallenge } from "authentik-api";
|
||||||
export type EmailChallenge = Challenge;
|
|
||||||
|
|
||||||
@customElement("ak-stage-email")
|
@customElement("ak-stage-email")
|
||||||
export class EmailStage extends BaseStage {
|
export class EmailStage extends BaseStage {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import AKGlobal from "../../../authentik.css";
|
import AKGlobal from "../../../authentik.css";
|
||||||
import "../../../elements/forms/FormElement";
|
import "../../../elements/forms/FormElement";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import { Challenge } from "../../../api/Flows";
|
import { IdentificationChallenge, UILoginButton } from "authentik-api";
|
||||||
|
|
||||||
export const PasswordManagerPrefill: {
|
export const PasswordManagerPrefill: {
|
||||||
password: string | undefined;
|
password: string | undefined;
|
||||||
|
@ -20,24 +20,6 @@ export const PasswordManagerPrefill: {
|
||||||
totp: undefined,
|
totp: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IdentificationChallenge extends Challenge {
|
|
||||||
|
|
||||||
user_fields?: string[];
|
|
||||||
primary_action: string;
|
|
||||||
sources?: UILoginButton[];
|
|
||||||
|
|
||||||
application_pre?: string;
|
|
||||||
|
|
||||||
enroll_url?: string;
|
|
||||||
recovery_url?: string;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UILoginButton {
|
|
||||||
name: string;
|
|
||||||
challenge: Challenge;
|
|
||||||
icon_url?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-identification")
|
@customElement("ak-stage-identification")
|
||||||
export class IdentificationStage extends BaseStage {
|
export class IdentificationStage extends BaseStage {
|
||||||
|
@ -131,8 +113,8 @@ export class IdentificationStage extends BaseStage {
|
||||||
|
|
||||||
renderSource(source: UILoginButton): TemplateResult {
|
renderSource(source: UILoginButton): TemplateResult {
|
||||||
let icon = html`<i class="fas fas fa-share-square" title="${source.name}"></i>`;
|
let icon = html`<i class="fas fas fa-share-square" title="${source.name}"></i>`;
|
||||||
if (source.icon_url) {
|
if (source.iconUrl) {
|
||||||
icon = html`<img src="${source.icon_url}" alt="${source.name}">`;
|
icon = html`<img src="${source.iconUrl}" alt="${source.name}">`;
|
||||||
}
|
}
|
||||||
return html`<li class="pf-c-login__main-footer-links-item">
|
return html`<li class="pf-c-login__main-footer-links-item">
|
||||||
<button type="button" @click=${() => {
|
<button type="button" @click=${() => {
|
||||||
|
@ -145,18 +127,18 @@ export class IdentificationStage extends BaseStage {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderFooter(): TemplateResult {
|
renderFooter(): TemplateResult {
|
||||||
if (!this.challenge?.enroll_url && !this.challenge?.recovery_url) {
|
if (!this.challenge?.enrollUrl && !this.challenge?.recoveryUrl) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
return html`<div class="pf-c-login__main-footer-band">
|
return html`<div class="pf-c-login__main-footer-band">
|
||||||
${this.challenge.enroll_url ? html`
|
${this.challenge.enrollUrl ? html`
|
||||||
<p class="pf-c-login__main-footer-band-item">
|
<p class="pf-c-login__main-footer-band-item">
|
||||||
${t`Need an account?`}
|
${t`Need an account?`}
|
||||||
<a id="enroll" href="${this.challenge.enroll_url}">${t`Sign up.`}</a>
|
<a id="enroll" href="${this.challenge.enrollUrl}">${t`Sign up.`}</a>
|
||||||
</p>` : html``}
|
</p>` : html``}
|
||||||
${this.challenge.recovery_url ? html`
|
${this.challenge.recoveryUrl ? html`
|
||||||
<p class="pf-c-login__main-footer-band-item">
|
<p class="pf-c-login__main-footer-band-item">
|
||||||
<a id="recovery" href="${this.challenge.recovery_url}">${t`Forgot username or password?`}</a>
|
<a id="recovery" href="${this.challenge.recoveryUrl}">${t`Forgot username or password?`}</a>
|
||||||
</p>` : html``}
|
</p>` : html``}
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
@ -164,15 +146,15 @@ export class IdentificationStage extends BaseStage {
|
||||||
renderInput(): TemplateResult {
|
renderInput(): TemplateResult {
|
||||||
let label = "";
|
let label = "";
|
||||||
let type = "text";
|
let type = "text";
|
||||||
if (!this.challenge?.user_fields) {
|
if (!this.challenge?.userFields) {
|
||||||
return html`<p>
|
return html`<p>
|
||||||
${t`Select one of the sources below to login.`}
|
${t`Select one of the sources below to login.`}
|
||||||
</p>`;
|
</p>`;
|
||||||
}
|
}
|
||||||
if (this.challenge?.user_fields === ["email"]) {
|
if (this.challenge?.userFields === ["email"]) {
|
||||||
label = t`Email`;
|
label = t`Email`;
|
||||||
type = "email";
|
type = "email";
|
||||||
} else if (this.challenge?.user_fields === ["username"]) {
|
} else if (this.challenge?.userFields === ["username"]) {
|
||||||
label = t`Username`;
|
label = t`Username`;
|
||||||
} else {
|
} else {
|
||||||
label = t`Email or username`;
|
label = t`Email or username`;
|
||||||
|
@ -181,10 +163,10 @@ export class IdentificationStage extends BaseStage {
|
||||||
label=${label}
|
label=${label}
|
||||||
?required="${true}"
|
?required="${true}"
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
.errors=${(this.challenge?.response_errors || {})["uid_field"]}>
|
.errors=${(this.challenge?.responseErrors || {})["uidField"]}>
|
||||||
<!-- @ts-ignore -->
|
<!-- @ts-ignore -->
|
||||||
<input type=${type}
|
<input type=${type}
|
||||||
name="uid_field"
|
name="uidField"
|
||||||
placeholder="Email or Username"
|
placeholder="Email or Username"
|
||||||
autofocus=""
|
autofocus=""
|
||||||
autocomplete="username"
|
autocomplete="username"
|
||||||
|
@ -193,7 +175,7 @@ export class IdentificationStage extends BaseStage {
|
||||||
</ak-form-element>
|
</ak-form-element>
|
||||||
<div class="pf-c-form__group pf-m-action">
|
<div class="pf-c-form__group pf-m-action">
|
||||||
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
||||||
${this.challenge.primary_action}
|
${this.challenge.primaryAction}
|
||||||
</button>
|
</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
@ -212,9 +194,9 @@ export class IdentificationStage extends BaseStage {
|
||||||
</header>
|
</header>
|
||||||
<div class="pf-c-login__main-body">
|
<div class="pf-c-login__main-body">
|
||||||
<form class="pf-c-form" @submit=${(e: Event) => {this.submitForm(e);}}>
|
<form class="pf-c-form" @submit=${(e: Event) => {this.submitForm(e);}}>
|
||||||
${this.challenge.application_pre ?
|
${this.challenge.applicationPre ?
|
||||||
html`<p>
|
html`<p>
|
||||||
${t`Login to continue to ${this.challenge.application_pre}.`}
|
${t`Login to continue to ${this.challenge.applicationPre}.`}
|
||||||
</p>`:
|
</p>`:
|
||||||
html``}
|
html``}
|
||||||
${this.renderInput()}
|
${this.renderInput()}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { WithUserInfoChallenge } from "../../../api/Flows";
|
|
||||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
@ -14,10 +13,7 @@ import "../../../elements/EmptyState";
|
||||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
|
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
|
||||||
import "../../FormStatic";
|
import "../../FormStatic";
|
||||||
import { FlowURLManager } from "../../../api/legacy";
|
import { FlowURLManager } from "../../../api/legacy";
|
||||||
|
import { PasswordChallenge } from "authentik-api";
|
||||||
export interface PasswordChallenge extends WithUserInfoChallenge {
|
|
||||||
recovery_url?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-password")
|
@customElement("ak-stage-password")
|
||||||
export class PasswordStage extends BaseStage {
|
export class PasswordStage extends BaseStage {
|
||||||
|
@ -45,18 +41,18 @@ export class PasswordStage extends BaseStage {
|
||||||
<form class="pf-c-form" @submit=${(e: Event) => {this.submitForm(e);}}>
|
<form class="pf-c-form" @submit=${(e: Event) => {this.submitForm(e);}}>
|
||||||
<ak-form-static
|
<ak-form-static
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
userAvatar="${this.challenge.pending_user_avatar}"
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
user=${this.challenge.pending_user}>
|
user=${this.challenge.pendingUser}>
|
||||||
<div slot="link">
|
<div slot="link">
|
||||||
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
<a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-static>
|
</ak-form-static>
|
||||||
<input name="username" autocomplete="username" type="hidden" value="${this.challenge.pending_user}">
|
<input name="username" autocomplete="username" type="hidden" value="${this.challenge.pendingUser}">
|
||||||
<ak-form-element
|
<ak-form-element
|
||||||
label="${t`Password`}"
|
label="${t`Password`}"
|
||||||
?required="${true}"
|
?required="${true}"
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
.errors=${(this.challenge?.response_errors || {})["password"]}>
|
.errors=${(this.challenge?.responseErrors || {})["password"]}>
|
||||||
<input type="password"
|
<input type="password"
|
||||||
name="password"
|
name="password"
|
||||||
placeholder="${t`Please enter your password`}"
|
placeholder="${t`Please enter your password`}"
|
||||||
|
@ -67,8 +63,8 @@ export class PasswordStage extends BaseStage {
|
||||||
value=${PasswordManagerPrefill.password || ""}>
|
value=${PasswordManagerPrefill.password || ""}>
|
||||||
</ak-form-element>
|
</ak-form-element>
|
||||||
|
|
||||||
${this.challenge.recovery_url ?
|
${this.challenge.recoveryUrl ?
|
||||||
html`<a href="${this.challenge.recovery_url}">
|
html`<a href="${this.challenge.recoveryUrl}">
|
||||||
${t`Forgot password?`}</a>` : ""}
|
${t`Forgot password?`}</a>` : ""}
|
||||||
|
|
||||||
<div class="pf-c-form__group pf-m-action">
|
<div class="pf-c-form__group pf-m-action">
|
||||||
|
|
|
@ -13,20 +13,9 @@ import { BaseStage } from "../base";
|
||||||
import "../../../elements/forms/FormElement";
|
import "../../../elements/forms/FormElement";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import "../../../elements/Divider";
|
import "../../../elements/Divider";
|
||||||
import { Challenge, Error } from "../../../api/Flows";
|
import { Error } from "../../../api/Flows";
|
||||||
|
import { Prompt, PromptChallenge } from "authentik-api";
|
||||||
|
|
||||||
export interface Prompt {
|
|
||||||
field_key: string;
|
|
||||||
label: string;
|
|
||||||
type: string;
|
|
||||||
required: boolean;
|
|
||||||
placeholder: string;
|
|
||||||
order: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PromptChallenge extends Challenge {
|
|
||||||
fields: Prompt[];
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-prompt")
|
@customElement("ak-stage-prompt")
|
||||||
export class PromptStage extends BaseStage {
|
export class PromptStage extends BaseStage {
|
||||||
|
@ -43,7 +32,7 @@ export class PromptStage extends BaseStage {
|
||||||
case "text":
|
case "text":
|
||||||
return `<input
|
return `<input
|
||||||
type="text"
|
type="text"
|
||||||
name="${prompt.field_key}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
|
@ -52,7 +41,7 @@ export class PromptStage extends BaseStage {
|
||||||
case "username":
|
case "username":
|
||||||
return `<input
|
return `<input
|
||||||
type="text"
|
type="text"
|
||||||
name="${prompt.field_key}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
autocomplete="username"
|
autocomplete="username"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
|
@ -61,7 +50,7 @@ export class PromptStage extends BaseStage {
|
||||||
case "email":
|
case "email":
|
||||||
return `<input
|
return `<input
|
||||||
type="email"
|
type="email"
|
||||||
name="${prompt.field_key}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}
|
?required=${prompt.required}
|
||||||
|
@ -69,7 +58,7 @@ export class PromptStage extends BaseStage {
|
||||||
case "password":
|
case "password":
|
||||||
return `<input
|
return `<input
|
||||||
type="password"
|
type="password"
|
||||||
name="${prompt.field_key}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
|
@ -77,28 +66,28 @@ export class PromptStage extends BaseStage {
|
||||||
case "number":
|
case "number":
|
||||||
return `<input
|
return `<input
|
||||||
type="number"
|
type="number"
|
||||||
name="${prompt.field_key}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}>`;
|
?required=${prompt.required}>`;
|
||||||
case "checkbox":
|
case "checkbox":
|
||||||
return `<input
|
return `<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="${prompt.field_key}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}>`;
|
?required=${prompt.required}>`;
|
||||||
case "date":
|
case "date":
|
||||||
return `<input
|
return `<input
|
||||||
type="date"
|
type="date"
|
||||||
name="${prompt.field_key}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}>`;
|
?required=${prompt.required}>`;
|
||||||
case "date-time":
|
case "date-time":
|
||||||
return `<input
|
return `<input
|
||||||
type="datetime"
|
type="datetime"
|
||||||
name="${prompt.field_key}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}>`;
|
?required=${prompt.required}>`;
|
||||||
|
@ -107,7 +96,7 @@ export class PromptStage extends BaseStage {
|
||||||
case "hidden":
|
case "hidden":
|
||||||
return `<input
|
return `<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
name="${prompt.field_key}"
|
name="${prompt.fieldKey}"
|
||||||
value="${prompt.placeholder}"
|
value="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}>`;
|
?required=${prompt.required}>`;
|
||||||
|
@ -158,12 +147,12 @@ export class PromptStage extends BaseStage {
|
||||||
label="${prompt.label}"
|
label="${prompt.label}"
|
||||||
?required="${prompt.required}"
|
?required="${prompt.required}"
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
.errors=${(this.challenge?.response_errors || {})[prompt.field_key]}>
|
.errors=${(this.challenge?.responseErrors || {})[prompt.fieldKey]}>
|
||||||
${unsafeHTML(this.renderPromptInner(prompt))}
|
${unsafeHTML(this.renderPromptInner(prompt))}
|
||||||
</ak-form-element>`;
|
</ak-form-element>`;
|
||||||
})}
|
})}
|
||||||
${"non_field_errors" in (this.challenge?.response_errors || {}) ?
|
${"non_field_errors" in (this.challenge?.responseErrors || {}) ?
|
||||||
this.renderNonFieldErrors(this.challenge?.response_errors?.non_field_errors || []):
|
this.renderNonFieldErrors(this.challenge?.responseErrors?.non_field_errors || []):
|
||||||
html``}
|
html``}
|
||||||
<div class="pf-c-form__group pf-m-action">
|
<div class="pf-c-form__group pf-m-action">
|
||||||
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
||||||
|
|
|
@ -63,6 +63,10 @@ msgstr "ANY, any policy must match to grant access."
|
||||||
msgid "ANY, any policy must match to include this stage access."
|
msgid "ANY, any policy must match to include this stage access."
|
||||||
msgstr "ANY, any policy must match to include this stage access."
|
msgstr "ANY, any policy must match to include this stage access."
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
msgid "API Hostname"
|
||||||
|
msgstr "API Hostname"
|
||||||
|
|
||||||
#: src/elements/notifications/APIDrawer.ts
|
#: src/elements/notifications/APIDrawer.ts
|
||||||
msgid "API Requests"
|
msgid "API Requests"
|
||||||
msgstr "API Requests"
|
msgstr "API Requests"
|
||||||
|
@ -180,6 +184,10 @@ msgstr "Allows/denys requests based on the users and/or the IPs reputation."
|
||||||
msgid "Also known as Entity ID. Defaults the Metadata URL."
|
msgid "Also known as Entity ID. Defaults the Metadata URL."
|
||||||
msgstr "Also known as Entity ID. Defaults the Metadata URL."
|
msgstr "Also known as Entity ID. Defaults the Metadata URL."
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
|
msgid "Alternatively, if your current device has Duo installed, click on this link:"
|
||||||
|
msgstr "Alternatively, if your current device has Duo installed, click on this link:"
|
||||||
|
|
||||||
#: src/pages/stages/consent/ConsentStageForm.ts
|
#: src/pages/stages/consent/ConsentStageForm.ts
|
||||||
msgid "Always require consent"
|
msgid "Always require consent"
|
||||||
msgstr "Always require consent"
|
msgstr "Always require consent"
|
||||||
|
@ -522,6 +530,10 @@ msgstr "Check IP"
|
||||||
msgid "Check Username"
|
msgid "Check Username"
|
||||||
msgstr "Check Username"
|
msgstr "Check Username"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
|
msgid "Check status"
|
||||||
|
msgstr "Check status"
|
||||||
|
|
||||||
#: src/flows/stages/email/EmailStage.ts
|
#: src/flows/stages/email/EmailStage.ts
|
||||||
msgid "Check your Emails for a password reset link."
|
msgid "Check your Emails for a password reset link."
|
||||||
msgstr "Check your Emails for a password reset link."
|
msgstr "Check your Emails for a password reset link."
|
||||||
|
@ -572,6 +584,7 @@ msgstr "Click to copy token"
|
||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
|
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
|
||||||
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
|
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
|
||||||
#: src/pages/sources/plex/PlexSourceForm.ts
|
#: src/pages/sources/plex/PlexSourceForm.ts
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
msgid "Client ID"
|
msgid "Client ID"
|
||||||
msgstr "Client ID"
|
msgstr "Client ID"
|
||||||
|
|
||||||
|
@ -583,6 +596,7 @@ msgid "Client IP"
|
||||||
msgstr "Client IP"
|
msgstr "Client IP"
|
||||||
|
|
||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
|
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
msgid "Client Secret"
|
msgid "Client Secret"
|
||||||
msgstr "Client Secret"
|
msgstr "Client Secret"
|
||||||
|
|
||||||
|
@ -616,6 +630,7 @@ msgstr "Confidential clients are capable of maintaining the confidentiality of t
|
||||||
msgid "Configuration"
|
msgid "Configuration"
|
||||||
msgstr "Configuration"
|
msgstr "Configuration"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -715,6 +730,7 @@ msgstr "Context"
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageDuo.ts
|
||||||
#: src/flows/stages/autosubmit/AutosubmitStage.ts
|
#: src/flows/stages/autosubmit/AutosubmitStage.ts
|
||||||
#: src/flows/stages/consent/ConsentStage.ts
|
#: src/flows/stages/consent/ConsentStage.ts
|
||||||
#: src/flows/stages/dummy/DummyStage.ts
|
#: src/flows/stages/dummy/DummyStage.ts
|
||||||
|
@ -1010,6 +1026,10 @@ msgstr "Determines how authentik sends the response back to the Service Provider
|
||||||
msgid "Determines how long a session lasts. Default of 0 seconds means that the sessions lasts until the browser is closed."
|
msgid "Determines how long a session lasts. Default of 0 seconds means that the sessions lasts until the browser is closed."
|
||||||
msgstr "Determines how long a session lasts. Default of 0 seconds means that the sessions lasts until the browser is closed."
|
msgstr "Determines how long a session lasts. Default of 0 seconds means that the sessions lasts until the browser is closed."
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
msgid "Device classes"
|
||||||
|
msgstr "Device classes"
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
msgid "Device classes which can be used to authenticate."
|
msgid "Device classes which can be used to authenticate."
|
||||||
msgstr "Device classes which can be used to authenticate."
|
msgstr "Device classes which can be used to authenticate."
|
||||||
|
@ -1032,6 +1052,7 @@ msgstr "Digits"
|
||||||
msgid "Disable"
|
msgid "Disable"
|
||||||
msgstr "Disable"
|
msgstr "Disable"
|
||||||
|
|
||||||
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts
|
||||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
||||||
msgid "Disable Static Tokens"
|
msgid "Disable Static Tokens"
|
||||||
msgstr "Disable Static Tokens"
|
msgstr "Disable Static Tokens"
|
||||||
|
@ -1070,6 +1091,22 @@ msgstr "Download Private key"
|
||||||
msgid "Dummy stage used for testing. Shows a simple continue button and always passes."
|
msgid "Dummy stage used for testing. Shows a simple continue button and always passes."
|
||||||
msgstr "Dummy stage used for testing. Shows a simple continue button and always passes."
|
msgstr "Dummy stage used for testing. Shows a simple continue button and always passes."
|
||||||
|
|
||||||
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts
|
||||||
|
msgid "Duo"
|
||||||
|
msgstr "Duo"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
msgid "Duo Authenticators"
|
||||||
|
msgstr "Duo Authenticators"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
|
msgid "Duo activation"
|
||||||
|
msgstr "Duo activation"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
msgid "Duo push-notifications"
|
||||||
|
msgstr "Duo push-notifications"
|
||||||
|
|
||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
|
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
|
||||||
msgid "Each provider has a different issuer, based on the application slug."
|
msgid "Each provider has a different issuer, based on the application slug."
|
||||||
msgstr "Each provider has a different issuer, based on the application slug."
|
msgstr "Each provider has a different issuer, based on the application slug."
|
||||||
|
@ -1159,6 +1196,7 @@ msgstr "Enable"
|
||||||
msgid "Enable StartTLS"
|
msgid "Enable StartTLS"
|
||||||
msgstr "Enable StartTLS"
|
msgstr "Enable StartTLS"
|
||||||
|
|
||||||
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts
|
||||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
||||||
msgid "Enable Static Tokens"
|
msgid "Enable Static Tokens"
|
||||||
msgstr "Enable Static Tokens"
|
msgstr "Enable Static Tokens"
|
||||||
|
@ -1431,6 +1469,7 @@ msgstr "Flow used before authentication."
|
||||||
msgid "Flow used by an authenticated user to configure their password. If empty, user will not be able to configure change their password."
|
msgid "Flow used by an authenticated user to configure their password. If empty, user will not be able to configure change their password."
|
||||||
msgstr "Flow used by an authenticated user to configure their password. If empty, user will not be able to configure change their password."
|
msgstr "Flow used by an authenticated user to configure their password. If empty, user will not be able to configure change their password."
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
||||||
|
@ -1803,10 +1842,12 @@ msgstr "Load servers"
|
||||||
#: src/flows/FlowExecutor.ts
|
#: src/flows/FlowExecutor.ts
|
||||||
#: src/flows/FlowExecutor.ts
|
#: src/flows/FlowExecutor.ts
|
||||||
#: src/flows/access_denied/FlowAccessDenied.ts
|
#: src/flows/access_denied/FlowAccessDenied.ts
|
||||||
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageDuo.ts
|
||||||
#: src/flows/stages/autosubmit/AutosubmitStage.ts
|
#: src/flows/stages/autosubmit/AutosubmitStage.ts
|
||||||
#: src/flows/stages/captcha/CaptchaStage.ts
|
#: src/flows/stages/captcha/CaptchaStage.ts
|
||||||
#: src/flows/stages/consent/ConsentStage.ts
|
#: src/flows/stages/consent/ConsentStage.ts
|
||||||
|
@ -1866,6 +1907,7 @@ msgstr "Loading"
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -2041,6 +2083,7 @@ msgstr "My Applications"
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
#: src/pages/sources/saml/SAMLSourceViewPage.ts
|
#: src/pages/sources/saml/SAMLSourceViewPage.ts
|
||||||
#: src/pages/stages/StageListPage.ts
|
#: src/pages/stages/StageListPage.ts
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -2173,9 +2216,11 @@ msgstr "Not found"
|
||||||
msgid "Not synced yet."
|
msgid "Not synced yet."
|
||||||
msgstr "Not synced yet."
|
msgstr "Not synced yet."
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageDuo.ts
|
||||||
#: src/flows/stages/captcha/CaptchaStage.ts
|
#: src/flows/stages/captcha/CaptchaStage.ts
|
||||||
#: src/flows/stages/consent/ConsentStage.ts
|
#: src/flows/stages/consent/ConsentStage.ts
|
||||||
#: src/flows/stages/password/PasswordStage.ts
|
#: src/flows/stages/password/PasswordStage.ts
|
||||||
|
@ -2617,6 +2662,10 @@ msgstr "RSA-SHA512"
|
||||||
msgid "Re-evaluate policies"
|
msgid "Re-evaluate policies"
|
||||||
msgstr "Re-evaluate policies"
|
msgstr "Re-evaluate policies"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
msgid "Receive a push notification on your phone to prove your identity."
|
||||||
|
msgstr "Receive a push notification on your phone to prove your identity."
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/FlowForm.ts
|
||||||
msgid "Recovery"
|
msgid "Recovery"
|
||||||
msgstr "Recovery"
|
msgstr "Recovery"
|
||||||
|
@ -2728,6 +2777,7 @@ msgid "Return home"
|
||||||
msgstr "Return home"
|
msgstr "Return home"
|
||||||
|
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageDuo.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts
|
||||||
msgid "Return to device picker"
|
msgid "Return to device picker"
|
||||||
msgstr "Return to device picker"
|
msgstr "Return to device picker"
|
||||||
|
@ -3033,6 +3083,10 @@ msgstr "Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenti
|
||||||
msgid "Stage used to configure a WebAutnn authenticator (i.e. Yubikey, FaceID/Windows Hello)."
|
msgid "Stage used to configure a WebAutnn authenticator (i.e. Yubikey, FaceID/Windows Hello)."
|
||||||
msgstr "Stage used to configure a WebAutnn authenticator (i.e. Yubikey, FaceID/Windows Hello)."
|
msgstr "Stage used to configure a WebAutnn authenticator (i.e. Yubikey, FaceID/Windows Hello)."
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
msgid "Stage used to configure a duo-based authenticator. This stage should be used for configuration flows."
|
||||||
|
msgstr "Stage used to configure a duo-based authenticator. This stage should be used for configuration flows."
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
||||||
msgstr "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
msgstr "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
||||||
|
@ -3041,6 +3095,7 @@ msgstr "Stage used to configure a static authenticator (i.e. static tokens). Thi
|
||||||
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
||||||
msgstr "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
msgstr "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -3074,7 +3129,7 @@ msgstr "State"
|
||||||
msgid "Static Tokens"
|
msgid "Static Tokens"
|
||||||
msgstr "Static Tokens"
|
msgstr "Static Tokens"
|
||||||
|
|
||||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
||||||
msgid "Static tokens"
|
msgid "Static tokens"
|
||||||
msgstr "Static tokens"
|
msgstr "Static tokens"
|
||||||
|
|
||||||
|
@ -3090,11 +3145,13 @@ msgstr "Statically deny the flow. To use this stage effectively, disable *Evalua
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts
|
||||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
||||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts
|
||||||
msgid "Status: Disabled"
|
msgid "Status: Disabled"
|
||||||
msgstr "Status: Disabled"
|
msgstr "Status: Disabled"
|
||||||
|
|
||||||
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorDuo.ts
|
||||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
||||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts
|
||||||
msgid "Status: Enabled"
|
msgid "Status: Enabled"
|
||||||
|
@ -3204,6 +3261,7 @@ msgstr "Successfully created service-connection."
|
||||||
msgid "Successfully created source."
|
msgid "Successfully created source."
|
||||||
msgstr "Successfully created source."
|
msgstr "Successfully created source."
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -3342,6 +3400,7 @@ msgstr "Successfully updated service-connection."
|
||||||
msgid "Successfully updated source."
|
msgid "Successfully updated source."
|
||||||
msgstr "Successfully updated source."
|
msgstr "Successfully updated source."
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -3533,7 +3592,7 @@ msgstr "Time in minutes the token sent is valid."
|
||||||
msgid "Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. (Format: hours=1;minutes=2;seconds=3)."
|
msgid "Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. (Format: hours=1;minutes=2;seconds=3)."
|
||||||
msgstr "Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. (Format: hours=1;minutes=2;seconds=3)."
|
msgstr "Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. (Format: hours=1;minutes=2;seconds=3)."
|
||||||
|
|
||||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorStatic.ts
|
#: src/pages/user-settings/settings/UserSettingsAuthenticatorTOTP.ts
|
||||||
msgid "Time-based One-Time Passwords"
|
msgid "Time-based One-Time Passwords"
|
||||||
msgstr "Time-based One-Time Passwords"
|
msgstr "Time-based One-Time Passwords"
|
||||||
|
|
||||||
|
@ -3893,7 +3952,6 @@ msgstr "User details"
|
||||||
msgid "User events"
|
msgid "User events"
|
||||||
msgstr "User events"
|
msgstr "User events"
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
|
||||||
#: src/pages/stages/identification/IdentificationStageForm.ts
|
#: src/pages/stages/identification/IdentificationStageForm.ts
|
||||||
msgid "User fields"
|
msgid "User fields"
|
||||||
msgstr "User fields"
|
msgstr "User fields"
|
||||||
|
|
|
@ -63,6 +63,10 @@ msgstr ""
|
||||||
msgid "ANY, any policy must match to include this stage access."
|
msgid "ANY, any policy must match to include this stage access."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "API Hostname"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "API Requests"
|
msgid "API Requests"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -180,6 +184,10 @@ msgstr ""
|
||||||
msgid "Also known as Entity ID. Defaults the Metadata URL."
|
msgid "Also known as Entity ID. Defaults the Metadata URL."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Alternatively, if your current device has Duo installed, click on this link:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "Always require consent"
|
msgid "Always require consent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -518,6 +526,10 @@ msgstr ""
|
||||||
msgid "Check Username"
|
msgid "Check Username"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Check status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "Check your Emails for a password reset link."
|
msgid "Check your Emails for a password reset link."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -566,6 +578,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Client ID"
|
msgid "Client ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -576,6 +589,7 @@ msgstr ""
|
||||||
msgid "Client IP"
|
msgid "Client IP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Client Secret"
|
msgid "Client Secret"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -614,6 +628,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Configuration flow"
|
msgid "Configuration flow"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -715,6 +730,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Continue"
|
msgid "Continue"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1002,6 +1018,10 @@ msgstr ""
|
||||||
msgid "Determines how long a session lasts. Default of 0 seconds means that the sessions lasts until the browser is closed."
|
msgid "Determines how long a session lasts. Default of 0 seconds means that the sessions lasts until the browser is closed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Device classes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "Device classes which can be used to authenticate."
|
msgid "Device classes which can be used to authenticate."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1024,6 +1044,7 @@ msgstr ""
|
||||||
msgid "Disable"
|
msgid "Disable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Disable Static Tokens"
|
msgid "Disable Static Tokens"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1062,6 +1083,22 @@ msgstr ""
|
||||||
msgid "Dummy stage used for testing. Shows a simple continue button and always passes."
|
msgid "Dummy stage used for testing. Shows a simple continue button and always passes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Duo"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Duo Authenticators"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Duo activation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Duo push-notifications"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "Each provider has a different issuer, based on the application slug."
|
msgid "Each provider has a different issuer, based on the application slug."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1151,6 +1188,7 @@ msgstr ""
|
||||||
msgid "Enable StartTLS"
|
msgid "Enable StartTLS"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Enable Static Tokens"
|
msgid "Enable Static Tokens"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1423,6 +1461,7 @@ msgstr ""
|
||||||
msgid "Flow used by an authenticated user to configure their password. If empty, user will not be able to configure change their password."
|
msgid "Flow used by an authenticated user to configure their password. If empty, user will not be able to configure change their password."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
||||||
|
@ -1811,6 +1850,8 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
|
#:
|
||||||
msgid "Loading"
|
msgid "Loading"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1867,6 +1908,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Loading..."
|
msgid "Loading..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -2054,6 +2096,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -2171,6 +2214,8 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
|
#:
|
||||||
msgid "Not you?"
|
msgid "Not you?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -2609,6 +2654,10 @@ msgstr ""
|
||||||
msgid "Re-evaluate policies"
|
msgid "Re-evaluate policies"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Receive a push notification on your phone to prove your identity."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "Recovery"
|
msgid "Recovery"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2719,6 +2768,7 @@ msgstr ""
|
||||||
msgid "Return home"
|
msgid "Return home"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Return to device picker"
|
msgid "Return to device picker"
|
||||||
|
@ -3025,6 +3075,10 @@ msgstr ""
|
||||||
msgid "Stage used to configure a WebAutnn authenticator (i.e. Yubikey, FaceID/Windows Hello)."
|
msgid "Stage used to configure a WebAutnn authenticator (i.e. Yubikey, FaceID/Windows Hello)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Stage used to configure a duo-based authenticator. This stage should be used for configuration flows."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -3044,6 +3098,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Stage-specific settings"
|
msgid "Stage-specific settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3082,11 +3137,13 @@ msgstr ""
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Status: Disabled"
|
msgid "Status: Disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
msgid "Status: Enabled"
|
msgid "Status: Enabled"
|
||||||
|
@ -3213,6 +3270,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Successfully created stage."
|
msgid "Successfully created stage."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3351,6 +3409,7 @@ msgstr ""
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
#:
|
#:
|
||||||
|
#:
|
||||||
msgid "Successfully updated stage."
|
msgid "Successfully updated stage."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3881,7 +3940,6 @@ msgstr ""
|
||||||
msgid "User events"
|
msgid "User events"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#:
|
|
||||||
#:
|
#:
|
||||||
msgid "User fields"
|
msgid "User fields"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
Reference in a new issue