flows: remove stage challenge type (#10476)

* flows: remove stage challenge type

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* improve coverage

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L
2024-07-13 18:37:29 +02:00
committed by GitHub
parent 8f7fe8e744
commit 8db1d86c6b
46 changed files with 75 additions and 255 deletions

View File

@ -8,7 +8,6 @@ from django.views import View
from authentik.core.models import Application from authentik.core.models import Application
from authentik.flows.challenge import ( from authentik.flows.challenge import (
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
HttpChallengeResponse, HttpChallengeResponse,
RedirectChallenge, RedirectChallenge,
) )
@ -74,7 +73,6 @@ class RedirectToAppStage(ChallengeStageView):
raise Http404 raise Http404
return RedirectChallenge( return RedirectChallenge(
instance={ instance={
"type": ChallengeTypes.REDIRECT.value,
"to": launch, "to": launch,
} }
) )

View File

@ -32,14 +32,6 @@ class FlowLayout(models.TextChoices):
SIDEBAR_RIGHT = "sidebar_right" SIDEBAR_RIGHT = "sidebar_right"
class ChallengeTypes(Enum):
"""Currently defined challenge types"""
NATIVE = "native"
SHELL = "shell"
REDIRECT = "redirect"
class ErrorDetailSerializer(PassiveSerializer): class ErrorDetailSerializer(PassiveSerializer):
"""Serializer for rest_framework's error messages""" """Serializer for rest_framework's error messages"""
@ -60,9 +52,6 @@ class Challenge(PassiveSerializer):
"""Challenge that gets sent to the client based on which stage """Challenge that gets sent to the client based on which stage
is currently active""" is currently active"""
type = ChoiceField(
choices=[(x.value, x.name) for x in ChallengeTypes],
)
flow_info = ContextualFlowInfo(required=False) flow_info = ContextualFlowInfo(required=False)
component = CharField(default="") component = CharField(default="")
@ -96,7 +85,6 @@ class FlowErrorChallenge(Challenge):
"""Challenge class when an unhandled error occurs during a stage. Normal users """Challenge class when an unhandled error occurs during a stage. Normal users
are shown an error message, superusers are shown a full stacktrace.""" are shown an error message, superusers are shown a full stacktrace."""
type = CharField(default=ChallengeTypes.NATIVE.value)
component = CharField(default="ak-stage-flow-error") component = CharField(default="ak-stage-flow-error")
request_id = CharField() request_id = CharField()

View File

@ -18,7 +18,6 @@ from authentik.flows.challenge import (
AccessDeniedChallenge, AccessDeniedChallenge,
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
ContextualFlowInfo, ContextualFlowInfo,
HttpChallengeResponse, HttpChallengeResponse,
RedirectChallenge, RedirectChallenge,
@ -244,7 +243,6 @@ class AccessDeniedChallengeView(ChallengeStageView):
return AccessDeniedChallenge( return AccessDeniedChallenge(
data={ data={
"error_message": str(self.error_message or "Unknown error"), "error_message": str(self.error_message or "Unknown error"),
"type": ChallengeTypes.NATIVE.value,
"component": "ak-stage-access-denied", "component": "ak-stage-access-denied",
} }
) )
@ -264,7 +262,6 @@ class RedirectStage(ChallengeStageView):
) )
return RedirectChallenge( return RedirectChallenge(
data={ data={
"type": ChallengeTypes.REDIRECT.value,
"to": destination, "to": destination,
} }
) )

View File

@ -8,7 +8,6 @@ from django.urls.base import reverse
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from authentik.core.models import User from authentik.core.models import User
from authentik.flows.challenge import ChallengeTypes
from authentik.flows.models import Flow from authentik.flows.models import Flow
@ -26,7 +25,6 @@ class FlowTestCase(APITestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
raw_response = loads(response.content.decode()) raw_response = loads(response.content.decode())
self.assertIsNotNone(raw_response["component"]) self.assertIsNotNone(raw_response["component"])
self.assertIsNotNone(raw_response["type"])
if flow: if flow:
self.assertIn("flow_info", raw_response) self.assertIn("flow_info", raw_response)
self.assertEqual(raw_response["flow_info"]["background"], flow.background_url) self.assertEqual(raw_response["flow_info"]["background"], flow.background_url)
@ -46,6 +44,4 @@ class FlowTestCase(APITestCase):
def assertStageRedirects(self, response: HttpResponse, to: str) -> dict[str, Any]: def assertStageRedirects(self, response: HttpResponse, to: str) -> dict[str, Any]:
"""Wrapper around assertStageResponse that checks for a redirect""" """Wrapper around assertStageResponse that checks for a redirect"""
return self.assertStageResponse( return self.assertStageResponse(response, component="xak-flow-redirect", to=to)
response, component="xak-flow-redirect", to=to, type=ChallengeTypes.REDIRECT.value
)

View File

@ -2,7 +2,7 @@
from django.test import TestCase from django.test import TestCase
from authentik.flows.challenge import AutosubmitChallenge, ChallengeTypes from authentik.flows.challenge import AutosubmitChallenge
class TestChallenges(TestCase): class TestChallenges(TestCase):
@ -12,7 +12,6 @@ class TestChallenges(TestCase):
"""Test blank autosubmit""" """Test blank autosubmit"""
challenge = AutosubmitChallenge( challenge = AutosubmitChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"url": "http://localhost", "url": "http://localhost",
"attrs": {}, "attrs": {},
} }
@ -21,7 +20,6 @@ class TestChallenges(TestCase):
# Test with an empty value # Test with an empty value
challenge = AutosubmitChallenge( challenge = AutosubmitChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"url": "http://localhost", "url": "http://localhost",
"attrs": {"foo": ""}, "attrs": {"foo": ""},
} }

View File

@ -7,7 +7,6 @@ from django.urls.base import reverse
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.challenge import ChallengeTypes
from authentik.flows.models import FlowDesignation, FlowStageBinding, InvalidResponseAction from authentik.flows.models import FlowDesignation, FlowStageBinding, InvalidResponseAction
from authentik.stages.dummy.models import DummyStage from authentik.stages.dummy.models import DummyStage
from authentik.stages.identification.models import IdentificationStage, UserFields from authentik.stages.identification.models import IdentificationStage, UserFields
@ -54,7 +53,6 @@ class TestFlowInspector(APITestCase):
"layout": "stacked", "layout": "stacked",
}, },
"flow_designation": "authentication", "flow_designation": "authentication",
"type": ChallengeTypes.NATIVE.value,
"password_fields": False, "password_fields": False,
"primary_action": "Log in", "primary_action": "Log in",
"sources": [], "sources": [],

View File

@ -30,7 +30,6 @@ from authentik.flows.apps import HIST_FLOW_EXECUTION_STAGE_TIME
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
FlowErrorChallenge, FlowErrorChallenge,
HttpChallengeResponse, HttpChallengeResponse,
RedirectChallenge, RedirectChallenge,
@ -552,7 +551,6 @@ def to_stage_response(request: HttpRequest, source: HttpResponse) -> HttpRespons
return HttpChallengeResponse( return HttpChallengeResponse(
RedirectChallenge( RedirectChallenge(
{ {
"type": ChallengeTypes.REDIRECT,
"to": str(redirect_url), "to": str(redirect_url),
} }
) )
@ -561,7 +559,6 @@ def to_stage_response(request: HttpRequest, source: HttpResponse) -> HttpRespons
return HttpChallengeResponse( return HttpChallengeResponse(
ShellChallenge( ShellChallenge(
{ {
"type": ChallengeTypes.SHELL,
"body": source.render().content.decode("utf-8"), "body": source.render().content.decode("utf-8"),
} }
) )
@ -571,7 +568,6 @@ def to_stage_response(request: HttpRequest, source: HttpResponse) -> HttpRespons
return HttpChallengeResponse( return HttpChallengeResponse(
ShellChallenge( ShellChallenge(
{ {
"type": ChallengeTypes.SHELL,
"body": source.content.decode("utf-8"), "body": source.content.decode("utf-8"),
} }
) )

View File

@ -10,7 +10,6 @@ from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import Application from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.flows.challenge import ChallengeTypes
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
from authentik.lib.utils.time import timedelta_from_string from authentik.lib.utils.time import timedelta_from_string
from authentik.providers.oauth2.constants import TOKEN_TYPE from authentik.providers.oauth2.constants import TOKEN_TYPE
@ -327,7 +326,6 @@ class TestAuthorize(OAuthTestCase):
response.content.decode(), response.content.decode(),
{ {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": f"foo://localhost?code={code.code}&state={state}", "to": f"foo://localhost?code={code.code}&state={state}",
}, },
) )
@ -397,7 +395,6 @@ class TestAuthorize(OAuthTestCase):
response.content.decode(), response.content.decode(),
{ {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": ( "to": (
f"http://localhost#access_token={token.token}" f"http://localhost#access_token={token.token}"
f"&id_token={provider.encode(token.id_token.to_dict())}" f"&id_token={provider.encode(token.id_token.to_dict())}"
@ -460,7 +457,6 @@ class TestAuthorize(OAuthTestCase):
response.content.decode(), response.content.decode(),
{ {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": (f"http://localhost#code={code.code}" f"&state={state}"), "to": (f"http://localhost#code={code.code}" f"&state={state}"),
}, },
) )
@ -516,7 +512,6 @@ class TestAuthorize(OAuthTestCase):
response.content.decode(), response.content.decode(),
{ {
"component": "ak-stage-autosubmit", "component": "ak-stage-autosubmit",
"type": ChallengeTypes.NATIVE.value,
"url": "http://localhost", "url": "http://localhost",
"title": f"Redirecting to {app.name}...", "title": f"Redirecting to {app.name}...",
"attrs": { "attrs": {
@ -564,7 +559,6 @@ class TestAuthorize(OAuthTestCase):
response.content.decode(), response.content.decode(),
{ {
"component": "ak-stage-autosubmit", "component": "ak-stage-autosubmit",
"type": ChallengeTypes.NATIVE.value,
"url": "http://localhost", "url": "http://localhost",
"title": f"Redirecting to {app.name}...", "title": f"Redirecting to {app.name}...",
"attrs": { "attrs": {

View File

@ -8,7 +8,6 @@ from django.urls import reverse
from authentik.core.models import Application from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.challenge import ChallengeTypes
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
from authentik.providers.oauth2.constants import GRANT_TYPE_AUTHORIZATION_CODE from authentik.providers.oauth2.constants import GRANT_TYPE_AUTHORIZATION_CODE
from authentik.providers.oauth2.models import AuthorizationCode, OAuth2Provider from authentik.providers.oauth2.models import AuthorizationCode, OAuth2Provider
@ -60,7 +59,6 @@ class TestTokenPKCE(OAuthTestCase):
response.content.decode(), response.content.decode(),
{ {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": f"foo://localhost?code={code.code}&state={state}", "to": f"foo://localhost?code={code.code}&state={state}",
}, },
) )
@ -123,7 +121,6 @@ class TestTokenPKCE(OAuthTestCase):
response.content.decode(), response.content.decode(),
{ {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": f"foo://localhost?code={code.code}&state={state}", "to": f"foo://localhost?code={code.code}&state={state}",
}, },
) )
@ -191,7 +188,6 @@ class TestTokenPKCE(OAuthTestCase):
response.content.decode(), response.content.decode(),
{ {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": f"foo://localhost?code={code.code}&state={state}", "to": f"foo://localhost?code={code.code}&state={state}",
}, },
) )
@ -242,7 +238,6 @@ class TestTokenPKCE(OAuthTestCase):
response.content.decode(), response.content.decode(),
{ {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": f"foo://localhost?code={code.code}&state={state}", "to": f"foo://localhost?code={code.code}&state={state}",
}, },
) )

View File

@ -22,7 +22,6 @@ from authentik.events.signals import get_login_event
from authentik.flows.challenge import ( from authentik.flows.challenge import (
PLAN_CONTEXT_TITLE, PLAN_CONTEXT_TITLE,
AutosubmitChallenge, AutosubmitChallenge,
ChallengeTypes,
HttpChallengeResponse, HttpChallengeResponse,
) )
from authentik.flows.exceptions import FlowNonApplicableException from authentik.flows.exceptions import FlowNonApplicableException
@ -484,7 +483,6 @@ class OAuthFulfillmentStage(StageView):
challenge = AutosubmitChallenge( challenge = AutosubmitChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"component": "ak-stage-autosubmit", "component": "ak-stage-autosubmit",
"title": self.executor.plan.context.get( "title": self.executor.plan.context.get(
PLAN_CONTEXT_TITLE, PLAN_CONTEXT_TITLE,

View File

@ -3,7 +3,7 @@
from django.http import HttpResponse from django.http import HttpResponse
from rest_framework.fields import CharField from rest_framework.fields import CharField
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.flows.planner import FlowPlan from authentik.flows.planner import FlowPlan
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
from authentik.flows.views.executor import SESSION_KEY_PLAN from authentik.flows.views.executor import SESSION_KEY_PLAN
@ -38,7 +38,6 @@ class OAuthDeviceCodeFinishStage(ChallengeStageView):
token.save() token.save()
return OAuthDeviceCodeFinishChallenge( return OAuthDeviceCodeFinishChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"component": "ak-provider-oauth2-device-code-finish", "component": "ak-provider-oauth2-device-code-finish",
} }
) )

View File

@ -10,7 +10,7 @@ from structlog.stdlib import get_logger
from authentik.brands.models import Brand from authentik.brands.models import Brand
from authentik.core.models import Application from authentik.core.models import Application
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.flows.exceptions import FlowNonApplicableException from authentik.flows.exceptions import FlowNonApplicableException
from authentik.flows.models import in_memory_stage from authentik.flows.models import in_memory_stage
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_SSO, FlowPlanner from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_SSO, FlowPlanner
@ -141,7 +141,6 @@ class OAuthDeviceCodeStage(ChallengeStageView):
def get_challenge(self, *args, **kwargs) -> Challenge: def get_challenge(self, *args, **kwargs) -> Challenge:
return OAuthDeviceCodeChallenge( return OAuthDeviceCodeChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"component": "ak-provider-oauth2-device-code", "component": "ak-provider-oauth2-device-code",
} }
) )

View File

@ -16,7 +16,6 @@ from authentik.flows.challenge import (
AutoSubmitChallengeResponse, AutoSubmitChallengeResponse,
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
) )
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION from authentik.flows.planner import PLAN_CONTEXT_APPLICATION
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
@ -81,7 +80,6 @@ class SAMLFlowFinalView(ChallengeStageView):
return super().get( return super().get(
self.request, self.request,
**{ **{
"type": ChallengeTypes.NATIVE.value,
"component": "ak-stage-autosubmit", "component": "ak-stage-autosubmit",
"title": self.executor.plan.context.get( "title": self.executor.plan.context.get(
PLAN_CONTEXT_TITLE, PLAN_CONTEXT_TITLE,

View File

@ -148,7 +148,6 @@ SPECTACULAR_SETTINGS = {
}, },
"ENUM_NAME_OVERRIDES": { "ENUM_NAME_OVERRIDES": {
"EventActions": "authentik.events.models.EventAction", "EventActions": "authentik.events.models.EventAction",
"ChallengeChoices": "authentik.flows.challenge.ChallengeTypes",
"FlowDesignationEnum": "authentik.flows.models.FlowDesignation", "FlowDesignationEnum": "authentik.flows.models.FlowDesignation",
"FlowLayoutEnum": "authentik.flows.models.FlowLayout", "FlowLayoutEnum": "authentik.flows.models.FlowLayout",
"PolicyEngineMode": "authentik.policies.models.PolicyEngineMode", "PolicyEngineMode": "authentik.policies.models.PolicyEngineMode",

View File

@ -9,7 +9,7 @@ from jwt import decode, encode
from rest_framework.fields import CharField from rest_framework.fields import CharField
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.sources.oauth.clients.oauth2 import OAuth2Client from authentik.sources.oauth.clients.oauth2 import OAuth2Client
from authentik.sources.oauth.models import OAuthSource from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
@ -130,6 +130,5 @@ class AppleType(SourceType):
"scope": "name email", "scope": "name email",
"redirect_uri": args["redirect_uri"], "redirect_uri": args["redirect_uri"],
"state": args["state"], "state": args["state"],
"type": ChallengeTypes.NATIVE.value,
} }
) )

View File

@ -8,7 +8,7 @@ from django.templatetags.static import static
from django.urls.base import reverse from django.urls.base import reverse
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.flows.challenge import Challenge, ChallengeTypes, RedirectChallenge from authentik.flows.challenge import Challenge, RedirectChallenge
from authentik.sources.oauth.models import OAuthSource from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.views.callback import OAuthCallback from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -48,7 +48,6 @@ class SourceType:
"""Allow types to return custom challenges""" """Allow types to return custom challenges"""
return RedirectChallenge( return RedirectChallenge(
data={ data={
"type": ChallengeTypes.REDIRECT.value,
"to": reverse( "to": reverse(
"authentik_sources_oauth:oauth-client-login", "authentik_sources_oauth:oauth-client-login",
kwargs={"source_slug": source.slug}, kwargs={"source_slug": source.slug},

View File

@ -10,7 +10,7 @@ from rest_framework.serializers import BaseSerializer, Serializer
from authentik.core.models import Source, UserSourceConnection from authentik.core.models import Source, UserSourceConnection
from authentik.core.types import UILoginButton, UserSettingSerializer from authentik.core.types import UILoginButton, UserSettingSerializer
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
@ -71,7 +71,6 @@ class PlexSource(Source):
return UILoginButton( return UILoginButton(
challenge=PlexAuthenticationChallenge( challenge=PlexAuthenticationChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"component": "ak-source-plex", "component": "ak-source-plex",
"client_id": self.client_id, "client_id": self.client_id,
"slug": self.slug, "slug": self.slug,

View File

@ -10,7 +10,7 @@ from rest_framework.serializers import Serializer
from authentik.core.models import Source, UserSourceConnection from authentik.core.models import Source, UserSourceConnection
from authentik.core.types import UILoginButton, UserSettingSerializer from authentik.core.types import UILoginButton, UserSettingSerializer
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
from authentik.flows.challenge import ChallengeTypes, RedirectChallenge from authentik.flows.challenge import RedirectChallenge
from authentik.flows.models import Flow from authentik.flows.models import Flow
from authentik.lib.utils.time import timedelta_string_validator from authentik.lib.utils.time import timedelta_string_validator
from authentik.sources.saml.processors.constants import ( from authentik.sources.saml.processors.constants import (
@ -204,7 +204,6 @@ class SAMLSource(Source):
return UILoginButton( return UILoginButton(
challenge=RedirectChallenge( challenge=RedirectChallenge(
data={ data={
"type": ChallengeTypes.REDIRECT.value,
"to": reverse( "to": reverse(
"authentik_sources_saml:login", "authentik_sources_saml:login",
kwargs={"source_slug": self.slug}, kwargs={"source_slug": self.slug},

View File

@ -21,7 +21,6 @@ from authentik.flows.challenge import (
AutosubmitChallenge, AutosubmitChallenge,
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
) )
from authentik.flows.exceptions import FlowNonApplicableException from authentik.flows.exceptions import FlowNonApplicableException
from authentik.flows.models import in_memory_stage from authentik.flows.models import in_memory_stage
@ -52,7 +51,6 @@ class AutosubmitStageView(ChallengeStageView):
def get_challenge(self, *args, **kwargs) -> Challenge: def get_challenge(self, *args, **kwargs) -> Challenge:
return AutosubmitChallenge( return AutosubmitChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"component": "ak-stage-autosubmit", "component": "ak-stage-autosubmit",
"title": self.executor.plan.context.get(PLAN_CONTEXT_TITLE, ""), "title": self.executor.plan.context.get(PLAN_CONTEXT_TITLE, ""),
"url": self.executor.plan.context.get(PLAN_CONTEXT_URL, ""), "url": self.executor.plan.context.get(PLAN_CONTEXT_URL, ""),

View File

@ -8,7 +8,6 @@ from authentik.events.models import Event, EventAction
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
WithUserInfoChallenge, WithUserInfoChallenge,
) )
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
@ -61,7 +60,6 @@ class AuthenticatorDuoStageView(ChallengeStageView):
enroll = self.request.session[SESSION_KEY_DUO_ENROLL] enroll = self.request.session[SESSION_KEY_DUO_ENROLL]
return AuthenticatorDuoChallenge( return AuthenticatorDuoChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"activation_barcode": enroll["activation_barcode"], "activation_barcode": enroll["activation_barcode"],
"activation_code": enroll["activation_code"], "activation_code": enroll["activation_code"],
"stage_uuid": str(stage.stage_uuid), "stage_uuid": str(stage.stage_uuid),

View File

@ -10,7 +10,6 @@ from rest_framework.fields import BooleanField, CharField, IntegerField
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
WithUserInfoChallenge, WithUserInfoChallenge,
) )
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
@ -90,7 +89,6 @@ class AuthenticatorSMSStageView(ChallengeStageView):
def get_challenge(self, *args, **kwargs) -> Challenge: def get_challenge(self, *args, **kwargs) -> Challenge:
return AuthenticatorSMSChallenge( return AuthenticatorSMSChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"phone_number_required": self._has_phone_number() is None, "phone_number_required": self._has_phone_number() is None,
} }
) )

View File

@ -3,7 +3,7 @@
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from rest_framework.fields import CharField, ListField from rest_framework.fields import CharField, ListField
from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge from authentik.flows.challenge import ChallengeResponse, WithUserInfoChallenge
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
from authentik.stages.authenticator_static.models import ( from authentik.stages.authenticator_static.models import (
@ -38,7 +38,6 @@ class AuthenticatorStaticStageView(ChallengeStageView):
tokens: list[StaticToken] = self.request.session[SESSION_STATIC_TOKENS] tokens: list[StaticToken] = self.request.session[SESSION_STATIC_TOKENS]
return AuthenticatorStaticChallenge( return AuthenticatorStaticChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"codes": [token.token for token in tokens], "codes": [token.token for token in tokens],
} }
) )

View File

@ -11,7 +11,6 @@ from rest_framework.serializers import ValidationError
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
WithUserInfoChallenge, WithUserInfoChallenge,
) )
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
@ -55,7 +54,6 @@ class AuthenticatorTOTPStageView(ChallengeStageView):
device: TOTPDevice = self.request.session[SESSION_TOTP_DEVICE] device: TOTPDevice = self.request.session[SESSION_TOTP_DEVICE]
return AuthenticatorTOTPChallenge( return AuthenticatorTOTPChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"config_url": device.config_url.replace( "config_url": device.config_url.replace(
OTP_TOTP_ISSUER, quote(self.request.brand.branding_title) OTP_TOTP_ISSUER, quote(self.request.brand.branding_title)
), ),

View File

@ -13,7 +13,7 @@ from rest_framework.serializers import ValidationError
from authentik.core.api.utils import JSONDictField, PassiveSerializer from authentik.core.api.utils import JSONDictField, PassiveSerializer
from authentik.core.models import User from authentik.core.models import User
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge from authentik.flows.challenge import ChallengeResponse, WithUserInfoChallenge
from authentik.flows.exceptions import FlowSkipStageException, StageInvalidException from authentik.flows.exceptions import FlowSkipStageException, StageInvalidException
from authentik.flows.models import FlowDesignation, NotConfiguredAction, Stage from authentik.flows.models import FlowDesignation, NotConfiguredAction, Stage
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
@ -337,7 +337,6 @@ class AuthenticatorValidateStageView(ChallengeStageView):
return AuthenticatorValidationChallenge( return AuthenticatorValidationChallenge(
data={ data={
"component": "ak-stage-authenticator-validate", "component": "ak-stage-authenticator-validate",
"type": ChallengeTypes.NATIVE.value,
"device_challenges": challenges, "device_challenges": challenges,
"configuration_stages": stage_challenges, "configuration_stages": stage_challenges,
} }

View File

@ -30,7 +30,6 @@ from authentik.core.models import User
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
WithUserInfoChallenge, WithUserInfoChallenge,
) )
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
@ -144,7 +143,6 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
self.request.session.save() self.request.session.save()
return AuthenticatorWebAuthnChallenge( return AuthenticatorWebAuthnChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"registration": loads(options_to_json(registration_options)), "registration": loads(options_to_json(registration_options)),
} }
) )

View File

@ -9,7 +9,6 @@ from rest_framework.serializers import ValidationError
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
WithUserInfoChallenge, WithUserInfoChallenge,
) )
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
@ -80,7 +79,6 @@ class CaptchaStageView(ChallengeStageView):
return CaptchaChallenge( return CaptchaChallenge(
data={ data={
"js_url": self.executor.current_stage.js_url, "js_url": self.executor.current_stage.js_url,
"type": ChallengeTypes.NATIVE.value,
"site_key": self.executor.current_stage.public_key, "site_key": self.executor.current_stage.public_key,
} }
) )

View File

@ -10,7 +10,6 @@ from authentik.core.api.utils import PassiveSerializer
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
WithUserInfoChallenge, WithUserInfoChallenge,
) )
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_PENDING_USER from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_PENDING_USER
@ -58,7 +57,6 @@ class ConsentStageView(ChallengeStageView):
token = str(uuid4()) token = str(uuid4())
self.request.session[SESSION_KEY_CONSENT_TOKEN] = token self.request.session[SESSION_KEY_CONSENT_TOKEN] = token
data = { data = {
"type": ChallengeTypes.NATIVE.value,
"permissions": self.executor.plan.context.get(PLAN_CONTEXT_CONSENT_PERMISSIONS, []), "permissions": self.executor.plan.context.get(PLAN_CONTEXT_CONSENT_PERMISSIONS, []),
"additional_permissions": self.executor.plan.context.get( "additional_permissions": self.executor.plan.context.get(
PLAN_CONTEXT_CONSENT_EXTRA_PERMISSIONS, [] PLAN_CONTEXT_CONSENT_EXTRA_PERMISSIONS, []

View File

@ -3,7 +3,7 @@
from django.http.response import HttpResponse from django.http.response import HttpResponse
from rest_framework.fields import CharField from rest_framework.fields import CharField
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
from authentik.lib.sentry import SentryIgnoredException from authentik.lib.sentry import SentryIgnoredException
@ -34,7 +34,6 @@ class DummyStageView(ChallengeStageView):
raise SentryIgnoredException("Test error") raise SentryIgnoredException("Test error")
return DummyChallenge( return DummyChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"title": self.executor.current_stage.name, "title": self.executor.current_stage.name,
"name": self.executor.current_stage.name, "name": self.executor.current_stage.name,
} }

View File

@ -15,7 +15,7 @@ from rest_framework.fields import CharField
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.flows.exceptions import StageInvalidException from authentik.flows.exceptions import StageInvalidException
from authentik.flows.models import FlowDesignation, FlowToken from authentik.flows.models import FlowDesignation, FlowToken
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
@ -160,7 +160,6 @@ class EmailStageView(ChallengeStageView):
def get_challenge(self) -> Challenge: def get_challenge(self) -> Challenge:
challenge = EmailChallenge( challenge = EmailChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"title": _("Email sent."), "title": _("Email sent."),
} }
) )

View File

@ -20,7 +20,6 @@ from authentik.events.utils import sanitize_item
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
RedirectChallenge, RedirectChallenge,
) )
from authentik.flows.models import FlowDesignation from authentik.flows.models import FlowDesignation
@ -194,7 +193,6 @@ class IdentificationStageView(ChallengeStageView):
current_stage: IdentificationStage = self.executor.current_stage current_stage: IdentificationStage = self.executor.current_stage
challenge = IdentificationChallenge( challenge = IdentificationChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"component": "ak-stage-identification", "component": "ak-stage-identification",
"primary_action": self.get_primary_action(), "primary_action": self.get_primary_action(),
"user_fields": current_stage.user_fields, "user_fields": current_stage.user_fields,

View File

@ -4,7 +4,6 @@ from django.urls import reverse
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.challenge import ChallengeTypes
from authentik.flows.models import FlowDesignation, FlowStageBinding from authentik.flows.models import FlowDesignation, FlowStageBinding
from authentik.flows.tests import FlowTestCase from authentik.flows.tests import FlowTestCase
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
@ -90,7 +89,6 @@ class TestIdentificationStage(FlowTestCase):
"challenge": { "challenge": {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"to": "/source/oauth/login/test/", "to": "/source/oauth/login/test/",
"type": ChallengeTypes.REDIRECT.value,
}, },
"icon_url": "/static/authentik/sources/default.svg", "icon_url": "/static/authentik/sources/default.svg",
"name": "test", "name": "test",
@ -126,7 +124,6 @@ class TestIdentificationStage(FlowTestCase):
"challenge": { "challenge": {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"to": "/source/oauth/login/test/", "to": "/source/oauth/login/test/",
"type": ChallengeTypes.REDIRECT.value,
}, },
"icon_url": "/static/authentik/sources/default.svg", "icon_url": "/static/authentik/sources/default.svg",
"name": "test", "name": "test",
@ -189,7 +186,6 @@ class TestIdentificationStage(FlowTestCase):
"challenge": { "challenge": {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"to": "/source/oauth/login/test/", "to": "/source/oauth/login/test/",
"type": ChallengeTypes.REDIRECT.value,
}, },
"icon_url": "/static/authentik/sources/default.svg", "icon_url": "/static/authentik/sources/default.svg",
"name": "test", "name": "test",
@ -240,7 +236,6 @@ class TestIdentificationStage(FlowTestCase):
"challenge": { "challenge": {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"to": "/source/oauth/login/test/", "to": "/source/oauth/login/test/",
"type": ChallengeTypes.REDIRECT.value,
}, },
} }
], ],
@ -276,7 +271,6 @@ class TestIdentificationStage(FlowTestCase):
"challenge": { "challenge": {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"to": "/source/oauth/login/test/", "to": "/source/oauth/login/test/",
"type": ChallengeTypes.REDIRECT.value,
}, },
"icon_url": "/static/authentik/sources/default.svg", "icon_url": "/static/authentik/sources/default.svg",
"name": "test", "name": "test",
@ -304,7 +298,6 @@ class TestIdentificationStage(FlowTestCase):
"challenge": { "challenge": {
"component": "xak-flow-redirect", "component": "xak-flow-redirect",
"to": "/source/oauth/login/test/", "to": "/source/oauth/login/test/",
"type": ChallengeTypes.REDIRECT.value,
}, },
"icon_url": "/static/authentik/sources/default.svg", "icon_url": "/static/authentik/sources/default.svg",
"name": "test", "name": "test",

View File

@ -18,7 +18,6 @@ from authentik.core.signals import login_failed
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
ChallengeResponse, ChallengeResponse,
ChallengeTypes,
WithUserInfoChallenge, WithUserInfoChallenge,
) )
from authentik.flows.exceptions import StageInvalidException from authentik.flows.exceptions import StageInvalidException
@ -135,11 +134,7 @@ class PasswordStageView(ChallengeStageView):
response_class = PasswordChallengeResponse response_class = PasswordChallengeResponse
def get_challenge(self) -> Challenge: def get_challenge(self) -> Challenge:
challenge = PasswordChallenge( challenge = PasswordChallenge(data={})
data={
"type": ChallengeTypes.NATIVE.value,
}
)
recovery_flow = Flow.objects.filter(designation=FlowDesignation.RECOVERY) recovery_flow = Flow.objects.filter(designation=FlowDesignation.RECOVERY)
if recovery_flow.exists(): if recovery_flow.exists():
recover_url = reverse( recover_url = reverse(

View File

@ -11,7 +11,7 @@ from rest_framework.viewsets import ModelViewSet
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.expression.exceptions import PropertyMappingExpressionException from authentik.core.expression.exceptions import PropertyMappingExpressionException
from authentik.flows.api.stages import StageSerializer from authentik.flows.api.stages import StageSerializer
from authentik.flows.challenge import ChallengeTypes, HttpChallengeResponse from authentik.flows.challenge import HttpChallengeResponse
from authentik.flows.planner import FlowPlan from authentik.flows.planner import FlowPlan
from authentik.flows.views.executor import FlowExecutorView from authentik.flows.views.executor import FlowExecutorView
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
@ -115,7 +115,6 @@ class PromptViewSet(UsedByMixin, ModelViewSet):
) )
challenge = PromptChallenge( challenge = PromptChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"fields": fields, "fields": fields,
}, },
) )

View File

@ -21,7 +21,7 @@ from rest_framework.serializers import ValidationError
from authentik.core.api.utils import PassiveSerializer from authentik.core.api.utils import PassiveSerializer
from authentik.core.models import User from authentik.core.models import User
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.flows.planner import FlowPlan from authentik.flows.planner import FlowPlan
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
from authentik.policies.engine import PolicyEngine from authentik.policies.engine import PolicyEngine
@ -227,7 +227,6 @@ class PromptStageView(ChallengeStageView):
serializers = self.get_prompt_challenge_fields(fields, context_prompt) serializers = self.get_prompt_challenge_fields(fields, context_prompt)
challenge = PromptChallenge( challenge = PromptChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value,
"fields": serializers, "fields": serializers,
}, },
) )

View File

@ -7,7 +7,6 @@ from django.urls import reverse
from rest_framework.exceptions import ErrorDetail, ValidationError from rest_framework.exceptions import ErrorDetail, ValidationError
from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.challenge import ChallengeTypes
from authentik.flows.markers import StageMarker from authentik.flows.markers import StageMarker
from authentik.flows.models import FlowStageBinding from authentik.flows.models import FlowStageBinding
from authentik.flows.planner import FlowPlan from authentik.flows.planner import FlowPlan
@ -596,7 +595,6 @@ class TestPromptStage(FlowTestCase):
self.assertJSONEqual( self.assertJSONEqual(
response.content.decode(), response.content.decode(),
{ {
"type": ChallengeTypes.NATIVE.value,
"component": "ak-stage-prompt", "component": "ak-stage-prompt",
"fields": [ "fields": [
{ {

View File

@ -10,7 +10,7 @@ from rest_framework.fields import BooleanField, CharField
from authentik.core.models import AuthenticatedSession, User from authentik.core.models import AuthenticatedSession, User
from authentik.events.middleware import audit_ignore from authentik.events.middleware import audit_ignore
from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge from authentik.flows.challenge import ChallengeResponse, WithUserInfoChallenge
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, PLAN_CONTEXT_SOURCE from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, PLAN_CONTEXT_SOURCE
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
from authentik.lib.utils.time import timedelta_from_string from authentik.lib.utils.time import timedelta_from_string
@ -45,11 +45,7 @@ class UserLoginStageView(ChallengeStageView):
response_class = UserLoginChallengeResponse response_class = UserLoginChallengeResponse
def get_challenge(self, *args, **kwargs) -> UserLoginChallenge: def get_challenge(self, *args, **kwargs) -> UserLoginChallenge:
return UserLoginChallenge( return UserLoginChallenge(data={})
data={
"type": ChallengeTypes.NATIVE.value,
}
)
def dispatch(self, request: HttpRequest) -> HttpResponse: def dispatch(self, request: HttpRequest) -> HttpResponse:
"""Check for remember_me, and do login""" """Check for remember_me, and do login"""

View File

@ -129,6 +129,11 @@ class TestUserLoginStage(FlowTestCase):
session[SESSION_KEY_PLAN] = plan session[SESSION_KEY_PLAN] = plan
session.save() session.save()
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
)
self.assertStageResponse(response, component="ak-stage-user-login")
response = self.client.post( response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}), reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
data={"remember_me": True}, data={"remember_me": True},

View File

@ -8,6 +8,7 @@ const (
StageIdentification = StageComponent("ak-stage-identification") StageIdentification = StageComponent("ak-stage-identification")
StagePassword = StageComponent("ak-stage-password") StagePassword = StageComponent("ak-stage-password")
StageUserLogin = StageComponent("ak-stage-user-login") StageUserLogin = StageComponent("ak-stage-user-login")
StageRedirect = StageComponent("xak-flow-redirect")
) )
const ( const (

View File

@ -110,9 +110,8 @@ func (fe *FlowExecutor) ApiClient() *api.APIClient {
return fe.api return fe.api
} }
type challengeInt interface { type challengeCommon interface {
GetComponent() string GetComponent() string
GetType() api.ChallengeChoices
GetResponseErrors() map[string][]api.ErrorDetail GetResponseErrors() map[string][]api.ErrorDetail
} }
@ -181,9 +180,8 @@ func (fe *FlowExecutor) getInitialChallenge() (*api.ChallengeTypes, error) {
if i == nil { if i == nil {
return nil, errors.New("response instance was null") return nil, errors.New("response instance was null")
} }
ch := i.(challengeInt) ch := i.(challengeCommon)
fe.log.WithField("component", ch.GetComponent()).WithField("type", ch.GetType()).Debug("Got challenge") fe.log.WithField("component", ch.GetComponent()).Debug("Got challenge")
gcsp.SetTag("authentik.flow.challenge", string(ch.GetType()))
gcsp.SetTag("authentik.flow.component", ch.GetComponent()) gcsp.SetTag("authentik.flow.component", ch.GetComponent())
gcsp.Finish() gcsp.Finish()
FlowTimingGet.With(prometheus.Labels{ FlowTimingGet.With(prometheus.Labels{
@ -201,7 +199,7 @@ func (fe *FlowExecutor) solveFlowChallenge(challenge *api.ChallengeTypes, depth
if i == nil { if i == nil {
return false, errors.New("response request instance was null") return false, errors.New("response request instance was null")
} }
ch := i.(challengeInt) ch := i.(challengeCommon)
// Check for any validation errors that we might've gotten // Check for any validation errors that we might've gotten
if len(ch.GetResponseErrors()) > 0 { if len(ch.GetResponseErrors()) > 0 {
@ -212,13 +210,12 @@ func (fe *FlowExecutor) solveFlowChallenge(challenge *api.ChallengeTypes, depth
} }
} }
switch ch.GetType() { switch ch.GetComponent() {
case api.CHALLENGECHOICES_REDIRECT: case string(StageAccessDenied):
return false, nil
case string(StageRedirect):
return true, nil return true, nil
case api.CHALLENGECHOICES_NATIVE: default:
if ch.GetComponent() == string(StageAccessDenied) {
return false, nil
}
solver, ok := fe.solvers[StageComponent(ch.GetComponent())] solver, ok := fe.solvers[StageComponent(ch.GetComponent())]
if !ok { if !ok {
return false, fmt.Errorf("unsupported challenge type %s", ch.GetComponent()) return false, fmt.Errorf("unsupported challenge type %s", ch.GetComponent())
@ -238,9 +235,8 @@ func (fe *FlowExecutor) solveFlowChallenge(challenge *api.ChallengeTypes, depth
if i == nil { if i == nil {
return false, errors.New("response instance was null") return false, errors.New("response instance was null")
} }
ch = i.(challengeInt) ch = i.(challengeCommon)
fe.log.WithField("component", ch.GetComponent()).WithField("type", ch.GetType()).Debug("Got response") fe.log.WithField("component", ch.GetComponent()).Debug("Got response")
scsp.SetTag("authentik.flow.challenge", string(ch.GetType()))
scsp.SetTag("authentik.flow.component", ch.GetComponent()) scsp.SetTag("authentik.flow.component", ch.GetComponent())
scsp.Finish() scsp.Finish()
FlowTimingPost.With(prometheus.Labels{ FlowTimingPost.With(prometheus.Labels{

View File

@ -0,0 +1,13 @@
package flow
import (
"testing"
"github.com/stretchr/testify/assert"
"goauthentik.io/api/v3"
)
func TestConvert(t *testing.T) {
var a challengeCommon = api.NewIdentificationChallengeWithDefaults()
assert.NotNil(t, a)
}

View File

@ -32844,8 +32844,6 @@ components:
type: object type: object
description: Challenge when a flow's active stage calls `stage_invalid()`. description: Challenge when a flow's active stage calls `stage_invalid()`.
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -32866,7 +32864,6 @@ components:
required: required:
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- type
AlgEnum: AlgEnum:
enum: enum:
- rsa - rsa
@ -32955,8 +32952,6 @@ components:
description: Special challenge for apple-native authentication flow, which happens description: Special challenge for apple-native authentication flow, which happens
on the client. on the client.
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -32981,7 +32976,6 @@ components:
- redirect_uri - redirect_uri
- scope - scope
- state - state
- type
Application: Application:
type: object type: object
description: Application Serializer description: Application Serializer
@ -33252,8 +33246,6 @@ components:
type: object type: object
description: Duo Challenge description: Duo Challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -33281,7 +33273,6 @@ components:
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- stage_uuid - stage_uuid
- type
AuthenticatorDuoChallengeResponseRequest: AuthenticatorDuoChallengeResponseRequest:
type: object type: object
description: Pseudo class for duo response description: Pseudo class for duo response
@ -33414,8 +33405,6 @@ components:
type: object type: object
description: SMS Setup challenge description: SMS Setup challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -33437,7 +33426,6 @@ components:
required: required:
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- type
AuthenticatorSMSChallengeResponseRequest: AuthenticatorSMSChallengeResponseRequest:
type: object type: object
description: SMS Challenge response, device is set by get_response_instance description: SMS Challenge response, device is set by get_response_instance
@ -33580,8 +33568,6 @@ components:
type: object type: object
description: Static authenticator challenge description: Static authenticator challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -33605,7 +33591,6 @@ components:
- codes - codes
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- type
AuthenticatorStaticChallengeResponseRequest: AuthenticatorStaticChallengeResponseRequest:
type: object type: object
description: Pseudo class for static response description: Pseudo class for static response
@ -33704,8 +33689,6 @@ components:
type: object type: object
description: TOTP Setup challenge description: TOTP Setup challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -33727,7 +33710,6 @@ components:
- config_url - config_url
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- type
AuthenticatorTOTPChallengeResponseRequest: AuthenticatorTOTPChallengeResponseRequest:
type: object type: object
description: TOTP Challenge response, device is set by get_response_instance description: TOTP Challenge response, device is set by get_response_instance
@ -33934,8 +33916,6 @@ components:
type: object type: object
description: Authenticator challenge description: Authenticator challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -33964,7 +33944,6 @@ components:
- device_challenges - device_challenges
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- type
AuthenticatorValidationChallengeResponseRequest: AuthenticatorValidationChallengeResponseRequest:
type: object type: object
description: Challenge used for Code-based and WebAuthn authenticators description: Challenge used for Code-based and WebAuthn authenticators
@ -33990,8 +33969,6 @@ components:
type: object type: object
description: WebAuthn Challenge description: WebAuthn Challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -34014,7 +33991,6 @@ components:
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- registration - registration
- type
AuthenticatorWebAuthnChallengeResponseRequest: AuthenticatorWebAuthnChallengeResponseRequest:
type: object type: object
description: WebAuthn Challenge response description: WebAuthn Challenge response
@ -34142,8 +34118,6 @@ components:
type: object type: object
description: Autosubmit challenge used to send and navigate a POST request description: Autosubmit challenge used to send and navigate a POST request
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -34165,7 +34139,6 @@ components:
type: string type: string
required: required:
- attrs - attrs
- type
- url - url
BackendsEnum: BackendsEnum:
enum: enum:
@ -34395,8 +34368,6 @@ components:
type: object type: object
description: Site public key description: Site public key
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -34421,7 +34392,6 @@ components:
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- site_key - site_key
- type
CaptchaChallengeResponseRequest: CaptchaChallengeResponseRequest:
type: object type: object
description: Validate captcha token description: Validate captcha token
@ -34652,12 +34622,6 @@ components:
required: required:
- certificate_data - certificate_data
- name - name
ChallengeChoices:
enum:
- native
- shell
- redirect
type: string
ChallengeTypes: ChallengeTypes:
oneOf: oneOf:
- $ref: '#/components/schemas/AccessDeniedChallenge' - $ref: '#/components/schemas/AccessDeniedChallenge'
@ -34790,8 +34754,6 @@ components:
type: object type: object
description: Challenge info for consent screens description: Challenge info for consent screens
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -34825,7 +34787,6 @@ components:
- pending_user_avatar - pending_user_avatar
- permissions - permissions
- token - token
- type
ConsentChallengeResponseRequest: ConsentChallengeResponseRequest:
type: object type: object
description: Consent challenge response, any valid response request is valid description: Consent challenge response, any valid response request is valid
@ -35274,8 +35235,6 @@ components:
type: object type: object
description: Dummy challenge description: Dummy challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -35291,7 +35250,6 @@ components:
type: string type: string
required: required:
- name - name
- type
DummyChallengeResponseRequest: DummyChallengeResponseRequest:
type: object type: object
description: Dummy challenge response description: Dummy challenge response
@ -35474,8 +35432,6 @@ components:
type: object type: object
description: Email challenge description: Email challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -35487,8 +35443,6 @@ components:
type: array type: array
items: items:
$ref: '#/components/schemas/ErrorDetail' $ref: '#/components/schemas/ErrorDetail'
required:
- type
EmailChallengeResponseRequest: EmailChallengeResponseRequest:
type: object type: object
description: |- description: |-
@ -36314,9 +36268,6 @@ components:
Challenge class when an unhandled error occurs during a stage. Normal users Challenge class when an unhandled error occurs during a stage. Normal users
are shown an error message, superusers are shown a full stacktrace. are shown an error message, superusers are shown a full stacktrace.
properties: properties:
type:
type: string
default: native
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -37098,8 +37049,6 @@ components:
type: object type: object
description: Identification challenges with all UI elements description: Identification challenges with all UI elements
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -37141,7 +37090,6 @@ components:
- password_fields - password_fields
- primary_action - primary_action
- show_source_labels - show_source_labels
- type
- user_fields - user_fields
IdentificationChallengeResponseRequest: IdentificationChallengeResponseRequest:
type: object type: object
@ -39160,8 +39108,6 @@ components:
type: object type: object
description: OAuth Device code challenge description: OAuth Device code challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -39173,8 +39119,6 @@ components:
type: array type: array
items: items:
$ref: '#/components/schemas/ErrorDetail' $ref: '#/components/schemas/ErrorDetail'
required:
- type
OAuthDeviceCodeChallengeResponseRequest: OAuthDeviceCodeChallengeResponseRequest:
type: object type: object
description: Response that includes the user-entered device code description: Response that includes the user-entered device code
@ -39191,8 +39135,6 @@ components:
type: object type: object
description: Final challenge after user enters their code description: Final challenge after user enters their code
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -39204,8 +39146,6 @@ components:
type: array type: array
items: items:
$ref: '#/components/schemas/ErrorDetail' $ref: '#/components/schemas/ErrorDetail'
required:
- type
OAuthDeviceCodeFinishChallengeResponseRequest: OAuthDeviceCodeFinishChallengeResponseRequest:
type: object type: object
description: Response that device has been authenticated and tab can be closed description: Response that device has been authenticated and tab can be closed
@ -40996,8 +40936,6 @@ components:
type: object type: object
description: Password challenge UI fields description: Password challenge UI fields
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -41018,7 +40956,6 @@ components:
required: required:
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- type
PasswordChallengeResponseRequest: PasswordChallengeResponseRequest:
type: object type: object
description: Password challenge response description: Password challenge response
@ -43909,8 +43846,6 @@ components:
type: object type: object
description: Challenge shown to the user in identification stage description: Challenge shown to the user in identification stage
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -43929,7 +43864,6 @@ components:
required: required:
- client_id - client_id
- slug - slug
- type
PlexAuthenticationChallengeResponseRequest: PlexAuthenticationChallengeResponseRequest:
type: object type: object
description: Pseudo class for plex response description: Pseudo class for plex response
@ -44378,8 +44312,6 @@ components:
type: object type: object
description: Initial challenge being sent, define fields description: Initial challenge being sent, define fields
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -44397,7 +44329,6 @@ components:
$ref: '#/components/schemas/StagePrompt' $ref: '#/components/schemas/StagePrompt'
required: required:
- fields - fields
- type
PromptChallengeResponseRequest: PromptChallengeResponseRequest:
type: object type: object
description: |- description: |-
@ -45459,8 +45390,6 @@ components:
type: object type: object
description: Challenge type to redirect the client description: Challenge type to redirect the client
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -45476,7 +45405,6 @@ components:
type: string type: string
required: required:
- to - to
- type
Reputation: Reputation:
type: object type: object
description: Reputation Serializer description: Reputation Serializer
@ -46959,8 +46887,6 @@ components:
type: object type: object
description: challenge type to render HTML as-is description: challenge type to render HTML as-is
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -46976,7 +46902,6 @@ components:
type: string type: string
required: required:
- body - body
- type
SignatureAlgorithmEnum: SignatureAlgorithmEnum:
enum: enum:
- http://www.w3.org/2000/09/xmldsig#rsa-sha1 - http://www.w3.org/2000/09/xmldsig#rsa-sha1
@ -48097,8 +48022,6 @@ components:
type: object type: object
description: Empty challenge description: Empty challenge
properties: properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info: flow_info:
$ref: '#/components/schemas/ContextualFlowInfo' $ref: '#/components/schemas/ContextualFlowInfo'
component: component:
@ -48117,7 +48040,6 @@ components:
required: required:
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- type
UserLoginChallengeResponseRequest: UserLoginChallengeResponseRequest:
type: object type: object
description: User login challenge description: User login challenge

View File

@ -33,7 +33,6 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { import {
CapabilitiesEnum, CapabilitiesEnum,
ChallengeChoices,
ChallengeTypes, ChallengeTypes,
ContextualFlowInfo, ContextualFlowInfo,
FetchError, FetchError,
@ -254,7 +253,6 @@ export class FlowExecutor extends Interface implements StageHost {
body = error.message; body = error.message;
} }
const challenge: FlowErrorChallenge = { const challenge: FlowErrorChallenge = {
type: ChallengeChoices.Native,
component: "ak-stage-flow-error", component: "ak-stage-flow-error",
error: body, error: body,
requestId: "", requestId: "",
@ -280,7 +278,11 @@ export class FlowExecutor extends Interface implements StageHost {
} }
} }
async renderChallengeNativeElement(): Promise<TemplateResult> { async renderChallenge(): Promise<TemplateResult> {
if (!this.challenge) {
return html`<ak-empty-state ?loading=${true} header=${msg("Loading")}>
</ak-empty-state>`;
}
switch (this.challenge?.component) { switch (this.challenge?.component) {
case "ak-stage-access-denied": case "ak-stage-access-denied":
await import("@goauthentik/flow/stages/access_denied/AccessDeniedStage"); await import("@goauthentik/flow/stages/access_denied/AccessDeniedStage");
@ -411,31 +413,17 @@ export class FlowExecutor extends Interface implements StageHost {
.host=${this as StageHost} .host=${this as StageHost}
.challenge=${this.challenge} .challenge=${this.challenge}
></ak-stage-flow-error>`; ></ak-stage-flow-error>`;
default: case "xak-flow-redirect":
return html`Invalid native challenge element`;
}
}
async renderChallenge(): Promise<TemplateResult> {
if (!this.challenge) {
return html`<ak-empty-state ?loading=${true} header=${msg("Loading")}>
</ak-empty-state>`;
}
switch (this.challenge.type) {
case ChallengeChoices.Redirect:
return html`<ak-stage-redirect return html`<ak-stage-redirect
.host=${this as StageHost} .host=${this as StageHost}
.challenge=${this.challenge} .challenge=${this.challenge}
?promptUser=${this.inspectorOpen} ?promptUser=${this.inspectorOpen}
> >
</ak-stage-redirect>`; </ak-stage-redirect>`;
case ChallengeChoices.Shell: case "xak-flow-shell":
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`; return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
case ChallengeChoices.Native:
return await this.renderChallengeNativeElement();
default: default:
console.debug(`authentik/flows: unexpected data type ${this.challenge.type}`); return html`Invalid native challenge element`;
return html``;
} }
} }

View File

@ -4,7 +4,7 @@ import { html } from "lit";
import "@patternfly/patternfly/components/Login/login.css"; import "@patternfly/patternfly/components/Login/login.css";
import { AccessDeniedChallenge, ChallengeChoices, UiThemeEnum } from "@goauthentik/api"; import { AccessDeniedChallenge, UiThemeEnum } from "@goauthentik/api";
import "../../../stories/flow-interface"; import "../../../stories/flow-interface";
import "./AccessDeniedStage"; import "./AccessDeniedStage";
@ -39,7 +39,6 @@ export const Challenge: StoryObj = {
args: { args: {
theme: "automatic", theme: "automatic",
challenge: { challenge: {
type: ChallengeChoices.Native,
pendingUser: "foo", pendingUser: "foo",
pendingUserAvatar: "https://picsum.photos/64", pendingUserAvatar: "https://picsum.photos/64",
errorMessage: "This is an error message", errorMessage: "This is an error message",

View File

@ -4,7 +4,7 @@ import { html } from "lit";
import "@patternfly/patternfly/components/Login/login.css"; import "@patternfly/patternfly/components/Login/login.css";
import { AuthenticatorTOTPChallenge, ChallengeChoices, UiThemeEnum } from "@goauthentik/api"; import { AuthenticatorTOTPChallenge, UiThemeEnum } from "@goauthentik/api";
import "../../../stories/flow-interface"; import "../../../stories/flow-interface";
import "./AuthenticatorTOTPStage"; import "./AuthenticatorTOTPStage";
@ -41,7 +41,6 @@ export const Challenge: StoryObj = {
args: { args: {
theme: "automatic", theme: "automatic",
challenge: { challenge: {
type: ChallengeChoices.Native,
pendingUser: "foo", pendingUser: "foo",
pendingUserAvatar: "https://picsum.photos/64", pendingUserAvatar: "https://picsum.photos/64",
configUrl: "", configUrl: "",

View File

@ -4,7 +4,7 @@ import { html } from "lit";
import "@patternfly/patternfly/components/Login/login.css"; import "@patternfly/patternfly/components/Login/login.css";
import { CaptchaChallenge, ChallengeChoices, UiThemeEnum } from "@goauthentik/api"; import { CaptchaChallenge, UiThemeEnum } from "@goauthentik/api";
import "../../../stories/flow-interface"; import "../../../stories/flow-interface";
import "./CaptchaStage"; import "./CaptchaStage";
@ -39,7 +39,6 @@ export const ChallengeGoogleReCaptcha: StoryObj = {
args: { args: {
theme: "automatic", theme: "automatic",
challenge: { challenge: {
type: ChallengeChoices.Native,
pendingUser: "foo", pendingUser: "foo",
pendingUserAvatar: "https://picsum.photos/64", pendingUserAvatar: "https://picsum.photos/64",
jsUrl: "https://www.google.com/recaptcha/api.js", jsUrl: "https://www.google.com/recaptcha/api.js",
@ -70,7 +69,6 @@ export const ChallengeHCaptcha: StoryObj = {
args: { args: {
theme: "automatic", theme: "automatic",
challenge: { challenge: {
type: ChallengeChoices.Native,
pendingUser: "foo", pendingUser: "foo",
pendingUserAvatar: "https://picsum.photos/64", pendingUserAvatar: "https://picsum.photos/64",
jsUrl: "https://js.hcaptcha.com/1/api.js", jsUrl: "https://js.hcaptcha.com/1/api.js",
@ -101,7 +99,6 @@ export const ChallengeTurnstile: StoryObj = {
args: { args: {
theme: "automatic", theme: "automatic",
challenge: { challenge: {
type: ChallengeChoices.Native,
pendingUser: "foo", pendingUser: "foo",
pendingUserAvatar: "https://picsum.photos/64", pendingUserAvatar: "https://picsum.photos/64",
jsUrl: "https://challenges.cloudflare.com/turnstile/v0/api.js", jsUrl: "https://challenges.cloudflare.com/turnstile/v0/api.js",

View File

@ -20,7 +20,6 @@ import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { import {
ChallengeChoices,
ChallengeTypes, ChallengeTypes,
FlowChallengeResponseRequest, FlowChallengeResponseRequest,
FlowErrorChallenge, FlowErrorChallenge,
@ -116,7 +115,6 @@ export class UserSettingsFlowExecutor
body = error.message; body = error.message;
} }
const challenge: FlowErrorChallenge = { const challenge: FlowErrorChallenge = {
type: ChallengeChoices.Native,
component: "ak-stage-flow-error", component: "ak-stage-flow-error",
error: body, error: body,
requestId: "", requestId: "",
@ -146,8 +144,15 @@ export class UserSettingsFlowExecutor
if (!this.challenge) { if (!this.challenge) {
return html``; return html``;
} }
switch (this.challenge.type) { switch (this.challenge.component) {
case ChallengeChoices.Redirect: case "ak-stage-prompt":
return html`<ak-user-stage-prompt
.host=${this as StageHost}
.challenge=${this.challenge}
></ak-user-stage-prompt>`;
case "xak-flow-shell":
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
case "xak-flow-redirect":
if ((this.challenge as RedirectChallenge).to !== "/") { if ((this.challenge as RedirectChallenge).to !== "/") {
return html`<a return html`<a
href="${(this.challenge as RedirectChallenge).to}" href="${(this.challenge as RedirectChallenge).to}"
@ -166,30 +171,16 @@ export class UserSettingsFlowExecutor
}); });
return html`<ak-empty-state ?loading=${true} header=${msg("Loading")}> return html`<ak-empty-state ?loading=${true} header=${msg("Loading")}>
</ak-empty-state>`; </ak-empty-state>`;
case ChallengeChoices.Shell:
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
case ChallengeChoices.Native:
switch (this.challenge.component) {
case "ak-stage-prompt":
return html`<ak-user-stage-prompt
.host=${this as StageHost}
.challenge=${this.challenge}
></ak-user-stage-prompt>`;
default:
console.debug(
`authentik/user/flows: unsupported stage type ${this.challenge.component}`,
);
return html`
<a href="/if/flow/${this.flowSlug}/" class="pf-c-button pf-m-primary">
${msg("Open settings")}
</a>
`;
}
default: default:
console.debug(`authentik/user/flows: unexpected data type ${this.challenge.type}`); console.debug(
break; `authentik/user/flows: unsupported stage type ${this.challenge.component}`,
);
return html`
<a href="/if/flow/${this.flowSlug}/" class="pf-c-button pf-m-primary">
${msg("Open settings")}
</a>
`;
} }
return html``;
} }
renderChallengeWrapper(): TemplateResult { renderChallengeWrapper(): TemplateResult {