root: bump python deps (django 5) (#7862)
* bump python deps Signed-off-by: Jens Langhammer <jens@goauthentik.io> * vendor pickle serializer for now Signed-off-by: Jens Langhammer <jens@goauthentik.io> #7761 * cleanup some things and re-build api scheme Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix web and go Signed-off-by: Jens Langhammer <jens@goauthentik.io> * actually fix go...? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * better annotate json fields Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use jsondictfield wherever Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove all virtualenvs? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * ? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * final version bump Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
ba174d810b
commit
729ef4d786
|
@ -61,10 +61,6 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup authentik env
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
postgresql_version: ${{ matrix.psql }}
|
|
||||||
- name: checkout stable
|
- name: checkout stable
|
||||||
run: |
|
run: |
|
||||||
# Delete all poetry envs
|
# Delete all poetry envs
|
||||||
|
@ -76,7 +72,7 @@ jobs:
|
||||||
git checkout version/$(python -c "from authentik import __version__; print(__version__)")
|
git checkout version/$(python -c "from authentik import __version__; print(__version__)")
|
||||||
rm -rf .github/ scripts/
|
rm -rf .github/ scripts/
|
||||||
mv ../.github ../scripts .
|
mv ../.github ../scripts .
|
||||||
- name: Setup authentik env (ensure stable deps are installed)
|
- name: Setup authentik env (stable)
|
||||||
uses: ./.github/actions/setup
|
uses: ./.github/actions/setup
|
||||||
with:
|
with:
|
||||||
postgresql_version: ${{ matrix.psql }}
|
postgresql_version: ${{ matrix.psql }}
|
||||||
|
@ -90,14 +86,13 @@ jobs:
|
||||||
git clean -d -fx .
|
git clean -d -fx .
|
||||||
git checkout $GITHUB_SHA
|
git checkout $GITHUB_SHA
|
||||||
# Delete previous poetry env
|
# Delete previous poetry env
|
||||||
rm -rf $(poetry env info --path)
|
rm -rf /home/runner/.cache/pypoetry/virtualenvs/*
|
||||||
- name: Setup authentik env (ensure latest deps are installed)
|
- name: Setup authentik env (ensure latest deps are installed)
|
||||||
uses: ./.github/actions/setup
|
uses: ./.github/actions/setup
|
||||||
with:
|
with:
|
||||||
postgresql_version: ${{ matrix.psql }}
|
postgresql_version: ${{ matrix.psql }}
|
||||||
- name: migrate to latest
|
- name: migrate to latest
|
||||||
run: |
|
run: |
|
||||||
poetry install
|
|
||||||
poetry run python -m lifecycle.migrate
|
poetry run python -m lifecycle.migrate
|
||||||
test-unittest:
|
test-unittest:
|
||||||
name: test-unittest - PostgreSQL ${{ matrix.psql }}
|
name: test-unittest - PostgreSQL ${{ matrix.psql }}
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -115,8 +115,9 @@ gen-diff: ## (Release) generate the changelog diff between the current schema a
|
||||||
npx prettier --write diff.md
|
npx prettier --write diff.md
|
||||||
|
|
||||||
gen-clean:
|
gen-clean:
|
||||||
rm -rf web/api/src/
|
rm -rf gen-go-api/
|
||||||
rm -rf api/
|
rm -rf gen-ts-api/
|
||||||
|
rm -rf web/node_modules/@goauthentik/api/
|
||||||
|
|
||||||
gen-client-ts: ## Build and install the authentik API for Typescript into the authentik UI Application
|
gen-client-ts: ## Build and install the authentik API for Typescript into the authentik UI Application
|
||||||
docker run \
|
docker run \
|
||||||
|
|
|
@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from drf_spectacular.utils import extend_schema, inline_serializer
|
from drf_spectacular.utils import extend_schema, inline_serializer
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.fields import CharField, DateTimeField, JSONField
|
from rest_framework.fields import CharField, DateTimeField
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import ListSerializer, ModelSerializer
|
from rest_framework.serializers import ListSerializer, ModelSerializer
|
||||||
|
@ -15,7 +15,7 @@ from authentik.blueprints.v1.importer import Importer
|
||||||
from authentik.blueprints.v1.oci import OCI_PREFIX
|
from authentik.blueprints.v1.oci import OCI_PREFIX
|
||||||
from authentik.blueprints.v1.tasks import apply_blueprint, blueprints_find_dict
|
from authentik.blueprints.v1.tasks import apply_blueprint, blueprints_find_dict
|
||||||
from authentik.core.api.used_by import UsedByMixin
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
from authentik.core.api.utils import PassiveSerializer
|
from authentik.core.api.utils import JSONDictField, PassiveSerializer
|
||||||
|
|
||||||
|
|
||||||
class ManagedSerializer:
|
class ManagedSerializer:
|
||||||
|
@ -28,7 +28,7 @@ class MetadataSerializer(PassiveSerializer):
|
||||||
"""Serializer for blueprint metadata"""
|
"""Serializer for blueprint metadata"""
|
||||||
|
|
||||||
name = CharField()
|
name = CharField()
|
||||||
labels = JSONField()
|
labels = JSONDictField()
|
||||||
|
|
||||||
|
|
||||||
class BlueprintInstanceSerializer(ModelSerializer):
|
class BlueprintInstanceSerializer(ModelSerializer):
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.fields import BooleanField, JSONField
|
from rest_framework.fields import BooleanField
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik.blueprints.v1.meta.registry import BaseMetaModel, MetaResult, registry
|
from authentik.blueprints.v1.meta.registry import BaseMetaModel, MetaResult, registry
|
||||||
from authentik.core.api.utils import PassiveSerializer, is_dict
|
from authentik.core.api.utils import JSONDictField, PassiveSerializer
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from authentik.blueprints.models import BlueprintInstance
|
from authentik.blueprints.models import BlueprintInstance
|
||||||
|
@ -17,7 +17,7 @@ LOGGER = get_logger()
|
||||||
class ApplyBlueprintMetaSerializer(PassiveSerializer):
|
class ApplyBlueprintMetaSerializer(PassiveSerializer):
|
||||||
"""Serializer for meta apply blueprint model"""
|
"""Serializer for meta apply blueprint model"""
|
||||||
|
|
||||||
identifiers = JSONField(validators=[is_dict])
|
identifiers = JSONDictField()
|
||||||
required = BooleanField(default=True)
|
required = BooleanField(default=True)
|
||||||
|
|
||||||
# We cannot override `instance` as that will confuse rest_framework
|
# We cannot override `instance` as that will confuse rest_framework
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django_filters.filterset import FilterSet
|
||||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||||
from guardian.shortcuts import get_objects_for_user
|
from guardian.shortcuts import get_objects_for_user
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import CharField, IntegerField, JSONField
|
from rest_framework.fields import CharField, IntegerField
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import ListSerializer, ModelSerializer, ValidationError
|
from rest_framework.serializers import ListSerializer, ModelSerializer, ValidationError
|
||||||
|
@ -16,7 +16,7 @@ from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from authentik.api.decorators import permission_required
|
from authentik.api.decorators import permission_required
|
||||||
from authentik.core.api.used_by import UsedByMixin
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
from authentik.core.api.utils import PassiveSerializer, is_dict
|
from authentik.core.api.utils import JSONDictField, PassiveSerializer
|
||||||
from authentik.core.models import Group, User
|
from authentik.core.models import Group, User
|
||||||
from authentik.rbac.api.roles import RoleSerializer
|
from authentik.rbac.api.roles import RoleSerializer
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ from authentik.rbac.api.roles import RoleSerializer
|
||||||
class GroupMemberSerializer(ModelSerializer):
|
class GroupMemberSerializer(ModelSerializer):
|
||||||
"""Stripped down user serializer to show relevant users for groups"""
|
"""Stripped down user serializer to show relevant users for groups"""
|
||||||
|
|
||||||
attributes = JSONField(validators=[is_dict], required=False)
|
attributes = JSONDictField(required=False)
|
||||||
uid = CharField(read_only=True)
|
uid = CharField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -44,7 +44,7 @@ class GroupMemberSerializer(ModelSerializer):
|
||||||
class GroupSerializer(ModelSerializer):
|
class GroupSerializer(ModelSerializer):
|
||||||
"""Group Serializer"""
|
"""Group Serializer"""
|
||||||
|
|
||||||
attributes = JSONField(validators=[is_dict], required=False)
|
attributes = JSONDictField(required=False)
|
||||||
users_obj = ListSerializer(
|
users_obj = ListSerializer(
|
||||||
child=GroupMemberSerializer(), read_only=True, source="users", required=False
|
child=GroupMemberSerializer(), read_only=True, source="users", required=False
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,13 +32,7 @@ from drf_spectacular.utils import (
|
||||||
)
|
)
|
||||||
from guardian.shortcuts import get_anonymous_user, get_objects_for_user
|
from guardian.shortcuts import get_anonymous_user, get_objects_for_user
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import (
|
from rest_framework.fields import CharField, IntegerField, ListField, SerializerMethodField
|
||||||
CharField,
|
|
||||||
IntegerField,
|
|
||||||
JSONField,
|
|
||||||
ListField,
|
|
||||||
SerializerMethodField,
|
|
||||||
)
|
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import (
|
from rest_framework.serializers import (
|
||||||
|
@ -57,7 +51,7 @@ from authentik.admin.api.metrics import CoordinateSerializer
|
||||||
from authentik.api.decorators import permission_required
|
from authentik.api.decorators import permission_required
|
||||||
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
|
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
|
||||||
from authentik.core.api.used_by import UsedByMixin
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
from authentik.core.api.utils import LinkSerializer, PassiveSerializer, is_dict
|
from authentik.core.api.utils import JSONDictField, LinkSerializer, PassiveSerializer
|
||||||
from authentik.core.middleware import (
|
from authentik.core.middleware import (
|
||||||
SESSION_KEY_IMPERSONATE_ORIGINAL_USER,
|
SESSION_KEY_IMPERSONATE_ORIGINAL_USER,
|
||||||
SESSION_KEY_IMPERSONATE_USER,
|
SESSION_KEY_IMPERSONATE_USER,
|
||||||
|
@ -89,7 +83,7 @@ LOGGER = get_logger()
|
||||||
class UserGroupSerializer(ModelSerializer):
|
class UserGroupSerializer(ModelSerializer):
|
||||||
"""Simplified Group Serializer for user's groups"""
|
"""Simplified Group Serializer for user's groups"""
|
||||||
|
|
||||||
attributes = JSONField(required=False)
|
attributes = JSONDictField(required=False)
|
||||||
parent_name = CharField(source="parent.name", read_only=True)
|
parent_name = CharField(source="parent.name", read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -110,7 +104,7 @@ class UserSerializer(ModelSerializer):
|
||||||
|
|
||||||
is_superuser = BooleanField(read_only=True)
|
is_superuser = BooleanField(read_only=True)
|
||||||
avatar = CharField(read_only=True)
|
avatar = CharField(read_only=True)
|
||||||
attributes = JSONField(validators=[is_dict], required=False)
|
attributes = JSONDictField(required=False)
|
||||||
groups = PrimaryKeyRelatedField(
|
groups = PrimaryKeyRelatedField(
|
||||||
allow_empty=True, many=True, source="ak_groups", queryset=Group.objects.all(), default=list
|
allow_empty=True, many=True, source="ak_groups", queryset=Group.objects.all(), default=list
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
|
from drf_spectacular.extensions import OpenApiSerializerFieldExtension
|
||||||
|
from drf_spectacular.plumbing import build_basic_type
|
||||||
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from rest_framework.fields import CharField, IntegerField, JSONField
|
from rest_framework.fields import CharField, IntegerField, JSONField
|
||||||
from rest_framework.serializers import Serializer, SerializerMethodField, ValidationError
|
from rest_framework.serializers import Serializer, SerializerMethodField, ValidationError
|
||||||
|
|
||||||
|
@ -13,6 +16,21 @@ def is_dict(value: Any):
|
||||||
raise ValidationError("Value must be a dictionary, and not have any duplicate keys.")
|
raise ValidationError("Value must be a dictionary, and not have any duplicate keys.")
|
||||||
|
|
||||||
|
|
||||||
|
class JSONDictField(JSONField):
|
||||||
|
"""JSON Field which only allows dictionaries"""
|
||||||
|
|
||||||
|
default_validators = [is_dict]
|
||||||
|
|
||||||
|
|
||||||
|
class JSONExtension(OpenApiSerializerFieldExtension):
|
||||||
|
"""Generate API Schema for JSON fields as"""
|
||||||
|
|
||||||
|
target_class = "authentik.core.api.utils.JSONDictField"
|
||||||
|
|
||||||
|
def map_serializer_field(self, auto_schema, direction):
|
||||||
|
return build_basic_type(OpenApiTypes.OBJECT)
|
||||||
|
|
||||||
|
|
||||||
class PassiveSerializer(Serializer):
|
class PassiveSerializer(Serializer):
|
||||||
"""Base serializer class which doesn't implement create/update methods"""
|
"""Base serializer class which doesn't implement create/update methods"""
|
||||||
|
|
||||||
|
@ -26,7 +44,7 @@ class PassiveSerializer(Serializer):
|
||||||
class PropertyMappingPreviewSerializer(PassiveSerializer):
|
class PropertyMappingPreviewSerializer(PassiveSerializer):
|
||||||
"""Preview how the current user is mapped via the property mappings selected in a provider"""
|
"""Preview how the current user is mapped via the property mappings selected in a provider"""
|
||||||
|
|
||||||
preview = JSONField(read_only=True)
|
preview = JSONDictField(read_only=True)
|
||||||
|
|
||||||
|
|
||||||
class MetaNameSerializer(PassiveSerializer):
|
class MetaNameSerializer(PassiveSerializer):
|
||||||
|
|
|
@ -9,13 +9,13 @@ from rest_framework.fields import BooleanField, CharField, DateTimeField
|
||||||
from rest_framework.relations import PrimaryKeyRelatedField
|
from rest_framework.relations import PrimaryKeyRelatedField
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import JSONField, ModelSerializer, ValidationError
|
from rest_framework.serializers import ModelSerializer, ValidationError
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from authentik import get_build_hash
|
from authentik import get_build_hash
|
||||||
from authentik.core.api.providers import ProviderSerializer
|
from authentik.core.api.providers import ProviderSerializer
|
||||||
from authentik.core.api.used_by import UsedByMixin
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
from authentik.core.api.utils import PassiveSerializer, is_dict
|
from authentik.core.api.utils import JSONDictField, PassiveSerializer
|
||||||
from authentik.core.models import Provider
|
from authentik.core.models import Provider
|
||||||
from authentik.outposts.api.service_connections import ServiceConnectionSerializer
|
from authentik.outposts.api.service_connections import ServiceConnectionSerializer
|
||||||
from authentik.outposts.apps import MANAGED_OUTPOST
|
from authentik.outposts.apps import MANAGED_OUTPOST
|
||||||
|
@ -34,7 +34,7 @@ from authentik.providers.radius.models import RadiusProvider
|
||||||
class OutpostSerializer(ModelSerializer):
|
class OutpostSerializer(ModelSerializer):
|
||||||
"""Outpost Serializer"""
|
"""Outpost Serializer"""
|
||||||
|
|
||||||
config = JSONField(validators=[is_dict], source="_config")
|
config = JSONDictField(source="_config")
|
||||||
# Need to set allow_empty=True for the embedded outpost with no providers
|
# Need to set allow_empty=True for the embedded outpost with no providers
|
||||||
# is checked for other providers in the API Viewset
|
# is checked for other providers in the API Viewset
|
||||||
providers = PrimaryKeyRelatedField(
|
providers = PrimaryKeyRelatedField(
|
||||||
|
@ -95,7 +95,7 @@ class OutpostSerializer(ModelSerializer):
|
||||||
class OutpostDefaultConfigSerializer(PassiveSerializer):
|
class OutpostDefaultConfigSerializer(PassiveSerializer):
|
||||||
"""Global default outpost config"""
|
"""Global default outpost config"""
|
||||||
|
|
||||||
config = JSONField(read_only=True)
|
config = JSONDictField(read_only=True)
|
||||||
|
|
||||||
|
|
||||||
class OutpostHealthSerializer(PassiveSerializer):
|
class OutpostHealthSerializer(PassiveSerializer):
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
"""Serializer for policy execution"""
|
"""Serializer for policy execution"""
|
||||||
from rest_framework.fields import BooleanField, CharField, DictField, JSONField, ListField
|
from rest_framework.fields import BooleanField, CharField, DictField, ListField
|
||||||
from rest_framework.relations import PrimaryKeyRelatedField
|
from rest_framework.relations import PrimaryKeyRelatedField
|
||||||
|
|
||||||
from authentik.core.api.utils import PassiveSerializer, is_dict
|
from authentik.core.api.utils import JSONDictField, PassiveSerializer
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ class PolicyTestSerializer(PassiveSerializer):
|
||||||
"""Test policy execution for a user with context"""
|
"""Test policy execution for a user with context"""
|
||||||
|
|
||||||
user = PrimaryKeyRelatedField(queryset=User.objects.all())
|
user = PrimaryKeyRelatedField(queryset=User.objects.all())
|
||||||
context = JSONField(required=False, validators=[is_dict])
|
context = JSONDictField(required=False)
|
||||||
|
|
||||||
|
|
||||||
class PolicyTestResultSerializer(PassiveSerializer):
|
class PolicyTestResultSerializer(PassiveSerializer):
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
"""
|
||||||
|
Module for abstract serializer/unserializer base classes.
|
||||||
|
"""
|
||||||
|
import pickle # nosec
|
||||||
|
|
||||||
|
|
||||||
|
class PickleSerializer:
|
||||||
|
"""
|
||||||
|
Simple wrapper around pickle to be used in signing.dumps()/loads() and
|
||||||
|
cache backends.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, protocol=None):
|
||||||
|
self.protocol = pickle.HIGHEST_PROTOCOL if protocol is None else protocol
|
||||||
|
|
||||||
|
def dumps(self, obj):
|
||||||
|
"""Pickle data to be stored in redis"""
|
||||||
|
return pickle.dumps(obj, self.protocol)
|
||||||
|
|
||||||
|
def loads(self, data):
|
||||||
|
"""Unpickle data to be loaded from redis"""
|
||||||
|
return pickle.loads(data) # nosec
|
|
@ -138,6 +138,7 @@ SPECTACULAR_SETTINGS = {
|
||||||
"EventActions": "authentik.events.models.EventAction",
|
"EventActions": "authentik.events.models.EventAction",
|
||||||
"ChallengeChoices": "authentik.flows.challenge.ChallengeTypes",
|
"ChallengeChoices": "authentik.flows.challenge.ChallengeTypes",
|
||||||
"FlowDesignationEnum": "authentik.flows.models.FlowDesignation",
|
"FlowDesignationEnum": "authentik.flows.models.FlowDesignation",
|
||||||
|
"FlowLayoutEnum": "authentik.flows.models.FlowLayout",
|
||||||
"PolicyEngineMode": "authentik.policies.models.PolicyEngineMode",
|
"PolicyEngineMode": "authentik.policies.models.PolicyEngineMode",
|
||||||
"ProxyMode": "authentik.providers.proxy.models.ProxyMode",
|
"ProxyMode": "authentik.providers.proxy.models.ProxyMode",
|
||||||
"PromptTypeEnum": "authentik.stages.prompt.models.FieldTypes",
|
"PromptTypeEnum": "authentik.stages.prompt.models.FieldTypes",
|
||||||
|
@ -204,7 +205,7 @@ DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
||||||
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
|
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
|
||||||
DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
|
DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
|
||||||
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
|
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
|
||||||
SESSION_SERIALIZER = "django.contrib.sessions.serializers.PickleSerializer"
|
SESSION_SERIALIZER = "authentik.root.sessions.pickle.PickleSerializer"
|
||||||
SESSION_CACHE_ALIAS = "default"
|
SESSION_CACHE_ALIAS = "default"
|
||||||
# Configured via custom SessionMiddleware
|
# Configured via custom SessionMiddleware
|
||||||
# SESSION_COOKIE_SAMESITE = "None"
|
# SESSION_COOKIE_SAMESITE = "None"
|
||||||
|
|
|
@ -22,8 +22,8 @@ from authentik.stages.authenticator.util import hex_validator, random_hex
|
||||||
class TOTPDigits(models.TextChoices):
|
class TOTPDigits(models.TextChoices):
|
||||||
"""OTP Time Digits"""
|
"""OTP Time Digits"""
|
||||||
|
|
||||||
SIX = 6, _("6 digits, widely compatible")
|
SIX = "6", _("6 digits, widely compatible")
|
||||||
EIGHT = 8, _("8 digits, not compatible with apps like Google Authenticator")
|
EIGHT = "8", _("8 digits, not compatible with apps like Google Authenticator")
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorTOTPStage(ConfigurableStage, FriendlyNamedStage, Stage):
|
class AuthenticatorTOTPStage(ConfigurableStage, FriendlyNamedStage, Stage):
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.http.response import Http404
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import gettext as __
|
from django.utils.translation import gettext as __
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework.fields import CharField, JSONField
|
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
|
||||||
from webauthn.authentication.generate_authentication_options import generate_authentication_options
|
from webauthn.authentication.generate_authentication_options import generate_authentication_options
|
||||||
|
@ -16,7 +16,7 @@ from webauthn.helpers.base64url_to_bytes import base64url_to_bytes
|
||||||
from webauthn.helpers.exceptions import InvalidAuthenticationResponse
|
from webauthn.helpers.exceptions import InvalidAuthenticationResponse
|
||||||
from webauthn.helpers.structs import AuthenticationCredential
|
from webauthn.helpers.structs import AuthenticationCredential
|
||||||
|
|
||||||
from authentik.core.api.utils import PassiveSerializer
|
from authentik.core.api.utils import JSONDictField, PassiveSerializer
|
||||||
from authentik.core.models import Application, User
|
from authentik.core.models import Application, User
|
||||||
from authentik.core.signals import login_failed
|
from authentik.core.signals import login_failed
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
|
@ -40,7 +40,7 @@ class DeviceChallenge(PassiveSerializer):
|
||||||
|
|
||||||
device_class = CharField()
|
device_class = CharField()
|
||||||
device_uid = CharField()
|
device_uid = CharField()
|
||||||
challenge = JSONField()
|
challenge = JSONDictField()
|
||||||
|
|
||||||
|
|
||||||
def get_challenge_for_device(
|
def get_challenge_for_device(
|
||||||
|
|
|
@ -6,10 +6,10 @@ from typing import Optional
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from jwt import PyJWTError, decode, encode
|
from jwt import PyJWTError, decode, encode
|
||||||
from rest_framework.fields import CharField, IntegerField, JSONField, ListField, UUIDField
|
from rest_framework.fields import CharField, IntegerField, ListField, UUIDField
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
|
|
||||||
from authentik.core.api.utils import 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, ChallengeTypes, WithUserInfoChallenge
|
||||||
|
@ -68,7 +68,7 @@ class AuthenticatorValidationChallengeResponse(ChallengeResponse):
|
||||||
selected_stage = CharField(required=False)
|
selected_stage = CharField(required=False)
|
||||||
|
|
||||||
code = CharField(required=False)
|
code = CharField(required=False)
|
||||||
webauthn = JSONField(required=False)
|
webauthn = JSONDictField(required=False)
|
||||||
duo = IntegerField(required=False)
|
duo = IntegerField(required=False)
|
||||||
component = CharField(default="ak-stage-authenticator-validate")
|
component = CharField(default="ak-stage-authenticator-validate")
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""WebAuthn stage"""
|
"""WebAuthn stage"""
|
||||||
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 CharField, JSONField
|
from rest_framework.fields import CharField
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
from webauthn.helpers.bytes_to_base64url import bytes_to_base64url
|
from webauthn.helpers.bytes_to_base64url import bytes_to_base64url
|
||||||
from webauthn.helpers.exceptions import InvalidRegistrationResponse
|
from webauthn.helpers.exceptions import InvalidRegistrationResponse
|
||||||
|
@ -16,6 +16,7 @@ from webauthn.registration.verify_registration_response import (
|
||||||
verify_registration_response,
|
verify_registration_response,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from authentik.core.api.utils import JSONDictField
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
from authentik.flows.challenge import (
|
from authentik.flows.challenge import (
|
||||||
Challenge,
|
Challenge,
|
||||||
|
@ -33,14 +34,14 @@ SESSION_KEY_WEBAUTHN_CHALLENGE = "authentik/stages/authenticator_webauthn/challe
|
||||||
class AuthenticatorWebAuthnChallenge(WithUserInfoChallenge):
|
class AuthenticatorWebAuthnChallenge(WithUserInfoChallenge):
|
||||||
"""WebAuthn Challenge"""
|
"""WebAuthn Challenge"""
|
||||||
|
|
||||||
registration = JSONField()
|
registration = JSONDictField()
|
||||||
component = CharField(default="ak-stage-authenticator-webauthn")
|
component = CharField(default="ak-stage-authenticator-webauthn")
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse):
|
class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse):
|
||||||
"""WebAuthn Challenge response"""
|
"""WebAuthn Challenge response"""
|
||||||
|
|
||||||
response = JSONField()
|
response = JSONDictField()
|
||||||
component = CharField(default="ak-stage-authenticator-webauthn")
|
component = CharField(default="ak-stage-authenticator-webauthn")
|
||||||
|
|
||||||
request: HttpRequest
|
request: HttpRequest
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
"""Invitation Stage API Views"""
|
"""Invitation Stage API Views"""
|
||||||
from django_filters.filters import BooleanFilter
|
from django_filters.filters import BooleanFilter
|
||||||
from django_filters.filterset import FilterSet
|
from django_filters.filterset import FilterSet
|
||||||
from rest_framework.fields import JSONField
|
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from authentik.core.api.groups import GroupMemberSerializer
|
from authentik.core.api.groups import GroupMemberSerializer
|
||||||
from authentik.core.api.used_by import UsedByMixin
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
from authentik.core.api.utils import is_dict
|
from authentik.core.api.utils import JSONDictField
|
||||||
from authentik.flows.api.flows import FlowSerializer
|
from authentik.flows.api.flows import FlowSerializer
|
||||||
from authentik.flows.api.stages import StageSerializer
|
from authentik.flows.api.stages import StageSerializer
|
||||||
from authentik.stages.invitation.models import Invitation, InvitationStage
|
from authentik.stages.invitation.models import Invitation, InvitationStage
|
||||||
|
@ -47,7 +46,7 @@ class InvitationSerializer(ModelSerializer):
|
||||||
"""Invitation Serializer"""
|
"""Invitation Serializer"""
|
||||||
|
|
||||||
created_by = GroupMemberSerializer(read_only=True)
|
created_by = GroupMemberSerializer(read_only=True)
|
||||||
fixed_data = JSONField(validators=[is_dict], required=False)
|
fixed_data = JSONDictField(required=False)
|
||||||
flow_obj = FlowSerializer(read_only=True, required=False, source="flow")
|
flow_obj = FlowSerializer(read_only=True, required=False, source="flow")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -81,7 +81,6 @@ var rootCmd = &cobra.Command{
|
||||||
for {
|
for {
|
||||||
<-ex
|
<-ex
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -82,3 +82,5 @@ require (
|
||||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace goauthentik.io/api/v3 => ./gen-go-api
|
||||||
|
|
|
@ -76,7 +76,6 @@ func NewAPIController(akURL url.URL, token string) *APIController {
|
||||||
// Because we don't know the outpost UUID, we simply do a list and pick the first
|
// Because we don't know the outpost UUID, we simply do a list and pick the first
|
||||||
// The service account this token belongs to should only have access to a single outpost
|
// The service account this token belongs to should only have access to a single outpost
|
||||||
outposts, _, err := apiClient.OutpostsApi.OutpostsInstancesList(context.Background()).Execute()
|
outposts, _, err := apiClient.OutpostsApi.OutpostsInstancesList(context.Background()).Execute()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Failed to fetch outpost configuration, retrying in 3 seconds")
|
log.WithError(err).Error("Failed to fetch outpost configuration, retrying in 3 seconds")
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
|
@ -168,7 +167,6 @@ func (a *APIController) OnRefresh() error {
|
||||||
// Because we don't know the outpost UUID, we simply do a list and pick the first
|
// Because we don't know the outpost UUID, we simply do a list and pick the first
|
||||||
// The service account this token belongs to should only have access to a single outpost
|
// The service account this token belongs to should only have access to a single outpost
|
||||||
outposts, _, err := a.Client.OutpostsApi.OutpostsInstancesList(context.Background()).Execute()
|
outposts, _, err := a.Client.OutpostsApi.OutpostsInstancesList(context.Background()).Execute()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Failed to fetch outpost configuration")
|
log.WithError(err).Error("Failed to fetch outpost configuration")
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -14,8 +14,10 @@ import (
|
||||||
webutils "goauthentik.io/internal/utils/web"
|
webutils "goauthentik.io/internal/utils/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
var initialSetup = false
|
var (
|
||||||
var tlsTransport *http.RoundTripper = nil
|
initialSetup = false
|
||||||
|
tlsTransport *http.RoundTripper = nil
|
||||||
|
)
|
||||||
|
|
||||||
func doGlobalSetup(outpost api.Outpost, globalConfig *api.Config) {
|
func doGlobalSetup(outpost api.Outpost, globalConfig *api.Config) {
|
||||||
l := log.WithField("logger", "authentik.outpost")
|
l := log.WithField("logger", "authentik.outpost")
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
package handler
|
package handler
|
||||||
|
|
||||||
type Handler interface {
|
type Handler interface{}
|
||||||
}
|
|
||||||
|
|
|
@ -78,5 +78,4 @@ func (ls *LDAPServer) fallbackRootDSE(req *search.Request) (ldap.ServerSearchRes
|
||||||
},
|
},
|
||||||
Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess,
|
Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,12 +59,12 @@ func (a *Application) addHeaders(headers http.Header, c *Claims) {
|
||||||
userAttributes := c.Proxy.UserAttributes
|
userAttributes := c.Proxy.UserAttributes
|
||||||
a.setAuthorizationHeader(headers, c)
|
a.setAuthorizationHeader(headers, c)
|
||||||
// Check if user has additional headers set that we should sent
|
// Check if user has additional headers set that we should sent
|
||||||
if additionalHeaders, ok := userAttributes["additionalHeaders"].(map[string]interface{}); ok {
|
if additionalHeaders, ok := userAttributes["additionalHeaders"]; ok {
|
||||||
a.log.WithField("headers", additionalHeaders).Trace("setting additional headers")
|
a.log.WithField("headers", additionalHeaders).Trace("setting additional headers")
|
||||||
if additionalHeaders == nil {
|
if additionalHeaders == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for key, value := range additionalHeaders {
|
for key, value := range additionalHeaders.(map[string]interface{}) {
|
||||||
headers.Set(key, toString(value))
|
headers.Set(key, toString(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package constants
|
package constants
|
||||||
|
|
||||||
const SessionOAuthState = "oauth_state"
|
const (
|
||||||
const SessionClaims = "claims"
|
SessionOAuthState = "oauth_state"
|
||||||
|
SessionClaims = "claims"
|
||||||
|
)
|
||||||
|
|
||||||
const SessionRedirect = "redirect"
|
const SessionRedirect = "redirect"
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusR
|
||||||
fe := flow.NewFlowExecutor(r.Context(), r.pi.flowSlug, r.pi.s.ac.Client.GetConfig(), log.Fields{
|
fe := flow.NewFlowExecutor(r.Context(), r.pi.flowSlug, r.pi.s.ac.Client.GetConfig(), log.Fields{
|
||||||
"username": username,
|
"username": username,
|
||||||
"client": r.RemoteAddr(),
|
"client": r.RemoteAddr(),
|
||||||
"requestId": r.ID,
|
"requestId": r.ID(),
|
||||||
})
|
})
|
||||||
fe.DelegateClientIP(r.RemoteAddr())
|
fe.DelegateClientIP(r.RemoteAddr())
|
||||||
fe.Params.Add("goauthentik.io/outpost/radius", "true")
|
fe.Params.Add("goauthentik.io/outpost/radius", "true")
|
||||||
|
@ -27,7 +27,6 @@ func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusR
|
||||||
}
|
}
|
||||||
|
|
||||||
passed, err := fe.Execute()
|
passed, err := fe.Execute()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Log().WithField("username", username).WithError(err).Warning("failed to execute flow")
|
r.Log().WithField("username", username).WithError(err).Warning("failed to execute flow")
|
||||||
metrics.RequestsRejected.With(prometheus.Labels{
|
metrics.RequestsRejected.With(prometheus.Labels{
|
||||||
|
|
|
@ -14,12 +14,10 @@ import (
|
||||||
"goauthentik.io/internal/utils/sentry"
|
"goauthentik.io/internal/utils/sentry"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var Requests = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||||
Requests = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
|
||||||
Name: "authentik_main_request_duration_seconds",
|
Name: "authentik_main_request_duration_seconds",
|
||||||
Help: "API request latencies in seconds",
|
Help: "API request latencies in seconds",
|
||||||
}, []string{"dest"})
|
}, []string{"dest"})
|
||||||
)
|
|
||||||
|
|
||||||
func (ws *WebServer) runMetricsServer() {
|
func (ws *WebServer) runMetricsServer() {
|
||||||
m := mux.NewRouter()
|
m := mux.NewRouter()
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
139
schema.yml
139
schema.yml
|
@ -18334,6 +18334,7 @@ paths:
|
||||||
- tr
|
- tr
|
||||||
- tt
|
- tt
|
||||||
- udm
|
- udm
|
||||||
|
- ug
|
||||||
- uk
|
- uk
|
||||||
- ur
|
- ur
|
||||||
- uz
|
- uz
|
||||||
|
@ -29205,9 +29206,7 @@ components:
|
||||||
path:
|
path:
|
||||||
type: string
|
type: string
|
||||||
default: ''
|
default: ''
|
||||||
context:
|
context: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
last_applied:
|
last_applied:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
|
@ -29227,8 +29226,6 @@ components:
|
||||||
type: string
|
type: string
|
||||||
readOnly: true
|
readOnly: true
|
||||||
metadata:
|
metadata:
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
readOnly: true
|
readOnly: true
|
||||||
content:
|
content:
|
||||||
type: string
|
type: string
|
||||||
|
@ -29250,9 +29247,7 @@ components:
|
||||||
path:
|
path:
|
||||||
type: string
|
type: string
|
||||||
default: ''
|
default: ''
|
||||||
context:
|
context: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
enabled:
|
enabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
content:
|
content:
|
||||||
|
@ -29772,10 +29767,24 @@ components:
|
||||||
cancel_url:
|
cancel_url:
|
||||||
type: string
|
type: string
|
||||||
layout:
|
layout:
|
||||||
$ref: '#/components/schemas/LayoutEnum'
|
$ref: '#/components/schemas/ContextualFlowInfoLayoutEnum'
|
||||||
required:
|
required:
|
||||||
- cancel_url
|
- cancel_url
|
||||||
- layout
|
- layout
|
||||||
|
ContextualFlowInfoLayoutEnum:
|
||||||
|
enum:
|
||||||
|
- stacked
|
||||||
|
- content_left
|
||||||
|
- content_right
|
||||||
|
- sidebar_left
|
||||||
|
- sidebar_right
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
* `stacked` - STACKED
|
||||||
|
* `content_left` - CONTENT_LEFT
|
||||||
|
* `content_right` - CONTENT_RIGHT
|
||||||
|
* `sidebar_left` - SIDEBAR_LEFT
|
||||||
|
* `sidebar_right` - SIDEBAR_RIGHT
|
||||||
Coordinate:
|
Coordinate:
|
||||||
type: object
|
type: object
|
||||||
description: Coordinates for diagrams
|
description: Coordinates for diagrams
|
||||||
|
@ -30493,16 +30502,12 @@ components:
|
||||||
format: uuid
|
format: uuid
|
||||||
readOnly: true
|
readOnly: true
|
||||||
title: Event uuid
|
title: Event uuid
|
||||||
user:
|
user: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
action:
|
action:
|
||||||
$ref: '#/components/schemas/EventActions'
|
$ref: '#/components/schemas/EventActions'
|
||||||
app:
|
app:
|
||||||
type: string
|
type: string
|
||||||
context:
|
context: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
client_ip:
|
client_ip:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
@ -30513,9 +30518,7 @@ components:
|
||||||
expires:
|
expires:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
tenant:
|
tenant: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
required:
|
required:
|
||||||
- action
|
- action
|
||||||
- app
|
- app
|
||||||
|
@ -30992,17 +30995,13 @@ components:
|
||||||
type: object
|
type: object
|
||||||
description: Event Serializer
|
description: Event Serializer
|
||||||
properties:
|
properties:
|
||||||
user:
|
user: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
action:
|
action:
|
||||||
$ref: '#/components/schemas/EventActions'
|
$ref: '#/components/schemas/EventActions'
|
||||||
app:
|
app:
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
context:
|
context: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
client_ip:
|
client_ip:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
@ -31010,9 +31009,7 @@ components:
|
||||||
expires:
|
expires:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
tenant:
|
tenant: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
required:
|
required:
|
||||||
- action
|
- action
|
||||||
- app
|
- app
|
||||||
|
@ -31311,7 +31308,7 @@ components:
|
||||||
description: Get export URL for flow
|
description: Get export URL for flow
|
||||||
readOnly: true
|
readOnly: true
|
||||||
layout:
|
layout:
|
||||||
$ref: '#/components/schemas/LayoutEnum'
|
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||||
denied_action:
|
denied_action:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||||
|
@ -31498,6 +31495,20 @@ components:
|
||||||
- next_planned_stage
|
- next_planned_stage
|
||||||
- plan_context
|
- plan_context
|
||||||
- session_id
|
- session_id
|
||||||
|
FlowLayoutEnum:
|
||||||
|
enum:
|
||||||
|
- stacked
|
||||||
|
- content_left
|
||||||
|
- content_right
|
||||||
|
- sidebar_left
|
||||||
|
- sidebar_right
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
* `stacked` - Stacked
|
||||||
|
* `content_left` - Content Left
|
||||||
|
* `content_right` - Content Right
|
||||||
|
* `sidebar_left` - Sidebar Left
|
||||||
|
* `sidebar_right` - Sidebar Right
|
||||||
FlowRequest:
|
FlowRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Flow Serializer
|
description: Flow Serializer
|
||||||
|
@ -31535,7 +31546,7 @@ components:
|
||||||
description: Enable compatibility mode, increases compatibility with password
|
description: Enable compatibility mode, increases compatibility with password
|
||||||
managers on mobile devices.
|
managers on mobile devices.
|
||||||
layout:
|
layout:
|
||||||
$ref: '#/components/schemas/LayoutEnum'
|
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||||
denied_action:
|
denied_action:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||||
|
@ -31613,7 +31624,7 @@ components:
|
||||||
description: Get export URL for flow
|
description: Get export URL for flow
|
||||||
readOnly: true
|
readOnly: true
|
||||||
layout:
|
layout:
|
||||||
$ref: '#/components/schemas/LayoutEnum'
|
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||||
denied_action:
|
denied_action:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||||
|
@ -31669,7 +31680,7 @@ components:
|
||||||
description: Enable compatibility mode, increases compatibility with password
|
description: Enable compatibility mode, increases compatibility with password
|
||||||
managers on mobile devices.
|
managers on mobile devices.
|
||||||
layout:
|
layout:
|
||||||
$ref: '#/components/schemas/LayoutEnum'
|
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||||
denied_action:
|
denied_action:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||||
|
@ -32361,8 +32372,6 @@ components:
|
||||||
description: Return internal model name
|
description: Return internal model name
|
||||||
readOnly: true
|
readOnly: true
|
||||||
kubeconfig:
|
kubeconfig:
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
description: Paste your kubeconfig here. authentik will automatically use
|
description: Paste your kubeconfig here. authentik will automatically use
|
||||||
the currently selected context.
|
the currently selected context.
|
||||||
verify_ssl:
|
verify_ssl:
|
||||||
|
@ -32387,8 +32396,6 @@ components:
|
||||||
description: If enabled, use the local connection. Required Docker socket/Kubernetes
|
description: If enabled, use the local connection. Required Docker socket/Kubernetes
|
||||||
Integration
|
Integration
|
||||||
kubeconfig:
|
kubeconfig:
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
description: Paste your kubeconfig here. authentik will automatically use
|
description: Paste your kubeconfig here. authentik will automatically use
|
||||||
the currently selected context.
|
the currently selected context.
|
||||||
verify_ssl:
|
verify_ssl:
|
||||||
|
@ -33053,20 +33060,6 @@ components:
|
||||||
required:
|
required:
|
||||||
- is_running
|
- is_running
|
||||||
- tasks
|
- tasks
|
||||||
LayoutEnum:
|
|
||||||
enum:
|
|
||||||
- stacked
|
|
||||||
- content_left
|
|
||||||
- content_right
|
|
||||||
- sidebar_left
|
|
||||||
- sidebar_right
|
|
||||||
type: string
|
|
||||||
description: |-
|
|
||||||
* `stacked` - STACKED
|
|
||||||
* `content_left` - CONTENT_LEFT
|
|
||||||
* `content_right` - CONTENT_RIGHT
|
|
||||||
* `sidebar_left` - SIDEBAR_LEFT
|
|
||||||
* `sidebar_right` - SIDEBAR_RIGHT
|
|
||||||
License:
|
License:
|
||||||
type: object
|
type: object
|
||||||
description: License Serializer
|
description: License Serializer
|
||||||
|
@ -34052,9 +34045,7 @@ components:
|
||||||
type: string
|
type: string
|
||||||
oidc_jwks_url:
|
oidc_jwks_url:
|
||||||
type: string
|
type: string
|
||||||
oidc_jwks:
|
oidc_jwks: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
required:
|
required:
|
||||||
- callback_url
|
- callback_url
|
||||||
- component
|
- component
|
||||||
|
@ -34151,9 +34142,7 @@ components:
|
||||||
type: string
|
type: string
|
||||||
oidc_jwks_url:
|
oidc_jwks_url:
|
||||||
type: string
|
type: string
|
||||||
oidc_jwks:
|
oidc_jwks: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
required:
|
required:
|
||||||
- consumer_key
|
- consumer_key
|
||||||
- consumer_secret
|
- consumer_secret
|
||||||
|
@ -36042,9 +36031,7 @@ components:
|
||||||
path:
|
path:
|
||||||
type: string
|
type: string
|
||||||
default: ''
|
default: ''
|
||||||
context:
|
context: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
enabled:
|
enabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
content:
|
content:
|
||||||
|
@ -36441,17 +36428,13 @@ components:
|
||||||
type: object
|
type: object
|
||||||
description: Event Serializer
|
description: Event Serializer
|
||||||
properties:
|
properties:
|
||||||
user:
|
user: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
action:
|
action:
|
||||||
$ref: '#/components/schemas/EventActions'
|
$ref: '#/components/schemas/EventActions'
|
||||||
app:
|
app:
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
context:
|
context: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
client_ip:
|
client_ip:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
@ -36459,9 +36442,7 @@ components:
|
||||||
expires:
|
expires:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
tenant:
|
tenant: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
PatchedExpressionPolicyRequest:
|
PatchedExpressionPolicyRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Group Membership Policy Serializer
|
description: Group Membership Policy Serializer
|
||||||
|
@ -36513,7 +36494,7 @@ components:
|
||||||
description: Enable compatibility mode, increases compatibility with password
|
description: Enable compatibility mode, increases compatibility with password
|
||||||
managers on mobile devices.
|
managers on mobile devices.
|
||||||
layout:
|
layout:
|
||||||
$ref: '#/components/schemas/LayoutEnum'
|
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||||
denied_action:
|
denied_action:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||||
|
@ -36703,8 +36684,6 @@ components:
|
||||||
description: If enabled, use the local connection. Required Docker socket/Kubernetes
|
description: If enabled, use the local connection. Required Docker socket/Kubernetes
|
||||||
Integration
|
Integration
|
||||||
kubeconfig:
|
kubeconfig:
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
description: Paste your kubeconfig here. authentik will automatically use
|
description: Paste your kubeconfig here. authentik will automatically use
|
||||||
the currently selected context.
|
the currently selected context.
|
||||||
verify_ssl:
|
verify_ssl:
|
||||||
|
@ -37165,9 +37144,7 @@ components:
|
||||||
type: string
|
type: string
|
||||||
oidc_jwks_url:
|
oidc_jwks_url:
|
||||||
type: string
|
type: string
|
||||||
oidc_jwks:
|
oidc_jwks: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
PatchedOutpostRequest:
|
PatchedOutpostRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Outpost Serializer
|
description: Outpost Serializer
|
||||||
|
@ -38011,9 +37988,7 @@ components:
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
description: Web Certificate used by the authentik Core webserver.
|
description: Web Certificate used by the authentik Core webserver.
|
||||||
attributes:
|
attributes: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
PatchedTokenRequest:
|
PatchedTokenRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Token Serializer
|
description: Token Serializer
|
||||||
|
@ -39686,9 +39661,7 @@ components:
|
||||||
type: string
|
type: string
|
||||||
ip:
|
ip:
|
||||||
type: string
|
type: string
|
||||||
ip_geo_data:
|
ip_geo_data: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
score:
|
score:
|
||||||
type: integer
|
type: integer
|
||||||
maximum: 9223372036854775807
|
maximum: 9223372036854775807
|
||||||
|
@ -41415,9 +41388,7 @@ components:
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
description: Web Certificate used by the authentik Core webserver.
|
description: Web Certificate used by the authentik Core webserver.
|
||||||
attributes:
|
attributes: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
required:
|
required:
|
||||||
- domain
|
- domain
|
||||||
- tenant_uuid
|
- tenant_uuid
|
||||||
|
@ -41474,9 +41445,7 @@ components:
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
description: Web Certificate used by the authentik Core webserver.
|
description: Web Certificate used by the authentik Core webserver.
|
||||||
attributes:
|
attributes: {}
|
||||||
type: object
|
|
||||||
additionalProperties: {}
|
|
||||||
required:
|
required:
|
||||||
- domain
|
- domain
|
||||||
Token:
|
Token:
|
||||||
|
|
|
@ -18,8 +18,8 @@ import {
|
||||||
DeniedActionEnum,
|
DeniedActionEnum,
|
||||||
Flow,
|
Flow,
|
||||||
FlowDesignationEnum,
|
FlowDesignationEnum,
|
||||||
|
FlowLayoutEnum,
|
||||||
FlowsApi,
|
FlowsApi,
|
||||||
LayoutEnum,
|
|
||||||
PolicyEngineMode,
|
PolicyEngineMode,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
@ -302,34 +302,34 @@ export class FlowForm extends ModelForm<Flow, string> {
|
||||||
>
|
>
|
||||||
<select class="pf-c-form-control">
|
<select class="pf-c-form-control">
|
||||||
<option
|
<option
|
||||||
value=${LayoutEnum.Stacked}
|
value=${FlowLayoutEnum.Stacked}
|
||||||
?selected=${this.instance?.layout === LayoutEnum.Stacked}
|
?selected=${this.instance?.layout === FlowLayoutEnum.Stacked}
|
||||||
>
|
>
|
||||||
${LayoutToLabel(LayoutEnum.Stacked)}
|
${LayoutToLabel(FlowLayoutEnum.Stacked)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${LayoutEnum.ContentLeft}
|
value=${FlowLayoutEnum.ContentLeft}
|
||||||
?selected=${this.instance?.layout === LayoutEnum.ContentLeft}
|
?selected=${this.instance?.layout === FlowLayoutEnum.ContentLeft}
|
||||||
>
|
>
|
||||||
${LayoutToLabel(LayoutEnum.ContentLeft)}
|
${LayoutToLabel(FlowLayoutEnum.ContentLeft)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${LayoutEnum.ContentRight}
|
value=${FlowLayoutEnum.ContentRight}
|
||||||
?selected=${this.instance?.layout === LayoutEnum.ContentRight}
|
?selected=${this.instance?.layout === FlowLayoutEnum.ContentRight}
|
||||||
>
|
>
|
||||||
${LayoutToLabel(LayoutEnum.ContentRight)}
|
${LayoutToLabel(FlowLayoutEnum.ContentRight)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${LayoutEnum.SidebarLeft}
|
value=${FlowLayoutEnum.SidebarLeft}
|
||||||
?selected=${this.instance?.layout === LayoutEnum.SidebarLeft}
|
?selected=${this.instance?.layout === FlowLayoutEnum.SidebarLeft}
|
||||||
>
|
>
|
||||||
${LayoutToLabel(LayoutEnum.SidebarLeft)}
|
${LayoutToLabel(FlowLayoutEnum.SidebarLeft)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${LayoutEnum.SidebarRight}
|
value=${FlowLayoutEnum.SidebarRight}
|
||||||
?selected=${this.instance?.layout === LayoutEnum.SidebarRight}
|
?selected=${this.instance?.layout === FlowLayoutEnum.SidebarRight}
|
||||||
>
|
>
|
||||||
${LayoutToLabel(LayoutEnum.SidebarRight)}
|
${LayoutToLabel(FlowLayoutEnum.SidebarRight)}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
|
|
||||||
import { Flow, FlowDesignationEnum, LayoutEnum } from "@goauthentik/api";
|
import { Flow, FlowDesignationEnum, FlowLayoutEnum } from "@goauthentik/api";
|
||||||
|
|
||||||
export function RenderFlowOption(flow: Flow): string {
|
export function RenderFlowOption(flow: Flow): string {
|
||||||
return `${flow.slug} (${flow.name})`;
|
return `${flow.slug} (${flow.name})`;
|
||||||
|
@ -27,19 +27,19 @@ export function DesignationToLabel(designation: FlowDesignationEnum): string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LayoutToLabel(layout: LayoutEnum): string {
|
export function LayoutToLabel(layout: FlowLayoutEnum): string {
|
||||||
switch (layout) {
|
switch (layout) {
|
||||||
case LayoutEnum.Stacked:
|
case FlowLayoutEnum.Stacked:
|
||||||
return msg("Stacked");
|
return msg("Stacked");
|
||||||
case LayoutEnum.ContentLeft:
|
case FlowLayoutEnum.ContentLeft:
|
||||||
return msg("Content left");
|
return msg("Content left");
|
||||||
case LayoutEnum.ContentRight:
|
case FlowLayoutEnum.ContentRight:
|
||||||
return msg("Content right");
|
return msg("Content right");
|
||||||
case LayoutEnum.SidebarLeft:
|
case FlowLayoutEnum.SidebarLeft:
|
||||||
return msg("Sidebar left");
|
return msg("Sidebar left");
|
||||||
case LayoutEnum.SidebarRight:
|
case FlowLayoutEnum.SidebarRight:
|
||||||
return msg("Sidebar right");
|
return msg("Sidebar right");
|
||||||
case LayoutEnum.UnknownDefaultOpenApi:
|
case FlowLayoutEnum.UnknownDefaultOpenApi:
|
||||||
return msg("Unknown layout");
|
return msg("Unknown layout");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,8 @@ import {
|
||||||
ContextualFlowInfo,
|
ContextualFlowInfo,
|
||||||
FlowChallengeResponseRequest,
|
FlowChallengeResponseRequest,
|
||||||
FlowErrorChallenge,
|
FlowErrorChallenge,
|
||||||
|
FlowLayoutEnum,
|
||||||
FlowsApi,
|
FlowsApi,
|
||||||
LayoutEnum,
|
|
||||||
ResponseError,
|
ResponseError,
|
||||||
ShellChallenge,
|
ShellChallenge,
|
||||||
UiThemeEnum,
|
UiThemeEnum,
|
||||||
|
@ -451,7 +451,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
getLayout(): string {
|
getLayout(): string {
|
||||||
const prefilledFlow = globalAK()?.flow?.layout || LayoutEnum.Stacked;
|
const prefilledFlow = globalAK()?.flow?.layout || FlowLayoutEnum.Stacked;
|
||||||
if (this.challenge) {
|
if (this.challenge) {
|
||||||
return this.challenge?.flowInfo?.layout || prefilledFlow;
|
return this.challenge?.flowInfo?.layout || prefilledFlow;
|
||||||
}
|
}
|
||||||
|
@ -461,11 +461,11 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||||
getLayoutClass(): string {
|
getLayoutClass(): string {
|
||||||
const layout = this.getLayout();
|
const layout = this.getLayout();
|
||||||
switch (layout) {
|
switch (layout) {
|
||||||
case LayoutEnum.ContentLeft:
|
case FlowLayoutEnum.ContentLeft:
|
||||||
return "pf-c-login__container";
|
return "pf-c-login__container";
|
||||||
case LayoutEnum.ContentRight:
|
case FlowLayoutEnum.ContentRight:
|
||||||
return "pf-c-login__container content-right";
|
return "pf-c-login__container content-right";
|
||||||
case LayoutEnum.Stacked:
|
case FlowLayoutEnum.Stacked:
|
||||||
default:
|
default:
|
||||||
return "ak-login-container";
|
return "ak-login-container";
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue