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
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
postgresql_version: ${{ matrix.psql }}
|
||||
- name: checkout stable
|
||||
run: |
|
||||
# Delete all poetry envs
|
||||
|
@ -76,7 +72,7 @@ jobs:
|
|||
git checkout version/$(python -c "from authentik import __version__; print(__version__)")
|
||||
rm -rf .github/ scripts/
|
||||
mv ../.github ../scripts .
|
||||
- name: Setup authentik env (ensure stable deps are installed)
|
||||
- name: Setup authentik env (stable)
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
postgresql_version: ${{ matrix.psql }}
|
||||
|
@ -90,14 +86,13 @@ jobs:
|
|||
git clean -d -fx .
|
||||
git checkout $GITHUB_SHA
|
||||
# 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)
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
postgresql_version: ${{ matrix.psql }}
|
||||
- name: migrate to latest
|
||||
run: |
|
||||
poetry install
|
||||
poetry run python -m lifecycle.migrate
|
||||
test-unittest:
|
||||
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
|
||||
|
||||
gen-clean:
|
||||
rm -rf web/api/src/
|
||||
rm -rf api/
|
||||
rm -rf gen-go-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
|
||||
docker run \
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
from drf_spectacular.utils import extend_schema, inline_serializer
|
||||
from rest_framework.decorators import action
|
||||
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.response import Response
|
||||
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.tasks import apply_blueprint, blueprints_find_dict
|
||||
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:
|
||||
|
@ -28,7 +28,7 @@ class MetadataSerializer(PassiveSerializer):
|
|||
"""Serializer for blueprint metadata"""
|
||||
|
||||
name = CharField()
|
||||
labels = JSONField()
|
||||
labels = JSONDictField()
|
||||
|
||||
|
||||
class BlueprintInstanceSerializer(ModelSerializer):
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
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 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:
|
||||
from authentik.blueprints.models import BlueprintInstance
|
||||
|
@ -17,7 +17,7 @@ LOGGER = get_logger()
|
|||
class ApplyBlueprintMetaSerializer(PassiveSerializer):
|
||||
"""Serializer for meta apply blueprint model"""
|
||||
|
||||
identifiers = JSONField(validators=[is_dict])
|
||||
identifiers = JSONDictField()
|
||||
required = BooleanField(default=True)
|
||||
|
||||
# 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 guardian.shortcuts import get_objects_for_user
|
||||
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.response import Response
|
||||
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.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.rbac.api.roles import RoleSerializer
|
||||
|
||||
|
@ -24,7 +24,7 @@ from authentik.rbac.api.roles import RoleSerializer
|
|||
class GroupMemberSerializer(ModelSerializer):
|
||||
"""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)
|
||||
|
||||
class Meta:
|
||||
|
@ -44,7 +44,7 @@ class GroupMemberSerializer(ModelSerializer):
|
|||
class GroupSerializer(ModelSerializer):
|
||||
"""Group Serializer"""
|
||||
|
||||
attributes = JSONField(validators=[is_dict], required=False)
|
||||
attributes = JSONDictField(required=False)
|
||||
users_obj = ListSerializer(
|
||||
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 rest_framework.decorators import action
|
||||
from rest_framework.fields import (
|
||||
CharField,
|
||||
IntegerField,
|
||||
JSONField,
|
||||
ListField,
|
||||
SerializerMethodField,
|
||||
)
|
||||
from rest_framework.fields import CharField, IntegerField, ListField, SerializerMethodField
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
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.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
|
||||
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 (
|
||||
SESSION_KEY_IMPERSONATE_ORIGINAL_USER,
|
||||
SESSION_KEY_IMPERSONATE_USER,
|
||||
|
@ -89,7 +83,7 @@ LOGGER = get_logger()
|
|||
class UserGroupSerializer(ModelSerializer):
|
||||
"""Simplified Group Serializer for user's groups"""
|
||||
|
||||
attributes = JSONField(required=False)
|
||||
attributes = JSONDictField(required=False)
|
||||
parent_name = CharField(source="parent.name", read_only=True)
|
||||
|
||||
class Meta:
|
||||
|
@ -110,7 +104,7 @@ class UserSerializer(ModelSerializer):
|
|||
|
||||
is_superuser = BooleanField(read_only=True)
|
||||
avatar = CharField(read_only=True)
|
||||
attributes = JSONField(validators=[is_dict], required=False)
|
||||
attributes = JSONDictField(required=False)
|
||||
groups = PrimaryKeyRelatedField(
|
||||
allow_empty=True, many=True, source="ak_groups", queryset=Group.objects.all(), default=list
|
||||
)
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
from typing import Any
|
||||
|
||||
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.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.")
|
||||
|
||||
|
||||
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):
|
||||
"""Base serializer class which doesn't implement create/update methods"""
|
||||
|
||||
|
@ -26,7 +44,7 @@ class PassiveSerializer(Serializer):
|
|||
class PropertyMappingPreviewSerializer(PassiveSerializer):
|
||||
"""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):
|
||||
|
|
|
@ -9,13 +9,13 @@ from rest_framework.fields import BooleanField, CharField, DateTimeField
|
|||
from rest_framework.relations import PrimaryKeyRelatedField
|
||||
from rest_framework.request import Request
|
||||
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 authentik import get_build_hash
|
||||
from authentik.core.api.providers import ProviderSerializer
|
||||
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.outposts.api.service_connections import ServiceConnectionSerializer
|
||||
from authentik.outposts.apps import MANAGED_OUTPOST
|
||||
|
@ -34,7 +34,7 @@ from authentik.providers.radius.models import RadiusProvider
|
|||
class OutpostSerializer(ModelSerializer):
|
||||
"""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
|
||||
# is checked for other providers in the API Viewset
|
||||
providers = PrimaryKeyRelatedField(
|
||||
|
@ -95,7 +95,7 @@ class OutpostSerializer(ModelSerializer):
|
|||
class OutpostDefaultConfigSerializer(PassiveSerializer):
|
||||
"""Global default outpost config"""
|
||||
|
||||
config = JSONField(read_only=True)
|
||||
config = JSONDictField(read_only=True)
|
||||
|
||||
|
||||
class OutpostHealthSerializer(PassiveSerializer):
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"""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 authentik.core.api.utils import PassiveSerializer, is_dict
|
||||
from authentik.core.api.utils import JSONDictField, PassiveSerializer
|
||||
from authentik.core.models import User
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@ class PolicyTestSerializer(PassiveSerializer):
|
|||
"""Test policy execution for a user with context"""
|
||||
|
||||
user = PrimaryKeyRelatedField(queryset=User.objects.all())
|
||||
context = JSONField(required=False, validators=[is_dict])
|
||||
context = JSONDictField(required=False)
|
||||
|
||||
|
||||
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",
|
||||
"ChallengeChoices": "authentik.flows.challenge.ChallengeTypes",
|
||||
"FlowDesignationEnum": "authentik.flows.models.FlowDesignation",
|
||||
"FlowLayoutEnum": "authentik.flows.models.FlowLayout",
|
||||
"PolicyEngineMode": "authentik.policies.models.PolicyEngineMode",
|
||||
"ProxyMode": "authentik.providers.proxy.models.ProxyMode",
|
||||
"PromptTypeEnum": "authentik.stages.prompt.models.FieldTypes",
|
||||
|
@ -204,7 +205,7 @@ DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
|||
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
|
||||
DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
|
||||
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"
|
||||
# Configured via custom SessionMiddleware
|
||||
# SESSION_COOKIE_SAMESITE = "None"
|
||||
|
|
|
@ -22,8 +22,8 @@ from authentik.stages.authenticator.util import hex_validator, random_hex
|
|||
class TOTPDigits(models.TextChoices):
|
||||
"""OTP Time Digits"""
|
||||
|
||||
SIX = 6, _("6 digits, widely compatible")
|
||||
EIGHT = 8, _("8 digits, not compatible with apps like Google Authenticator")
|
||||
SIX = "6", _("6 digits, widely compatible")
|
||||
EIGHT = "8", _("8 digits, not compatible with apps like Google Authenticator")
|
||||
|
||||
|
||||
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.utils.translation import gettext 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 structlog.stdlib import get_logger
|
||||
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.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.signals import login_failed
|
||||
from authentik.events.models import Event, EventAction
|
||||
|
@ -40,7 +40,7 @@ class DeviceChallenge(PassiveSerializer):
|
|||
|
||||
device_class = CharField()
|
||||
device_uid = CharField()
|
||||
challenge = JSONField()
|
||||
challenge = JSONDictField()
|
||||
|
||||
|
||||
def get_challenge_for_device(
|
||||
|
|
|
@ -6,10 +6,10 @@ from typing import Optional
|
|||
from django.conf import settings
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
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 authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.core.api.utils import JSONDictField, PassiveSerializer
|
||||
from authentik.core.models import User
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge
|
||||
|
@ -68,7 +68,7 @@ class AuthenticatorValidationChallengeResponse(ChallengeResponse):
|
|||
selected_stage = CharField(required=False)
|
||||
|
||||
code = CharField(required=False)
|
||||
webauthn = JSONField(required=False)
|
||||
webauthn = JSONDictField(required=False)
|
||||
duo = IntegerField(required=False)
|
||||
component = CharField(default="ak-stage-authenticator-validate")
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""WebAuthn stage"""
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
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 webauthn.helpers.bytes_to_base64url import bytes_to_base64url
|
||||
from webauthn.helpers.exceptions import InvalidRegistrationResponse
|
||||
|
@ -16,6 +16,7 @@ from webauthn.registration.verify_registration_response import (
|
|||
verify_registration_response,
|
||||
)
|
||||
|
||||
from authentik.core.api.utils import JSONDictField
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import (
|
||||
Challenge,
|
||||
|
@ -33,14 +34,14 @@ SESSION_KEY_WEBAUTHN_CHALLENGE = "authentik/stages/authenticator_webauthn/challe
|
|||
class AuthenticatorWebAuthnChallenge(WithUserInfoChallenge):
|
||||
"""WebAuthn Challenge"""
|
||||
|
||||
registration = JSONField()
|
||||
registration = JSONDictField()
|
||||
component = CharField(default="ak-stage-authenticator-webauthn")
|
||||
|
||||
|
||||
class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse):
|
||||
"""WebAuthn Challenge response"""
|
||||
|
||||
response = JSONField()
|
||||
response = JSONDictField()
|
||||
component = CharField(default="ak-stage-authenticator-webauthn")
|
||||
|
||||
request: HttpRequest
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
"""Invitation Stage API Views"""
|
||||
from django_filters.filters import BooleanFilter
|
||||
from django_filters.filterset import FilterSet
|
||||
from rest_framework.fields import JSONField
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.groups import GroupMemberSerializer
|
||||
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.stages import StageSerializer
|
||||
from authentik.stages.invitation.models import Invitation, InvitationStage
|
||||
|
@ -47,7 +46,7 @@ class InvitationSerializer(ModelSerializer):
|
|||
"""Invitation Serializer"""
|
||||
|
||||
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")
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -81,7 +81,6 @@ var rootCmd = &cobra.Command{
|
|||
for {
|
||||
<-ex
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -82,3 +82,5 @@ require (
|
|||
gopkg.in/square/go-jose.v2 v2.5.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
|
||||
// The service account this token belongs to should only have access to a single outpost
|
||||
outposts, _, err := apiClient.OutpostsApi.OutpostsInstancesList(context.Background()).Execute()
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to fetch outpost configuration, retrying in 3 seconds")
|
||||
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
|
||||
// The service account this token belongs to should only have access to a single outpost
|
||||
outposts, _, err := a.Client.OutpostsApi.OutpostsInstancesList(context.Background()).Execute()
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to fetch outpost configuration")
|
||||
return err
|
||||
|
|
|
@ -14,8 +14,10 @@ import (
|
|||
webutils "goauthentik.io/internal/utils/web"
|
||||
)
|
||||
|
||||
var initialSetup = false
|
||||
var tlsTransport *http.RoundTripper = nil
|
||||
var (
|
||||
initialSetup = false
|
||||
tlsTransport *http.RoundTripper = nil
|
||||
)
|
||||
|
||||
func doGlobalSetup(outpost api.Outpost, globalConfig *api.Config) {
|
||||
l := log.WithField("logger", "authentik.outpost")
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
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,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
|
|
@ -59,12 +59,12 @@ func (a *Application) addHeaders(headers http.Header, c *Claims) {
|
|||
userAttributes := c.Proxy.UserAttributes
|
||||
a.setAuthorizationHeader(headers, c)
|
||||
// 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")
|
||||
if additionalHeaders == nil {
|
||||
return
|
||||
}
|
||||
for key, value := range additionalHeaders {
|
||||
for key, value := range additionalHeaders.(map[string]interface{}) {
|
||||
headers.Set(key, toString(value))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package constants
|
||||
|
||||
const SessionOAuthState = "oauth_state"
|
||||
const SessionClaims = "claims"
|
||||
const (
|
||||
SessionOAuthState = "oauth_state"
|
||||
SessionClaims = "claims"
|
||||
)
|
||||
|
||||
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{
|
||||
"username": username,
|
||||
"client": r.RemoteAddr(),
|
||||
"requestId": r.ID,
|
||||
"requestId": r.ID(),
|
||||
})
|
||||
fe.DelegateClientIP(r.RemoteAddr())
|
||||
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()
|
||||
|
||||
if err != nil {
|
||||
r.Log().WithField("username", username).WithError(err).Warning("failed to execute flow")
|
||||
metrics.RequestsRejected.With(prometheus.Labels{
|
||||
|
|
|
@ -14,12 +14,10 @@ import (
|
|||
"goauthentik.io/internal/utils/sentry"
|
||||
)
|
||||
|
||||
var (
|
||||
Requests = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
var Requests = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Name: "authentik_main_request_duration_seconds",
|
||||
Help: "API request latencies in seconds",
|
||||
}, []string{"dest"})
|
||||
)
|
||||
|
||||
func (ws *WebServer) runMetricsServer() {
|
||||
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
|
||||
- tt
|
||||
- udm
|
||||
- ug
|
||||
- uk
|
||||
- ur
|
||||
- uz
|
||||
|
@ -29205,9 +29206,7 @@ components:
|
|||
path:
|
||||
type: string
|
||||
default: ''
|
||||
context:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
context: {}
|
||||
last_applied:
|
||||
type: string
|
||||
format: date-time
|
||||
|
@ -29227,8 +29226,6 @@ components:
|
|||
type: string
|
||||
readOnly: true
|
||||
metadata:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
readOnly: true
|
||||
content:
|
||||
type: string
|
||||
|
@ -29250,9 +29247,7 @@ components:
|
|||
path:
|
||||
type: string
|
||||
default: ''
|
||||
context:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
context: {}
|
||||
enabled:
|
||||
type: boolean
|
||||
content:
|
||||
|
@ -29772,10 +29767,24 @@ components:
|
|||
cancel_url:
|
||||
type: string
|
||||
layout:
|
||||
$ref: '#/components/schemas/LayoutEnum'
|
||||
$ref: '#/components/schemas/ContextualFlowInfoLayoutEnum'
|
||||
required:
|
||||
- cancel_url
|
||||
- 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:
|
||||
type: object
|
||||
description: Coordinates for diagrams
|
||||
|
@ -30493,16 +30502,12 @@ components:
|
|||
format: uuid
|
||||
readOnly: true
|
||||
title: Event uuid
|
||||
user:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
user: {}
|
||||
action:
|
||||
$ref: '#/components/schemas/EventActions'
|
||||
app:
|
||||
type: string
|
||||
context:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
context: {}
|
||||
client_ip:
|
||||
type: string
|
||||
nullable: true
|
||||
|
@ -30513,9 +30518,7 @@ components:
|
|||
expires:
|
||||
type: string
|
||||
format: date-time
|
||||
tenant:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
tenant: {}
|
||||
required:
|
||||
- action
|
||||
- app
|
||||
|
@ -30992,17 +30995,13 @@ components:
|
|||
type: object
|
||||
description: Event Serializer
|
||||
properties:
|
||||
user:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
user: {}
|
||||
action:
|
||||
$ref: '#/components/schemas/EventActions'
|
||||
app:
|
||||
type: string
|
||||
minLength: 1
|
||||
context:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
context: {}
|
||||
client_ip:
|
||||
type: string
|
||||
nullable: true
|
||||
|
@ -31010,9 +31009,7 @@ components:
|
|||
expires:
|
||||
type: string
|
||||
format: date-time
|
||||
tenant:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
tenant: {}
|
||||
required:
|
||||
- action
|
||||
- app
|
||||
|
@ -31311,7 +31308,7 @@ components:
|
|||
description: Get export URL for flow
|
||||
readOnly: true
|
||||
layout:
|
||||
$ref: '#/components/schemas/LayoutEnum'
|
||||
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||
denied_action:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||
|
@ -31498,6 +31495,20 @@ components:
|
|||
- next_planned_stage
|
||||
- plan_context
|
||||
- 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:
|
||||
type: object
|
||||
description: Flow Serializer
|
||||
|
@ -31535,7 +31546,7 @@ components:
|
|||
description: Enable compatibility mode, increases compatibility with password
|
||||
managers on mobile devices.
|
||||
layout:
|
||||
$ref: '#/components/schemas/LayoutEnum'
|
||||
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||
denied_action:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||
|
@ -31613,7 +31624,7 @@ components:
|
|||
description: Get export URL for flow
|
||||
readOnly: true
|
||||
layout:
|
||||
$ref: '#/components/schemas/LayoutEnum'
|
||||
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||
denied_action:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||
|
@ -31669,7 +31680,7 @@ components:
|
|||
description: Enable compatibility mode, increases compatibility with password
|
||||
managers on mobile devices.
|
||||
layout:
|
||||
$ref: '#/components/schemas/LayoutEnum'
|
||||
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||
denied_action:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||
|
@ -32361,8 +32372,6 @@ components:
|
|||
description: Return internal model name
|
||||
readOnly: true
|
||||
kubeconfig:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
description: Paste your kubeconfig here. authentik will automatically use
|
||||
the currently selected context.
|
||||
verify_ssl:
|
||||
|
@ -32387,8 +32396,6 @@ components:
|
|||
description: If enabled, use the local connection. Required Docker socket/Kubernetes
|
||||
Integration
|
||||
kubeconfig:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
description: Paste your kubeconfig here. authentik will automatically use
|
||||
the currently selected context.
|
||||
verify_ssl:
|
||||
|
@ -33053,20 +33060,6 @@ components:
|
|||
required:
|
||||
- is_running
|
||||
- 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:
|
||||
type: object
|
||||
description: License Serializer
|
||||
|
@ -34052,9 +34045,7 @@ components:
|
|||
type: string
|
||||
oidc_jwks_url:
|
||||
type: string
|
||||
oidc_jwks:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
oidc_jwks: {}
|
||||
required:
|
||||
- callback_url
|
||||
- component
|
||||
|
@ -34151,9 +34142,7 @@ components:
|
|||
type: string
|
||||
oidc_jwks_url:
|
||||
type: string
|
||||
oidc_jwks:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
oidc_jwks: {}
|
||||
required:
|
||||
- consumer_key
|
||||
- consumer_secret
|
||||
|
@ -36042,9 +36031,7 @@ components:
|
|||
path:
|
||||
type: string
|
||||
default: ''
|
||||
context:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
context: {}
|
||||
enabled:
|
||||
type: boolean
|
||||
content:
|
||||
|
@ -36441,17 +36428,13 @@ components:
|
|||
type: object
|
||||
description: Event Serializer
|
||||
properties:
|
||||
user:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
user: {}
|
||||
action:
|
||||
$ref: '#/components/schemas/EventActions'
|
||||
app:
|
||||
type: string
|
||||
minLength: 1
|
||||
context:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
context: {}
|
||||
client_ip:
|
||||
type: string
|
||||
nullable: true
|
||||
|
@ -36459,9 +36442,7 @@ components:
|
|||
expires:
|
||||
type: string
|
||||
format: date-time
|
||||
tenant:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
tenant: {}
|
||||
PatchedExpressionPolicyRequest:
|
||||
type: object
|
||||
description: Group Membership Policy Serializer
|
||||
|
@ -36513,7 +36494,7 @@ components:
|
|||
description: Enable compatibility mode, increases compatibility with password
|
||||
managers on mobile devices.
|
||||
layout:
|
||||
$ref: '#/components/schemas/LayoutEnum'
|
||||
$ref: '#/components/schemas/FlowLayoutEnum'
|
||||
denied_action:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/DeniedActionEnum'
|
||||
|
@ -36703,8 +36684,6 @@ components:
|
|||
description: If enabled, use the local connection. Required Docker socket/Kubernetes
|
||||
Integration
|
||||
kubeconfig:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
description: Paste your kubeconfig here. authentik will automatically use
|
||||
the currently selected context.
|
||||
verify_ssl:
|
||||
|
@ -37165,9 +37144,7 @@ components:
|
|||
type: string
|
||||
oidc_jwks_url:
|
||||
type: string
|
||||
oidc_jwks:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
oidc_jwks: {}
|
||||
PatchedOutpostRequest:
|
||||
type: object
|
||||
description: Outpost Serializer
|
||||
|
@ -38011,9 +37988,7 @@ components:
|
|||
format: uuid
|
||||
nullable: true
|
||||
description: Web Certificate used by the authentik Core webserver.
|
||||
attributes:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
attributes: {}
|
||||
PatchedTokenRequest:
|
||||
type: object
|
||||
description: Token Serializer
|
||||
|
@ -39686,9 +39661,7 @@ components:
|
|||
type: string
|
||||
ip:
|
||||
type: string
|
||||
ip_geo_data:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
ip_geo_data: {}
|
||||
score:
|
||||
type: integer
|
||||
maximum: 9223372036854775807
|
||||
|
@ -41415,9 +41388,7 @@ components:
|
|||
format: uuid
|
||||
nullable: true
|
||||
description: Web Certificate used by the authentik Core webserver.
|
||||
attributes:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
attributes: {}
|
||||
required:
|
||||
- domain
|
||||
- tenant_uuid
|
||||
|
@ -41474,9 +41445,7 @@ components:
|
|||
format: uuid
|
||||
nullable: true
|
||||
description: Web Certificate used by the authentik Core webserver.
|
||||
attributes:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
attributes: {}
|
||||
required:
|
||||
- domain
|
||||
Token:
|
||||
|
|
|
@ -18,8 +18,8 @@ import {
|
|||
DeniedActionEnum,
|
||||
Flow,
|
||||
FlowDesignationEnum,
|
||||
FlowLayoutEnum,
|
||||
FlowsApi,
|
||||
LayoutEnum,
|
||||
PolicyEngineMode,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
|
@ -302,34 +302,34 @@ export class FlowForm extends ModelForm<Flow, string> {
|
|||
>
|
||||
<select class="pf-c-form-control">
|
||||
<option
|
||||
value=${LayoutEnum.Stacked}
|
||||
?selected=${this.instance?.layout === LayoutEnum.Stacked}
|
||||
value=${FlowLayoutEnum.Stacked}
|
||||
?selected=${this.instance?.layout === FlowLayoutEnum.Stacked}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.Stacked)}
|
||||
${LayoutToLabel(FlowLayoutEnum.Stacked)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.ContentLeft}
|
||||
?selected=${this.instance?.layout === LayoutEnum.ContentLeft}
|
||||
value=${FlowLayoutEnum.ContentLeft}
|
||||
?selected=${this.instance?.layout === FlowLayoutEnum.ContentLeft}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.ContentLeft)}
|
||||
${LayoutToLabel(FlowLayoutEnum.ContentLeft)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.ContentRight}
|
||||
?selected=${this.instance?.layout === LayoutEnum.ContentRight}
|
||||
value=${FlowLayoutEnum.ContentRight}
|
||||
?selected=${this.instance?.layout === FlowLayoutEnum.ContentRight}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.ContentRight)}
|
||||
${LayoutToLabel(FlowLayoutEnum.ContentRight)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.SidebarLeft}
|
||||
?selected=${this.instance?.layout === LayoutEnum.SidebarLeft}
|
||||
value=${FlowLayoutEnum.SidebarLeft}
|
||||
?selected=${this.instance?.layout === FlowLayoutEnum.SidebarLeft}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.SidebarLeft)}
|
||||
${LayoutToLabel(FlowLayoutEnum.SidebarLeft)}
|
||||
</option>
|
||||
<option
|
||||
value=${LayoutEnum.SidebarRight}
|
||||
?selected=${this.instance?.layout === LayoutEnum.SidebarRight}
|
||||
value=${FlowLayoutEnum.SidebarRight}
|
||||
?selected=${this.instance?.layout === FlowLayoutEnum.SidebarRight}
|
||||
>
|
||||
${LayoutToLabel(LayoutEnum.SidebarRight)}
|
||||
${LayoutToLabel(FlowLayoutEnum.SidebarRight)}
|
||||
</option>
|
||||
</select>
|
||||
</ak-form-element-horizontal>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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 {
|
||||
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) {
|
||||
case LayoutEnum.Stacked:
|
||||
case FlowLayoutEnum.Stacked:
|
||||
return msg("Stacked");
|
||||
case LayoutEnum.ContentLeft:
|
||||
case FlowLayoutEnum.ContentLeft:
|
||||
return msg("Content left");
|
||||
case LayoutEnum.ContentRight:
|
||||
case FlowLayoutEnum.ContentRight:
|
||||
return msg("Content right");
|
||||
case LayoutEnum.SidebarLeft:
|
||||
case FlowLayoutEnum.SidebarLeft:
|
||||
return msg("Sidebar left");
|
||||
case LayoutEnum.SidebarRight:
|
||||
case FlowLayoutEnum.SidebarRight:
|
||||
return msg("Sidebar right");
|
||||
case LayoutEnum.UnknownDefaultOpenApi:
|
||||
case FlowLayoutEnum.UnknownDefaultOpenApi:
|
||||
return msg("Unknown layout");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ import {
|
|||
ContextualFlowInfo,
|
||||
FlowChallengeResponseRequest,
|
||||
FlowErrorChallenge,
|
||||
FlowLayoutEnum,
|
||||
FlowsApi,
|
||||
LayoutEnum,
|
||||
ResponseError,
|
||||
ShellChallenge,
|
||||
UiThemeEnum,
|
||||
|
@ -451,7 +451,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||
}
|
||||
|
||||
getLayout(): string {
|
||||
const prefilledFlow = globalAK()?.flow?.layout || LayoutEnum.Stacked;
|
||||
const prefilledFlow = globalAK()?.flow?.layout || FlowLayoutEnum.Stacked;
|
||||
if (this.challenge) {
|
||||
return this.challenge?.flowInfo?.layout || prefilledFlow;
|
||||
}
|
||||
|
@ -461,11 +461,11 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||
getLayoutClass(): string {
|
||||
const layout = this.getLayout();
|
||||
switch (layout) {
|
||||
case LayoutEnum.ContentLeft:
|
||||
case FlowLayoutEnum.ContentLeft:
|
||||
return "pf-c-login__container";
|
||||
case LayoutEnum.ContentRight:
|
||||
case FlowLayoutEnum.ContentRight:
|
||||
return "pf-c-login__container content-right";
|
||||
case LayoutEnum.Stacked:
|
||||
case FlowLayoutEnum.Stacked:
|
||||
default:
|
||||
return "ak-login-container";
|
||||
}
|
||||
|
|
Reference in New Issue