stages/identification: fix challenges not being annotated correctly and API client not loading data correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
ec4c3f44cb
commit
53100a72fe
|
@ -2,7 +2,7 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
from rest_framework.fields import CharField, DictField
|
||||
from rest_framework.fields import CharField
|
||||
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.flows.challenge import Challenge
|
||||
|
@ -22,14 +22,6 @@ class UILoginButton:
|
|||
icon_url: Optional[str] = None
|
||||
|
||||
|
||||
class UILoginButtonSerializer(PassiveSerializer):
|
||||
"""Serializer for Login buttons of sources"""
|
||||
|
||||
name = CharField()
|
||||
challenge = DictField()
|
||||
icon_url = CharField(required=False, allow_null=True)
|
||||
|
||||
|
||||
class UserSettingSerializer(PassiveSerializer):
|
||||
"""Serializer for User settings for stages and sources"""
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ class FlowExecutorView(APIView):
|
|||
@extend_schema(
|
||||
responses={
|
||||
200: PolymorphicProxySerializer(
|
||||
component_name="FlowChallengeRequest",
|
||||
component_name="ChallengeTypes",
|
||||
serializers=challenge_types(),
|
||||
resource_type_field_name="component",
|
||||
),
|
||||
|
@ -214,7 +214,7 @@ class FlowExecutorView(APIView):
|
|||
@extend_schema(
|
||||
responses={
|
||||
200: PolymorphicProxySerializer(
|
||||
component_name="FlowChallengeRequest",
|
||||
component_name="ChallengeTypes",
|
||||
serializers=challenge_types(),
|
||||
resource_type_field_name="component",
|
||||
),
|
||||
|
|
|
@ -8,19 +8,25 @@ from django.db.models import Q
|
|||
from django.http import HttpResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from rest_framework.fields import BooleanField, CharField, ListField
|
||||
from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field
|
||||
from rest_framework.fields import (
|
||||
BooleanField,
|
||||
CharField,
|
||||
DictField,
|
||||
ListField,
|
||||
)
|
||||
from rest_framework.serializers import ValidationError
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.core.models import Application, Source, User
|
||||
from authentik.core.types import UILoginButtonSerializer
|
||||
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||
from authentik.flows.stage import (
|
||||
PLAN_CONTEXT_PENDING_USER_IDENTIFIER,
|
||||
ChallengeStageView,
|
||||
)
|
||||
from authentik.flows.views import SESSION_KEY_APPLICATION_PRE
|
||||
from authentik.flows.views import SESSION_KEY_APPLICATION_PRE, challenge_types
|
||||
from authentik.stages.identification.models import IdentificationStage
|
||||
from authentik.stages.identification.signals import identification_failed
|
||||
from authentik.stages.password.stage import authenticate
|
||||
|
@ -28,6 +34,26 @@ from authentik.stages.password.stage import authenticate
|
|||
LOGGER = get_logger()
|
||||
|
||||
|
||||
@extend_schema_field(
|
||||
PolymorphicProxySerializer(
|
||||
component_name="ChallengeTypes",
|
||||
serializers=challenge_types(),
|
||||
resource_type_field_name="component",
|
||||
)
|
||||
)
|
||||
class ChallengeDictWrapper(DictField):
|
||||
"""Wrapper around DictField that annotates itself as challenge proxy"""
|
||||
|
||||
|
||||
class LoginSourceSerializer(PassiveSerializer):
|
||||
"""Serializer for Login buttons of sources"""
|
||||
|
||||
name = CharField()
|
||||
icon_url = CharField(required=False, allow_null=True)
|
||||
|
||||
challenge = ChallengeDictWrapper()
|
||||
|
||||
|
||||
class IdentificationChallenge(Challenge):
|
||||
"""Identification challenges with all UI elements"""
|
||||
|
||||
|
@ -38,7 +64,7 @@ class IdentificationChallenge(Challenge):
|
|||
enroll_url = CharField(required=False)
|
||||
recovery_url = CharField(required=False)
|
||||
primary_action = CharField()
|
||||
sources = UILoginButtonSerializer(many=True, required=False)
|
||||
sources = LoginSourceSerializer(many=True, required=False)
|
||||
|
||||
component = CharField(default="ak-stage-identification")
|
||||
|
||||
|
@ -154,6 +180,7 @@ class IdentificationStageView(ChallengeStageView):
|
|||
button = asdict(ui_login_button)
|
||||
button["challenge"] = ui_login_button.challenge.data
|
||||
ui_sources.append(button)
|
||||
print(ui_sources)
|
||||
challenge.initial_data["sources"] = ui_sources
|
||||
return challenge
|
||||
|
||||
|
|
137
schema.yml
137
schema.yml
|
@ -4608,7 +4608,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/FlowChallengeRequest'
|
||||
$ref: '#/components/schemas/ChallengeTypes'
|
||||
description: ''
|
||||
'404':
|
||||
description: No Token found
|
||||
|
@ -4654,7 +4654,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/FlowChallengeRequest'
|
||||
$ref: '#/components/schemas/ChallengeTypes'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
|
@ -18412,12 +18412,75 @@ components:
|
|||
required:
|
||||
- certificate_data
|
||||
- name
|
||||
ChallT:
|
||||
type: object
|
||||
description: |-
|
||||
Challenge that gets sent to the client based on which stage
|
||||
is currently active
|
||||
properties:
|
||||
type:
|
||||
$ref: '#/components/schemas/ChallengeChoices'
|
||||
flow_info:
|
||||
$ref: '#/components/schemas/ContextualFlowInfo'
|
||||
component:
|
||||
type: string
|
||||
default: ''
|
||||
response_errors:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ErrorDetail'
|
||||
required:
|
||||
- type
|
||||
ChallengeChoices:
|
||||
enum:
|
||||
- native
|
||||
- shell
|
||||
- redirect
|
||||
type: string
|
||||
ChallengeTypes:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/AccessDeniedChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorDuoChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorStaticChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorTOTPChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorValidationChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorWebAuthnChallenge'
|
||||
- $ref: '#/components/schemas/AutosubmitChallenge'
|
||||
- $ref: '#/components/schemas/CaptchaChallenge'
|
||||
- $ref: '#/components/schemas/ChallT'
|
||||
- $ref: '#/components/schemas/ConsentChallenge'
|
||||
- $ref: '#/components/schemas/DummyChallenge'
|
||||
- $ref: '#/components/schemas/EmailChallenge'
|
||||
- $ref: '#/components/schemas/IdentificationChallenge'
|
||||
- $ref: '#/components/schemas/PasswordChallenge'
|
||||
- $ref: '#/components/schemas/PlexAuthenticationChallenge'
|
||||
- $ref: '#/components/schemas/PromptChallenge'
|
||||
- $ref: '#/components/schemas/RedirectChallenge'
|
||||
- $ref: '#/components/schemas/ShellChallenge'
|
||||
discriminator:
|
||||
propertyName: component
|
||||
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'
|
||||
? ''
|
||||
: '#/components/schemas/ChallT'
|
||||
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'
|
||||
ClientTypeEnum:
|
||||
enum:
|
||||
- confidential
|
||||
|
@ -19388,45 +19451,6 @@ components:
|
|||
- slug
|
||||
- stages
|
||||
- title
|
||||
FlowChallengeRequest:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/AccessDeniedChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorDuoChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorStaticChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorTOTPChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorValidationChallenge'
|
||||
- $ref: '#/components/schemas/AuthenticatorWebAuthnChallenge'
|
||||
- $ref: '#/components/schemas/AutosubmitChallenge'
|
||||
- $ref: '#/components/schemas/CaptchaChallenge'
|
||||
- $ref: '#/components/schemas/ConsentChallenge'
|
||||
- $ref: '#/components/schemas/DummyChallenge'
|
||||
- $ref: '#/components/schemas/EmailChallenge'
|
||||
- $ref: '#/components/schemas/IdentificationChallenge'
|
||||
- $ref: '#/components/schemas/PasswordChallenge'
|
||||
- $ref: '#/components/schemas/PlexAuthenticationChallenge'
|
||||
- $ref: '#/components/schemas/PromptChallenge'
|
||||
- $ref: '#/components/schemas/RedirectChallenge'
|
||||
- $ref: '#/components/schemas/ShellChallenge'
|
||||
discriminator:
|
||||
propertyName: component
|
||||
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'
|
||||
FlowChallengeResponseRequest:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/AuthenticatorDuoChallengeResponseRequest'
|
||||
|
@ -19776,7 +19800,7 @@ components:
|
|||
sources:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UILoginButton'
|
||||
$ref: '#/components/schemas/LoginSource'
|
||||
required:
|
||||
- password_fields
|
||||
- primary_action
|
||||
|
@ -20472,6 +20496,20 @@ components:
|
|||
required:
|
||||
- logins_failed_per_1h
|
||||
- logins_per_1h
|
||||
LoginSource:
|
||||
type: object
|
||||
description: Serializer for Login buttons of sources
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
icon_url:
|
||||
type: string
|
||||
nullable: true
|
||||
challenge:
|
||||
$ref: '#/components/schemas/ChallengeTypes'
|
||||
required:
|
||||
- challenge
|
||||
- name
|
||||
NameIdPolicyEnum:
|
||||
enum:
|
||||
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||
|
@ -27526,21 +27564,6 @@ components:
|
|||
- description
|
||||
- model_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
|
||||
UsedBy:
|
||||
type: object
|
||||
description: A list of all objects referencing the queried object
|
||||
|
|
|
@ -26,7 +26,7 @@ import "./stages/password/PasswordStage";
|
|||
import "./stages/prompt/PromptStage";
|
||||
import "./sources/plex/PlexLoginInit";
|
||||
import { StageHost } from "./stages/base";
|
||||
import { ChallengeChoices, CurrentTenant, FlowChallengeRequest, FlowChallengeResponseRequest, FlowsApi, RedirectChallenge, ShellChallenge } from "authentik-api";
|
||||
import { ChallengeChoices, CurrentTenant, ChallengeTypes, FlowChallengeResponseRequest, FlowsApi, RedirectChallenge, ShellChallenge } from "authentik-api";
|
||||
import { DEFAULT_CONFIG, tenant } from "../api/Config";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import { until } from "lit-html/directives/until";
|
||||
|
@ -40,7 +40,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
|||
flowSlug: string;
|
||||
|
||||
@property({attribute: false})
|
||||
challenge?: FlowChallengeRequest;
|
||||
challenge?: ChallengeTypes;
|
||||
|
||||
@property({type: Boolean})
|
||||
loading = false;
|
||||
|
@ -163,7 +163,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
|||
</li>
|
||||
</ul>
|
||||
</footer>`
|
||||
} as FlowChallengeRequest;
|
||||
} as ChallengeTypes;
|
||||
}
|
||||
|
||||
renderLoading(): TemplateResult {
|
||||
|
|
|
@ -11,7 +11,7 @@ import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
|
|||
import AKGlobal from "../../../authentik.css";
|
||||
import "../../../elements/forms/FormElement";
|
||||
import "../../../elements/EmptyState";
|
||||
import { FlowChallengeRequest, IdentificationChallenge, IdentificationChallengeResponseRequest, UILoginButton, UserFieldsEnum } from "authentik-api";
|
||||
import { IdentificationChallenge, IdentificationChallengeResponseRequest, LoginSource, UserFieldsEnum } from "authentik-api";
|
||||
|
||||
export const PasswordManagerPrefill: {
|
||||
password: string | undefined;
|
||||
|
@ -110,7 +110,7 @@ export class IdentificationStage extends BaseStage<IdentificationChallenge, Iden
|
|||
wrapperForm.appendChild(totp);
|
||||
}
|
||||
|
||||
renderSource(source: UILoginButton): TemplateResult {
|
||||
renderSource(source: LoginSource): TemplateResult {
|
||||
let icon = html`<i class="fas fas fa-share-square" title="${source.name}"></i>`;
|
||||
if (source.iconUrl) {
|
||||
icon = html`<img src="${source.iconUrl}" alt="${source.name}">`;
|
||||
|
@ -118,7 +118,7 @@ export class IdentificationStage extends BaseStage<IdentificationChallenge, Iden
|
|||
return html`<li class="pf-c-login__main-footer-links-item">
|
||||
<button type="button" @click=${() => {
|
||||
if (!this.host) return;
|
||||
this.host.challenge = source.challenge as FlowChallengeRequest;
|
||||
this.host.challenge = source.challenge;
|
||||
}}>
|
||||
${icon}
|
||||
</button>
|
||||
|
|
Reference in a new issue