Compare commits
3 Commits
core/objec
...
saml-provi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4f1a1b118 | ||
|
|
11cc78e751 | ||
|
|
22ace95a82 |
8
.github/actions/setup/action.yml
vendored
@@ -25,7 +25,7 @@ runs:
|
||||
if: ${{ contains(inputs.dependencies, 'system') || contains(inputs.dependencies, 'python') }}
|
||||
uses: gerlero/apt-install@f4fa5265092af9e750549565d28c99aec7189639
|
||||
with:
|
||||
packages: libpq-dev openssl libxmlsec1-dev pkg-config gettext libclang-dev libkadm5clnt-mit12 libkadm5clnt7t64-heimdal libkrb5-dev krb5-kdc krb5-user krb5-admin-server
|
||||
packages: libpq-dev openssl libxmlsec1-dev pkg-config gettext krb5-multidev libkrb5-dev heimdal-multidev libclang-dev krb5-kdc krb5-user krb5-admin-server
|
||||
update: true
|
||||
upgrade: false
|
||||
install-recommends: false
|
||||
@@ -52,19 +52,19 @@ runs:
|
||||
run: uv sync --all-extras --dev --locked
|
||||
- name: Setup rust (stable)
|
||||
if: ${{ contains(inputs.dependencies, 'rust') && !contains(inputs.dependencies, 'rust-nightly') }}
|
||||
uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
|
||||
uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1
|
||||
with:
|
||||
rustflags: ""
|
||||
- name: Setup rust (nightly)
|
||||
if: ${{ contains(inputs.dependencies, 'rust-nightly') }}
|
||||
uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
|
||||
uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: rustfmt
|
||||
rustflags: ""
|
||||
- name: Setup rust dependencies
|
||||
if: ${{ contains(inputs.dependencies, 'rust') }}
|
||||
uses: taiki-e/install-action@ec28e287910af896fd98e04056d31fa68607e7ad # v2
|
||||
uses: taiki-e/install-action@711e1c3275189d76dcc4d34ddea63bf96ac49090 # v2
|
||||
with:
|
||||
tool: cargo-deny cargo-machete cargo-llvm-cov nextest
|
||||
- name: Setup node (web)
|
||||
|
||||
6
.github/workflows/qa-codeql.yml
vendored
@@ -28,10 +28,10 @@ jobs:
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4.35.4
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v4.35.4
|
||||
uses: github/codeql-action/autobuild@v4
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v4.35.4
|
||||
uses: github/codeql-action/analyze@v4
|
||||
|
||||
6
.github/workflows/release-branch-off.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
next_version:
|
||||
description: Next version (for example, if you're currently releasing 2026.5, then enter 2026.8)
|
||||
description: Next major version (for example, if releasing 2042.2, this is 2042.4)
|
||||
required: true
|
||||
type: string
|
||||
|
||||
@@ -68,14 +68,10 @@ jobs:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
dependencies: "system,python,go,node,runtime,rust-nightly"
|
||||
- name: Run migrations
|
||||
run: make migrate
|
||||
- name: Bump version
|
||||
run: "make bump version=${{ inputs.next_version }}.0-rc1"
|
||||
- name: Re-generate API Clients
|
||||
run: make gen
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7
|
||||
with:
|
||||
|
||||
2
.github/workflows/release-publish.yml
vendored
@@ -191,7 +191,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # v6.1.1
|
||||
- uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
|
||||
with:
|
||||
role-to-assume: "arn:aws:iam::016170277896:role/github_goauthentik_authentik"
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
|
||||
4
.github/workflows/release-tag.yml
vendored
@@ -82,14 +82,10 @@ jobs:
|
||||
token: "${{ steps.app-token.outputs.token }}"
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
dependencies: "system,python,go,node,runtime,rust-nightly"
|
||||
- name: Run migrations
|
||||
run: make migrate
|
||||
- name: Bump version
|
||||
run: "make bump version=${{ inputs.version }}"
|
||||
- name: Re-generate API Clients
|
||||
run: make gen
|
||||
- name: Commit and push
|
||||
run: |
|
||||
# ID from https://api.github.com/users/authentik-automation[bot]
|
||||
|
||||
28
Cargo.lock
generated
@@ -1744,6 +1744,16 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iri-string"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
@@ -3193,9 +3203,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||
|
||||
[[package]]
|
||||
name = "sentry"
|
||||
version = "0.48.1"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b93b3e19f45495ddd41d8222a152c48c84f6ba45abe9c69e2527e9cdea29bb5b"
|
||||
checksum = "e8ac94aab850a23d7507307cc505332ed2bafd36c65930dfc5c43610f9e9b477"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"httpdate",
|
||||
@@ -3390,9 +3400,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.19.0"
|
||||
version = "3.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f05839ce67618e14a09b286535c0d9c94e85ef25469b0e13cb4f844e5593eb19"
|
||||
checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
@@ -3924,9 +3934,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.52.3"
|
||||
version = "1.52.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
|
||||
checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
@@ -4072,21 +4082,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.10"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
|
||||
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"iri-string",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -67,7 +67,7 @@ reqwest-middleware = { version = "= 0.5.1", features = [
|
||||
"rustls",
|
||||
] }
|
||||
rustls = { version = "= 0.23.40", features = ["fips"] }
|
||||
sentry = { version = "= 0.48.1", default-features = false, features = [
|
||||
sentry = { version = "= 0.48.0", default-features = false, features = [
|
||||
"backtrace",
|
||||
"contexts",
|
||||
"debug-images",
|
||||
@@ -80,7 +80,7 @@ sentry = { version = "= 0.48.1", default-features = false, features = [
|
||||
serde = { version = "= 1.0.228", features = ["derive"] }
|
||||
serde_json = "= 1.0.149"
|
||||
serde_repr = "= 0.1.20"
|
||||
serde_with = { version = "= 3.19.0", default-features = false, features = [
|
||||
serde_with = { version = "= 3.18.0", default-features = false, features = [
|
||||
"base64",
|
||||
] }
|
||||
sqlx = { version = "= 0.8.6", default-features = false, features = [
|
||||
@@ -97,12 +97,12 @@ sqlx = { version = "= 0.8.6", default-features = false, features = [
|
||||
tempfile = "= 3.27.0"
|
||||
thiserror = "= 2.0.18"
|
||||
time = { version = "= 0.3.47", features = ["macros"] }
|
||||
tokio = { version = "= 1.52.3", features = ["full", "tracing"] }
|
||||
tokio = { version = "= 1.52.1", features = ["full", "tracing"] }
|
||||
tokio-retry2 = "= 0.9.1"
|
||||
tokio-rustls = "= 0.26.4"
|
||||
tokio-util = { version = "= 0.7.18", features = ["full"] }
|
||||
tower = "= 0.5.3"
|
||||
tower-http = { version = "= 0.6.10", features = ["timeout"] }
|
||||
tower-http = { version = "= 0.6.8", features = ["timeout"] }
|
||||
tracing = "= 0.1.44"
|
||||
tracing-error = "= 0.2.1"
|
||||
tracing-subscriber = { version = "= 0.3.23", features = [
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
"""Meta API"""
|
||||
|
||||
from django.apps import apps
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.fields import BooleanField, CharField
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import ViewSet
|
||||
|
||||
from authentik.api.validation import validate
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.core.models import AttributesMixin
|
||||
from authentik.lib.api import Models
|
||||
from authentik.lib.utils.reflection import get_apps
|
||||
|
||||
@@ -39,19 +36,12 @@ class AppsViewSet(ViewSet):
|
||||
class ModelViewSet(ViewSet):
|
||||
"""Read-only view list all installed models"""
|
||||
|
||||
class ModelFilterSerializer(PassiveSerializer):
|
||||
filter_has_attributes = BooleanField(allow_null=True, default=None)
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
@extend_schema(responses={200: AppSerializer(many=True)}, parameters=[ModelFilterSerializer])
|
||||
@validate(ModelFilterSerializer, "query")
|
||||
def list(self, request: Request, query: ModelFilterSerializer) -> Response:
|
||||
@extend_schema(responses={200: AppSerializer(many=True)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""Read-only view list all installed models"""
|
||||
data = []
|
||||
for name, label in Models.choices:
|
||||
if query.validated_data["filter_has_attributes"]:
|
||||
if not issubclass(apps.get_model(name), AttributesMixin):
|
||||
continue
|
||||
data.append({"name": name, "label": label})
|
||||
return Response(AppSerializer(data, many=True).data)
|
||||
|
||||
@@ -42,29 +42,11 @@ def validate_auth(header: bytes, format="bearer") -> str | None:
|
||||
return auth_credentials
|
||||
|
||||
|
||||
class VirtualUser(AnonymousUser):
|
||||
is_active = True
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return UserTypes.INTERNAL_SERVICE_ACCOUNT
|
||||
|
||||
@property
|
||||
def is_anonymous(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_authenticated(self):
|
||||
return True
|
||||
|
||||
def all_roles(self):
|
||||
return []
|
||||
|
||||
|
||||
class IPCUser(VirtualUser):
|
||||
class IPCUser(AnonymousUser):
|
||||
"""'Virtual' user for IPC communication between authentik core and the authentik router"""
|
||||
|
||||
username = "authentik:system"
|
||||
is_active = True
|
||||
is_superuser = True
|
||||
|
||||
@property
|
||||
@@ -80,6 +62,17 @@ class IPCUser(VirtualUser):
|
||||
def has_module_perms(self, module):
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_anonymous(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_authenticated(self):
|
||||
return True
|
||||
|
||||
def all_roles(self):
|
||||
return []
|
||||
|
||||
|
||||
class TokenAuthentication(BaseAuthentication):
|
||||
"""Token-based authentication using HTTP Bearer authentication"""
|
||||
|
||||
@@ -6,7 +6,6 @@ from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
|
||||
from authentik.core.api.object_attributes import AttributesMixinSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import ModelSerializer
|
||||
from authentik.core.models import (
|
||||
@@ -15,7 +14,7 @@ from authentik.core.models import (
|
||||
)
|
||||
|
||||
|
||||
class ApplicationEntitlementSerializer(AttributesMixinSerializer, ModelSerializer):
|
||||
class ApplicationEntitlementSerializer(ModelSerializer):
|
||||
"""ApplicationEntitlement Serializer"""
|
||||
|
||||
def validate_app(self, app: Application) -> Application:
|
||||
|
||||
@@ -30,7 +30,6 @@ from authentik.api.search.fields import (
|
||||
JSONSearchField,
|
||||
)
|
||||
from authentik.api.validation import validate
|
||||
from authentik.core.api.object_attributes import AttributesMixinSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import JSONDictField, ModelSerializer, PassiveSerializer
|
||||
from authentik.core.models import Group, User
|
||||
@@ -147,7 +146,7 @@ class RelatedGroupSerializer(ModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
class GroupSerializer(AttributesMixinSerializer, ModelSerializer):
|
||||
class GroupSerializer(ModelSerializer):
|
||||
"""Group Serializer"""
|
||||
|
||||
attributes = JSONDictField(required=False)
|
||||
@@ -247,25 +246,6 @@ class GroupSerializer(AttributesMixinSerializer, ModelSerializer):
|
||||
)
|
||||
return superuser
|
||||
|
||||
def validate_users(self, users: list) -> list:
|
||||
"""Require add_user_to_group permission when adding new members via group PATCH."""
|
||||
request: Request = self.context.get("request", None)
|
||||
if not request:
|
||||
return users
|
||||
if not self.instance:
|
||||
return users
|
||||
# BulkManyRelatedField returns raw PKs, not model instances
|
||||
current_user_pks = set(self.instance.users.values_list("pk", flat=True))
|
||||
new_users = [u for u in users if u not in current_user_pks]
|
||||
if not new_users:
|
||||
return users
|
||||
has_perm = request.user.has_perm(
|
||||
"authentik_core.add_user_to_group"
|
||||
) or request.user.has_perm("authentik_core.add_user_to_group", self.instance)
|
||||
if not has_perm:
|
||||
raise ValidationError(_("User does not have permission to add members to this group."))
|
||||
return users
|
||||
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = [
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
from typing import Any
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import CharField, SerializerMethodField
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.utils import ModelSerializer
|
||||
from authentik.core.models import AttributesMixin, ObjectAttribute
|
||||
from authentik.lib.utils.dict import get_path_from_dict
|
||||
|
||||
|
||||
class AttributesMixinSerializer(ModelSerializer):
|
||||
|
||||
def validate(self, data: dict[str, Any]) -> dict[str, Any]:
|
||||
model = self.Meta.model
|
||||
attrs = data.get("attributes", {})
|
||||
attributes = ObjectAttribute.objects.filter(
|
||||
object_type=ContentType.objects.get_for_model(model),
|
||||
enabled=True,
|
||||
)
|
||||
for attr in attributes:
|
||||
value = get_path_from_dict(attrs, attr.key)
|
||||
attr.run_validation(value)
|
||||
return data
|
||||
|
||||
|
||||
class ContentTypeSerializer(ModelSerializer):
|
||||
app_label = CharField(read_only=True)
|
||||
model = CharField(read_only=True)
|
||||
verbose_name_plural = SerializerMethodField()
|
||||
fully_qualified_model = SerializerMethodField()
|
||||
|
||||
def get_fully_qualified_model(self, ct: ContentType) -> str:
|
||||
return f"{ct.app_label}.{ct.model}"
|
||||
|
||||
def get_verbose_name_plural(self, ct: ContentType) -> str:
|
||||
return ct.model_class()._meta.verbose_name_plural
|
||||
|
||||
class Meta:
|
||||
model = ContentType
|
||||
fields = ("id", "app_label", "model", "verbose_name_plural", "fully_qualified_model")
|
||||
|
||||
|
||||
class ObjectAttributeSerializer(ModelSerializer):
|
||||
|
||||
object_type = CharField()
|
||||
object_type_obj = ContentTypeSerializer(read_only=True, source="object_type")
|
||||
|
||||
def validate_object_type(self, fqm: str) -> ContentType:
|
||||
app_label, _, model = fqm.partition(".")
|
||||
ct = ContentType.objects.filter(app_label=app_label, model=model).first()
|
||||
if not ct or not issubclass(ct.model_class(), AttributesMixin):
|
||||
raise ValidationError("Invalid object type")
|
||||
return ct
|
||||
|
||||
def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
|
||||
if attrs.get("is_unique") and attrs.get("is_array"):
|
||||
raise ValidationError(_("Unique cannot be enabled for arrays."))
|
||||
return super().validate(attrs)
|
||||
|
||||
class Meta:
|
||||
model = ObjectAttribute
|
||||
fields = [
|
||||
"pk",
|
||||
"object_type",
|
||||
"object_type_obj",
|
||||
"enabled",
|
||||
"created",
|
||||
"key",
|
||||
"label",
|
||||
"last_updated",
|
||||
"regex",
|
||||
"type",
|
||||
"group",
|
||||
"managed",
|
||||
"is_unique",
|
||||
"is_required",
|
||||
"is_array",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"last_updated": {"read_only": True},
|
||||
"created": {"read_only": True},
|
||||
"pk": {"read_only": True},
|
||||
}
|
||||
|
||||
|
||||
class ObjectAttributeViewSet(ModelViewSet):
|
||||
serializer_class = ObjectAttributeSerializer
|
||||
queryset = ObjectAttribute.objects.all()
|
||||
filterset_fields = ["object_type__model", "object_type__app_label", "enabled"]
|
||||
search_fields = ["key", "label", "group", "object_type__model", "object_type__app_label"]
|
||||
ordering = ["key"]
|
||||
@@ -65,7 +65,6 @@ from authentik.api.search.fields import (
|
||||
from authentik.api.validation import validate
|
||||
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
|
||||
from authentik.brands.models import Brand
|
||||
from authentik.core.api.object_attributes import AttributesMixinSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import (
|
||||
JSONDictField,
|
||||
@@ -135,7 +134,7 @@ class PartialGroupSerializer(ModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
class UserSerializer(AttributesMixinSerializer, ModelSerializer):
|
||||
class UserSerializer(ModelSerializer):
|
||||
"""User Serializer"""
|
||||
|
||||
is_superuser = SerializerMethodField()
|
||||
@@ -298,36 +297,6 @@ class UserSerializer(AttributesMixinSerializer, ModelSerializer):
|
||||
raise ValidationError(_("Setting a user to internal service account is not allowed."))
|
||||
return user_type
|
||||
|
||||
def validate_groups(self, groups: list) -> list:
|
||||
"""Require enable_group_superuser permission when adding a user to a superuser group."""
|
||||
request: Request = self.context.get("request", None)
|
||||
if not request:
|
||||
return groups
|
||||
current_groups = set(self.instance.groups.all()) if self.instance else set()
|
||||
for group in groups:
|
||||
if not group.is_superuser:
|
||||
continue
|
||||
if group in current_groups:
|
||||
continue
|
||||
if not request.user.has_perm("authentik_core.enable_group_superuser"):
|
||||
raise ValidationError(
|
||||
_("User does not have permission to add members to a superuser group.")
|
||||
)
|
||||
return groups
|
||||
|
||||
def validate_roles(self, roles: list) -> list:
|
||||
"""Require change_role permission when assigning new roles to a user."""
|
||||
request: Request = self.context.get("request", None)
|
||||
if not request:
|
||||
return roles
|
||||
current_roles = set(self.instance.roles.all()) if self.instance else set()
|
||||
new_roles = [r for r in roles if r not in current_roles]
|
||||
if not new_roles:
|
||||
return roles
|
||||
if not request.user.has_perm("authentik_rbac.change_role"):
|
||||
raise ValidationError(_("User does not have permission to assign roles."))
|
||||
return roles
|
||||
|
||||
def validate(self, attrs: dict) -> dict:
|
||||
if self.instance and self.instance.type == UserTypes.INTERNAL_SERVICE_ACCOUNT:
|
||||
raise ValidationError(_("Can't modify internal service account users"))
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
# Generated by Django 5.2.13 on 2026-04-11 18:35
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_core", "0057_remove_user_groups_remove_user_user_permissions_and_more"),
|
||||
("contenttypes", "0002_remove_content_type_name"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="ObjectAttribute",
|
||||
fields=[
|
||||
("created", models.DateTimeField(auto_now_add=True)),
|
||||
("last_updated", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"managed",
|
||||
models.TextField(
|
||||
default=None,
|
||||
help_text="Objects that are managed by authentik. These objects are created and updated automatically. This flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.",
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="Managed by authentik",
|
||||
),
|
||||
),
|
||||
(
|
||||
"attribute_id",
|
||||
models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False),
|
||||
),
|
||||
("enabled", models.BooleanField(default=True)),
|
||||
("label", models.TextField()),
|
||||
("group", models.TextField(blank=True)),
|
||||
("key", models.TextField()),
|
||||
(
|
||||
"type",
|
||||
models.TextField(
|
||||
choices=[("text", "Text"), ("number", "Number"), ("boolean", "Boolean")]
|
||||
),
|
||||
),
|
||||
("is_unique", models.BooleanField(default=False)),
|
||||
("is_required", models.BooleanField(default=False)),
|
||||
("regex", models.TextField(blank=True)),
|
||||
("is_array", models.BooleanField(default=False)),
|
||||
(
|
||||
"object_type",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="contenttypes.contenttype"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Object Attribute",
|
||||
"verbose_name_plural": "Object Attributes",
|
||||
"unique_together": {("object_type", "key", "enabled")},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -13,7 +13,6 @@ from deepmerge import always_merger
|
||||
from django.contrib.auth.hashers import check_password, identify_hasher
|
||||
from django.contrib.auth.models import AbstractUser, Permission
|
||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.sessions.base_session import AbstractBaseSession
|
||||
from django.core.validators import validate_slug
|
||||
from django.db import models
|
||||
@@ -27,7 +26,6 @@ from guardian.models import RoleModelPermission, RoleObjectPermission
|
||||
from model_utils.managers import InheritanceManager
|
||||
from psqlextra.indexes import UniqueIndex
|
||||
from psqlextra.models import PostgresMaterializedViewModel
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.serializers import Serializer
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
@@ -1394,61 +1392,3 @@ class AuthenticatedSession(SerializerModel):
|
||||
session=Session.objects.filter(session_key=request.session.session_key).first(),
|
||||
user=user,
|
||||
)
|
||||
|
||||
|
||||
class ObjectAttribute(SerializerModel, ManagedModel, CreatedUpdatedModel):
|
||||
"""User-defined schema for models' `attributes` JSON field."""
|
||||
|
||||
class AttributeType(models.TextChoices):
|
||||
TEXT = "text"
|
||||
NUMBER = "number"
|
||||
BOOLEAN = "boolean"
|
||||
|
||||
attribute_id = models.UUIDField(default=uuid4, primary_key=True)
|
||||
|
||||
enabled = models.BooleanField(default=True)
|
||||
|
||||
object_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
||||
label = models.TextField()
|
||||
group = models.TextField(blank=True)
|
||||
key = models.TextField()
|
||||
|
||||
type = models.TextField(choices=AttributeType.choices)
|
||||
is_unique = models.BooleanField(default=False)
|
||||
is_required = models.BooleanField(default=False)
|
||||
regex = models.TextField(blank=True)
|
||||
is_array = models.BooleanField(default=False)
|
||||
|
||||
def run_validation(self, value: Any) -> None:
|
||||
err_key = f"attributes_{self.key.replace(".", "_")}"
|
||||
if self.is_required and value is None:
|
||||
raise ValidationError({err_key: _("This field is required")})
|
||||
if self.is_array:
|
||||
if not isinstance(value, (list, tuple)):
|
||||
raise ValidationError({err_key: _("Value must be an array.")})
|
||||
if self.regex != "":
|
||||
if not all(re.fullmatch(self.regex, v) for v in value):
|
||||
raise ValidationError({err_key: _("Value does not match configured pattern.")})
|
||||
else:
|
||||
if self.is_unique:
|
||||
model: type[models.Model] = self.object_type.model_class()
|
||||
lookup_key = f"attributes__{self.key.replace(".", "__")}"
|
||||
if model.objects.filter(**{lookup_key: value}).exists():
|
||||
raise ValidationError({err_key: _("Value is not unique.")})
|
||||
if self.regex != "":
|
||||
if not re.fullmatch(self.regex, value):
|
||||
raise ValidationError({err_key: _("Value does not match configured pattern.")})
|
||||
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
from authentik.core.api.object_attributes import ObjectAttributeSerializer
|
||||
|
||||
return ObjectAttributeSerializer
|
||||
|
||||
def __str__(self):
|
||||
return f"Object attribute '{self.key}' for content type {self.object_type_id}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Object Attribute")
|
||||
verbose_name_plural = _("Object Attributes")
|
||||
unique_together = (("object_type", "key", "enabled"),)
|
||||
|
||||
@@ -158,58 +158,3 @@ class TestGroupsAPI(APITestCase):
|
||||
data={"name": generate_id(), "is_superuser": True},
|
||||
)
|
||||
self.assertEqual(res.status_code, 201)
|
||||
|
||||
def test_patch_users_no_perm(self):
|
||||
"""PATCH group with new users without add_user_to_group must be rejected."""
|
||||
group = Group.objects.create(name=generate_id())
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.view_group", group)
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.change_group", group)
|
||||
self.client.force_login(self.login_user)
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:group-detail", kwargs={"pk": group.pk}),
|
||||
data={"users": [self.user.pk]},
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
|
||||
def test_patch_users_with_global_perm(self):
|
||||
"""PATCH group with new users with global add_user_to_group must succeed."""
|
||||
group = Group.objects.create(name=generate_id())
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.view_group", group)
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.change_group", group)
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.add_user_to_group")
|
||||
self.client.force_login(self.login_user)
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:group-detail", kwargs={"pk": group.pk}),
|
||||
data={"users": [self.user.pk]},
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_patch_users_with_obj_perm(self):
|
||||
"""PATCH group with new users with object-level add_user_to_group must succeed."""
|
||||
group = Group.objects.create(name=generate_id())
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.view_group", group)
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.change_group", group)
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.add_user_to_group", group)
|
||||
self.client.force_login(self.login_user)
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:group-detail", kwargs={"pk": group.pk}),
|
||||
data={"users": [self.user.pk]},
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_patch_existing_users_no_perm(self):
|
||||
"""PATCH group keeping existing membership without add_user_to_group must succeed."""
|
||||
group = Group.objects.create(name=generate_id())
|
||||
group.users.add(self.user)
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.view_group", group)
|
||||
self.login_user.assign_perms_to_managed_role("authentik_core.change_group", group)
|
||||
self.client.force_login(self.login_user)
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:group-detail", kwargs={"pk": group.pk}),
|
||||
data={"users": [self.user.pk]},
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
"""Test object attributes API"""
|
||||
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.api.object_attributes import ContentType
|
||||
from authentik.core.models import ObjectAttribute, User
|
||||
from authentik.core.tests.utils import create_test_admin_user, create_test_user
|
||||
from authentik.lib.generators import generate_id
|
||||
|
||||
|
||||
class TestObjectAttributesAPI(APITestCase):
|
||||
"""Test object attributes API"""
|
||||
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
self.user = create_test_admin_user()
|
||||
self.client.force_login(self.user)
|
||||
|
||||
def test_create(self):
|
||||
res = self.client.post(
|
||||
reverse("authentik_api:objectattribute-list"),
|
||||
data={
|
||||
"object_type": "authentik_core.user",
|
||||
"enabled": False,
|
||||
"key": "employeeNumber",
|
||||
"label": "Employee Number",
|
||||
"type": "text",
|
||||
"group": "Employee",
|
||||
"is_unique": False,
|
||||
"is_required": False,
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 201)
|
||||
attr = ObjectAttribute.objects.filter(key="employeeNumber").first()
|
||||
self.assertIsNotNone(attr)
|
||||
|
||||
def test_create_invalid(self):
|
||||
res = self.client.post(
|
||||
reverse("authentik_api:objectattribute-list"),
|
||||
data={
|
||||
"object_type": "authentik_core.objectattribute",
|
||||
"enabled": False,
|
||||
"key": "employeeNumber",
|
||||
"label": "Employee Number",
|
||||
"type": "text",
|
||||
"group": "Employee",
|
||||
"is_unique": False,
|
||||
"is_required": False,
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertJSONEqual(res.content, {"object_type": ["Invalid object type"]})
|
||||
|
||||
def test_create_invalid_array_unique(self):
|
||||
res = self.client.post(
|
||||
reverse("authentik_api:objectattribute-list"),
|
||||
data={
|
||||
"object_type": "authentik_core.user",
|
||||
"enabled": False,
|
||||
"key": "employeeNumber",
|
||||
"label": "Employee Number",
|
||||
"type": "text",
|
||||
"group": "Employee",
|
||||
"is_unique": True,
|
||||
"is_required": False,
|
||||
"is_array": True,
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertJSONEqual(
|
||||
res.content, {"non_field_errors": ["Unique cannot be enabled for arrays."]}
|
||||
)
|
||||
|
||||
def test_update(self):
|
||||
attr = ObjectAttribute.objects.create(
|
||||
object_type=ContentType.objects.get_for_model(User),
|
||||
label="foo",
|
||||
key=generate_id(),
|
||||
type=ObjectAttribute.AttributeType.TEXT,
|
||||
)
|
||||
res = self.client.put(
|
||||
reverse("authentik_api:objectattribute-detail", kwargs={"pk": attr.pk}),
|
||||
data={
|
||||
"object_type": "authentik_core.user",
|
||||
"enabled": False,
|
||||
"key": attr.key,
|
||||
"label": "Employee Number",
|
||||
"type": "text",
|
||||
"group": "Employee",
|
||||
"is_unique": False,
|
||||
"is_required": False,
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
attr.refresh_from_db()
|
||||
self.assertEqual(attr.label, "Employee Number")
|
||||
|
||||
def test_user_attrib_validation_required(self):
|
||||
attr = ObjectAttribute.objects.create(
|
||||
object_type=ContentType.objects.get_for_model(User),
|
||||
label="foo",
|
||||
key=generate_id(),
|
||||
type=ObjectAttribute.AttributeType.TEXT,
|
||||
is_required=True,
|
||||
)
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:user-detail", kwargs={"pk": self.user.pk}),
|
||||
data={
|
||||
"attributes": {},
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertJSONEqual(res.content, {f"attributes_{attr.key}": ["This field is required"]})
|
||||
|
||||
def test_user_attrib_validation_unique(self):
|
||||
attr = ObjectAttribute.objects.create(
|
||||
object_type=ContentType.objects.get_for_model(User),
|
||||
label="foo",
|
||||
key=generate_id(),
|
||||
type=ObjectAttribute.AttributeType.TEXT,
|
||||
is_unique=True,
|
||||
)
|
||||
other_user = create_test_user()
|
||||
other_user.attributes[attr.key] = "foo"
|
||||
other_user.save()
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:user-detail", kwargs={"pk": self.user.pk}),
|
||||
data={
|
||||
"attributes": {attr.key: "foo"},
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertJSONEqual(res.content, {f"attributes_{attr.key}": ["Value is not unique."]})
|
||||
|
||||
def test_user_attrib_validation_regex(self):
|
||||
attr = ObjectAttribute.objects.create(
|
||||
object_type=ContentType.objects.get_for_model(User),
|
||||
label="foo",
|
||||
key=generate_id(),
|
||||
type=ObjectAttribute.AttributeType.TEXT,
|
||||
regex="bar",
|
||||
)
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:user-detail", kwargs={"pk": self.user.pk}),
|
||||
data={
|
||||
"attributes": {attr.key: "foo"},
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertJSONEqual(
|
||||
res.content, {f"attributes_{attr.key}": ["Value does not match configured pattern."]}
|
||||
)
|
||||
|
||||
def test_user_attrib_validation_array(self):
|
||||
attr = ObjectAttribute.objects.create(
|
||||
object_type=ContentType.objects.get_for_model(User),
|
||||
label="foo",
|
||||
key=generate_id(),
|
||||
type=ObjectAttribute.AttributeType.TEXT,
|
||||
is_array=True,
|
||||
)
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:user-detail", kwargs={"pk": self.user.pk}),
|
||||
data={
|
||||
"attributes": {attr.key: "foo"},
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertJSONEqual(res.content, {f"attributes_{attr.key}": ["Value must be an array."]})
|
||||
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:user-detail", kwargs={"pk": self.user.pk}),
|
||||
data={
|
||||
"attributes": {attr.key: ["foo"]},
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_user_attrib_validation_array_regex(self):
|
||||
attr = ObjectAttribute.objects.create(
|
||||
object_type=ContentType.objects.get_for_model(User),
|
||||
label="foo",
|
||||
key=generate_id(),
|
||||
type=ObjectAttribute.AttributeType.TEXT,
|
||||
is_array=True,
|
||||
regex="bar",
|
||||
)
|
||||
res = self.client.patch(
|
||||
reverse("authentik_api:user-detail", kwargs={"pk": self.user.pk}),
|
||||
data={
|
||||
"attributes": {attr.key: ["foo"]},
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertJSONEqual(
|
||||
res.content, {f"attributes_{attr.key}": ["Value does not match configured pattern."]}
|
||||
)
|
||||
@@ -12,7 +12,6 @@ from authentik.brands.models import Brand
|
||||
from authentik.core.models import (
|
||||
USER_ATTRIBUTE_TOKEN_EXPIRING,
|
||||
AuthenticatedSession,
|
||||
Group,
|
||||
Session,
|
||||
Token,
|
||||
User,
|
||||
@@ -26,7 +25,6 @@ from authentik.core.tests.utils import (
|
||||
)
|
||||
from authentik.flows.models import FlowAuthenticationRequirement, FlowDesignation
|
||||
from authentik.lib.generators import generate_id, generate_key
|
||||
from authentik.rbac.models import Role
|
||||
from authentik.stages.email.models import EmailStage
|
||||
|
||||
INVALID_PASSWORD_HASH = "not-a-valid-hash"
|
||||
@@ -941,79 +939,3 @@ class TestUsersAPI(APITestCase):
|
||||
self.assertIn(user2.pk, pks)
|
||||
# Verify user2 comes before user1 in descending order
|
||||
self.assertLess(pks.index(user2.pk), pks.index(user1.pk))
|
||||
|
||||
|
||||
class TestUsersAPIGroupRoleValidation(APITestCase):
|
||||
"""Test that PATCH /api/v3/core/users/{pk}/ enforces group and role permission checks."""
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.actor = create_test_user()
|
||||
self.target = create_test_user()
|
||||
|
||||
def _patch(self, data: dict):
|
||||
self.client.force_login(self.actor)
|
||||
return self.client.patch(
|
||||
reverse("authentik_api:user-detail", kwargs={"pk": self.target.pk}),
|
||||
data=data,
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
def test_patch_superuser_group_no_perm(self):
|
||||
"""Assigning a superuser group without enable_group_superuser must be rejected."""
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.view_user")
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.target)
|
||||
group = Group.objects.create(name=generate_id(), is_superuser=True)
|
||||
res = self._patch({"groups": [str(group.pk)]})
|
||||
self.assertEqual(res.status_code, 400)
|
||||
|
||||
def test_patch_superuser_group_with_perm(self):
|
||||
"""Assigning a superuser group with enable_group_superuser must succeed."""
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.view_user")
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.target)
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.enable_group_superuser")
|
||||
group = Group.objects.create(name=generate_id(), is_superuser=True)
|
||||
res = self._patch({"groups": [str(group.pk)]})
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_patch_non_superuser_group_no_perm(self):
|
||||
"""Assigning a non-superuser group without special permission must succeed."""
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.view_user")
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.target)
|
||||
group = Group.objects.create(name=generate_id(), is_superuser=False)
|
||||
res = self._patch({"groups": [str(group.pk)]})
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_patch_existing_superuser_group_no_perm(self):
|
||||
"""Keeping an existing superuser group membership without the permission must succeed."""
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.view_user")
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.target)
|
||||
group = Group.objects.create(name=generate_id(), is_superuser=True)
|
||||
self.target.groups.add(group)
|
||||
res = self._patch({"groups": [str(group.pk)]})
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_patch_role_no_perm(self):
|
||||
"""Assigning a new role without change_role must be rejected."""
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.view_user")
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.target)
|
||||
role = Role.objects.create(name=generate_id())
|
||||
res = self._patch({"roles": [str(role.pk)]})
|
||||
self.assertEqual(res.status_code, 400)
|
||||
|
||||
def test_patch_role_with_perm(self):
|
||||
"""Assigning a new role with change_role must succeed."""
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.view_user")
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.target)
|
||||
self.actor.assign_perms_to_managed_role("authentik_rbac.change_role")
|
||||
role = Role.objects.create(name=generate_id())
|
||||
res = self._patch({"roles": [str(role.pk)]})
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_patch_existing_role_no_perm(self):
|
||||
"""Keeping an existing role without change_role must succeed."""
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.view_user")
|
||||
self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.target)
|
||||
role = Role.objects.create(name=generate_id())
|
||||
self.target.roles.add(role)
|
||||
res = self._patch({"roles": [str(role.pk)]})
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
@@ -8,7 +8,6 @@ from authentik.core.api.applications import ApplicationViewSet
|
||||
from authentik.core.api.authenticated_sessions import AuthenticatedSessionViewSet
|
||||
from authentik.core.api.devices import AdminDeviceViewSet, DeviceViewSet
|
||||
from authentik.core.api.groups import GroupViewSet
|
||||
from authentik.core.api.object_attributes import ObjectAttributeViewSet
|
||||
from authentik.core.api.property_mappings import PropertyMappingViewSet
|
||||
from authentik.core.api.providers import ProviderViewSet
|
||||
from authentik.core.api.sources import (
|
||||
@@ -88,7 +87,6 @@ api_urlpatterns = [
|
||||
("core/groups", GroupViewSet),
|
||||
("core/users", UserViewSet),
|
||||
("core/tokens", TokenViewSet),
|
||||
("core/object_attributes", ObjectAttributeViewSet),
|
||||
("sources/all", SourceViewSet),
|
||||
("sources/user_connections/all", UserSourceConnectionViewSet),
|
||||
("sources/group_connections/all", GroupSourceConnectionViewSet),
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.object_attributes import AttributesMixinSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import ModelSerializer
|
||||
from authentik.endpoints.models import DeviceAccessGroup
|
||||
|
||||
|
||||
class DeviceAccessGroupSerializer(AttributesMixinSerializer, ModelSerializer):
|
||||
class DeviceAccessGroupSerializer(ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = DeviceAccessGroup
|
||||
|
||||
@@ -7,7 +7,7 @@ from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_sche
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied, ValidationError
|
||||
from rest_framework.fields import ChoiceField
|
||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.relations import PrimaryKeyRelatedField
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
@@ -44,6 +44,7 @@ from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_ME
|
||||
|
||||
|
||||
class AgentConnectorSerializer(ConnectorSerializer):
|
||||
|
||||
class Meta(ConnectorSerializer.Meta):
|
||||
model = AgentConnector
|
||||
fields = ConnectorSerializer.Meta.fields + [
|
||||
@@ -62,6 +63,7 @@ class AgentConnectorSerializer(ConnectorSerializer):
|
||||
|
||||
|
||||
class MDMConfigSerializer(PassiveSerializer):
|
||||
|
||||
platform = ChoiceField(choices=OSFamily.choices)
|
||||
enrollment_token = PrimaryKeyRelatedField(
|
||||
queryset=EnrollmentToken.objects.including_expired().all()
|
||||
@@ -87,6 +89,7 @@ class AgentConnectorViewSet(
|
||||
UsedByMixin,
|
||||
ModelViewSet,
|
||||
):
|
||||
|
||||
queryset = AgentConnector.objects.all()
|
||||
serializer_class = AgentConnectorSerializer
|
||||
search_fields = ["name"]
|
||||
@@ -118,8 +121,6 @@ class AgentConnectorViewSet(
|
||||
methods=["POST"],
|
||||
detail=False,
|
||||
authentication_classes=[AgentEnrollmentAuth],
|
||||
# Permissions are handled via AgentEnrollmentAuth
|
||||
permission_classes=[AllowAny],
|
||||
)
|
||||
def enroll(self, request: Request):
|
||||
token: EnrollmentToken = request.auth
|
||||
@@ -150,13 +151,7 @@ class AgentConnectorViewSet(
|
||||
request=OpenApiTypes.NONE,
|
||||
responses=AgentConfigSerializer(),
|
||||
)
|
||||
@action(
|
||||
methods=["GET"],
|
||||
detail=False,
|
||||
authentication_classes=[AgentAuth],
|
||||
# Permissions are handled via AgentAuth
|
||||
permission_classes=[AllowAny],
|
||||
)
|
||||
@action(methods=["GET"], detail=False, authentication_classes=[AgentAuth])
|
||||
def agent_config(self, request: Request):
|
||||
token: DeviceToken = request.auth
|
||||
connector: AgentConnector = token.device.connector.agentconnector
|
||||
@@ -170,13 +165,7 @@ class AgentConnectorViewSet(
|
||||
request=DeviceFacts(),
|
||||
responses={204: OpenApiResponse(description="Successfully checked in")},
|
||||
)
|
||||
@action(
|
||||
methods=["POST"],
|
||||
detail=False,
|
||||
authentication_classes=[AgentAuth],
|
||||
# Permissions are handled via AgentAuth
|
||||
permission_classes=[AllowAny],
|
||||
)
|
||||
@action(methods=["POST"], detail=False, authentication_classes=[AgentAuth])
|
||||
def check_in(self, request: Request):
|
||||
token: DeviceToken = request.auth
|
||||
data = DeviceFacts(data=request.data)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from typing import Any
|
||||
|
||||
from django.db.models import Model
|
||||
from django.http import HttpRequest
|
||||
from django.utils.timezone import now
|
||||
from drf_spectacular.extensions import OpenApiAuthenticationExtension
|
||||
@@ -10,7 +9,7 @@ from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.request import Request
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.api.authentication import VirtualUser, validate_auth
|
||||
from authentik.api.authentication import IPCUser, validate_auth
|
||||
from authentik.core.middleware import CTX_AUTH_VIA
|
||||
from authentik.core.models import User
|
||||
from authentik.crypto.apps import MANAGED_KEY
|
||||
@@ -26,18 +25,9 @@ LOGGER = get_logger()
|
||||
PLATFORM_ISSUER = "goauthentik.io/platform"
|
||||
|
||||
|
||||
class DeviceUser(VirtualUser):
|
||||
|
||||
class DeviceUser(IPCUser):
|
||||
username = "authentik:endpoints:device"
|
||||
|
||||
def has_perm(self, perm: str, obj: Model | None = None) -> bool:
|
||||
if perm in [
|
||||
"authentik_core.view_user",
|
||||
"authentik_core.view_group",
|
||||
]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class AgentEnrollmentAuth(BaseAuthentication):
|
||||
|
||||
|
||||
@@ -223,17 +223,3 @@ class TestAgentAPI(APITestCase):
|
||||
data={"platform": OSFamily.macOS, "enrollment_token": self.token.pk},
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_users_list(self):
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:user-list"),
|
||||
HTTP_AUTHORIZATION=f"Bearer+agent {self.device_token.key}",
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_other_api_forbidden(self):
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:application-list"),
|
||||
HTTP_AUTHORIZATION=f"Bearer+agent {self.device_token.key}",
|
||||
)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
@@ -2,7 +2,6 @@ from django.urls import reverse
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from structlog.stdlib import get_logger
|
||||
@@ -26,13 +25,7 @@ class AgentConnectorViewSetMixin:
|
||||
request=OpenApiTypes.NONE,
|
||||
responses=AgentAuthenticationResponse(),
|
||||
)
|
||||
@action(
|
||||
methods=["POST"],
|
||||
detail=False,
|
||||
authentication_classes=[AgentAuth],
|
||||
# Permissions are handled via AgentAuth
|
||||
permission_classes=[AllowAny],
|
||||
)
|
||||
@action(methods=["POST"], detail=False, authentication_classes=[AgentAuth])
|
||||
@enterprise_action
|
||||
def auth_ia(self, request: Request) -> Response:
|
||||
token: DeviceToken = request.auth
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from dataclasses import dataclass
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from django.http import HttpRequest
|
||||
from django.shortcuts import get_object_or_404
|
||||
@@ -56,9 +55,7 @@ class SignInRequest:
|
||||
_, provider = req.get_app_provider()
|
||||
if not req.wreply:
|
||||
req.wreply = provider.acs_url
|
||||
reply = urlparse(req.wreply)
|
||||
configured = urlparse(provider.acs_url)
|
||||
if not (reply[:2] == configured[:2] and reply.path.startswith(configured.path)):
|
||||
if not req.wreply.startswith(provider.acs_url):
|
||||
raise ValueError("Invalid wreply")
|
||||
return req
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from dataclasses import dataclass
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from django.http import HttpRequest
|
||||
from django.shortcuts import get_object_or_404
|
||||
@@ -33,9 +32,7 @@ class SignOutRequest:
|
||||
_, provider = req.get_app_provider()
|
||||
if not req.wreply:
|
||||
req.wreply = provider.acs_url
|
||||
reply = urlparse(req.wreply)
|
||||
configured = urlparse(provider.acs_url)
|
||||
if not (reply[:2] == configured[:2] and reply.path.startswith(configured.path)):
|
||||
if not req.wreply.startswith(provider.acs_url):
|
||||
raise ValueError("Invalid wreply")
|
||||
return req
|
||||
|
||||
|
||||
@@ -27,27 +27,12 @@ class TestWSFedSignIn(TestCase):
|
||||
name=generate_id(),
|
||||
authorization_flow=self.flow,
|
||||
signing_kp=self.cert,
|
||||
acs_url="https://t.goauthentik.io",
|
||||
audience="foo",
|
||||
)
|
||||
self.app = Application.objects.create(
|
||||
name=generate_id(), slug=generate_id(), provider=self.provider
|
||||
)
|
||||
self.factory = RequestFactory()
|
||||
|
||||
def test_wreply(self):
|
||||
request = self.factory.get(
|
||||
"/?wreply=https://t.goauthentik.io/foo&wa=wsignin1.0&wtrealm=foo",
|
||||
user=get_anonymous_user(),
|
||||
)
|
||||
SignInRequest.parse(request)
|
||||
with self.assertRaises(ValueError):
|
||||
request = self.factory.get(
|
||||
"/?wreply=https://t.goauthentik.io.invalid.com&wa=wsignin1.0&wtrealm=foo",
|
||||
user=get_anonymous_user(),
|
||||
)
|
||||
SignInRequest.parse(request)
|
||||
|
||||
def test_token_gen(self):
|
||||
request = self.factory.get("/", user=get_anonymous_user())
|
||||
proc = SignInProcessor(
|
||||
|
||||
@@ -4,13 +4,13 @@ from django.urls import reverse
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, SerializerMethodField
|
||||
from rest_framework.permissions import BasePermission
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.core.api.groups import PartialUserSerializer
|
||||
from authentik.core.api.object_attributes import ContentTypeSerializer
|
||||
from authentik.core.api.utils import ModelSerializer
|
||||
from authentik.enterprise.api import EnterpriseRequiredMixin
|
||||
from authentik.enterprise.reports.models import DataExport
|
||||
@@ -18,6 +18,19 @@ from authentik.enterprise.reports.tasks import generate_export
|
||||
from authentik.rbac.permissions import HasPermission
|
||||
|
||||
|
||||
class ContentTypeSerializer(ModelSerializer):
|
||||
app_label = CharField(read_only=True)
|
||||
model = CharField(read_only=True)
|
||||
verbose_name_plural = SerializerMethodField()
|
||||
|
||||
def get_verbose_name_plural(self, ct: ContentType) -> str:
|
||||
return ct.model_class()._meta.verbose_name_plural
|
||||
|
||||
class Meta:
|
||||
model = ContentType
|
||||
fields = ("id", "app_label", "model", "verbose_name_plural")
|
||||
|
||||
|
||||
class DataExportSerializer(EnterpriseRequiredMixin, ModelSerializer):
|
||||
requested_by = PartialUserSerializer(read_only=True)
|
||||
content_type = ContentTypeSerializer(read_only=True)
|
||||
|
||||
@@ -10,7 +10,6 @@ from typing import TYPE_CHECKING, Any
|
||||
|
||||
from cachetools import TLRUCache, cached
|
||||
from django.core.exceptions import FieldError
|
||||
from django.db.models import Model
|
||||
from django.http import HttpRequest
|
||||
from django.utils.text import slugify
|
||||
from django.utils.timezone import now
|
||||
@@ -23,7 +22,6 @@ from structlog.stdlib import get_logger
|
||||
from authentik.core.models import User
|
||||
from authentik.events.models import Event
|
||||
from authentik.lib.expression.exceptions import ControlFlowException
|
||||
from authentik.lib.utils.dict import get_path_from_dict
|
||||
from authentik.lib.utils.email import normalize_addresses
|
||||
from authentik.lib.utils.http import get_http_session
|
||||
from authentik.lib.utils.time import timedelta_from_string
|
||||
@@ -72,7 +70,6 @@ class BaseEvaluator:
|
||||
"ak_send_email": self.expr_send_email,
|
||||
"ak_user_by": BaseEvaluator.expr_user_by,
|
||||
"ak_user_has_authenticator": BaseEvaluator.expr_func_user_has_authenticator,
|
||||
"ak_obj_attr": BaseEvaluator.expr_obj_attr,
|
||||
"ip_address": ip_address,
|
||||
"ip_network": ip_network,
|
||||
"list_flatten": BaseEvaluator.expr_flatten,
|
||||
@@ -165,16 +162,6 @@ class BaseEvaluator:
|
||||
return False
|
||||
return len(list(user_devices)) > 0
|
||||
|
||||
@staticmethod
|
||||
def expr_obj_attr(obj: Model, attr_key: str, fallback: str) -> Any:
|
||||
"""Get an attribute of the given object if set by its dotted path, otherwise
|
||||
return fallback value."""
|
||||
attrs = getattr(obj, "attributes", {})
|
||||
value = get_path_from_dict(attrs, attr_key)
|
||||
if value is None and fallback:
|
||||
return getattr(obj, fallback)
|
||||
return value
|
||||
|
||||
def expr_event_create(self, action: str, **kwargs):
|
||||
"""Create event with supplied data and try to extract as much relevant data
|
||||
from the context"""
|
||||
|
||||
@@ -9,10 +9,10 @@ from rest_framework.fields import CharField, ListField, SerializerMethodField
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.core.api.providers import ProviderSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.users import UserSerializer
|
||||
from authentik.core.api.utils import MetaNameSerializer, ModelSerializer
|
||||
from authentik.providers.oauth2.api.providers import OAuth2ProviderSerializer
|
||||
from authentik.providers.oauth2.models import AccessToken, AuthorizationCode, RefreshToken
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class ExpiringBaseGrantModelSerializer(ModelSerializer, MetaNameSerializer):
|
||||
"""Serializer for BaseGrantModel and ExpiringBaseGrant"""
|
||||
|
||||
user = UserSerializer()
|
||||
provider = ProviderSerializer()
|
||||
provider = OAuth2ProviderSerializer()
|
||||
scope = ListField(child=CharField())
|
||||
|
||||
class Meta:
|
||||
|
||||
@@ -61,11 +61,6 @@ class SAMLProviderSerializer(ProviderSerializer):
|
||||
url_download_metadata = SerializerMethodField()
|
||||
url_issuer = SerializerMethodField()
|
||||
|
||||
# Unified SAML endpoint (primary)
|
||||
url_unified = SerializerMethodField()
|
||||
url_unified_init = SerializerMethodField()
|
||||
|
||||
# Legacy endpoints (for backward compatibility)
|
||||
url_sso_post = SerializerMethodField()
|
||||
url_sso_redirect = SerializerMethodField()
|
||||
url_sso_init = SerializerMethodField()
|
||||
@@ -102,21 +97,6 @@ class SAMLProviderSerializer(ProviderSerializer):
|
||||
if "request" not in self._context:
|
||||
return DEFAULT_ISSUER
|
||||
request: HttpRequest = self._context["request"]._request
|
||||
try:
|
||||
return request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_saml:metadata-download",
|
||||
kwargs={"application_slug": instance.application.slug},
|
||||
)
|
||||
)
|
||||
except Provider.application.RelatedObjectDoesNotExist:
|
||||
return DEFAULT_ISSUER
|
||||
|
||||
def get_url_unified(self, instance: SAMLProvider) -> str:
|
||||
"""Get unified SAML endpoint URL (handles SSO and SLO)"""
|
||||
if "request" not in self._context:
|
||||
return ""
|
||||
request: HttpRequest = self._context["request"]._request
|
||||
try:
|
||||
return request.build_absolute_uri(
|
||||
reverse(
|
||||
@@ -125,22 +105,7 @@ class SAMLProviderSerializer(ProviderSerializer):
|
||||
)
|
||||
)
|
||||
except Provider.application.RelatedObjectDoesNotExist:
|
||||
return "-"
|
||||
|
||||
def get_url_unified_init(self, instance: SAMLProvider) -> str:
|
||||
"""Get IdP-initiated SAML URL"""
|
||||
if "request" not in self._context:
|
||||
return ""
|
||||
request: HttpRequest = self._context["request"]._request
|
||||
try:
|
||||
return request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_saml:init",
|
||||
kwargs={"application_slug": instance.application.slug},
|
||||
)
|
||||
)
|
||||
except Provider.application.RelatedObjectDoesNotExist:
|
||||
return "-"
|
||||
return DEFAULT_ISSUER
|
||||
|
||||
def get_url_sso_post(self, instance: SAMLProvider) -> str:
|
||||
"""Get SSO Post URL"""
|
||||
@@ -278,8 +243,6 @@ class SAMLProviderSerializer(ProviderSerializer):
|
||||
"default_name_id_policy",
|
||||
"url_download_metadata",
|
||||
"url_issuer",
|
||||
"url_unified",
|
||||
"url_unified_init",
|
||||
"url_sso_post",
|
||||
"url_sso_redirect",
|
||||
"url_sso_init",
|
||||
|
||||
@@ -241,7 +241,7 @@ class SAMLProvider(Provider):
|
||||
"""Use IDP-Initiated SAML flow as launch URL"""
|
||||
try:
|
||||
return reverse(
|
||||
"authentik_providers_saml:init",
|
||||
"authentik_providers_saml:sso-init",
|
||||
kwargs={"application_slug": self.application.slug},
|
||||
)
|
||||
except Provider.application.RelatedObjectDoesNotExist:
|
||||
|
||||
@@ -147,7 +147,7 @@ class AssertionProcessor:
|
||||
|
||||
return self.http_request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_saml:metadata-download",
|
||||
"authentik_providers_saml:base",
|
||||
kwargs={"application_slug": self.provider.application.slug},
|
||||
)
|
||||
)
|
||||
|
||||
@@ -48,7 +48,7 @@ class MetadataProcessor:
|
||||
|
||||
return self.http_request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_saml:metadata-download",
|
||||
"authentik_providers_saml:base",
|
||||
kwargs={"application_slug": self.provider.application.slug},
|
||||
)
|
||||
)
|
||||
@@ -81,35 +81,54 @@ class MetadataProcessor:
|
||||
element.text = name_id_format
|
||||
yield element
|
||||
|
||||
def _get_unified_url(self) -> str:
|
||||
"""Get the unified SAML endpoint URL"""
|
||||
return self.http_request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_saml:base",
|
||||
kwargs={"application_slug": self.provider.application.slug},
|
||||
)
|
||||
)
|
||||
|
||||
def get_sso_bindings(self) -> Iterator[Element]:
|
||||
"""Get all SSO Bindings - both point to unified endpoint"""
|
||||
unified_url = self._get_unified_url()
|
||||
for binding in [SAML_BINDING_REDIRECT, SAML_BINDING_POST]:
|
||||
"""Get all Bindings supported"""
|
||||
binding_url_map = {
|
||||
(SAML_BINDING_REDIRECT, "SingleSignOnService"): self.http_request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_saml:sso-redirect",
|
||||
kwargs={"application_slug": self.provider.application.slug},
|
||||
)
|
||||
),
|
||||
(SAML_BINDING_POST, "SingleSignOnService"): self.http_request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_saml:sso-post",
|
||||
kwargs={"application_slug": self.provider.application.slug},
|
||||
)
|
||||
),
|
||||
}
|
||||
for binding_svc, url in binding_url_map.items():
|
||||
binding, svc = binding_svc
|
||||
if self.force_binding and self.force_binding != binding:
|
||||
continue
|
||||
element = Element(f"{{{NS_SAML_METADATA}}}SingleSignOnService")
|
||||
element = Element(f"{{{NS_SAML_METADATA}}}{svc}")
|
||||
element.attrib["Binding"] = binding
|
||||
element.attrib["Location"] = unified_url
|
||||
element.attrib["Location"] = url
|
||||
yield element
|
||||
|
||||
def get_slo_bindings(self) -> Iterator[Element]:
|
||||
"""Get all SLO Bindings - both point to unified endpoint"""
|
||||
unified_url = self._get_unified_url()
|
||||
for binding in [SAML_BINDING_REDIRECT, SAML_BINDING_POST]:
|
||||
"""Get all Bindings supported"""
|
||||
binding_url_map = {
|
||||
(SAML_BINDING_REDIRECT, "SingleLogoutService"): self.http_request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_saml:slo-redirect",
|
||||
kwargs={"application_slug": self.provider.application.slug},
|
||||
)
|
||||
),
|
||||
(SAML_BINDING_POST, "SingleLogoutService"): self.http_request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_providers_saml:slo-post",
|
||||
kwargs={"application_slug": self.provider.application.slug},
|
||||
)
|
||||
),
|
||||
}
|
||||
for binding_svc, url in binding_url_map.items():
|
||||
binding, svc = binding_svc
|
||||
if self.force_binding and self.force_binding != binding:
|
||||
continue
|
||||
element = Element(f"{{{NS_SAML_METADATA}}}SingleLogoutService")
|
||||
element = Element(f"{{{NS_SAML_METADATA}}}{svc}")
|
||||
element.attrib["Binding"] = binding
|
||||
element.attrib["Location"] = unified_url
|
||||
element.attrib["Location"] = url
|
||||
yield element
|
||||
|
||||
def _prepare_signature(self, entity_descriptor: _Element):
|
||||
|
||||
@@ -53,6 +53,7 @@ class ServiceProviderMetadata:
|
||||
)
|
||||
provider.sp_binding = self.acs_binding
|
||||
provider.acs_url = self.acs_location
|
||||
provider.audience = self.entity_id
|
||||
provider.default_name_id_policy = self.name_id_policy
|
||||
# Single Logout Service
|
||||
if self.sls_location:
|
||||
|
||||
@@ -103,7 +103,7 @@ class TestServiceProviderMetadataParser(TestCase):
|
||||
provider.verification_kp.certificate_data, load_fixture("fixtures/cert.pem")
|
||||
)
|
||||
self.assertIsNotNone(provider.signing_kp)
|
||||
self.assertEqual(provider.audience, "")
|
||||
self.assertEqual(provider.audience, "http://localhost:8080/apps/user_saml/saml/metadata")
|
||||
|
||||
def test_with_signing_cert_invalid_signature(self):
|
||||
"""Test Metadata with signing cert (invalid signature)"""
|
||||
|
||||
@@ -4,26 +4,19 @@ from django.urls import path
|
||||
|
||||
from authentik.providers.saml.api.property_mappings import SAMLPropertyMappingViewSet
|
||||
from authentik.providers.saml.api.providers import SAMLProviderViewSet
|
||||
from authentik.providers.saml.views import metadata, sso, unified
|
||||
from authentik.providers.saml.views import metadata, sso
|
||||
from authentik.providers.saml.views.sp_slo import (
|
||||
SPInitiatedSLOBindingPOSTView,
|
||||
SPInitiatedSLOBindingRedirectView,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
# Unified Endpoint - handles SSO and SLO based on message type
|
||||
# Base path for Issuer/Entity ID
|
||||
path(
|
||||
"<slug:application_slug>/",
|
||||
unified.SAMLUnifiedView.as_view(),
|
||||
sso.SAMLSSOBindingRedirectView.as_view(),
|
||||
name="base",
|
||||
),
|
||||
# IdP-initiated
|
||||
path(
|
||||
"<slug:application_slug>/init/",
|
||||
sso.SAMLSSOBindingInitView.as_view(),
|
||||
name="init",
|
||||
),
|
||||
# LEGACY Endpoints (backward compatibility)
|
||||
# SSO Bindings
|
||||
path(
|
||||
"<slug:application_slug>/sso/binding/redirect/",
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
"""Unified SAML endpoint - handles SSO and SLO based on message type"""
|
||||
|
||||
from base64 import b64decode
|
||||
|
||||
from defusedxml.lxml import fromstring
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.common.saml.constants import NS_MAP
|
||||
from authentik.flows.views.executor import SESSION_KEY_POST
|
||||
from authentik.lib.views import bad_request_message
|
||||
from authentik.providers.saml.utils.encoding import decode_base64_and_inflate
|
||||
from authentik.providers.saml.views.flows import (
|
||||
REQUEST_KEY_SAML_REQUEST,
|
||||
REQUEST_KEY_SAML_RESPONSE,
|
||||
)
|
||||
from authentik.providers.saml.views.sp_slo import (
|
||||
SPInitiatedSLOBindingPOSTView,
|
||||
SPInitiatedSLOBindingRedirectView,
|
||||
)
|
||||
from authentik.providers.saml.views.sso import (
|
||||
SAMLSSOBindingPOSTView,
|
||||
SAMLSSOBindingRedirectView,
|
||||
)
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
# SAML message type constants
|
||||
SAML_MESSAGE_TYPE_AUTHN_REQUEST = "AuthnRequest"
|
||||
SAML_MESSAGE_TYPE_LOGOUT_REQUEST = "LogoutRequest"
|
||||
|
||||
|
||||
def detect_saml_message_type(saml_request: str, is_post_binding: bool) -> str | None:
|
||||
"""Parse SAML request to determine if AuthnRequest or LogoutRequest."""
|
||||
try:
|
||||
if is_post_binding:
|
||||
decoded_xml = b64decode(saml_request.encode())
|
||||
else:
|
||||
decoded_xml = decode_base64_and_inflate(saml_request)
|
||||
|
||||
root = fromstring(decoded_xml)
|
||||
if len(root.xpath("//samlp:AuthnRequest", namespaces=NS_MAP)):
|
||||
return SAML_MESSAGE_TYPE_AUTHN_REQUEST
|
||||
if len(root.xpath("//samlp:LogoutRequest", namespaces=NS_MAP)):
|
||||
return SAML_MESSAGE_TYPE_LOGOUT_REQUEST
|
||||
return None
|
||||
except Exception: # noqa: BLE001
|
||||
return None
|
||||
|
||||
|
||||
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
class SAMLUnifiedView(View):
|
||||
"""Unified SAML endpoint - handles SSO and SLO based on message type.
|
||||
|
||||
The operation type is determined by parsing
|
||||
the incoming SAML message:
|
||||
- AuthnRequest -> SSO flow (delegates to SAMLSSOBindingRedirectView/POSTView)
|
||||
- LogoutRequest -> SLO flow (delegates to SPInitiatedSLOBindingRedirectView/POSTView)
|
||||
- LogoutResponse -> SLO completion (delegates to SPInitiatedSLOBindingRedirectView/POSTView)
|
||||
"""
|
||||
|
||||
def dispatch(self, request: HttpRequest, application_slug: str) -> HttpResponse:
|
||||
"""Route the request based on SAML message type."""
|
||||
# ak user was not logged in, redirected to login, and is back w POST payload in session
|
||||
if SESSION_KEY_POST in request.session:
|
||||
return self._delegate_to_sso(request, application_slug, is_post_binding=True)
|
||||
|
||||
# Determine binding from HTTP method
|
||||
is_post_binding = request.method == "POST"
|
||||
data = request.POST if is_post_binding else request.GET
|
||||
|
||||
# LogoutResponse - delegate to SLO view (handles it in dispatch)
|
||||
if REQUEST_KEY_SAML_RESPONSE in data:
|
||||
return self._delegate_to_slo(request, application_slug, is_post_binding)
|
||||
|
||||
# Check for SAML request
|
||||
if REQUEST_KEY_SAML_REQUEST not in data:
|
||||
LOGGER.info("SAML payload missing")
|
||||
return bad_request_message(request, "The SAML request payload is missing.")
|
||||
|
||||
# Detect message type and delegate
|
||||
saml_request = data[REQUEST_KEY_SAML_REQUEST]
|
||||
message_type = detect_saml_message_type(saml_request, is_post_binding)
|
||||
|
||||
if message_type == SAML_MESSAGE_TYPE_AUTHN_REQUEST:
|
||||
return self._delegate_to_sso(request, application_slug, is_post_binding)
|
||||
elif message_type == SAML_MESSAGE_TYPE_LOGOUT_REQUEST:
|
||||
return self._delegate_to_slo(request, application_slug, is_post_binding)
|
||||
else:
|
||||
LOGGER.warning("Unknown SAML message type", message_type=message_type)
|
||||
return bad_request_message(
|
||||
request, f"Unsupported SAML message type: {message_type or 'unknown'}"
|
||||
)
|
||||
|
||||
def _delegate_to_sso(
|
||||
self, request: HttpRequest, application_slug: str, is_post_binding: bool
|
||||
) -> HttpResponse:
|
||||
"""Delegate to the appropriate SSO view."""
|
||||
if is_post_binding:
|
||||
view = SAMLSSOBindingPOSTView.as_view()
|
||||
else:
|
||||
view = SAMLSSOBindingRedirectView.as_view()
|
||||
return view(request, application_slug=application_slug)
|
||||
|
||||
def _delegate_to_slo(
|
||||
self, request: HttpRequest, application_slug: str, is_post_binding: bool
|
||||
) -> HttpResponse:
|
||||
"""Delegate to the appropriate SLO view."""
|
||||
if is_post_binding:
|
||||
view = SPInitiatedSLOBindingPOSTView.as_view()
|
||||
else:
|
||||
view = SPInitiatedSLOBindingRedirectView.as_view()
|
||||
return view(request, application_slug=application_slug)
|
||||
@@ -1,7 +1,6 @@
|
||||
"""authentik saml source processor"""
|
||||
|
||||
from base64 import b64decode
|
||||
from datetime import UTC, datetime
|
||||
from time import mktime
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -41,7 +40,6 @@ from authentik.sources.saml.exceptions import (
|
||||
InvalidSignature,
|
||||
MismatchedRequestID,
|
||||
MissingSAMLResponse,
|
||||
SAMLException,
|
||||
UnsupportedNameIDFormat,
|
||||
)
|
||||
from authentik.sources.saml.models import (
|
||||
@@ -97,7 +95,6 @@ class ResponseProcessor:
|
||||
|
||||
self._verify_request_id()
|
||||
self._verify_status()
|
||||
self._verify_conditions()
|
||||
|
||||
def _decrypt_response(self):
|
||||
"""Decrypt SAMLResponse EncryptedAssertion Element"""
|
||||
@@ -129,20 +126,6 @@ class ResponseProcessor:
|
||||
)
|
||||
self._assertion = decrypted_assertion
|
||||
|
||||
def _verify_conditions(self):
|
||||
conditions = self.get_assertion().find(f"{{{NS_SAML_ASSERTION}}}Conditions")
|
||||
if conditions is None:
|
||||
return
|
||||
_now = now()
|
||||
before = conditions.attrib.get("NotBefore")
|
||||
if before:
|
||||
if datetime.fromisoformat(before).replace(tzinfo=UTC) > _now:
|
||||
raise SAMLException("Assertion is not valid yet or expired.")
|
||||
on_or_after = conditions.attrib.get("NotOnOrAfter")
|
||||
if on_or_after:
|
||||
if datetime.fromisoformat(on_or_after).replace(tzinfo=UTC) < _now:
|
||||
raise SAMLException("Assertion is not valid yet or expired.")
|
||||
|
||||
def _verify_signature(self, signature_node: _Element):
|
||||
"""Verify a single signature node"""
|
||||
xmlsec.tree.add_ids(self._root, ["ID"])
|
||||
@@ -232,9 +215,10 @@ class ResponseProcessor:
|
||||
user has an attribute that refers to our Source for cleanup. The user is also deleted
|
||||
on logout and periodically."""
|
||||
# Create a temporary User
|
||||
name_id_el, name_id = self._get_name_id()
|
||||
name_id = self._get_name_id()
|
||||
username = name_id.text
|
||||
# trim username to ensure it is max 150 chars
|
||||
username = f"ak-{name_id[: USERNAME_MAX_LENGTH - 14]}-transient"
|
||||
username = f"ak-{username[: USERNAME_MAX_LENGTH - 14]}-transient"
|
||||
expiry = mktime(
|
||||
(now() + timedelta_from_string(self._source.temporary_user_delete_after)).timetuple()
|
||||
)
|
||||
@@ -250,18 +234,20 @@ class ResponseProcessor:
|
||||
},
|
||||
path=self._source.get_user_path(),
|
||||
)
|
||||
LOGGER.debug("Created temporary user for NameID Transient", username=name_id)
|
||||
LOGGER.debug("Created temporary user for NameID Transient", username=name_id.text)
|
||||
user.set_unusable_password()
|
||||
user.save()
|
||||
UserSAMLSourceConnection.objects.create(source=self._source, user=user, identifier=name_id)
|
||||
UserSAMLSourceConnection.objects.create(
|
||||
source=self._source, user=user, identifier=name_id.text
|
||||
)
|
||||
return SAMLSourceFlowManager(
|
||||
source=self._source,
|
||||
request=self._http_request,
|
||||
identifier=str(name_id),
|
||||
identifier=str(name_id.text),
|
||||
user_info={
|
||||
"root": self._root,
|
||||
"assertion": self.get_assertion(),
|
||||
"name_id": name_id_el,
|
||||
"name_id": name_id,
|
||||
},
|
||||
policy_context={},
|
||||
)
|
||||
@@ -272,7 +258,7 @@ class ResponseProcessor:
|
||||
return self._assertion
|
||||
return self._root.find(f"{{{NS_SAML_ASSERTION}}}Assertion")
|
||||
|
||||
def _get_name_id(self) -> tuple[Element, str]:
|
||||
def _get_name_id(self) -> Element:
|
||||
"""Get NameID Element"""
|
||||
assertion = self.get_assertion()
|
||||
if assertion is None:
|
||||
@@ -283,11 +269,12 @@ class ResponseProcessor:
|
||||
name_id = subject.find(f"{{{NS_SAML_ASSERTION}}}NameID")
|
||||
if name_id is None:
|
||||
raise ValueError("NameID element not found")
|
||||
return name_id, "".join(name_id.itertext())
|
||||
return name_id
|
||||
|
||||
def _get_name_id_filter(self) -> dict[str, str]:
|
||||
"""Returns the subject's NameID as a Filter for the `User`"""
|
||||
name_id_el, name_id = self._get_name_id()
|
||||
name_id_el = self._get_name_id()
|
||||
name_id = name_id_el.text
|
||||
if not name_id:
|
||||
raise UnsupportedNameIDFormat("Subject's NameID is empty.")
|
||||
_format = name_id_el.attrib["Format"]
|
||||
@@ -308,26 +295,26 @@ class ResponseProcessor:
|
||||
|
||||
def prepare_flow_manager(self) -> SourceFlowManager:
|
||||
"""Prepare flow plan depending on whether or not the user exists"""
|
||||
name_id_el, name_id = self._get_name_id()
|
||||
name_id = self._get_name_id()
|
||||
# Sanity check, show a warning if NameIDPolicy doesn't match what we go
|
||||
if self._source.name_id_policy != name_id_el.attrib["Format"]:
|
||||
if self._source.name_id_policy != name_id.attrib["Format"]:
|
||||
LOGGER.warning(
|
||||
"NameID from IdP doesn't match our policy",
|
||||
expected=self._source.name_id_policy,
|
||||
got=name_id_el.attrib["Format"],
|
||||
got=name_id.attrib["Format"],
|
||||
)
|
||||
# transient NameIDs are handled separately as they don't have to go through flows.
|
||||
if name_id_el.attrib["Format"] == SAML_NAME_ID_FORMAT_TRANSIENT:
|
||||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_TRANSIENT:
|
||||
return self._handle_name_id_transient()
|
||||
|
||||
return SAMLSourceFlowManager(
|
||||
source=self._source,
|
||||
request=self._http_request,
|
||||
identifier=str(name_id),
|
||||
identifier=str(name_id.text),
|
||||
user_info={
|
||||
"root": self._root,
|
||||
"assertion": self.get_assertion(),
|
||||
"name_id": name_id_el,
|
||||
"name_id": name_id,
|
||||
},
|
||||
policy_context={
|
||||
"saml_response": etree.tostring(self._root),
|
||||
|
||||
@@ -4,7 +4,6 @@ from base64 import b64encode
|
||||
|
||||
from defusedxml.lxml import fromstring
|
||||
from django.test import TestCase
|
||||
from freezegun import freeze_time
|
||||
|
||||
from authentik.common.saml.constants import NS_SAML_ASSERTION
|
||||
from authentik.core.tests.utils import RequestFactory, create_test_flow
|
||||
@@ -35,7 +34,6 @@ class TestPropertyMappings(TestCase):
|
||||
pre_authentication_flow=create_test_flow(),
|
||||
)
|
||||
|
||||
@freeze_time("2022-10-14T14:15:00")
|
||||
def test_user_base_properties(self):
|
||||
"""Test user base properties"""
|
||||
properties = self.source.get_base_user_properties(
|
||||
@@ -63,7 +61,6 @@ class TestPropertyMappings(TestCase):
|
||||
properties = self.source.get_base_group_properties(root=ROOT, group_id=group_id)
|
||||
self.assertEqual(properties, {"name": group_id})
|
||||
|
||||
@freeze_time("2022-10-14T14:15:00")
|
||||
def test_user_property_mappings(self):
|
||||
"""Test user property mappings"""
|
||||
self.source.user_property_mappings.add(
|
||||
@@ -97,7 +94,6 @@ class TestPropertyMappings(TestCase):
|
||||
},
|
||||
)
|
||||
|
||||
@freeze_time("2022-10-14T14:15:00")
|
||||
def test_group_property_mappings(self):
|
||||
"""Test group property mappings"""
|
||||
self.source.group_property_mappings.add(
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from base64 import b64encode
|
||||
|
||||
from django.test import TestCase
|
||||
from freezegun import freeze_time
|
||||
|
||||
from authentik.core.tests.utils import RequestFactory, create_test_cert, create_test_flow
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
@@ -47,7 +46,6 @@ class TestResponseProcessor(TestCase):
|
||||
):
|
||||
ResponseProcessor(self.source, request).parse()
|
||||
|
||||
@freeze_time("2022-10-14T14:15:00")
|
||||
def test_success(self):
|
||||
"""Test success"""
|
||||
request = self.factory.post(
|
||||
@@ -74,7 +72,6 @@ class TestResponseProcessor(TestCase):
|
||||
},
|
||||
)
|
||||
|
||||
@freeze_time("2022-10-14T14:16:40Z")
|
||||
def test_success_with_status_message_and_detail(self):
|
||||
"""Test success with StatusMessage and StatusDetail present (should not raise error)"""
|
||||
request = self.factory.post(
|
||||
@@ -91,7 +88,6 @@ class TestResponseProcessor(TestCase):
|
||||
sfm = parser.prepare_flow_manager()
|
||||
self.assertEqual(sfm.user_properties["username"], "jens@goauthentik.io")
|
||||
|
||||
@freeze_time("2022-10-14T14:16:40Z")
|
||||
def test_error_with_message_and_detail(self):
|
||||
"""Test error status with StatusMessage and StatusDetail includes both in error"""
|
||||
request = self.factory.post(
|
||||
@@ -109,7 +105,6 @@ class TestResponseProcessor(TestCase):
|
||||
self.assertIn("User account is disabled", str(ctx.exception))
|
||||
self.assertIn("Authentication failed", str(ctx.exception))
|
||||
|
||||
@freeze_time("2024-08-07T15:48:09.325Z")
|
||||
def test_encrypted_correct(self):
|
||||
"""Test encrypted"""
|
||||
key = load_fixture("fixtures/encrypted-key.pem")
|
||||
@@ -147,7 +142,6 @@ class TestResponseProcessor(TestCase):
|
||||
with self.assertRaises(InvalidEncryption):
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2022-10-14T14:16:40Z")
|
||||
def test_verification_assertion(self):
|
||||
"""Test verifying signature inside assertion"""
|
||||
key = load_fixture("fixtures/signature_cert.pem")
|
||||
@@ -170,7 +164,6 @@ class TestResponseProcessor(TestCase):
|
||||
parser = ResponseProcessor(self.source, request)
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2014-07-17T01:02:18Z")
|
||||
def test_verification_assertion_duplicate(self):
|
||||
"""Test verifying signature inside assertion, where the response has another assertion
|
||||
before our signed assertion"""
|
||||
@@ -193,35 +186,9 @@ class TestResponseProcessor(TestCase):
|
||||
|
||||
parser = ResponseProcessor(self.source, request)
|
||||
parser.parse()
|
||||
self.assertNotEqual(parser._get_name_id()[1], "bad")
|
||||
self.assertEqual(parser._get_name_id()[1], "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7")
|
||||
self.assertNotEqual(parser._get_name_id().text, "bad")
|
||||
self.assertEqual(parser._get_name_id().text, "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7")
|
||||
|
||||
@freeze_time("2022-10-14T14:15:00")
|
||||
def test_name_id_comment(self):
|
||||
"""Test comment in name ID"""
|
||||
fixture = load_fixture("fixtures/response_signed_assertion_dup.xml")
|
||||
fixture = fixture.replace(
|
||||
"_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7",
|
||||
"_ce3d2948b4cf20146dee0a0b3dd6f<!--x-->69b6cf86f62d7",
|
||||
)
|
||||
key = load_fixture("fixtures/signature_cert.pem")
|
||||
kp = CertificateKeyPair.objects.create(
|
||||
name=generate_id(),
|
||||
certificate_data=key,
|
||||
)
|
||||
self.source.verification_kp = kp
|
||||
self.source.signed_assertion = True
|
||||
self.source.signed_response = False
|
||||
request = self.factory.post(
|
||||
"/",
|
||||
data={"SAMLResponse": b64encode(fixture.encode()).decode()},
|
||||
)
|
||||
|
||||
parser = ResponseProcessor(self.source, request)
|
||||
parser.parse()
|
||||
self.assertEqual(parser._get_name_id()[1], "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7")
|
||||
|
||||
@freeze_time("2014-07-17T01:02:18Z")
|
||||
def test_verification_response(self):
|
||||
"""Test verifying signature inside response"""
|
||||
key = load_fixture("fixtures/signature_cert.pem")
|
||||
@@ -244,7 +211,6 @@ class TestResponseProcessor(TestCase):
|
||||
parser = ResponseProcessor(self.source, request)
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2024-01-18T06:20:48Z")
|
||||
def test_verification_response_and_assertion(self):
|
||||
"""Test verifying signature inside response and assertion"""
|
||||
key = load_fixture("fixtures/signature_cert.pem")
|
||||
@@ -291,7 +257,6 @@ class TestResponseProcessor(TestCase):
|
||||
with self.assertRaisesMessage(InvalidSignature, ""):
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2022-10-14T14:15:00")
|
||||
def test_verification_no_signature(self):
|
||||
"""Test rejecting response without signature when signed_assertion is True"""
|
||||
key = load_fixture("fixtures/signature_cert.pem")
|
||||
@@ -338,7 +303,6 @@ class TestResponseProcessor(TestCase):
|
||||
with self.assertRaisesMessage(InvalidSignature, ""):
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2025-10-30T05:45:47.619Z")
|
||||
def test_signed_encrypted_response(self):
|
||||
"""Test signed & encrypted response"""
|
||||
verification_key = load_fixture("fixtures/signature_cert2.pem")
|
||||
@@ -366,7 +330,6 @@ class TestResponseProcessor(TestCase):
|
||||
parser = ResponseProcessor(self.source, request)
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2026-01-21T14:23")
|
||||
def test_transient(self):
|
||||
"""Test SAML transient NameID"""
|
||||
verification_key = load_fixture("fixtures/signature_cert2.pem")
|
||||
|
||||
@@ -4,7 +4,6 @@ from base64 import b64encode
|
||||
|
||||
from django.test import RequestFactory, TestCase
|
||||
from django.urls import reverse
|
||||
from freezegun import freeze_time
|
||||
|
||||
from authentik.core.tests.utils import create_test_flow
|
||||
from authentik.flows.planner import PLAN_CONTEXT_REDIRECT, FlowPlan
|
||||
@@ -27,7 +26,6 @@ class TestViews(TestCase):
|
||||
pre_authentication_flow=create_test_flow(),
|
||||
)
|
||||
|
||||
@freeze_time("2022-10-14T14:15:00")
|
||||
def test_enroll(self):
|
||||
"""Enroll"""
|
||||
flow = create_test_flow()
|
||||
@@ -54,7 +52,6 @@ class TestViews(TestCase):
|
||||
plan: FlowPlan = self.client.session.get(SESSION_KEY_PLAN)
|
||||
self.assertIsNotNone(plan)
|
||||
|
||||
@freeze_time("2022-10-14T14:15:00")
|
||||
def test_enroll_redirect(self):
|
||||
"""Enroll when attempting to access a provider"""
|
||||
initial_redirect = f"http://{generate_id()}"
|
||||
|
||||
@@ -36,10 +36,14 @@ entries:
|
||||
attrs:
|
||||
order: 50
|
||||
initial_value: |
|
||||
actor_uuid = str(getattr(http_request.user, "pk", ""))
|
||||
pending_user = user if getattr(user, "is_authenticated", False) else None
|
||||
target_uuid = str(getattr(pending_user, "pk", ""))
|
||||
is_self_service = not target_uuid or target_uuid == actor_uuid
|
||||
target_uuid = (http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
|
||||
current_user_uuid = str(getattr(user, "pk", "") or getattr(http_request.user, "pk", ""))
|
||||
is_self_service = not target_uuid or target_uuid == current_user_uuid
|
||||
pending_user = None
|
||||
if target_uuid and not is_self_service:
|
||||
from authentik.core.models import User
|
||||
|
||||
pending_user = User.objects.filter(pk=target_uuid).first()
|
||||
if is_self_service:
|
||||
return (
|
||||
"<p><strong>You are about to lock down your own account.</strong></p>"
|
||||
@@ -59,15 +63,14 @@ entries:
|
||||
from django.utils.html import escape
|
||||
|
||||
if pending_user:
|
||||
detail = pending_user.email or pending_user.name
|
||||
user_html = f"<code>{escape(pending_user.username)}</code>"
|
||||
if detail and detail != pending_user.username:
|
||||
user_html = f"{user_html} ({escape(detail)})"
|
||||
email = escape(pending_user.email or pending_user.name or "No email")
|
||||
user_html = f"<p><code>{escape(pending_user.username)}</code> ({email})</p>"
|
||||
else:
|
||||
user_html = "the account selected when this one-time lockdown link was created"
|
||||
user_html = "<p>the account selected when this one-time lockdown link was created</p>"
|
||||
|
||||
return (
|
||||
f"<p><strong>You are about to lock down the following account:</strong> {user_html}</p>"
|
||||
"<p><strong>You are about to lock down the following account:</strong></p>"
|
||||
f"{user_html}"
|
||||
"<p>This is an emergency action for cutting off access to the account right away. "
|
||||
"It does not lock the administrator who opened this page.</p>"
|
||||
"<p><strong>This will immediately:</strong></p>"
|
||||
@@ -96,9 +99,9 @@ entries:
|
||||
attrs:
|
||||
order: 100
|
||||
initial_value: |
|
||||
actor_uuid = str(getattr(http_request.user, "pk", ""))
|
||||
target_uuid = str(getattr(user, "pk", ""))
|
||||
is_self_service = not target_uuid or target_uuid == actor_uuid
|
||||
target_uuid = (http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
|
||||
current_user_uuid = str(getattr(user, "pk", "") or getattr(http_request.user, "pk", ""))
|
||||
is_self_service = not target_uuid or target_uuid == current_user_uuid
|
||||
if is_self_service:
|
||||
info = (
|
||||
"Use this if you no longer trust your current password or sessions. "
|
||||
@@ -131,9 +134,9 @@ entries:
|
||||
attrs:
|
||||
order: 200
|
||||
placeholder: |
|
||||
actor_uuid = str(getattr(http_request.user, "pk", ""))
|
||||
target_uuid = str(getattr(user, "pk", ""))
|
||||
is_self_service = not target_uuid or target_uuid == actor_uuid
|
||||
target_uuid = (http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
|
||||
current_user_uuid = str(getattr(user, "pk", "") or getattr(http_request.user, "pk", ""))
|
||||
is_self_service = not target_uuid or target_uuid == current_user_uuid
|
||||
if is_self_service:
|
||||
return "Describe why you are locking your account..."
|
||||
return "Describe why this account is being locked down..."
|
||||
@@ -181,10 +184,14 @@ entries:
|
||||
attrs:
|
||||
order: 300
|
||||
initial_value: |
|
||||
target_uuid = (http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
|
||||
from django.utils.html import escape
|
||||
from authentik.core.models import User
|
||||
|
||||
if getattr(user, "is_authenticated", False):
|
||||
return f"<p><code>{escape(user.username)}</code> has been locked down.</p>"
|
||||
if target_uuid:
|
||||
target = User.objects.filter(pk=target_uuid).first()
|
||||
if target:
|
||||
return f"<p><code>{escape(target.username)}</code> has been locked down.</p>"
|
||||
|
||||
return "<p>The selected account has been locked down.</p>"
|
||||
initial_value_expression: true
|
||||
@@ -214,9 +221,9 @@ entries:
|
||||
attrs:
|
||||
name: default-account-lockdown-admin-policy
|
||||
expression: |
|
||||
actor_uuid = str(getattr(request.http_request.user, "pk", ""))
|
||||
target_uuid = str(getattr(request.user, "pk", ""))
|
||||
return bool(target_uuid) and target_uuid != actor_uuid
|
||||
target_uuid = (request.http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
|
||||
current_user_uuid = str(getattr(request.user, "pk", "") or getattr(request.http_request.user, "pk", ""))
|
||||
return bool(target_uuid) and target_uuid != current_user_uuid
|
||||
identifiers:
|
||||
name: default-account-lockdown-admin-policy
|
||||
id: admin-policy
|
||||
|
||||
@@ -296,46 +296,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"model",
|
||||
"identifiers"
|
||||
],
|
||||
"properties": {
|
||||
"model": {
|
||||
"const": "authentik_core.objectattribute"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"absent",
|
||||
"created",
|
||||
"must_created",
|
||||
"present"
|
||||
],
|
||||
"default": "present"
|
||||
},
|
||||
"conditions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"$ref": "#/$defs/model_authentik_core.objectattribute_permissions"
|
||||
},
|
||||
"attrs": {
|
||||
"$ref": "#/$defs/model_authentik_core.objectattribute"
|
||||
},
|
||||
"identifiers": {
|
||||
"$ref": "#/$defs/model_authentik_core.objectattribute"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -5460,95 +5420,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"model_authentik_core.objectattribute": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"object_type": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Object type"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"title": "Enabled"
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Key"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Label"
|
||||
},
|
||||
"regex": {
|
||||
"type": "string",
|
||||
"title": "Regex"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"text",
|
||||
"number",
|
||||
"boolean"
|
||||
],
|
||||
"title": "Type"
|
||||
},
|
||||
"group": {
|
||||
"type": "string",
|
||||
"title": "Group"
|
||||
},
|
||||
"managed": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"minLength": 1,
|
||||
"title": "Managed by authentik",
|
||||
"description": "Objects that are managed by authentik. These objects are created and updated automatically. This flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update."
|
||||
},
|
||||
"is_unique": {
|
||||
"type": "boolean",
|
||||
"title": "Is unique"
|
||||
},
|
||||
"is_required": {
|
||||
"type": "boolean",
|
||||
"title": "Is required"
|
||||
},
|
||||
"is_array": {
|
||||
"type": "boolean",
|
||||
"title": "Is array"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"model_authentik_core.objectattribute_permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"permission"
|
||||
],
|
||||
"properties": {
|
||||
"permission": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"add_objectattribute",
|
||||
"change_objectattribute",
|
||||
"delete_objectattribute",
|
||||
"view_objectattribute"
|
||||
]
|
||||
},
|
||||
"user": {
|
||||
"type": "integer"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"model_authentik_core.token": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5739,7 +5610,6 @@
|
||||
"authentik_core.add_groupancestrynode",
|
||||
"authentik_core.add_groupparentagenode",
|
||||
"authentik_core.add_groupsourceconnection",
|
||||
"authentik_core.add_objectattribute",
|
||||
"authentik_core.add_propertymapping",
|
||||
"authentik_core.add_provider",
|
||||
"authentik_core.add_source",
|
||||
@@ -5754,7 +5624,6 @@
|
||||
"authentik_core.change_groupancestrynode",
|
||||
"authentik_core.change_groupparentagenode",
|
||||
"authentik_core.change_groupsourceconnection",
|
||||
"authentik_core.change_objectattribute",
|
||||
"authentik_core.change_propertymapping",
|
||||
"authentik_core.change_provider",
|
||||
"authentik_core.change_source",
|
||||
@@ -5768,7 +5637,6 @@
|
||||
"authentik_core.delete_groupancestrynode",
|
||||
"authentik_core.delete_groupparentagenode",
|
||||
"authentik_core.delete_groupsourceconnection",
|
||||
"authentik_core.delete_objectattribute",
|
||||
"authentik_core.delete_propertymapping",
|
||||
"authentik_core.delete_provider",
|
||||
"authentik_core.delete_source",
|
||||
@@ -5789,7 +5657,6 @@
|
||||
"authentik_core.view_groupancestrynode",
|
||||
"authentik_core.view_groupparentagenode",
|
||||
"authentik_core.view_groupsourceconnection",
|
||||
"authentik_core.view_objectattribute",
|
||||
"authentik_core.view_propertymapping",
|
||||
"authentik_core.view_provider",
|
||||
"authentik_core.view_source",
|
||||
@@ -9218,7 +9085,6 @@
|
||||
"authentik_core.application",
|
||||
"authentik_core.applicationentitlement",
|
||||
"authentik_core.token",
|
||||
"authentik_core.objectattribute",
|
||||
"authentik_crypto.certificatekeypair",
|
||||
"authentik_endpoints.deviceuserbinding",
|
||||
"authentik_endpoints.deviceaccessgroup",
|
||||
@@ -11510,7 +11376,6 @@
|
||||
"authentik_core.add_groupancestrynode",
|
||||
"authentik_core.add_groupparentagenode",
|
||||
"authentik_core.add_groupsourceconnection",
|
||||
"authentik_core.add_objectattribute",
|
||||
"authentik_core.add_propertymapping",
|
||||
"authentik_core.add_provider",
|
||||
"authentik_core.add_source",
|
||||
@@ -11525,7 +11390,6 @@
|
||||
"authentik_core.change_groupancestrynode",
|
||||
"authentik_core.change_groupparentagenode",
|
||||
"authentik_core.change_groupsourceconnection",
|
||||
"authentik_core.change_objectattribute",
|
||||
"authentik_core.change_propertymapping",
|
||||
"authentik_core.change_provider",
|
||||
"authentik_core.change_source",
|
||||
@@ -11539,7 +11403,6 @@
|
||||
"authentik_core.delete_groupancestrynode",
|
||||
"authentik_core.delete_groupparentagenode",
|
||||
"authentik_core.delete_groupsourceconnection",
|
||||
"authentik_core.delete_objectattribute",
|
||||
"authentik_core.delete_propertymapping",
|
||||
"authentik_core.delete_provider",
|
||||
"authentik_core.delete_source",
|
||||
@@ -11560,7 +11423,6 @@
|
||||
"authentik_core.view_groupancestrynode",
|
||||
"authentik_core.view_groupparentagenode",
|
||||
"authentik_core.view_groupsourceconnection",
|
||||
"authentik_core.view_objectattribute",
|
||||
"authentik_core.view_propertymapping",
|
||||
"authentik_core.view_provider",
|
||||
"authentik_core.view_source",
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
version: 1
|
||||
metadata:
|
||||
labels:
|
||||
blueprints.goauthentik.io/system: "true"
|
||||
name: System - Object Attributes - User
|
||||
entries:
|
||||
identity:
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: givenName
|
||||
managed: goauthentik.io/object-attrs/user/identity/givenName
|
||||
attrs:
|
||||
group: Identity
|
||||
object_type: authentik_core.user
|
||||
label: Given Name
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: familyName
|
||||
managed: goauthentik.io/object-attrs/user/identity/familyName
|
||||
attrs:
|
||||
group: Identity
|
||||
object_type: authentik_core.user
|
||||
label: Family Name
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
ak:
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: settings.locale
|
||||
managed: goauthentik.io/object-attrs/user/settings/locale
|
||||
attrs:
|
||||
group: Settings
|
||||
object_type: authentik_core.user
|
||||
label: Locale
|
||||
enabled: true
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
address:
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: street
|
||||
managed: goauthentik.io/object-attrs/user/address/street
|
||||
attrs:
|
||||
group: Address
|
||||
object_type: authentik_core.user
|
||||
label: Street
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: state
|
||||
managed: goauthentik.io/object-attrs/user/address/state
|
||||
attrs:
|
||||
group: Address
|
||||
object_type: authentik_core.user
|
||||
label: State
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: location
|
||||
managed: goauthentik.io/object-attrs/user/address/location
|
||||
attrs:
|
||||
group: Address
|
||||
object_type: authentik_core.user
|
||||
label: Location
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: postalCode
|
||||
managed: goauthentik.io/object-attrs/user/address/postal-code
|
||||
attrs:
|
||||
group: Address
|
||||
object_type: authentik_core.user
|
||||
label: Postal code
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
contact:
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: phoneNumber
|
||||
managed: goauthentik.io/object-attrs/user/contact/phone-number
|
||||
attrs:
|
||||
group: Contact
|
||||
object_type: authentik_core.user
|
||||
label: Phone number(s)
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
is_array: true
|
||||
unix:
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: shell
|
||||
managed: goauthentik.io/object-attrs/user/unix/shell
|
||||
attrs:
|
||||
group: Unix
|
||||
object_type: authentik_core.user
|
||||
label: Shell
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
employee:
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: employeeNumber
|
||||
managed: goauthentik.io/object-attrs/user/employee/number
|
||||
attrs:
|
||||
group: Employee
|
||||
object_type: authentik_core.user
|
||||
label: Employee Number
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
- model: authentik_core.objectattribute
|
||||
identifiers:
|
||||
key: jobTitle
|
||||
managed: goauthentik.io/object-attrs/user/employee/title
|
||||
attrs:
|
||||
group: Employee
|
||||
object_type: authentik_core.user
|
||||
label: Title
|
||||
enabled: false
|
||||
is_required: false
|
||||
is_unique: false
|
||||
type: text
|
||||
@@ -35,13 +35,14 @@ entries:
|
||||
description: "General Profile Information"
|
||||
expression: |
|
||||
return {
|
||||
# Because authentik only saves the user's full name, and has no concept of first and last names,
|
||||
# the full name is used as given name.
|
||||
# You can override this behaviour in custom mappings, i.e. `request.user.name.split(" ")`
|
||||
"name": request.user.name,
|
||||
"given_name": ak_obj_attr(request.user, "givenName", "name"),
|
||||
"family_name": ak_obj_attr(request.user, "familyName"),
|
||||
"given_name": request.user.name,
|
||||
"preferred_username": request.user.username,
|
||||
"nickname": request.user.username,
|
||||
"groups": [group.name for group in request.user.groups.all()],
|
||||
"picture": request.user.avatar,
|
||||
}
|
||||
- identifiers:
|
||||
managed: goauthentik.io/providers/oauth2/scope-entitlements
|
||||
|
||||
@@ -42,8 +42,8 @@ entries:
|
||||
"userName": request.user.username,
|
||||
"name": {
|
||||
"formatted": formatted,
|
||||
"givenName": ak_obj_attr(request.user, "givenName") or givenName,
|
||||
"familyName": ak_obj_attr(request.user, "familyName") or familyName,
|
||||
"givenName": givenName,
|
||||
"familyName": familyName,
|
||||
},
|
||||
"displayName": request.user.name,
|
||||
"photos": photos,
|
||||
|
||||
14
go.mod
@@ -7,10 +7,10 @@ require (
|
||||
beryju.io/radius-eap v0.1.0
|
||||
github.com/avast/retry-go/v4 v4.7.0
|
||||
github.com/coreos/go-oidc/v3 v3.18.0
|
||||
github.com/getsentry/sentry-go v0.46.2
|
||||
github.com/getsentry/sentry-go v0.46.1
|
||||
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
||||
github.com/go-ldap/ldap/v3 v3.4.13
|
||||
github.com/go-openapi/runtime v0.29.5
|
||||
github.com/go-openapi/runtime v0.29.4
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/handlers v1.5.2
|
||||
@@ -57,7 +57,7 @@ require (
|
||||
github.com/go-openapi/jsonreference v0.21.5 // indirect
|
||||
github.com/go-openapi/loads v0.23.3 // indirect
|
||||
github.com/go-openapi/spec v0.22.4 // indirect
|
||||
github.com/go-openapi/strfmt v0.26.2 // indirect
|
||||
github.com/go-openapi/strfmt v0.26.1 // indirect
|
||||
github.com/go-openapi/swag/conv v0.26.0 // indirect
|
||||
github.com/go-openapi/swag/fileutils v0.26.0 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.25.5 // indirect
|
||||
@@ -90,10 +90,10 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.43.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.50.0 // indirect
|
||||
golang.org/x/net v0.53.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
golang.org/x/crypto v0.49.0 // indirect
|
||||
golang.org/x/net v0.52.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
36
go.sum
@@ -20,8 +20,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/getsentry/sentry-go v0.46.2 h1:1jhYwrKGa3sIpo/y5iDNXS5wDoT7I1KNzMHrnK6ojns=
|
||||
github.com/getsentry/sentry-go v0.46.2/go.mod h1:evVbw2qotNUdYG8KxXbAdjOQWWvWIwKxpjdZZIvcIPw=
|
||||
github.com/getsentry/sentry-go v0.46.1 h1:mZyQFaQYkPxAdDG4HR8gDg6j4CnKYVWt4TF92N7i3XY=
|
||||
github.com/getsentry/sentry-go v0.46.1/go.mod h1:evVbw2qotNUdYG8KxXbAdjOQWWvWIwKxpjdZZIvcIPw=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
@@ -51,12 +51,12 @@ github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe
|
||||
github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
|
||||
github.com/go-openapi/loads v0.23.3 h1:g5Xap1JfwKkUnZdn+S0L3SzBDpcTIYzZ5Qaag0YDkKQ=
|
||||
github.com/go-openapi/loads v0.23.3/go.mod h1:NOH07zLajXo8y55hom0omlHWDVVvCwBM/S+csCK8LqA=
|
||||
github.com/go-openapi/runtime v0.29.5 h1:uc5+/TtqLIfDBTUxnF3uppoGMt+9DzonwUWsviINlrY=
|
||||
github.com/go-openapi/runtime v0.29.5/go.mod h1:D9IUbWccdYv+km8QwmAm90FZvDcQk47vP2Y7y5as/D8=
|
||||
github.com/go-openapi/runtime v0.29.4 h1:k2lDxrGoSAJRdhFG2tONKMpkizY/4X1cciSdtzk4Jjo=
|
||||
github.com/go-openapi/runtime v0.29.4/go.mod h1:K0k/2raY6oqXJnZAgWJB2i/12QKrhUKpZcH4PfV9P18=
|
||||
github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ=
|
||||
github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ=
|
||||
github.com/go-openapi/strfmt v0.26.2 h1:ysjheCh4i1rmFEo2LanhELDNucNzfWTZhUDKgWWPaFM=
|
||||
github.com/go-openapi/strfmt v0.26.2/go.mod h1:fXh1e449cyUn2NYuz+wb3wARBUdMl7qPEZwX00nqivY=
|
||||
github.com/go-openapi/strfmt v0.26.1 h1:7zGCHji7zSYDC2tCXIusoxYQz/48jAf2q+sF6wXTG+c=
|
||||
github.com/go-openapi/strfmt v0.26.1/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y=
|
||||
github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I=
|
||||
github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE=
|
||||
github.com/go-openapi/swag/fileutils v0.26.0 h1:WJoPRvsA7QRiiWluowkLJa9jaYR7FCuxmDvnCgaRRxU=
|
||||
@@ -77,10 +77,10 @@ github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFu
|
||||
github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
|
||||
github.com/go-openapi/testify/enable/yaml/v2 v2.5.0 h1:3hZD1fwydvCx/cc1R2uYNQirHqf2s6lqpKV3FcNTURA=
|
||||
github.com/go-openapi/testify/enable/yaml/v2 v2.5.0/go.mod h1:TvDZKBH7ZbMaF3EqH2AwTvNQCmzyZq8K1agRjf1B+Nk=
|
||||
github.com/go-openapi/testify/v2 v2.5.0 h1:UOCr63aAsMIDydZbZGqo5Ev01D4eydItRbekDuZMJLw=
|
||||
github.com/go-openapi/testify/v2 v2.5.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
|
||||
github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0=
|
||||
github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE=
|
||||
github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
|
||||
github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
|
||||
github.com/go-openapi/validate v0.25.2 h1:12NsfLAwGegqbGWr2CnvT65X/Q2USJipmJ9b7xDJZz0=
|
||||
github.com/go-openapi/validate v0.25.2/go.mod h1:Pgl1LpPPGFnZ+ys4/hTlDiRYQdI1ocKypgE+8Q8BLfY=
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||
@@ -216,8 +216,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab h1:628ME69lBm9C6JY2wXhAph/yjN3jezx1z7BIDLUwxjo=
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@@ -227,8 +227,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -245,8 +245,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -258,8 +258,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
|
||||
@@ -110,6 +110,17 @@ func (a *Application) getTraefikForwardUrl(r *http.Request) (*url.URL, error) {
|
||||
|
||||
// getNginxForwardUrl See https://github.com/kubernetes/ingress-nginx/blob/main/rootfs/etc/nginx/template/nginx.tmpl
|
||||
func (a *Application) getNginxForwardUrl(r *http.Request) (*url.URL, error) {
|
||||
ou := r.Header.Get("X-Original-URI")
|
||||
if ou != "" {
|
||||
// Turn this full URL into a relative URL
|
||||
u := &url.URL{
|
||||
Host: "",
|
||||
Scheme: "",
|
||||
Path: ou,
|
||||
}
|
||||
a.log.WithField("url", u.String()).Info("building forward URL from X-Original-URI")
|
||||
return u, nil
|
||||
}
|
||||
h := r.Header.Get("X-Original-URL")
|
||||
if len(h) < 1 {
|
||||
return nil, errors.New("no forward URL found")
|
||||
|
||||
@@ -5,8 +5,10 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"goauthentik.io/internal/outpost/proxyv2/constants"
|
||||
"goauthentik.io/internal/outpost/proxyv2/types"
|
||||
api "goauthentik.io/packages/client-go"
|
||||
)
|
||||
|
||||
@@ -45,6 +47,67 @@ func TestForwardHandleNginx_Single_Headers(t *testing.T) {
|
||||
assert.Equal(t, "http://test.goauthentik.io/app", s.Values[constants.SessionRedirect])
|
||||
}
|
||||
|
||||
func TestForwardHandleNginx_Single_URI(t *testing.T) {
|
||||
a := newTestApplication()
|
||||
req, _ := http.NewRequest("GET", "https://foo.bar/outpost.goauthentik.io/auth/nginx", nil)
|
||||
req.Header.Set("X-Original-URI", "/app")
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
a.forwardHandleNginx(rr, req)
|
||||
|
||||
assert.Equal(t, http.StatusUnauthorized, rr.Code)
|
||||
|
||||
s, _ := a.sessions.Get(req, a.SessionName())
|
||||
assert.Equal(t, "/app", s.Values[constants.SessionRedirect])
|
||||
}
|
||||
|
||||
func TestForwardHandleNginx_Single_Claims(t *testing.T) {
|
||||
a := newTestApplication()
|
||||
req, _ := http.NewRequest("GET", "/outpost.goauthentik.io/auth/nginx", nil)
|
||||
req.Header.Set("X-Original-URI", "/")
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
a.forwardHandleNginx(rr, req)
|
||||
|
||||
s, _ := a.sessions.Get(req, a.SessionName())
|
||||
s.ID = uuid.New().String()
|
||||
s.Options.MaxAge = 86400
|
||||
s.Values[constants.SessionClaims] = types.Claims{
|
||||
Sub: "foo",
|
||||
Proxy: &types.ProxyClaims{
|
||||
UserAttributes: map[string]any{
|
||||
"username": "foo",
|
||||
"password": "bar",
|
||||
"additionalHeaders": map[string]any{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err := a.sessions.Save(req, rr, s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rr = httptest.NewRecorder()
|
||||
a.forwardHandleNginx(rr, req)
|
||||
|
||||
h := rr.Result().Header
|
||||
|
||||
assert.Equal(t, []string{"Basic Zm9vOmJhcg=="}, h["Authorization"])
|
||||
assert.Equal(t, []string{"bar"}, h["Foo"])
|
||||
assert.Equal(t, []string{""}, h["User-Agent"])
|
||||
assert.Equal(t, []string{""}, h["X-Authentik-Email"])
|
||||
assert.Equal(t, []string{""}, h["X-Authentik-Groups"])
|
||||
assert.Equal(t, []string{""}, h["X-Authentik-Jwt"])
|
||||
assert.Equal(t, []string{""}, h["X-Authentik-Meta-App"])
|
||||
assert.Equal(t, []string{""}, h["X-Authentik-Meta-Jwks"])
|
||||
assert.Equal(t, []string{""}, h["X-Authentik-Meta-Outpost"])
|
||||
assert.Equal(t, []string{""}, h["X-Authentik-Name"])
|
||||
assert.Equal(t, []string{"foo"}, h["X-Authentik-Uid"])
|
||||
assert.Equal(t, []string{""}, h["X-Authentik-Username"])
|
||||
}
|
||||
|
||||
func TestForwardHandleNginx_Domain_Blank(t *testing.T) {
|
||||
a := newTestApplication()
|
||||
a.proxyConfig.Mode = api.PROXYMODE_FORWARD_DOMAIN.Ptr()
|
||||
|
||||
@@ -38,10 +38,6 @@ function run_authentik {
|
||||
echo cargo run -- "$@"
|
||||
fi
|
||||
;;
|
||||
manage)
|
||||
shift 1
|
||||
echo python -m manage "$@"
|
||||
;;
|
||||
*)
|
||||
echo "$@"
|
||||
;;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Stage: Build webui
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24-trixie-slim@sha256:4f2b45e32dc7d2caf66b6dbd59fac50e32f8077769efe0ef4d4c3f114672537d AS node-builder
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24-trixie-slim@sha256:735dd688da64d22ebd9dd374b3e7e5a874635668fd2a6ec20ca1f99264294086 AS node-builder
|
||||
|
||||
ARG GIT_BUILD_HASH
|
||||
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
|
||||
@@ -228,7 +228,8 @@ RUN apt-get update && \
|
||||
# Required for runtime
|
||||
apt-get install -y --no-install-recommends \
|
||||
libpq5 libmaxminddb0 ca-certificates \
|
||||
libkadm5clnt-mit12 libkadm5clnt7t64-heimdal \
|
||||
krb5-multidev libkrb5-3 libkdb5-10 libkadm5clnt-mit12 \
|
||||
heimdal-multidev libkadm5clnt7t64-heimdal \
|
||||
libltdl7 libxslt1.1 && \
|
||||
# Required for bootstrap & healtcheck
|
||||
apt-get install -y --no-install-recommends runit && \
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-05-13 05:39+0000\n"
|
||||
"POT-Creation-Date: 2026-05-06 00:27+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -226,10 +226,6 @@ msgstr ""
|
||||
msgid "The slug '{slug}' is reserved and cannot be used for applications."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "User does not have permission to add members to this group."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
"When not set all providers are returned. When set to true, only backchannel "
|
||||
@@ -260,14 +256,6 @@ msgstr ""
|
||||
msgid "Setting a user to internal service account is not allowed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/users.py
|
||||
msgid "User does not have permission to add members to a superuser group."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/users.py
|
||||
msgid "User does not have permission to assign roles."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/users.py
|
||||
msgid "Can't modify internal service account users"
|
||||
msgstr ""
|
||||
|
||||
@@ -11,4 +11,3 @@ Naur
|
||||
Wärting
|
||||
Aadit
|
||||
Kilby
|
||||
Kahmen
|
||||
|
||||
@@ -164,4 +164,3 @@ yamltags
|
||||
zxcvbn
|
||||
~uuid
|
||||
~uuids
|
||||
wreply
|
||||
|
||||
18
packages/client-ts/src/apis/AdminApi.ts
generated
@@ -58,10 +58,6 @@ export interface AdminFileUsedByListRequest {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface AdminModelsListRequest {
|
||||
filterHasAttributes?: boolean | null;
|
||||
}
|
||||
|
||||
export interface AdminSettingsPartialUpdateRequest {
|
||||
patchedSettingsRequest?: PatchedSettingsRequest;
|
||||
}
|
||||
@@ -404,15 +400,9 @@ export class AdminApi extends runtime.BaseAPI {
|
||||
/**
|
||||
* Creates request options for adminModelsList without sending the request
|
||||
*/
|
||||
async adminModelsListRequestOpts(
|
||||
requestParameters: AdminModelsListRequest,
|
||||
): Promise<runtime.RequestOpts> {
|
||||
async adminModelsListRequestOpts(): Promise<runtime.RequestOpts> {
|
||||
const queryParameters: any = {};
|
||||
|
||||
if (requestParameters["filterHasAttributes"] != null) {
|
||||
queryParameters["filter_has_attributes"] = requestParameters["filterHasAttributes"];
|
||||
}
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
if (this.configuration && this.configuration.accessToken) {
|
||||
@@ -438,10 +428,9 @@ export class AdminApi extends runtime.BaseAPI {
|
||||
* Read-only view list all installed models
|
||||
*/
|
||||
async adminModelsListRaw(
|
||||
requestParameters: AdminModelsListRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<runtime.ApiResponse<Array<App>>> {
|
||||
const requestOptions = await this.adminModelsListRequestOpts(requestParameters);
|
||||
const requestOptions = await this.adminModelsListRequestOpts();
|
||||
const response = await this.request(requestOptions, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(AppFromJSON));
|
||||
@@ -451,10 +440,9 @@ export class AdminApi extends runtime.BaseAPI {
|
||||
* Read-only view list all installed models
|
||||
*/
|
||||
async adminModelsList(
|
||||
requestParameters: AdminModelsListRequest = {},
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<Array<App>> {
|
||||
const response = await this.adminModelsListRaw(requestParameters, initOverrides);
|
||||
const response = await this.adminModelsListRaw(initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
|
||||
460
packages/client-ts/src/apis/CoreApi.ts
generated
@@ -28,14 +28,11 @@ import type {
|
||||
ImpersonationRequest,
|
||||
IntentEnum,
|
||||
Link,
|
||||
ObjectAttribute,
|
||||
ObjectAttributeRequest,
|
||||
PaginatedApplicationEntitlementList,
|
||||
PaginatedApplicationList,
|
||||
PaginatedAuthenticatedSessionList,
|
||||
PaginatedBrandList,
|
||||
PaginatedGroupList,
|
||||
PaginatedObjectAttributeList,
|
||||
PaginatedTokenList,
|
||||
PaginatedUserConsentList,
|
||||
PaginatedUserList,
|
||||
@@ -43,7 +40,6 @@ import type {
|
||||
PatchedApplicationRequest,
|
||||
PatchedBrandRequest,
|
||||
PatchedGroupRequest,
|
||||
PatchedObjectAttributeRequest,
|
||||
PatchedTokenRequest,
|
||||
PatchedUserRequest,
|
||||
PolicyTestResult,
|
||||
@@ -84,14 +80,11 @@ import {
|
||||
GroupRequestToJSON,
|
||||
ImpersonationRequestToJSON,
|
||||
LinkFromJSON,
|
||||
ObjectAttributeFromJSON,
|
||||
ObjectAttributeRequestToJSON,
|
||||
PaginatedApplicationEntitlementListFromJSON,
|
||||
PaginatedApplicationListFromJSON,
|
||||
PaginatedAuthenticatedSessionListFromJSON,
|
||||
PaginatedBrandListFromJSON,
|
||||
PaginatedGroupListFromJSON,
|
||||
PaginatedObjectAttributeListFromJSON,
|
||||
PaginatedTokenListFromJSON,
|
||||
PaginatedUserConsentListFromJSON,
|
||||
PaginatedUserListFromJSON,
|
||||
@@ -99,7 +92,6 @@ import {
|
||||
PatchedApplicationRequestToJSON,
|
||||
PatchedBrandRequestToJSON,
|
||||
PatchedGroupRequestToJSON,
|
||||
PatchedObjectAttributeRequestToJSON,
|
||||
PatchedTokenRequestToJSON,
|
||||
PatchedUserRequestToJSON,
|
||||
PolicyTestResultFromJSON,
|
||||
@@ -340,38 +332,6 @@ export interface CoreGroupsUsedByListRequest {
|
||||
groupUuid: string;
|
||||
}
|
||||
|
||||
export interface CoreObjectAttributesCreateRequest {
|
||||
objectAttributeRequest: ObjectAttributeRequest;
|
||||
}
|
||||
|
||||
export interface CoreObjectAttributesDestroyRequest {
|
||||
attributeId: string;
|
||||
}
|
||||
|
||||
export interface CoreObjectAttributesListRequest {
|
||||
enabled?: boolean;
|
||||
objectTypeAppLabel?: string;
|
||||
objectTypeModel?: string;
|
||||
ordering?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
search?: string;
|
||||
}
|
||||
|
||||
export interface CoreObjectAttributesPartialUpdateRequest {
|
||||
attributeId: string;
|
||||
patchedObjectAttributeRequest?: PatchedObjectAttributeRequest;
|
||||
}
|
||||
|
||||
export interface CoreObjectAttributesRetrieveRequest {
|
||||
attributeId: string;
|
||||
}
|
||||
|
||||
export interface CoreObjectAttributesUpdateRequest {
|
||||
attributeId: string;
|
||||
objectAttributeRequest: ObjectAttributeRequest;
|
||||
}
|
||||
|
||||
export interface CoreTokensCreateRequest {
|
||||
tokenRequest: TokenRequest;
|
||||
}
|
||||
@@ -3277,426 +3237,6 @@ export class CoreApi extends runtime.BaseAPI {
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates request options for coreObjectAttributesCreate without sending the request
|
||||
*/
|
||||
async coreObjectAttributesCreateRequestOpts(
|
||||
requestParameters: CoreObjectAttributesCreateRequest,
|
||||
): Promise<runtime.RequestOpts> {
|
||||
if (requestParameters["objectAttributeRequest"] == null) {
|
||||
throw new runtime.RequiredError(
|
||||
"objectAttributeRequest",
|
||||
'Required parameter "objectAttributeRequest" was null or undefined when calling coreObjectAttributesCreate().',
|
||||
);
|
||||
}
|
||||
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
headerParameters["Content-Type"] = "application/json";
|
||||
|
||||
if (this.configuration && this.configuration.accessToken) {
|
||||
const token = this.configuration.accessToken;
|
||||
const tokenString = await token("authentik", []);
|
||||
|
||||
if (tokenString) {
|
||||
headerParameters["Authorization"] = `Bearer ${tokenString}`;
|
||||
}
|
||||
}
|
||||
|
||||
let urlPath = `/core/object_attributes/`;
|
||||
|
||||
return {
|
||||
path: urlPath,
|
||||
method: "POST",
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
body: ObjectAttributeRequestToJSON(requestParameters["objectAttributeRequest"]),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesCreateRaw(
|
||||
requestParameters: CoreObjectAttributesCreateRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<runtime.ApiResponse<ObjectAttribute>> {
|
||||
const requestOptions = await this.coreObjectAttributesCreateRequestOpts(requestParameters);
|
||||
const response = await this.request(requestOptions, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) =>
|
||||
ObjectAttributeFromJSON(jsonValue),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesCreate(
|
||||
requestParameters: CoreObjectAttributesCreateRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<ObjectAttribute> {
|
||||
const response = await this.coreObjectAttributesCreateRaw(requestParameters, initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates request options for coreObjectAttributesDestroy without sending the request
|
||||
*/
|
||||
async coreObjectAttributesDestroyRequestOpts(
|
||||
requestParameters: CoreObjectAttributesDestroyRequest,
|
||||
): Promise<runtime.RequestOpts> {
|
||||
if (requestParameters["attributeId"] == null) {
|
||||
throw new runtime.RequiredError(
|
||||
"attributeId",
|
||||
'Required parameter "attributeId" was null or undefined when calling coreObjectAttributesDestroy().',
|
||||
);
|
||||
}
|
||||
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
if (this.configuration && this.configuration.accessToken) {
|
||||
const token = this.configuration.accessToken;
|
||||
const tokenString = await token("authentik", []);
|
||||
|
||||
if (tokenString) {
|
||||
headerParameters["Authorization"] = `Bearer ${tokenString}`;
|
||||
}
|
||||
}
|
||||
|
||||
let urlPath = `/core/object_attributes/{attribute_id}/`;
|
||||
urlPath = urlPath.replace(
|
||||
`{${"attribute_id"}}`,
|
||||
encodeURIComponent(String(requestParameters["attributeId"])),
|
||||
);
|
||||
|
||||
return {
|
||||
path: urlPath,
|
||||
method: "DELETE",
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesDestroyRaw(
|
||||
requestParameters: CoreObjectAttributesDestroyRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<runtime.ApiResponse<void>> {
|
||||
const requestOptions = await this.coreObjectAttributesDestroyRequestOpts(requestParameters);
|
||||
const response = await this.request(requestOptions, initOverrides);
|
||||
|
||||
return new runtime.VoidApiResponse(response);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesDestroy(
|
||||
requestParameters: CoreObjectAttributesDestroyRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<void> {
|
||||
await this.coreObjectAttributesDestroyRaw(requestParameters, initOverrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates request options for coreObjectAttributesList without sending the request
|
||||
*/
|
||||
async coreObjectAttributesListRequestOpts(
|
||||
requestParameters: CoreObjectAttributesListRequest,
|
||||
): Promise<runtime.RequestOpts> {
|
||||
const queryParameters: any = {};
|
||||
|
||||
if (requestParameters["enabled"] != null) {
|
||||
queryParameters["enabled"] = requestParameters["enabled"];
|
||||
}
|
||||
|
||||
if (requestParameters["objectTypeAppLabel"] != null) {
|
||||
queryParameters["object_type__app_label"] = requestParameters["objectTypeAppLabel"];
|
||||
}
|
||||
|
||||
if (requestParameters["objectTypeModel"] != null) {
|
||||
queryParameters["object_type__model"] = requestParameters["objectTypeModel"];
|
||||
}
|
||||
|
||||
if (requestParameters["ordering"] != null) {
|
||||
queryParameters["ordering"] = requestParameters["ordering"];
|
||||
}
|
||||
|
||||
if (requestParameters["page"] != null) {
|
||||
queryParameters["page"] = requestParameters["page"];
|
||||
}
|
||||
|
||||
if (requestParameters["pageSize"] != null) {
|
||||
queryParameters["page_size"] = requestParameters["pageSize"];
|
||||
}
|
||||
|
||||
if (requestParameters["search"] != null) {
|
||||
queryParameters["search"] = requestParameters["search"];
|
||||
}
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
if (this.configuration && this.configuration.accessToken) {
|
||||
const token = this.configuration.accessToken;
|
||||
const tokenString = await token("authentik", []);
|
||||
|
||||
if (tokenString) {
|
||||
headerParameters["Authorization"] = `Bearer ${tokenString}`;
|
||||
}
|
||||
}
|
||||
|
||||
let urlPath = `/core/object_attributes/`;
|
||||
|
||||
return {
|
||||
path: urlPath,
|
||||
method: "GET",
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesListRaw(
|
||||
requestParameters: CoreObjectAttributesListRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<runtime.ApiResponse<PaginatedObjectAttributeList>> {
|
||||
const requestOptions = await this.coreObjectAttributesListRequestOpts(requestParameters);
|
||||
const response = await this.request(requestOptions, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) =>
|
||||
PaginatedObjectAttributeListFromJSON(jsonValue),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesList(
|
||||
requestParameters: CoreObjectAttributesListRequest = {},
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<PaginatedObjectAttributeList> {
|
||||
const response = await this.coreObjectAttributesListRaw(requestParameters, initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates request options for coreObjectAttributesPartialUpdate without sending the request
|
||||
*/
|
||||
async coreObjectAttributesPartialUpdateRequestOpts(
|
||||
requestParameters: CoreObjectAttributesPartialUpdateRequest,
|
||||
): Promise<runtime.RequestOpts> {
|
||||
if (requestParameters["attributeId"] == null) {
|
||||
throw new runtime.RequiredError(
|
||||
"attributeId",
|
||||
'Required parameter "attributeId" was null or undefined when calling coreObjectAttributesPartialUpdate().',
|
||||
);
|
||||
}
|
||||
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
headerParameters["Content-Type"] = "application/json";
|
||||
|
||||
if (this.configuration && this.configuration.accessToken) {
|
||||
const token = this.configuration.accessToken;
|
||||
const tokenString = await token("authentik", []);
|
||||
|
||||
if (tokenString) {
|
||||
headerParameters["Authorization"] = `Bearer ${tokenString}`;
|
||||
}
|
||||
}
|
||||
|
||||
let urlPath = `/core/object_attributes/{attribute_id}/`;
|
||||
urlPath = urlPath.replace(
|
||||
`{${"attribute_id"}}`,
|
||||
encodeURIComponent(String(requestParameters["attributeId"])),
|
||||
);
|
||||
|
||||
return {
|
||||
path: urlPath,
|
||||
method: "PATCH",
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
body: PatchedObjectAttributeRequestToJSON(
|
||||
requestParameters["patchedObjectAttributeRequest"],
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesPartialUpdateRaw(
|
||||
requestParameters: CoreObjectAttributesPartialUpdateRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<runtime.ApiResponse<ObjectAttribute>> {
|
||||
const requestOptions =
|
||||
await this.coreObjectAttributesPartialUpdateRequestOpts(requestParameters);
|
||||
const response = await this.request(requestOptions, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) =>
|
||||
ObjectAttributeFromJSON(jsonValue),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesPartialUpdate(
|
||||
requestParameters: CoreObjectAttributesPartialUpdateRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<ObjectAttribute> {
|
||||
const response = await this.coreObjectAttributesPartialUpdateRaw(
|
||||
requestParameters,
|
||||
initOverrides,
|
||||
);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates request options for coreObjectAttributesRetrieve without sending the request
|
||||
*/
|
||||
async coreObjectAttributesRetrieveRequestOpts(
|
||||
requestParameters: CoreObjectAttributesRetrieveRequest,
|
||||
): Promise<runtime.RequestOpts> {
|
||||
if (requestParameters["attributeId"] == null) {
|
||||
throw new runtime.RequiredError(
|
||||
"attributeId",
|
||||
'Required parameter "attributeId" was null or undefined when calling coreObjectAttributesRetrieve().',
|
||||
);
|
||||
}
|
||||
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
if (this.configuration && this.configuration.accessToken) {
|
||||
const token = this.configuration.accessToken;
|
||||
const tokenString = await token("authentik", []);
|
||||
|
||||
if (tokenString) {
|
||||
headerParameters["Authorization"] = `Bearer ${tokenString}`;
|
||||
}
|
||||
}
|
||||
|
||||
let urlPath = `/core/object_attributes/{attribute_id}/`;
|
||||
urlPath = urlPath.replace(
|
||||
`{${"attribute_id"}}`,
|
||||
encodeURIComponent(String(requestParameters["attributeId"])),
|
||||
);
|
||||
|
||||
return {
|
||||
path: urlPath,
|
||||
method: "GET",
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesRetrieveRaw(
|
||||
requestParameters: CoreObjectAttributesRetrieveRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<runtime.ApiResponse<ObjectAttribute>> {
|
||||
const requestOptions =
|
||||
await this.coreObjectAttributesRetrieveRequestOpts(requestParameters);
|
||||
const response = await this.request(requestOptions, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) =>
|
||||
ObjectAttributeFromJSON(jsonValue),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesRetrieve(
|
||||
requestParameters: CoreObjectAttributesRetrieveRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<ObjectAttribute> {
|
||||
const response = await this.coreObjectAttributesRetrieveRaw(
|
||||
requestParameters,
|
||||
initOverrides,
|
||||
);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates request options for coreObjectAttributesUpdate without sending the request
|
||||
*/
|
||||
async coreObjectAttributesUpdateRequestOpts(
|
||||
requestParameters: CoreObjectAttributesUpdateRequest,
|
||||
): Promise<runtime.RequestOpts> {
|
||||
if (requestParameters["attributeId"] == null) {
|
||||
throw new runtime.RequiredError(
|
||||
"attributeId",
|
||||
'Required parameter "attributeId" was null or undefined when calling coreObjectAttributesUpdate().',
|
||||
);
|
||||
}
|
||||
|
||||
if (requestParameters["objectAttributeRequest"] == null) {
|
||||
throw new runtime.RequiredError(
|
||||
"objectAttributeRequest",
|
||||
'Required parameter "objectAttributeRequest" was null or undefined when calling coreObjectAttributesUpdate().',
|
||||
);
|
||||
}
|
||||
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
headerParameters["Content-Type"] = "application/json";
|
||||
|
||||
if (this.configuration && this.configuration.accessToken) {
|
||||
const token = this.configuration.accessToken;
|
||||
const tokenString = await token("authentik", []);
|
||||
|
||||
if (tokenString) {
|
||||
headerParameters["Authorization"] = `Bearer ${tokenString}`;
|
||||
}
|
||||
}
|
||||
|
||||
let urlPath = `/core/object_attributes/{attribute_id}/`;
|
||||
urlPath = urlPath.replace(
|
||||
`{${"attribute_id"}}`,
|
||||
encodeURIComponent(String(requestParameters["attributeId"])),
|
||||
);
|
||||
|
||||
return {
|
||||
path: urlPath,
|
||||
method: "PUT",
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
body: ObjectAttributeRequestToJSON(requestParameters["objectAttributeRequest"]),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesUpdateRaw(
|
||||
requestParameters: CoreObjectAttributesUpdateRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<runtime.ApiResponse<ObjectAttribute>> {
|
||||
const requestOptions = await this.coreObjectAttributesUpdateRequestOpts(requestParameters);
|
||||
const response = await this.request(requestOptions, initOverrides);
|
||||
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) =>
|
||||
ObjectAttributeFromJSON(jsonValue),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async coreObjectAttributesUpdate(
|
||||
requestParameters: CoreObjectAttributesUpdateRequest,
|
||||
initOverrides?: RequestInit | runtime.InitOverrideFunction,
|
||||
): Promise<ObjectAttribute> {
|
||||
const response = await this.coreObjectAttributesUpdateRaw(requestParameters, initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates request options for coreTokensCreate without sending the request
|
||||
*/
|
||||
|
||||
14
packages/client-ts/src/models/ContentType.ts
generated
@@ -42,12 +42,6 @@ export interface ContentType {
|
||||
* @memberof ContentType
|
||||
*/
|
||||
readonly verboseNamePlural: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ContentType
|
||||
*/
|
||||
readonly fullyQualifiedModel: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,8 +52,6 @@ export function instanceOfContentType(value: object): value is ContentType {
|
||||
if (!("appLabel" in value) || value["appLabel"] === undefined) return false;
|
||||
if (!("model" in value) || value["model"] === undefined) return false;
|
||||
if (!("verboseNamePlural" in value) || value["verboseNamePlural"] === undefined) return false;
|
||||
if (!("fullyQualifiedModel" in value) || value["fullyQualifiedModel"] === undefined)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,7 +68,6 @@ export function ContentTypeFromJSONTyped(json: any, ignoreDiscriminator: boolean
|
||||
appLabel: json["app_label"],
|
||||
model: json["model"],
|
||||
verboseNamePlural: json["verbose_name_plural"],
|
||||
fullyQualifiedModel: json["fully_qualified_model"],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -85,10 +76,7 @@ export function ContentTypeToJSON(json: any): ContentType {
|
||||
}
|
||||
|
||||
export function ContentTypeToJSONTyped(
|
||||
value?: Omit<
|
||||
ContentType,
|
||||
"id" | "app_label" | "model" | "verbose_name_plural" | "fully_qualified_model"
|
||||
> | null,
|
||||
value?: Omit<ContentType, "id" | "app_label" | "model" | "verbose_name_plural"> | null,
|
||||
ignoreDiscriminator: boolean = false,
|
||||
): any {
|
||||
if (value == null) {
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import type { Provider } from "./Provider";
|
||||
import { ProviderFromJSON, ProviderToJSON } from "./Provider";
|
||||
import type { OAuth2Provider } from "./OAuth2Provider";
|
||||
import { OAuth2ProviderFromJSON, OAuth2ProviderToJSON } from "./OAuth2Provider";
|
||||
import type { User } from "./User";
|
||||
import { UserFromJSON, UserToJSON } from "./User";
|
||||
|
||||
@@ -31,10 +31,10 @@ export interface ExpiringBaseGrantModel {
|
||||
readonly pk: number;
|
||||
/**
|
||||
*
|
||||
* @type {Provider}
|
||||
* @type {OAuth2Provider}
|
||||
* @memberof ExpiringBaseGrantModel
|
||||
*/
|
||||
provider: Provider;
|
||||
provider: OAuth2Provider;
|
||||
/**
|
||||
*
|
||||
* @type {User}
|
||||
@@ -86,7 +86,7 @@ export function ExpiringBaseGrantModelFromJSONTyped(
|
||||
}
|
||||
return {
|
||||
pk: json["pk"],
|
||||
provider: ProviderFromJSON(json["provider"]),
|
||||
provider: OAuth2ProviderFromJSON(json["provider"]),
|
||||
user: UserFromJSON(json["user"]),
|
||||
isExpired: json["is_expired"],
|
||||
expires: json["expires"] == null ? undefined : new Date(json["expires"]),
|
||||
@@ -107,7 +107,7 @@ export function ExpiringBaseGrantModelToJSONTyped(
|
||||
}
|
||||
|
||||
return {
|
||||
provider: ProviderToJSON(value["provider"]),
|
||||
provider: OAuth2ProviderToJSON(value["provider"]),
|
||||
user: UserToJSON(value["user"]),
|
||||
expires: value["expires"] == null ? value["expires"] : value["expires"].toISOString(),
|
||||
scope: value["scope"],
|
||||
|
||||
1
packages/client-ts/src/models/ModelEnum.ts
generated
@@ -23,7 +23,6 @@ export const ModelEnum = {
|
||||
AuthentikCoreApplication: "authentik_core.application",
|
||||
AuthentikCoreApplicationentitlement: "authentik_core.applicationentitlement",
|
||||
AuthentikCoreToken: "authentik_core.token",
|
||||
AuthentikCoreObjectattribute: "authentik_core.objectattribute",
|
||||
AuthentikCryptoCertificatekeypair: "authentik_crypto.certificatekeypair",
|
||||
AuthentikEndpointsDeviceuserbinding: "authentik_endpoints.deviceuserbinding",
|
||||
AuthentikEndpointsDeviceaccessgroup: "authentik_endpoints.deviceaccessgroup",
|
||||
|
||||
191
packages/client-ts/src/models/ObjectAttribute.ts
generated
@@ -1,191 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* authentik
|
||||
* Making authentication simple.
|
||||
*
|
||||
* The version of the OpenAPI document: 2026.5.0-rc1
|
||||
* Contact: hello@goauthentik.io
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import type { ContentType } from "./ContentType";
|
||||
import { ContentTypeFromJSON } from "./ContentType";
|
||||
import type { ObjectAttributeTypeEnum } from "./ObjectAttributeTypeEnum";
|
||||
import {
|
||||
ObjectAttributeTypeEnumFromJSON,
|
||||
ObjectAttributeTypeEnumToJSON,
|
||||
} from "./ObjectAttributeTypeEnum";
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface ObjectAttribute
|
||||
*/
|
||||
export interface ObjectAttribute {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
readonly pk: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
objectType: string;
|
||||
/**
|
||||
*
|
||||
* @type {ContentType}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
readonly objectTypeObj: ContentType;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {Date}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
readonly created: Date;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
*
|
||||
* @type {Date}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
readonly lastUpdated: Date;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
regex?: string;
|
||||
/**
|
||||
*
|
||||
* @type {ObjectAttributeTypeEnum}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
type: ObjectAttributeTypeEnum;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
group?: string;
|
||||
/**
|
||||
* Objects that are managed by authentik. These objects are created and updated automatically. This flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.
|
||||
* @type {string}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
managed?: string | null;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
isUnique?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
isRequired?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ObjectAttribute
|
||||
*/
|
||||
isArray?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the ObjectAttribute interface.
|
||||
*/
|
||||
export function instanceOfObjectAttribute(value: object): value is ObjectAttribute {
|
||||
if (!("pk" in value) || value["pk"] === undefined) return false;
|
||||
if (!("objectType" in value) || value["objectType"] === undefined) return false;
|
||||
if (!("objectTypeObj" in value) || value["objectTypeObj"] === undefined) return false;
|
||||
if (!("created" in value) || value["created"] === undefined) return false;
|
||||
if (!("key" in value) || value["key"] === undefined) return false;
|
||||
if (!("label" in value) || value["label"] === undefined) return false;
|
||||
if (!("lastUpdated" in value) || value["lastUpdated"] === undefined) return false;
|
||||
if (!("type" in value) || value["type"] === undefined) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function ObjectAttributeFromJSON(json: any): ObjectAttribute {
|
||||
return ObjectAttributeFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function ObjectAttributeFromJSONTyped(
|
||||
json: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): ObjectAttribute {
|
||||
if (json == null) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
pk: json["pk"],
|
||||
objectType: json["object_type"],
|
||||
objectTypeObj: ContentTypeFromJSON(json["object_type_obj"]),
|
||||
enabled: json["enabled"] == null ? undefined : json["enabled"],
|
||||
created: new Date(json["created"]),
|
||||
key: json["key"],
|
||||
label: json["label"],
|
||||
lastUpdated: new Date(json["last_updated"]),
|
||||
regex: json["regex"] == null ? undefined : json["regex"],
|
||||
type: ObjectAttributeTypeEnumFromJSON(json["type"]),
|
||||
group: json["group"] == null ? undefined : json["group"],
|
||||
managed: json["managed"] == null ? undefined : json["managed"],
|
||||
isUnique: json["is_unique"] == null ? undefined : json["is_unique"],
|
||||
isRequired: json["is_required"] == null ? undefined : json["is_required"],
|
||||
isArray: json["is_array"] == null ? undefined : json["is_array"],
|
||||
};
|
||||
}
|
||||
|
||||
export function ObjectAttributeToJSON(json: any): ObjectAttribute {
|
||||
return ObjectAttributeToJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function ObjectAttributeToJSONTyped(
|
||||
value?: Omit<ObjectAttribute, "pk" | "object_type_obj" | "created" | "last_updated"> | null,
|
||||
ignoreDiscriminator: boolean = false,
|
||||
): any {
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return {
|
||||
object_type: value["objectType"],
|
||||
enabled: value["enabled"],
|
||||
key: value["key"],
|
||||
label: value["label"],
|
||||
regex: value["regex"],
|
||||
type: ObjectAttributeTypeEnumToJSON(value["type"]),
|
||||
group: value["group"],
|
||||
managed: value["managed"],
|
||||
is_unique: value["isUnique"],
|
||||
is_required: value["isRequired"],
|
||||
is_array: value["isArray"],
|
||||
};
|
||||
}
|
||||
157
packages/client-ts/src/models/ObjectAttributeRequest.ts
generated
@@ -1,157 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* authentik
|
||||
* Making authentication simple.
|
||||
*
|
||||
* The version of the OpenAPI document: 2026.5.0-rc1
|
||||
* Contact: hello@goauthentik.io
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import type { ObjectAttributeTypeEnum } from "./ObjectAttributeTypeEnum";
|
||||
import {
|
||||
ObjectAttributeTypeEnumFromJSON,
|
||||
ObjectAttributeTypeEnumToJSON,
|
||||
} from "./ObjectAttributeTypeEnum";
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface ObjectAttributeRequest
|
||||
*/
|
||||
export interface ObjectAttributeRequest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
objectType: string;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
regex?: string;
|
||||
/**
|
||||
*
|
||||
* @type {ObjectAttributeTypeEnum}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
type: ObjectAttributeTypeEnum;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
group?: string;
|
||||
/**
|
||||
* Objects that are managed by authentik. These objects are created and updated automatically. This flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.
|
||||
* @type {string}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
managed?: string | null;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
isUnique?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
isRequired?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof ObjectAttributeRequest
|
||||
*/
|
||||
isArray?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the ObjectAttributeRequest interface.
|
||||
*/
|
||||
export function instanceOfObjectAttributeRequest(value: object): value is ObjectAttributeRequest {
|
||||
if (!("objectType" in value) || value["objectType"] === undefined) return false;
|
||||
if (!("key" in value) || value["key"] === undefined) return false;
|
||||
if (!("label" in value) || value["label"] === undefined) return false;
|
||||
if (!("type" in value) || value["type"] === undefined) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function ObjectAttributeRequestFromJSON(json: any): ObjectAttributeRequest {
|
||||
return ObjectAttributeRequestFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function ObjectAttributeRequestFromJSONTyped(
|
||||
json: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): ObjectAttributeRequest {
|
||||
if (json == null) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
objectType: json["object_type"],
|
||||
enabled: json["enabled"] == null ? undefined : json["enabled"],
|
||||
key: json["key"],
|
||||
label: json["label"],
|
||||
regex: json["regex"] == null ? undefined : json["regex"],
|
||||
type: ObjectAttributeTypeEnumFromJSON(json["type"]),
|
||||
group: json["group"] == null ? undefined : json["group"],
|
||||
managed: json["managed"] == null ? undefined : json["managed"],
|
||||
isUnique: json["is_unique"] == null ? undefined : json["is_unique"],
|
||||
isRequired: json["is_required"] == null ? undefined : json["is_required"],
|
||||
isArray: json["is_array"] == null ? undefined : json["is_array"],
|
||||
};
|
||||
}
|
||||
|
||||
export function ObjectAttributeRequestToJSON(json: any): ObjectAttributeRequest {
|
||||
return ObjectAttributeRequestToJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function ObjectAttributeRequestToJSONTyped(
|
||||
value?: ObjectAttributeRequest | null,
|
||||
ignoreDiscriminator: boolean = false,
|
||||
): any {
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return {
|
||||
object_type: value["objectType"],
|
||||
enabled: value["enabled"],
|
||||
key: value["key"],
|
||||
label: value["label"],
|
||||
regex: value["regex"],
|
||||
type: ObjectAttributeTypeEnumToJSON(value["type"]),
|
||||
group: value["group"],
|
||||
managed: value["managed"],
|
||||
is_unique: value["isUnique"],
|
||||
is_required: value["isRequired"],
|
||||
is_array: value["isArray"],
|
||||
};
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* authentik
|
||||
* Making authentication simple.
|
||||
*
|
||||
* The version of the OpenAPI document: 2026.5.0-rc1
|
||||
* Contact: hello@goauthentik.io
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
*/
|
||||
export const ObjectAttributeTypeEnum = {
|
||||
Text: "text",
|
||||
Number: "number",
|
||||
Boolean: "boolean",
|
||||
UnknownDefaultOpenApi: "11184809",
|
||||
} as const;
|
||||
export type ObjectAttributeTypeEnum =
|
||||
(typeof ObjectAttributeTypeEnum)[keyof typeof ObjectAttributeTypeEnum];
|
||||
|
||||
export function instanceOfObjectAttributeTypeEnum(value: any): boolean {
|
||||
for (const key in ObjectAttributeTypeEnum) {
|
||||
if (Object.prototype.hasOwnProperty.call(ObjectAttributeTypeEnum, key)) {
|
||||
if (ObjectAttributeTypeEnum[key as keyof typeof ObjectAttributeTypeEnum] === value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function ObjectAttributeTypeEnumFromJSON(json: any): ObjectAttributeTypeEnum {
|
||||
return ObjectAttributeTypeEnumFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function ObjectAttributeTypeEnumFromJSONTyped(
|
||||
json: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): ObjectAttributeTypeEnum {
|
||||
return json as ObjectAttributeTypeEnum;
|
||||
}
|
||||
|
||||
export function ObjectAttributeTypeEnumToJSON(value?: ObjectAttributeTypeEnum | null): any {
|
||||
return value as any;
|
||||
}
|
||||
|
||||
export function ObjectAttributeTypeEnumToJSONTyped(
|
||||
value: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): ObjectAttributeTypeEnum {
|
||||
return value as ObjectAttributeTypeEnum;
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* authentik
|
||||
* Making authentication simple.
|
||||
*
|
||||
* The version of the OpenAPI document: 2026.5.0-rc1
|
||||
* Contact: hello@goauthentik.io
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import type { ObjectAttribute } from "./ObjectAttribute";
|
||||
import { ObjectAttributeFromJSON, ObjectAttributeToJSON } from "./ObjectAttribute";
|
||||
import type { Pagination } from "./Pagination";
|
||||
import { PaginationFromJSON, PaginationToJSON } from "./Pagination";
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface PaginatedObjectAttributeList
|
||||
*/
|
||||
export interface PaginatedObjectAttributeList {
|
||||
/**
|
||||
*
|
||||
* @type {Pagination}
|
||||
* @memberof PaginatedObjectAttributeList
|
||||
*/
|
||||
pagination: Pagination;
|
||||
/**
|
||||
*
|
||||
* @type {Array<ObjectAttribute>}
|
||||
* @memberof PaginatedObjectAttributeList
|
||||
*/
|
||||
results: Array<ObjectAttribute>;
|
||||
/**
|
||||
*
|
||||
* @type {{ [key: string]: any; }}
|
||||
* @memberof PaginatedObjectAttributeList
|
||||
*/
|
||||
autocomplete: { [key: string]: any };
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the PaginatedObjectAttributeList interface.
|
||||
*/
|
||||
export function instanceOfPaginatedObjectAttributeList(
|
||||
value: object,
|
||||
): value is PaginatedObjectAttributeList {
|
||||
if (!("pagination" in value) || value["pagination"] === undefined) return false;
|
||||
if (!("results" in value) || value["results"] === undefined) return false;
|
||||
if (!("autocomplete" in value) || value["autocomplete"] === undefined) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function PaginatedObjectAttributeListFromJSON(json: any): PaginatedObjectAttributeList {
|
||||
return PaginatedObjectAttributeListFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function PaginatedObjectAttributeListFromJSONTyped(
|
||||
json: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): PaginatedObjectAttributeList {
|
||||
if (json == null) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
pagination: PaginationFromJSON(json["pagination"]),
|
||||
results: (json["results"] as Array<any>).map(ObjectAttributeFromJSON),
|
||||
autocomplete: json["autocomplete"],
|
||||
};
|
||||
}
|
||||
|
||||
export function PaginatedObjectAttributeListToJSON(json: any): PaginatedObjectAttributeList {
|
||||
return PaginatedObjectAttributeListToJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function PaginatedObjectAttributeListToJSONTyped(
|
||||
value?: PaginatedObjectAttributeList | null,
|
||||
ignoreDiscriminator: boolean = false,
|
||||
): any {
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return {
|
||||
pagination: PaginationToJSON(value["pagination"]),
|
||||
results: (value["results"] as Array<any>).map(ObjectAttributeToJSON),
|
||||
autocomplete: value["autocomplete"],
|
||||
};
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* authentik
|
||||
* Making authentication simple.
|
||||
*
|
||||
* The version of the OpenAPI document: 2026.5.0-rc1
|
||||
* Contact: hello@goauthentik.io
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import type { ObjectAttributeTypeEnum } from "./ObjectAttributeTypeEnum";
|
||||
import {
|
||||
ObjectAttributeTypeEnumFromJSON,
|
||||
ObjectAttributeTypeEnumToJSON,
|
||||
} from "./ObjectAttributeTypeEnum";
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface PatchedObjectAttributeRequest
|
||||
*/
|
||||
export interface PatchedObjectAttributeRequest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
objectType?: string;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
key?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
label?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
regex?: string;
|
||||
/**
|
||||
*
|
||||
* @type {ObjectAttributeTypeEnum}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
type?: ObjectAttributeTypeEnum;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
group?: string;
|
||||
/**
|
||||
* Objects that are managed by authentik. These objects are created and updated automatically. This flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.
|
||||
* @type {string}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
managed?: string | null;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
isUnique?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
isRequired?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PatchedObjectAttributeRequest
|
||||
*/
|
||||
isArray?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the PatchedObjectAttributeRequest interface.
|
||||
*/
|
||||
export function instanceOfPatchedObjectAttributeRequest(
|
||||
value: object,
|
||||
): value is PatchedObjectAttributeRequest {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function PatchedObjectAttributeRequestFromJSON(json: any): PatchedObjectAttributeRequest {
|
||||
return PatchedObjectAttributeRequestFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function PatchedObjectAttributeRequestFromJSONTyped(
|
||||
json: any,
|
||||
ignoreDiscriminator: boolean,
|
||||
): PatchedObjectAttributeRequest {
|
||||
if (json == null) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
objectType: json["object_type"] == null ? undefined : json["object_type"],
|
||||
enabled: json["enabled"] == null ? undefined : json["enabled"],
|
||||
key: json["key"] == null ? undefined : json["key"],
|
||||
label: json["label"] == null ? undefined : json["label"],
|
||||
regex: json["regex"] == null ? undefined : json["regex"],
|
||||
type: json["type"] == null ? undefined : ObjectAttributeTypeEnumFromJSON(json["type"]),
|
||||
group: json["group"] == null ? undefined : json["group"],
|
||||
managed: json["managed"] == null ? undefined : json["managed"],
|
||||
isUnique: json["is_unique"] == null ? undefined : json["is_unique"],
|
||||
isRequired: json["is_required"] == null ? undefined : json["is_required"],
|
||||
isArray: json["is_array"] == null ? undefined : json["is_array"],
|
||||
};
|
||||
}
|
||||
|
||||
export function PatchedObjectAttributeRequestToJSON(json: any): PatchedObjectAttributeRequest {
|
||||
return PatchedObjectAttributeRequestToJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function PatchedObjectAttributeRequestToJSONTyped(
|
||||
value?: PatchedObjectAttributeRequest | null,
|
||||
ignoreDiscriminator: boolean = false,
|
||||
): any {
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return {
|
||||
object_type: value["objectType"],
|
||||
enabled: value["enabled"],
|
||||
key: value["key"],
|
||||
label: value["label"],
|
||||
regex: value["regex"],
|
||||
type: ObjectAttributeTypeEnumToJSON(value["type"]),
|
||||
group: value["group"],
|
||||
managed: value["managed"],
|
||||
is_unique: value["isUnique"],
|
||||
is_required: value["isRequired"],
|
||||
is_array: value["isArray"],
|
||||
};
|
||||
}
|
||||
18
packages/client-ts/src/models/SAMLProvider.ts
generated
@@ -266,18 +266,6 @@ export interface SAMLProvider {
|
||||
* @memberof SAMLProvider
|
||||
*/
|
||||
readonly urlIssuer: string;
|
||||
/**
|
||||
* Get unified SAML endpoint URL (handles SSO and SLO)
|
||||
* @type {string}
|
||||
* @memberof SAMLProvider
|
||||
*/
|
||||
readonly urlUnified: string;
|
||||
/**
|
||||
* Get IdP-initiated SAML URL
|
||||
* @type {string}
|
||||
* @memberof SAMLProvider
|
||||
*/
|
||||
readonly urlUnifiedInit: string;
|
||||
/**
|
||||
* Get SSO Post URL
|
||||
* @type {string}
|
||||
@@ -340,8 +328,6 @@ export function instanceOfSAMLProvider(value: object): value is SAMLProvider {
|
||||
if (!("urlDownloadMetadata" in value) || value["urlDownloadMetadata"] === undefined)
|
||||
return false;
|
||||
if (!("urlIssuer" in value) || value["urlIssuer"] === undefined) return false;
|
||||
if (!("urlUnified" in value) || value["urlUnified"] === undefined) return false;
|
||||
if (!("urlUnifiedInit" in value) || value["urlUnifiedInit"] === undefined) return false;
|
||||
if (!("urlSsoPost" in value) || value["urlSsoPost"] === undefined) return false;
|
||||
if (!("urlSsoRedirect" in value) || value["urlSsoRedirect"] === undefined) return false;
|
||||
if (!("urlSsoInit" in value) || value["urlSsoInit"] === undefined) return false;
|
||||
@@ -428,8 +414,6 @@ export function SAMLProviderFromJSONTyped(json: any, ignoreDiscriminator: boolea
|
||||
: SAMLNameIDPolicyEnumFromJSON(json["default_name_id_policy"]),
|
||||
urlDownloadMetadata: json["url_download_metadata"],
|
||||
urlIssuer: json["url_issuer"],
|
||||
urlUnified: json["url_unified"],
|
||||
urlUnifiedInit: json["url_unified_init"],
|
||||
urlSsoPost: json["url_sso_post"],
|
||||
urlSsoRedirect: json["url_sso_redirect"],
|
||||
urlSsoInit: json["url_sso_init"],
|
||||
@@ -456,8 +440,6 @@ export function SAMLProviderToJSONTyped(
|
||||
| "meta_model_name"
|
||||
| "url_download_metadata"
|
||||
| "url_issuer"
|
||||
| "url_unified"
|
||||
| "url_unified_init"
|
||||
| "url_sso_post"
|
||||
| "url_sso_redirect"
|
||||
| "url_sso_init"
|
||||
|
||||
12
packages/client-ts/src/models/TokenModel.ts
generated
@@ -12,8 +12,8 @@
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import type { Provider } from "./Provider";
|
||||
import { ProviderFromJSON, ProviderToJSON } from "./Provider";
|
||||
import type { OAuth2Provider } from "./OAuth2Provider";
|
||||
import { OAuth2ProviderFromJSON, OAuth2ProviderToJSON } from "./OAuth2Provider";
|
||||
import type { User } from "./User";
|
||||
import { UserFromJSON, UserToJSON } from "./User";
|
||||
|
||||
@@ -31,10 +31,10 @@ export interface TokenModel {
|
||||
readonly pk: number;
|
||||
/**
|
||||
*
|
||||
* @type {Provider}
|
||||
* @type {OAuth2Provider}
|
||||
* @memberof TokenModel
|
||||
*/
|
||||
provider: Provider;
|
||||
provider: OAuth2Provider;
|
||||
/**
|
||||
*
|
||||
* @type {User}
|
||||
@@ -96,7 +96,7 @@ export function TokenModelFromJSONTyped(json: any, ignoreDiscriminator: boolean)
|
||||
}
|
||||
return {
|
||||
pk: json["pk"],
|
||||
provider: ProviderFromJSON(json["provider"]),
|
||||
provider: OAuth2ProviderFromJSON(json["provider"]),
|
||||
user: UserFromJSON(json["user"]),
|
||||
isExpired: json["is_expired"],
|
||||
expires: json["expires"] == null ? undefined : new Date(json["expires"]),
|
||||
@@ -119,7 +119,7 @@ export function TokenModelToJSONTyped(
|
||||
}
|
||||
|
||||
return {
|
||||
provider: ProviderToJSON(value["provider"]),
|
||||
provider: OAuth2ProviderToJSON(value["provider"]),
|
||||
user: UserToJSON(value["user"]),
|
||||
expires: value["expires"] == null ? value["expires"] : value["expires"].toISOString(),
|
||||
scope: value["scope"],
|
||||
|
||||
5
packages/client-ts/src/models/index.ts
generated
@@ -344,9 +344,6 @@ export * from "./OAuthSource";
|
||||
export * from "./OAuthSourcePropertyMapping";
|
||||
export * from "./OAuthSourcePropertyMappingRequest";
|
||||
export * from "./OAuthSourceRequest";
|
||||
export * from "./ObjectAttribute";
|
||||
export * from "./ObjectAttributeRequest";
|
||||
export * from "./ObjectAttributeTypeEnum";
|
||||
export * from "./OpenIDConnectConfiguration";
|
||||
export * from "./OperatingSystem";
|
||||
export * from "./OperatingSystemRequest";
|
||||
@@ -442,7 +439,6 @@ export * from "./PaginatedNotificationWebhookMappingList";
|
||||
export * from "./PaginatedOAuth2ProviderList";
|
||||
export * from "./PaginatedOAuthSourceList";
|
||||
export * from "./PaginatedOAuthSourcePropertyMappingList";
|
||||
export * from "./PaginatedObjectAttributeList";
|
||||
export * from "./PaginatedOutpostList";
|
||||
export * from "./PaginatedPasswordExpiryPolicyList";
|
||||
export * from "./PaginatedPasswordPolicyList";
|
||||
@@ -599,7 +595,6 @@ export * from "./PatchedNotificationWebhookMappingRequest";
|
||||
export * from "./PatchedOAuth2ProviderRequest";
|
||||
export * from "./PatchedOAuthSourcePropertyMappingRequest";
|
||||
export * from "./PatchedOAuthSourceRequest";
|
||||
export * from "./PatchedObjectAttributeRequest";
|
||||
export * from "./PatchedOutpostRequest";
|
||||
export * from "./PatchedPasswordExpiryPolicyRequest";
|
||||
export * from "./PatchedPasswordPolicyRequest";
|
||||
|
||||
@@ -60,7 +60,7 @@ export const LogLevels = /** @type {Level[]} */ (Object.keys(LogLevelLabel));
|
||||
/**
|
||||
* @callback LoggerFactory
|
||||
* @param {string | null} [prefix]
|
||||
* @param {...string[]} args
|
||||
* @param {...string} args
|
||||
* @returns {Logger}
|
||||
*/
|
||||
|
||||
@@ -207,7 +207,7 @@ export function pinoLight(options) {
|
||||
* Creates a logger with the given prefix.
|
||||
*
|
||||
* @param {string} [prefix]
|
||||
* @param {...string[]} args
|
||||
* @param {...string} args
|
||||
* @returns {Logger}
|
||||
*
|
||||
*/
|
||||
|
||||
6
packages/logger-js/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@goauthentik/logger-js",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@goauthentik/logger-js",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.1",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.3",
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"../tsconfig": {
|
||||
"name": "@goauthentik/tsconfig",
|
||||
"version": "1.0.9",
|
||||
"version": "1.0.8",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@goauthentik/logger-js",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.1",
|
||||
"description": "Pino-based logger for authentik",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
@@ -7,7 +7,7 @@ requires-python = "==3.14.*"
|
||||
dependencies = [
|
||||
"ak-guardian==3.2.0",
|
||||
"argon2-cffi==25.1.0",
|
||||
"cachetools==7.1.1",
|
||||
"cachetools==7.0.6",
|
||||
"channels==4.3.2",
|
||||
"cryptography==48.0.0",
|
||||
"dacite==1.9.2",
|
||||
@@ -36,7 +36,7 @@ dependencies = [
|
||||
"fido2==2.2.0",
|
||||
"geoip2==5.2.0",
|
||||
"geopy==2.4.1",
|
||||
"google-api-python-client==2.195.0",
|
||||
"google-api-python-client==2.194.0",
|
||||
"gssapi==1.11.1",
|
||||
"gunicorn==25.3.0",
|
||||
"jsonpatch==1.33",
|
||||
@@ -47,22 +47,22 @@ dependencies = [
|
||||
"msgraph-sdk==1.56.0",
|
||||
"opencontainers==0.0.15",
|
||||
"packaging==26.2",
|
||||
"paramiko==5.0.0",
|
||||
"paramiko==4.0.0",
|
||||
"psycopg[c,pool]==3.3.4",
|
||||
"pydantic-scim==0.0.8",
|
||||
"pydantic==2.13.4",
|
||||
"pydantic==2.13.3",
|
||||
"pyjwt==2.11.0",
|
||||
"pyrad==2.5.4",
|
||||
"python-kadmin-rs==0.7.2",
|
||||
"python-kadmin-rs==0.7.0",
|
||||
"pyyaml==6.0.3",
|
||||
"requests-oauthlib==2.0.0",
|
||||
"scim2-filter-parser==0.7.0",
|
||||
"sentry-sdk==2.59.0",
|
||||
"sentry-sdk==2.58.0",
|
||||
"service-identity==24.2.0",
|
||||
"setproctitle==1.3.7",
|
||||
"structlog==25.5.0",
|
||||
"swagger-spec-validator==3.0.4",
|
||||
"twilio==9.10.9",
|
||||
"twilio==9.10.5",
|
||||
"ua-parser==1.0.2",
|
||||
"unidecode==1.4.0",
|
||||
"urllib3<3",
|
||||
@@ -76,7 +76,7 @@ dependencies = [
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"aws-cdk-lib==2.252.0",
|
||||
"aws-cdk-lib==2.251.0",
|
||||
"bandit==1.9.4",
|
||||
"black==26.3.1",
|
||||
"bpython==0.26",
|
||||
@@ -85,7 +85,7 @@ dev = [
|
||||
"coverage[toml]==7.13.5",
|
||||
"daphne==4.2.1",
|
||||
"debugpy==1.8.20",
|
||||
"django-stubs[compatible-mypy]==6.0.4",
|
||||
"django-stubs[compatible-mypy]==6.0.3",
|
||||
"djangorestframework-stubs[compatible-mypy]==3.16.9",
|
||||
"drf-jsonschema-serializer==3.0.0",
|
||||
"freezegun==1.5.5",
|
||||
@@ -107,7 +107,7 @@ dev = [
|
||||
"types-docker==7.1.0.20260409",
|
||||
"types-jwcrypto==1.5.7.20260409",
|
||||
"types-ldap3==2.9.13.20260408",
|
||||
"types-requests==2.33.0.20260503",
|
||||
"types-requests==2.33.0.20260408",
|
||||
"types-zxcvbn==4.5.0.20260408",
|
||||
]
|
||||
|
||||
|
||||
355
schema.yml
@@ -134,12 +134,6 @@ paths:
|
||||
get:
|
||||
operationId: admin_models_list
|
||||
description: Read-only view list all installed models
|
||||
parameters:
|
||||
- in: query
|
||||
name: filter_has_attributes
|
||||
schema:
|
||||
type: boolean
|
||||
nullable: true
|
||||
tags:
|
||||
- admin
|
||||
security:
|
||||
@@ -3726,172 +3720,6 @@ paths:
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
/core/object_attributes/:
|
||||
get:
|
||||
operationId: core_object_attributes_list
|
||||
parameters:
|
||||
- in: query
|
||||
name: enabled
|
||||
schema:
|
||||
type: boolean
|
||||
- in: query
|
||||
name: object_type__app_label
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: object_type__model
|
||||
schema:
|
||||
type: string
|
||||
- $ref: '#/components/parameters/QueryPaginationOrdering'
|
||||
- $ref: '#/components/parameters/QueryPaginationPage'
|
||||
- $ref: '#/components/parameters/QueryPaginationPageSize'
|
||||
- $ref: '#/components/parameters/QuerySearch'
|
||||
tags:
|
||||
- core
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PaginatedObjectAttributeList'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
post:
|
||||
operationId: core_object_attributes_create
|
||||
tags:
|
||||
- core
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ObjectAttributeRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'201':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ObjectAttribute'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
/core/object_attributes/{attribute_id}/:
|
||||
get:
|
||||
operationId: core_object_attributes_retrieve
|
||||
parameters:
|
||||
- in: path
|
||||
name: attribute_id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Object Attribute.
|
||||
required: true
|
||||
tags:
|
||||
- core
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ObjectAttribute'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
put:
|
||||
operationId: core_object_attributes_update
|
||||
parameters:
|
||||
- in: path
|
||||
name: attribute_id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Object Attribute.
|
||||
required: true
|
||||
tags:
|
||||
- core
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ObjectAttributeRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ObjectAttribute'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
patch:
|
||||
operationId: core_object_attributes_partial_update
|
||||
parameters:
|
||||
- in: path
|
||||
name: attribute_id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Object Attribute.
|
||||
required: true
|
||||
tags:
|
||||
- core
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PatchedObjectAttributeRequest'
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ObjectAttribute'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
delete:
|
||||
operationId: core_object_attributes_destroy
|
||||
parameters:
|
||||
- in: path
|
||||
name: attribute_id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Object Attribute.
|
||||
required: true
|
||||
tags:
|
||||
- core
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'204':
|
||||
description: No response body
|
||||
'400':
|
||||
$ref: '#/components/responses/ValidationErrorResponse'
|
||||
'403':
|
||||
$ref: '#/components/responses/GenericErrorResponse'
|
||||
/core/tokens/:
|
||||
get:
|
||||
operationId: core_tokens_list
|
||||
@@ -5558,8 +5386,6 @@ paths:
|
||||
using this object
|
||||
tags:
|
||||
- endpoints
|
||||
security:
|
||||
- {}
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
@@ -5604,8 +5430,6 @@ paths:
|
||||
using this object
|
||||
tags:
|
||||
- endpoints
|
||||
security:
|
||||
- {}
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
@@ -5629,8 +5453,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DeviceFactsRequest'
|
||||
security:
|
||||
- {}
|
||||
responses:
|
||||
'204':
|
||||
description: Successfully checked in
|
||||
@@ -5651,8 +5473,6 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/EnrollRequest'
|
||||
required: true
|
||||
security:
|
||||
- {}
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
@@ -37030,12 +36850,8 @@ components:
|
||||
verbose_name_plural:
|
||||
type: string
|
||||
readOnly: true
|
||||
fully_qualified_model:
|
||||
type: string
|
||||
readOnly: true
|
||||
required:
|
||||
- app_label
|
||||
- fully_qualified_model
|
||||
- id
|
||||
- model
|
||||
- verbose_name_plural
|
||||
@@ -39262,7 +39078,7 @@ components:
|
||||
readOnly: true
|
||||
title: ID
|
||||
provider:
|
||||
$ref: '#/components/schemas/Provider'
|
||||
$ref: '#/components/schemas/OAuth2Provider'
|
||||
user:
|
||||
$ref: '#/components/schemas/User'
|
||||
is_expired:
|
||||
@@ -43597,7 +43413,6 @@ components:
|
||||
- authentik_core.application
|
||||
- authentik_core.applicationentitlement
|
||||
- authentik_core.token
|
||||
- authentik_core.objectattribute
|
||||
- authentik_crypto.certificatekeypair
|
||||
- authentik_endpoints.deviceuserbinding
|
||||
- authentik_endpoints.deviceaccessgroup
|
||||
@@ -44879,111 +44694,6 @@ components:
|
||||
- name
|
||||
- provider_type
|
||||
- slug
|
||||
ObjectAttribute:
|
||||
type: object
|
||||
properties:
|
||||
pk:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
title: Attribute id
|
||||
object_type:
|
||||
type: string
|
||||
object_type_obj:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/ContentType'
|
||||
readOnly: true
|
||||
enabled:
|
||||
type: boolean
|
||||
default: true
|
||||
created:
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
key:
|
||||
type: string
|
||||
label:
|
||||
type: string
|
||||
last_updated:
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
regex:
|
||||
type: string
|
||||
type:
|
||||
$ref: '#/components/schemas/ObjectAttributeTypeEnum'
|
||||
group:
|
||||
type: string
|
||||
managed:
|
||||
type: string
|
||||
nullable: true
|
||||
title: Managed by authentik
|
||||
description: Objects that are managed by authentik. These objects are created
|
||||
and updated automatically. This flag only indicates that an object can
|
||||
be overwritten by migrations. You can still modify the objects via the
|
||||
API, but expect changes to be overwritten in a later update.
|
||||
is_unique:
|
||||
type: boolean
|
||||
is_required:
|
||||
type: boolean
|
||||
is_array:
|
||||
type: boolean
|
||||
required:
|
||||
- created
|
||||
- key
|
||||
- label
|
||||
- last_updated
|
||||
- object_type
|
||||
- object_type_obj
|
||||
- pk
|
||||
- type
|
||||
ObjectAttributeRequest:
|
||||
type: object
|
||||
properties:
|
||||
object_type:
|
||||
type: string
|
||||
minLength: 1
|
||||
enabled:
|
||||
type: boolean
|
||||
default: true
|
||||
key:
|
||||
type: string
|
||||
minLength: 1
|
||||
label:
|
||||
type: string
|
||||
minLength: 1
|
||||
regex:
|
||||
type: string
|
||||
type:
|
||||
$ref: '#/components/schemas/ObjectAttributeTypeEnum'
|
||||
group:
|
||||
type: string
|
||||
managed:
|
||||
type: string
|
||||
nullable: true
|
||||
minLength: 1
|
||||
title: Managed by authentik
|
||||
description: Objects that are managed by authentik. These objects are created
|
||||
and updated automatically. This flag only indicates that an object can
|
||||
be overwritten by migrations. You can still modify the objects via the
|
||||
API, but expect changes to be overwritten in a later update.
|
||||
is_unique:
|
||||
type: boolean
|
||||
is_required:
|
||||
type: boolean
|
||||
is_array:
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
- label
|
||||
- object_type
|
||||
- type
|
||||
ObjectAttributeTypeEnum:
|
||||
enum:
|
||||
- text
|
||||
- number
|
||||
- boolean
|
||||
type: string
|
||||
OpenIDConnectConfiguration:
|
||||
type: object
|
||||
description: rest_framework Serializer for OIDC Configuration
|
||||
@@ -46534,21 +46244,6 @@ components:
|
||||
- autocomplete
|
||||
- pagination
|
||||
- results
|
||||
PaginatedObjectAttributeList:
|
||||
type: object
|
||||
properties:
|
||||
pagination:
|
||||
$ref: '#/components/schemas/Pagination'
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ObjectAttribute'
|
||||
autocomplete:
|
||||
$ref: '#/components/schemas/Autocomplete'
|
||||
required:
|
||||
- autocomplete
|
||||
- pagination
|
||||
- results
|
||||
PaginatedOutpostList:
|
||||
type: object
|
||||
properties:
|
||||
@@ -50331,42 +50026,6 @@ components:
|
||||
- $ref: '#/components/schemas/AuthorizationCodeAuthMethodEnum'
|
||||
description: How to perform authentication during an authorization_code
|
||||
token request flow
|
||||
PatchedObjectAttributeRequest:
|
||||
type: object
|
||||
properties:
|
||||
object_type:
|
||||
type: string
|
||||
minLength: 1
|
||||
enabled:
|
||||
type: boolean
|
||||
default: true
|
||||
key:
|
||||
type: string
|
||||
minLength: 1
|
||||
label:
|
||||
type: string
|
||||
minLength: 1
|
||||
regex:
|
||||
type: string
|
||||
type:
|
||||
$ref: '#/components/schemas/ObjectAttributeTypeEnum'
|
||||
group:
|
||||
type: string
|
||||
managed:
|
||||
type: string
|
||||
nullable: true
|
||||
minLength: 1
|
||||
title: Managed by authentik
|
||||
description: Objects that are managed by authentik. These objects are created
|
||||
and updated automatically. This flag only indicates that an object can
|
||||
be overwritten by migrations. You can still modify the objects via the
|
||||
API, but expect changes to be overwritten in a later update.
|
||||
is_unique:
|
||||
type: boolean
|
||||
is_required:
|
||||
type: boolean
|
||||
is_array:
|
||||
type: boolean
|
||||
PatchedOutpostRequest:
|
||||
type: object
|
||||
description: Outpost Serializer
|
||||
@@ -54669,14 +54328,6 @@ components:
|
||||
type: string
|
||||
description: Get Issuer/EntityID URL
|
||||
readOnly: true
|
||||
url_unified:
|
||||
type: string
|
||||
description: Get unified SAML endpoint URL (handles SSO and SLO)
|
||||
readOnly: true
|
||||
url_unified_init:
|
||||
type: string
|
||||
description: Get IdP-initiated SAML URL
|
||||
readOnly: true
|
||||
url_sso_post:
|
||||
type: string
|
||||
description: Get SSO Post URL
|
||||
@@ -54716,8 +54367,6 @@ components:
|
||||
- url_sso_init
|
||||
- url_sso_post
|
||||
- url_sso_redirect
|
||||
- url_unified
|
||||
- url_unified_init
|
||||
- verbose_name
|
||||
- verbose_name_plural
|
||||
SAMLProviderImportRequest:
|
||||
@@ -57594,7 +57243,7 @@ components:
|
||||
readOnly: true
|
||||
title: ID
|
||||
provider:
|
||||
$ref: '#/components/schemas/Provider'
|
||||
$ref: '#/components/schemas/OAuth2Provider'
|
||||
user:
|
||||
$ref: '#/components/schemas/User'
|
||||
is_expired:
|
||||
|
||||
164
uv.lock
generated
@@ -316,7 +316,7 @@ dev = [
|
||||
requires-dist = [
|
||||
{ name = "ak-guardian", editable = "packages/ak-guardian" },
|
||||
{ name = "argon2-cffi", specifier = "==25.1.0" },
|
||||
{ name = "cachetools", specifier = "==7.1.1" },
|
||||
{ name = "cachetools", specifier = "==7.0.6" },
|
||||
{ name = "channels", specifier = "==4.3.2" },
|
||||
{ name = "cryptography", specifier = "==48.0.0" },
|
||||
{ name = "dacite", specifier = "==1.9.2" },
|
||||
@@ -345,7 +345,7 @@ requires-dist = [
|
||||
{ name = "fido2", specifier = "==2.2.0" },
|
||||
{ name = "geoip2", specifier = "==5.2.0" },
|
||||
{ name = "geopy", specifier = "==2.4.1" },
|
||||
{ name = "google-api-python-client", specifier = "==2.195.0" },
|
||||
{ name = "google-api-python-client", specifier = "==2.194.0" },
|
||||
{ name = "gssapi", specifier = "==1.11.1" },
|
||||
{ name = "gunicorn", specifier = "==25.3.0" },
|
||||
{ name = "jsonpatch", specifier = "==1.33" },
|
||||
@@ -356,22 +356,22 @@ requires-dist = [
|
||||
{ name = "msgraph-sdk", specifier = "==1.56.0" },
|
||||
{ name = "opencontainers", git = "https://github.com/vsoch/oci-python?rev=ceb4fcc090851717a3069d78e85ceb1e86c2740c" },
|
||||
{ name = "packaging", specifier = "==26.2" },
|
||||
{ name = "paramiko", specifier = "==5.0.0" },
|
||||
{ name = "paramiko", specifier = "==4.0.0" },
|
||||
{ name = "psycopg", extras = ["c", "pool"], specifier = "==3.3.4" },
|
||||
{ name = "pydantic", specifier = "==2.13.4" },
|
||||
{ name = "pydantic", specifier = "==2.13.3" },
|
||||
{ name = "pydantic-scim", specifier = "==0.0.8" },
|
||||
{ name = "pyjwt", specifier = "==2.11.0" },
|
||||
{ name = "pyrad", specifier = "==2.5.4" },
|
||||
{ name = "python-kadmin-rs", specifier = "==0.7.2" },
|
||||
{ name = "python-kadmin-rs", specifier = "==0.7.0" },
|
||||
{ name = "pyyaml", specifier = "==6.0.3" },
|
||||
{ name = "requests-oauthlib", specifier = "==2.0.0" },
|
||||
{ name = "scim2-filter-parser", specifier = "==0.7.0" },
|
||||
{ name = "sentry-sdk", specifier = "==2.59.0" },
|
||||
{ name = "sentry-sdk", specifier = "==2.58.0" },
|
||||
{ name = "service-identity", specifier = "==24.2.0" },
|
||||
{ name = "setproctitle", specifier = "==1.3.7" },
|
||||
{ name = "structlog", specifier = "==25.5.0" },
|
||||
{ name = "swagger-spec-validator", specifier = "==3.0.4" },
|
||||
{ name = "twilio", specifier = "==9.10.9" },
|
||||
{ name = "twilio", specifier = "==9.10.5" },
|
||||
{ name = "ua-parser", specifier = "==1.0.2" },
|
||||
{ name = "unidecode", specifier = "==1.4.0" },
|
||||
{ name = "urllib3", specifier = "<3" },
|
||||
@@ -385,7 +385,7 @@ requires-dist = [
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "aws-cdk-lib", specifier = "==2.252.0" },
|
||||
{ name = "aws-cdk-lib", specifier = "==2.251.0" },
|
||||
{ name = "bandit", specifier = "==1.9.4" },
|
||||
{ name = "black", specifier = "==26.3.1" },
|
||||
{ name = "bpython", specifier = "==0.26" },
|
||||
@@ -394,7 +394,7 @@ dev = [
|
||||
{ name = "coverage", extras = ["toml"], specifier = "==7.13.5" },
|
||||
{ name = "daphne", specifier = "==4.2.1" },
|
||||
{ name = "debugpy", specifier = "==1.8.20" },
|
||||
{ name = "django-stubs", extras = ["compatible-mypy"], specifier = "==6.0.4" },
|
||||
{ name = "django-stubs", extras = ["compatible-mypy"], specifier = "==6.0.3" },
|
||||
{ name = "djangorestframework-stubs", extras = ["compatible-mypy"], specifier = "==3.16.9" },
|
||||
{ name = "drf-jsonschema-serializer", specifier = "==3.0.0" },
|
||||
{ name = "freezegun", specifier = "==1.5.5" },
|
||||
@@ -416,7 +416,7 @@ dev = [
|
||||
{ name = "types-docker", specifier = "==7.1.0.20260409" },
|
||||
{ name = "types-jwcrypto", specifier = "==1.5.7.20260409" },
|
||||
{ name = "types-ldap3", specifier = "==2.9.13.20260408" },
|
||||
{ name = "types-requests", specifier = "==2.33.0.20260503" },
|
||||
{ name = "types-requests", specifier = "==2.33.0.20260408" },
|
||||
{ name = "types-zxcvbn", specifier = "==4.5.0.20260408" },
|
||||
]
|
||||
|
||||
@@ -495,7 +495,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-cdk-lib"
|
||||
version = "2.252.0"
|
||||
version = "2.251.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aws-cdk-asset-awscli-v1" },
|
||||
@@ -506,9 +506,9 @@ dependencies = [
|
||||
{ name = "publication" },
|
||||
{ name = "typeguard" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0b/2e/468ed756570af782831bc0518b4f187773b036342ce1b6f3d4e13e6127d8/aws_cdk_lib-2.252.0.tar.gz", hash = "sha256:2498d771ab141599c48494bd2564ee9a4fbaade54befa9356811e9454616d0a0", size = 49479070, upload-time = "2026-04-30T12:31:54.452Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b8/6c/d60d96e1848aabf1882e6a1d30a27de4a592affc9437d6918848f0e06497/aws_cdk_lib-2.251.0.tar.gz", hash = "sha256:ed69e7ea6896c62ac2ce01857083601baf541d5d875370bee6d213d641e8921e", size = 49353237, upload-time = "2026-04-24T23:21:04.805Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/94/32c21ad93dc21554286955fd5ebc68cb91149cc5f7f3154b07927c3fc693/aws_cdk_lib-2.252.0-py3-none-any.whl", hash = "sha256:c96d02582d344ee81ea2ef8a5e22b6e680789973804720ec9f0e95a050257db1", size = 50157828, upload-time = "2026-04-30T12:31:11.041Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/fb/ab682b518e3ca5d18b23b252832e0fade4e6617a2c0f2b0ae0d8d2e74312/aws_cdk_lib-2.251.0-py3-none-any.whl", hash = "sha256:a684f3461d096443ac688adbf559abe1af2d50dd5c8e0fa7dbf4a5f361702db8", size = 50035969, upload-time = "2026-04-24T23:20:18.952Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -688,11 +688,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "cachetools"
|
||||
version = "7.1.1"
|
||||
version = "7.0.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ff/e2/85f227594656000ff4d8adadae91a21f536d4a84c6c716a86bd6685874be/cachetools-7.1.1.tar.gz", hash = "sha256:27bdf856d68fd3c71c26c01b5edc312124ed427524d1ddb31aa2b7746fe20d4b", size = 40202, upload-time = "2026-05-03T20:00:29.391Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/76/7b/1755ed2c6bfabd1d98b37ae73152f8dcf94aa40fee119d163c19ed484704/cachetools-7.0.6.tar.gz", hash = "sha256:e5d524d36d65703a87243a26ff08ad84f73352adbeafb1cde81e207b456aaf24", size = 37526, upload-time = "2026-04-20T19:02:23.289Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/0f/f897abe4ea0a8c408ae65c8c83bffab4936ad65d6032d4fb4cd35bbdc3ee/cachetools-7.1.1-py3-none-any.whl", hash = "sha256:0335cd7a0952d2b22327441fb0628139e234c565559eeb91a8a4ac7551c5353d", size = 16775, upload-time = "2026-05-03T20:00:27.857Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/c4/cf76242a5da1410917107ff14551764aa405a5fd10cd10cf9a5ca8fa77f4/cachetools-7.0.6-py3-none-any.whl", hash = "sha256:4e94956cfdd3086f12042cdd29318f5ced3893014f7d0d059bf3ead3f85b7f8b", size = 13976, upload-time = "2026-04-20T19:02:21.187Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1269,7 +1269,7 @@ s3 = [
|
||||
|
||||
[[package]]
|
||||
name = "django-stubs"
|
||||
version = "6.0.4"
|
||||
version = "6.0.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
@@ -1277,9 +1277,9 @@ dependencies = [
|
||||
{ name = "types-pyyaml" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f9/82/ccf2a2dc9cdb4bd9cbe91f11e887589bf2da7609506db00ccbc73bd8a6da/django_stubs-6.0.4.tar.gz", hash = "sha256:7aee77e8de9c14c0d9cf84988befe826d93cbc15a87e0ade2943f14d553451cf", size = 280019, upload-time = "2026-05-09T21:24:30.436Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/86/0c/8d0d875af79bf774c1c3997c84aa118dba3a77be12086b9c14e130e8ec72/django_stubs-6.0.3.tar.gz", hash = "sha256:ee895f403c373608eeb50822f0733f9d9ec5ab12731d4ab58956053bb95fdd9e", size = 278214, upload-time = "2026-04-18T15:11:22.327Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/e7/5128914ada94dd6277626ef5a4a5680a4def7d2f9366214d26c1cd86723b/django_stubs-6.0.4-py3-none-any.whl", hash = "sha256:e991c68f77239663577a5f4fc75e99c84f867f378cafc97cbf4acc5aff378279", size = 543791, upload-time = "2026-05-09T21:24:28.218Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/a3/6751b7684d20fc4f228bdd3dd8341d382ab3faaf65d3d050c0d59ab0a1b0/django_stubs-6.0.3-py3-none-any.whl", hash = "sha256:5fee22bcbbad59a78c727a820b6f4e68ff442ca76a922b7002e57c25dd7cb390", size = 541570, upload-time = "2026-04-18T15:11:20.711Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -1597,7 +1597,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "google-api-python-client"
|
||||
version = "2.195.0"
|
||||
version = "2.194.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "google-api-core" },
|
||||
@@ -1606,9 +1606,9 @@ dependencies = [
|
||||
{ name = "httplib2" },
|
||||
{ name = "uritemplate" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/69/07/08d759b9cb10f48af14b25262dd0d6685ca8cda6c1f9e8a8109f57457205/google_api_python_client-2.195.0.tar.gz", hash = "sha256:c72cf2661c3addf01c880ce60541e83e1df354644b874f7f9d8d5ed2070446ae", size = 14584819, upload-time = "2026-04-30T21:51:50.638Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/60/ab/e83af0eb043e4ccc49571ca7a6a49984e9d00f4e9e6e6f1238d60bc84dce/google_api_python_client-2.194.0.tar.gz", hash = "sha256:db92647bd1a90f40b79c9618461553c2b20b6a43ce7395fa6de07132dc14f023", size = 14443469, upload-time = "2026-04-08T23:07:35.757Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/21/b9/2c71095e31fff57668fec7c07ac897df065f15521d070e63229e13689590/google_api_python_client-2.195.0-py3-none-any.whl", hash = "sha256:753e62057f23049a89534bea0162b60fe391b85fb86d80bcdf884d05ec91c5bf", size = 15162418, upload-time = "2026-04-30T21:51:47.444Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/34/5a624e49f179aa5b0cb87b2ce8093960299030ff40423bfbde09360eb908/google_api_python_client-2.194.0-py3-none-any.whl", hash = "sha256:61eaaac3b8fc8fdf11c08af87abc3d1342d1b37319cc1b57405f86ef7697e717", size = 15016514, upload-time = "2026-04-08T23:07:33.093Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2589,7 +2589,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "paramiko"
|
||||
version = "5.0.0"
|
||||
version = "4.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "bcrypt" },
|
||||
@@ -2597,9 +2597,9 @@ dependencies = [
|
||||
{ name = "invoke" },
|
||||
{ name = "pynacl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/62/93/dcc25d52f49022ae6175d15e6bd751f1acc99b98bc61fc55e5155a7be2e7/paramiko-5.0.0.tar.gz", hash = "sha256:36763b5b95c2a0dcfdf1abc48e48156ee425b21efe2f0e787c2dd5a95c0e5e79", size = 1548586, upload-time = "2026-05-09T18:28:52.256Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/e7/81fdcbc7f190cdb058cffc9431587eb289833bdd633e2002455ca9bb13d4/paramiko-4.0.0.tar.gz", hash = "sha256:6a25f07b380cc9c9a88d2b920ad37167ac4667f8d9886ccebd8f90f654b5d69f", size = 1630743, upload-time = "2025-08-04T01:02:03.711Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/82/5b/eadf6d45de38d30ab603f49393b6cd2cbe7e233af8cf90197e32782b68a9/paramiko-5.0.0-py3-none-any.whl", hash = "sha256:b7044611c30140d9a75261653210e2002977b71a0497ff3ba0d98d7edbf62f7c", size = 208919, upload-time = "2026-05-09T18:28:50.295Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/90/a744336f5af32c433bd09af7854599682a383b37cfd78f7de263de6ad6cb/paramiko-4.0.0-py3-none-any.whl", hash = "sha256:0e20e00ac666503bf0b4eda3b6d833465a2b7aff2e2b3d79a8bba5ef144ee3b9", size = 223932, upload-time = "2025-08-04T01:02:02.029Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2813,7 +2813,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.13.4"
|
||||
version = "2.13.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-types" },
|
||||
@@ -2821,9 +2821,9 @@ dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/e4/40d09941a2cebcb20609b86a559817d5b9291c49dd6f8c87e5feffbe703a/pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d", size = 844068, upload-time = "2026-04-20T14:46:43.632Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/0a/fd7d723f8f8153418fb40cf9c940e82004fce7e987026b08a68a36dd3fe7/pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927", size = 471981, upload-time = "2026-04-20T14:46:41.402Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -2833,43 +2833,43 @@ email = [
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.46.4"
|
||||
version = "2.46.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2a/ef/f7abb56c49382a246fd2ce9c799691e3c3e7175ec74b14d99e798bcddb1a/pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c", size = 471412, upload-time = "2026-04-20T14:40:56.672Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/db/a7bcb4940183fda36022cd18ba8dd12f2dff40740ec7b58ce7457befa416/pydantic_core-2.46.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:afa3aa644f74e290cdede48a7b0bee37d1c35e71b05105f6b340d484af536d9b", size = 2097614, upload-time = "2026-04-20T14:44:38.374Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/35/e4066358a22e3e99519db370494c7528f5a2aa1367370e80e27e20283543/pydantic_core-2.46.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ced3310e51aa425f7f77da8bbbb5212616655bedbe82c70944320bc1dbe5e018", size = 1951896, upload-time = "2026-04-20T14:40:53.996Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/92/37cf4049d1636996e4b888c05a501f40a43ff218983a551d57f9d5e14f0d/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e29908922ce9da1a30b4da490bd1d3d82c01dcfdf864d2a74aacee674d0bfa34", size = 1979314, upload-time = "2026-04-20T14:41:49.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/36/9ff4d676dfbdfb2d591cf43f3d90ded01e15b1404fd101180ed2d62a2fd3/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c9ff69140423eea8ed2d5477df3ba037f671f5e897d206d921bc9fdc39613e7", size = 2056133, upload-time = "2026-04-20T14:42:23.574Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/f0/405b442a4d7ba855b06eec8b2bf9c617d43b8432d099dfdc7bf999293495/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b675ab0a0d5b1c8fdb81195dc5bcefea3f3c240871cdd7ff9a2de8aa50772eb2", size = 2228726, upload-time = "2026-04-20T14:44:22.816Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/f8/65cd92dd5a0bd89ba277a98ecbfaf6fc36bbd3300973c7a4b826d6ab1391/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0087084960f209a9a4af50ecd1fb063d9ad3658c07bb81a7a53f452dacbfb2ba", size = 2301214, upload-time = "2026-04-20T14:44:48.792Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/86/ef96a4c6e79e7a2d0410826a68fbc0eccc0fd44aa733be199d5fcac3bb87/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed42e6cc8e1b0e2b9b96e2276bad70ae625d10d6d524aed0c93de974ae029f9f", size = 2099927, upload-time = "2026-04-20T14:41:40.196Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/53/269caf30e0096e0a8a8f929d1982a27b3879872cca2d917d17c2f9fdf4fe/pydantic_core-2.46.3-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f1771ce258afb3e4201e67d154edbbae712a76a6081079fe247c2f53c6322c22", size = 2128789, upload-time = "2026-04-20T14:41:15.868Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/b0/1a6d9b6a587e118482910c244a1c5acf4d192604174132efd12bf0ac486f/pydantic_core-2.46.3-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a7610b6a5242a6c736d8ad47fd5fff87fcfe8f833b281b1c409c3d6835d9227f", size = 2173815, upload-time = "2026-04-20T14:44:25.152Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/56/e7e00d4041a7e62b5a40815590114db3b535bf3ca0bf4dca9f16cef25246/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:ff5e7783bcc5476e1db448bf268f11cb257b1c276d3e89f00b5727be86dd0127", size = 2181608, upload-time = "2026-04-20T14:41:28.933Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/22/4bd23c3d41f7c185d60808a1de83c76cf5aeabf792f6c636a55c3b1ec7f9/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:9d2e32edcc143bc01e95300671915d9ca052d4f745aa0a49c48d4803f8a85f2c", size = 2326968, upload-time = "2026-04-20T14:42:03.962Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/ac/66cd45129e3915e5ade3b292cb3bc7fd537f58f8f8dbdaba6170f7cabb74/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d83d1c6b87fa56b521479cff237e626a292f3b31b6345c15a99121b454c1", size = 2369842, upload-time = "2026-04-20T14:41:35.52Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/51/dd4248abb84113615473aa20d5545b7c4cd73c8644003b5259686f93996c/pydantic_core-2.46.3-cp314-cp314-win32.whl", hash = "sha256:07bc6d2a28c3adb4f7c6ae46aa4f2d2929af127f587ed44057af50bf1ce0f505", size = 1959661, upload-time = "2026-04-20T14:41:00.042Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/eb/59980e5f1ae54a3b86372bd9f0fa373ea2d402e8cdcd3459334430f91e91/pydantic_core-2.46.3-cp314-cp314-win_amd64.whl", hash = "sha256:8940562319bc621da30714617e6a7eaa6b98c84e8c685bcdc02d7ed5e7c7c44e", size = 2071686, upload-time = "2026-04-20T14:43:16.471Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/db/1cf77e5247047dfee34bc01fa9bca134854f528c8eb053e144298893d370/pydantic_core-2.46.3-cp314-cp314-win_arm64.whl", hash = "sha256:5dcbbcf4d22210ced8f837c96db941bdb078f419543472aca5d9a0bb7cddc7df", size = 2026907, upload-time = "2026-04-20T14:43:31.732Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/c0/b3df9f6a543276eadba0a48487b082ca1f201745329d97dbfa287034a230/pydantic_core-2.46.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d0fe3dce1e836e418f912c1ad91c73357d03e556a4d286f441bf34fed2dbeecf", size = 2095047, upload-time = "2026-04-20T14:42:37.982Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/57/886a938073b97556c168fd99e1a7305bb363cd30a6d2c76086bf0587b32a/pydantic_core-2.46.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9ce92e58abc722dac1bf835a6798a60b294e48eb0e625ec9fd994b932ac5feee", size = 1934329, upload-time = "2026-04-20T14:43:49.655Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/7c/b42eaa5c34b13b07ecb51da21761297a9b8eb43044c864a035999998f328/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03e6467f0f5ab796a486146d1b887b2dc5e5f9b3288898c1b1c3ad974e53e4a", size = 1974847, upload-time = "2026-04-20T14:42:10.737Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/9b/92b42db6543e7de4f99ae977101a2967b63122d4b6cf7773812da2d7d5b5/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2798b6ba041b9d70acfb9071a2ea13c8456dd1e6a5555798e41ba7b0790e329c", size = 2041742, upload-time = "2026-04-20T14:40:44.262Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/19/46fbe1efabb5aa2834b43b9454e70f9a83ad9c338c1291e48bdc4fecf167/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9be3e221bdc6d69abf294dcf7aff6af19c31a5cdcc8f0aa3b14be29df4bd03b1", size = 2236235, upload-time = "2026-04-20T14:41:27.307Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/da/b3f95bc009ad60ec53120f5d16c6faa8cabdbe8a20d83849a1f2b8728148/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13936129ce841f2a5ddf6f126fea3c43cd128807b5a59588c37cf10178c2e64", size = 2282633, upload-time = "2026-04-20T14:44:33.271Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/6e/401336117722e28f32fb8220df676769d28ebdf08f2f4469646d404c43a3/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b5f2ef03416facccb1c6ef744c69793175fd27e44ef15669201601cf423acb", size = 2109679, upload-time = "2026-04-20T14:44:41.065Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/53/b289f9bc8756a32fe718c46f55afaeaf8d489ee18d1a1e7be1db73f42cc4/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:830d1247d77ad23852314f069e9d7ddafeec5f684baf9d7e7065ed46a049c4e6", size = 2108342, upload-time = "2026-04-20T14:42:50.144Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/5b/8292fc7c1f9111f1b2b7c1b0dcf1179edcd014fc3ea4517499f50b829d71/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0793c90c1a3c74966e7975eaef3ed30ebdff3260a0f815a62a22adc17e4c01c", size = 2157208, upload-time = "2026-04-20T14:42:08.133Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/9e/f80044e9ec07580f057a89fc131f78dda7a58751ddf52bbe05eaf31db50f/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d2d0aead851b66f5245ec0c4fb2612ef457f8bbafefdf65a2bf9d6bac6140f47", size = 2167237, upload-time = "2026-04-20T14:42:25.412Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/84/6781a1b037f3b96be9227edbd1101f6d3946746056231bf4ac48cdff1a8d/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:2f40e4246676beb31c5ce77c38a55ca4e465c6b38d11ea1bd935420568e0b1ab", size = 2312540, upload-time = "2026-04-20T14:40:40.313Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/db/19c0839feeb728e7df03255581f198dfdf1c2aeb1e174a8420b63c5252e5/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:cf489cf8986c543939aeee17a09c04d6ffb43bfef8ca16fcbcc5cfdcbed24dba", size = 2369556, upload-time = "2026-04-20T14:41:09.427Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/15/3228774cb7cd45f5f721ddf1b2242747f4eb834d0c491f0c02d606f09fed/pydantic_core-2.46.3-cp314-cp314t-win32.whl", hash = "sha256:ffe0883b56cfc05798bf994164d2b2ff03efe2d22022a2bb080f3b626176dd56", size = 1949756, upload-time = "2026-04-20T14:41:25.717Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/2a/c79cf53fd91e5a87e30d481809f52f9a60dd221e39de66455cf04deaad37/pydantic_core-2.46.3-cp314-cp314t-win_amd64.whl", hash = "sha256:706d9d0ce9cf4593d07270d8e9f53b161f90c57d315aeec4fb4fd7a8b10240d8", size = 2051305, upload-time = "2026-04-20T14:43:18.627Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/db/d8182a7f1d9343a032265aae186eb063fe26ca4c40f256b21e8da4498e89/pydantic_core-2.46.3-cp314-cp314t-win_arm64.whl", hash = "sha256:77706aeb41df6a76568434701e0917da10692da28cb69d5fb6919ce5fdb07374", size = 2026310, upload-time = "2026-04-20T14:41:01.778Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3083,18 +3083,18 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "python-kadmin-rs"
|
||||
version = "0.7.2"
|
||||
version = "0.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ab/96/f5ed764f06621d1c06b469ec2a24c2da64a0fdb9f13d1c7005c70fd7804d/python_kadmin_rs-0.7.2.tar.gz", hash = "sha256:1f57ab7b61540c420eb684154e56638d42e4bafe2ac66362c2d667cda7d0ce8c", size = 119177, upload-time = "2026-05-11T13:31:19.071Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c6/18/2773570703e5ab13fc0390797685cb6c09b8002d96438c57a8e887cc3234/python_kadmin_rs-0.7.0.tar.gz", hash = "sha256:e8a539fda1a1006fe5f0868c0e59a36b3b90d451da9c0c2bc3a9bfc7173efbdc", size = 112469, upload-time = "2026-01-15T17:49:10.467Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/63/f2/e86b79e1cc8d43c8865f65b5b9c7b06fbfb56e56b812bd279c38faa100cd/python_kadmin_rs-0.7.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:2c77b425805669831e2c4eb316304b9f4690ac27a74cb34e2b92dc0979ab0d3c", size = 512988, upload-time = "2026-05-11T13:31:01.655Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/d6/200dd8ca05bbdf48d77050a0a75c183fca740f2d33e59c8083832514d300/python_kadmin_rs-0.7.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:403c04a395f42d87cbfa46d60f9145841a8b5c6d8ac1f2dab0f457e3e3b7049c", size = 527527, upload-time = "2026-05-11T13:31:03.528Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/03/e9ebb35c7c1441722ced8097c19c1737b1db28c18d9a0c219fe12fe94257/python_kadmin_rs-0.7.2-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:5f1560747e1a936cc9509c87d45180e351096b3be47c8af81a6f3dd4516ca34b", size = 564813, upload-time = "2026-05-11T13:31:05.464Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/d8/c2706859bec76cc629d7665effd6fd540d31b10631d800796269806c86cc/python_kadmin_rs-0.7.2-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:cb51f980597383c4f4adb308e3e4c0c796e5dba560f68b17e4b3cd269c043ae2", size = 562188, upload-time = "2026-05-11T13:31:06.875Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/ad/808be9b2b5a52ff0244e323a4d2ec00b66c21c98e49088399a744da15085/python_kadmin_rs-0.7.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:08fea0f139d5cfdcda24446355578071b8ac02223bb9433077b895df6655cb9e", size = 511783, upload-time = "2026-05-11T13:31:08.291Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/9a/73ab8930b37eafa3a41341c245df6066d38a5b8076cae4f39d7f59eab7bb/python_kadmin_rs-0.7.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:ff124a363e6c8707d738191969e22c08d2cef73b3d6fc0ce86f1dcd81715e170", size = 526356, upload-time = "2026-05-11T13:31:10.137Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/26/acddc2766900537b94e923ecd12c9f4d5ee6a0f551ffe7998826055c8193/python_kadmin_rs-0.7.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:5124b7f27b67d034c6c13ebfbb65c036e197e30bc47c457853489e08d535cb3c", size = 561923, upload-time = "2026-05-11T13:31:11.843Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/4e/42b317789b5e204995431762b7dcede1544581ee5caacebac36d8991f478/python_kadmin_rs-0.7.2-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:0741de2fd55338b356a424899c2cc400314dd57ae2031ed879a2765edfc2f0a1", size = 562006, upload-time = "2026-05-11T13:31:13.206Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/05/94e7575a69ea5d3fc23d4df4a8e4d5acb6f6d3633f23b0a8b6b6360da775/python_kadmin_rs-0.7.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d1418825ba6c161d504b7905a99ef475d5ec1fdf15e6f5b72e4641f350fbc261", size = 510261, upload-time = "2026-01-15T17:48:52.002Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/16/58671c341caef38a492e327cf3e0b24aba2842419da15566f8e3d42c9382/python_kadmin_rs-0.7.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b247bc5f5a075107088cdcec22c67125aa6706fdcd2e264a99a478f1bedecd7d", size = 527751, upload-time = "2026-01-15T17:48:53.504Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/d1/505e34ce204601aae0fcecaf56c66e808803426199948d3a26a6c16a9e5b/python_kadmin_rs-0.7.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:8e6d8ea17a02bb0527219abadac08a63a47f97351f41c79fade77dd11a380795", size = 552634, upload-time = "2026-01-15T17:48:54.96Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/51/391a3d8ee99aeb2466efe499e52ef6a7479d7ac426635d92cd050a5fe3f9/python_kadmin_rs-0.7.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:82107ee5ea3dc1a3b716323687febc64ed2fa462ebd986565fba7394add04792", size = 554659, upload-time = "2026-01-15T17:48:56.408Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/77/6a2fe8a9bef6e3d94f842492db7216c4d0a47c5a67a8a7265c126ed5be58/python_kadmin_rs-0.7.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:ed58ec35dd89a381408fa92f0404d6321f2e6687c58c974f820f113a7052f39f", size = 512638, upload-time = "2026-01-15T17:48:58.519Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/e4/ddd909d4b5ff00a3ed277699f3e2204785367a52088dcb41465b8e01f733/python_kadmin_rs-0.7.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:6a6b63680e10a450e553a84a15216f61af838d86d623caec1fb1c2977907d1ef", size = 530752, upload-time = "2026-01-15T17:49:00.108Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/b2/7d4ea81b768a4ea6be57d9bc70f1841828483a092598b60243a7ad8c798c/python_kadmin_rs-0.7.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e48cdf80bdece9fdcc70d9ef9237821ae9366cf7944742cd412ac2ebd07a40cc", size = 553270, upload-time = "2026-01-15T17:49:01.682Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/b7/87851916c895f31e67a9fe827dabfe3a2f09cf8ecf090cb4ac513f100157/python_kadmin_rs-0.7.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:e63aec5daa1a8469f5b617aa8a5b5a689e2b18241026c7e666ca0f8b5e8688c8", size = 556308, upload-time = "2026-01-15T17:49:03.199Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3332,15 +3332,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "2.59.0"
|
||||
version = "2.58.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "urllib3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/65/e0/9bf5e5fc7442b10880f3ec0eff0ef4208b84a099606f343ec4f5445227fb/sentry_sdk-2.59.0.tar.gz", hash = "sha256:cd265808ef8bf3f3edf69b527c0a0b2b6b1322762679e55b8987db2e9584aec1", size = 447331, upload-time = "2026-05-04T12:19:06.538Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/26/b3/fb8291170d0e844173164709fc0fa0c221ed75a5da740c8746f2a83b4eb1/sentry_sdk-2.58.0.tar.gz", hash = "sha256:c1144d947352d54e5b7daa63596d9f848adf684989c06c4f5a659f0c85a18f6f", size = 438764, upload-time = "2026-04-13T17:23:26.265Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/00/b8cc413748fb6383d1582e7cda51314f99743351c462a92dc690d5b5853b/sentry_sdk-2.59.0-py2.py3-none-any.whl", hash = "sha256:abcf65ee9a9d9cdebf9ad369782408ecca9c1c792686ef06ba34f5ab233527fe", size = 468432, upload-time = "2026-05-04T12:19:04.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/eb/d875669993b762556ae8b2efd86219943b4c0864d22204d622a9aee3052b/sentry_sdk-2.58.0-py2.py3-none-any.whl", hash = "sha256:688d1c704ddecf382ea3326f21a67453d4caa95592d722b7c780a36a9d23109e", size = 460919, upload-time = "2026-04-13T17:23:24.675Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3524,7 +3524,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "twilio"
|
||||
version = "9.10.9"
|
||||
version = "9.10.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
@@ -3532,9 +3532,9 @@ dependencies = [
|
||||
{ name = "pyjwt" },
|
||||
{ name = "requests" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/30/af/275130be4783c6e2b2122d3b278b63da0007611d1dc073d6414adcc6be03/twilio-9.10.9.tar.gz", hash = "sha256:eb74fc026c85a89372836414f57e262119efaa160b9419cf4d05b59056b8e89d", size = 1762839, upload-time = "2026-05-07T17:34:38.162Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b5/97/c439bc2c058f8a24edd732f5cc82adedd8794bcc2da0836c2eff1e2dbe91/twilio-9.10.5.tar.gz", hash = "sha256:d9f93b9280349ee7b52e7f17a0600fd7bfd0f7ff88eb00c40270164bc058743f", size = 1641690, upload-time = "2026-04-14T09:52:09.392Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/6b/df08b499d01ba6b9f7f42f9dd51b82aab1eb26c93602f3b89179a520494f/twilio-9.10.9-py2.py3-none-any.whl", hash = "sha256:1c50bfb394b5dbc044bacab24b2e3b550bee0c08da51c4a1fa4816293303e66c", size = 2452983, upload-time = "2026-05-07T17:34:36.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/97/4fdde5e54fcbb789aa1a70c371f2f33d7eb1e58e8a6131fdbd8a98490976/twilio-9.10.5-py2.py3-none-any.whl", hash = "sha256:7972db54496fbf501b238f34d1f717f80ff22720313dc706632787aad5934997", size = 2284944, upload-time = "2026-04-14T09:52:07.333Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3663,14 +3663,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.33.0.20260503"
|
||||
version = "2.33.0.20260408"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "urllib3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/b8/57e94268c0d82ac3eaa2fc35aa8ca7bbc2542f726b67dcf90b0b00a3b14d/types_requests-2.33.0.20260503.tar.gz", hash = "sha256:9721b2d9dbee7131f2fb39f20f0ebb1999c18cef4b512c9a7932f3722de7c5f4", size = 23931, upload-time = "2026-05-03T05:20:08.882Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/69/6a/749dc53a54a3f35842c1f8197b3ca6b54af6d7458a1bfc75f6629b6da666/types_requests-2.33.0.20260408.tar.gz", hash = "sha256:95b9a86376807a216b2fb412b47617b202091c3ea7c078f47cc358d5528ccb7b", size = 23882, upload-time = "2026-04-08T04:34:49.33Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/82/959113a6351f3ca046cd0a8cd2cee071d7ea47473560557a01eeae9a6fe2/types_requests-2.33.0.20260503-py3-none-any.whl", hash = "sha256:02aaa7e3577a13471715bb1bddb693cc985ea514f754b503bf033e6a09a3e528", size = 20736, upload-time = "2026-05-03T05:20:07.858Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/b8/78fd6c037de4788c040fdd323b3369804400351b7827473920f6c1d03c10/types_requests-2.33.0.20260408-py3-none-any.whl", hash = "sha256:81f31d5ea4acb39f03be7bc8bed569ba6d5a9c5d97e89f45ac43d819b68ca50f", size = 20739, upload-time = "2026-04-08T04:34:48.325Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3791,11 +3791,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.7.0"
|
||||
version = "2.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 2.9 KiB |
@@ -1 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="d" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 3064.87 487.37"><defs><symbol id="a" viewBox="0 0 2865.3 437.72"><g style="isolation:isolate;"><path d="M238.73,125.38h76.4v304.5h-76.4v-32.18c-14.91,14.18-29.87,24.4-44.87,30.65-15,6.25-31.26,9.37-48.78,9.37-39.32,0-73.33-15.25-102.04-45.76C14.35,361.45,0,323.53,0,278.19s13.89-85.54,41.65-115.58c27.77-30.04,61.5-45.06,101.19-45.06,18.26,0,35.4,3.45,51.43,10.35,16.03,6.91,30.84,17.26,44.45,31.07v-33.58ZM158.41,188.07c-23.62,0-43.24,8.35-58.86,25.05-15.62,16.7-23.43,38.11-23.43,64.23s7.95,47.96,23.84,64.93c15.9,16.98,35.47,25.47,58.72,25.47s43.89-8.35,59.69-25.05c15.8-16.7,23.71-38.57,23.71-65.63s-7.9-47.95-23.71-64.37c-15.81-16.42-35.8-24.63-59.97-24.63Z" style="fill:#fd4b2d;"/><path d="M403.16,125.38h77.24v146.65c0,28.55,1.96,48.37,5.89,59.47,3.93,11.1,10.24,19.73,18.94,25.89,8.69,6.16,19.4,9.24,32.12,9.24s23.52-3.03,32.4-9.1c8.88-6.06,15.47-14.97,19.78-26.73,3.18-8.77,4.77-27.52,4.77-56.25V125.38h76.41v129.02c0,53.18-4.2,89.56-12.59,109.15-10.26,23.88-25.38,42.22-45.34,54.99-19.97,12.78-45.34,19.17-76.13,19.17-33.4,0-60.41-7.46-81.02-22.39-20.62-14.92-35.13-35.73-43.52-62.41-5.97-18.47-8.96-52.06-8.96-100.75v-126.78Z" style="fill:#fd4b2d;"/><path d="M796.76,13.15h76.41v112.23h45.34v65.77h-45.34v238.73h-76.41v-238.73h-39.18v-65.77h39.18V13.15Z" style="fill:#fd4b2d;"/><path d="M999.76,7.84h75.85v148.33c14.93-12.88,29.95-22.53,45.06-28.97,15.11-6.44,30.41-9.65,45.9-9.65,30.23,0,55.7,10.45,76.41,31.34,17.73,18.1,26.59,44.69,26.59,79.76v201.23h-75.29v-133.5c0-35.27-1.68-59.15-5.04-71.65-3.36-12.5-9.09-21.83-17.21-27.99-8.12-6.15-18.15-9.23-30.09-9.23-15.49,0-28.78,5.13-39.88,15.39-11.11,10.26-18.8,24.26-23.09,41.98-2.24,9.14-3.36,30.04-3.36,62.69v122.3h-75.85V7.84Z" style="fill:#fd4b2d;"/><path d="M1688.63,299.74h-245.45c3.54,21.65,13.01,38.86,28.41,51.64,15.39,12.78,35.03,19.17,58.91,19.17,28.55,0,53.08-9.98,73.6-29.95l64.37,30.23c-16.05,22.77-35.26,39.6-57.65,50.52-22.39,10.91-48.98,16.37-79.76,16.37-47.77,0-86.67-15.06-116.71-45.2-30.04-30.13-45.06-67.87-45.06-113.21s14.97-85.03,44.92-115.73c29.95-30.69,67.49-46.04,112.65-46.04,47.95,0,86.95,15.35,116.99,46.04,30.04,30.69,45.06,71.23,45.06,121.61l-.28,14.55ZM1612.22,239.57c-5.05-16.98-15-30.79-29.86-41.42-14.86-10.63-32.1-15.95-51.72-15.95-21.3,0-40,5.98-56.07,17.91-10.09,7.47-19.44,20.62-28.03,39.46h165.68Z" style="fill:#fd4b2d;"/><path d="M1790.6,125.38h76.41v31.21c17.33-14.61,33.02-24.77,47.09-30.48,14.06-5.71,28.46-8.57,43.18-8.57,30.18,0,55.8,10.54,76.85,31.62,17.7,17.91,26.55,44.41,26.55,79.48v201.23h-75.57v-133.35c0-36.34-1.63-60.47-4.89-72.4-3.26-11.93-8.93-21.01-17.03-27.26-8.1-6.24-18.1-9.36-30.01-9.36-15.45,0-28.71,5.17-39.78,15.51-11.08,10.35-18.76,24.65-23.04,42.91-2.24,9.5-3.35,30.1-3.35,61.78v122.16h-76.41V125.38Z" style="fill:#fd4b2d;"/><path d="M2183.92,13.15h76.41v112.23h45.34v65.77h-45.34v238.73h-76.41v-238.73h-39.18v-65.77h39.18V13.15Z" style="fill:#fd4b2d;"/><path d="M2416.46,0c13.39,0,24.88,4.85,34.46,14.55,9.58,9.7,14.38,21.46,14.38,35.27s-4.75,25.24-14.24,34.84c-9.49,9.61-20.84,14.41-34.04,14.41s-25.16-4.9-34.75-14.69c-9.58-9.79-14.37-21.69-14.37-35.68s4.74-24.91,14.23-34.43c9.49-9.51,20.93-14.27,34.33-14.27ZM2378.26,125.38h76.41v304.5h-76.41V125.38Z" style="fill:#fd4b2d;"/><path d="M2564.75,7.84h76.41v243.09l112.51-125.54h95.96l-131.17,145.94,146.86,158.56h-94.85l-129.3-140.34v140.34h-76.41V7.84Z" style="fill:#fd4b2d;"/></g></symbol></defs><use width="2865.3" height="437.72" transform="translate(99.78 24.83)" xlink:href="#a"/></svg>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 144.29"><defs><style>.cls-1{fill:#fd4b2d;}</style></defs><path class="cls-1" d="M106,41.08h25.39v101.2H106v-10.7a50,50,0,0,1-14.92,10.19,41.84,41.84,0,0,1-16.21,3.11q-19.61,0-33.91-15.21T26.64,91.86q0-23.43,13.85-38.41t33.63-15a42.78,42.78,0,0,1,17.09,3.44A46.82,46.82,0,0,1,106,52.24ZM79.29,61.91a25.65,25.65,0,0,0-19.56,8.33q-7.78,8.33-7.79,21.34t7.93,21.58a25.66,25.66,0,0,0,19.51,8.47,26.15,26.15,0,0,0,19.84-8.33q7.88-8.33,7.88-21.81,0-13.2-7.88-21.39T79.29,61.91Z"/><path class="cls-1" d="M168.39,41.08h25.67V89.82q0,14.22,2,19.76a17.24,17.24,0,0,0,6.29,8.61A18.06,18.06,0,0,0,213,121.26a18.6,18.6,0,0,0,10.77-3,17.7,17.7,0,0,0,6.57-8.88q1.59-4.36,1.59-18.7V41.08h25.39V84q0,26.51-4.18,36.27a39.6,39.6,0,0,1-15.07,18.28q-10,6.38-25.3,6.37-16.65,0-26.93-7.44T171.36,116.7q-3-9.21-3-33.49Z"/><path class="cls-1" d="M297.3,3.78h25.39v37.3h15.07V62.93H322.69v79.35H297.3V62.93h-13V41.08h13Z"/><path class="cls-1" d="M362.86,2h25.21v49.3a57.74,57.74,0,0,1,15-9.63,38.56,38.56,0,0,1,15.25-3.21,34.36,34.36,0,0,1,25.39,10.42q8.83,9,8.84,26.51v66.88h-25V97.91q0-17.58-1.68-23.81t-5.71-9.3a16.07,16.07,0,0,0-10-3.07,18.85,18.85,0,0,0-13.26,5.11q-5.53,5.11-7.67,14-1.12,4.56-1.12,20.84v40.65H362.86Z"/><path class="cls-1" d="M589.91,99H508.33q1.77,10.78,9.44,17.16t19.58,6.37a33.86,33.86,0,0,0,24.46-10l21.4,10a50.54,50.54,0,0,1-19.16,16.79q-11.16,5.44-26.51,5.44-23.82,0-38.79-15t-15-37.63q0-23.16,14.93-38.46t37.44-15.3q23.91,0,38.88,15.3t15,40.42Zm-25.4-20a25.48,25.48,0,0,0-9.92-13.77A28.81,28.81,0,0,0,537.4,60a30.42,30.42,0,0,0-18.64,5.95q-5,3.72-9.31,13.12Z"/><path class="cls-1" d="M621.89,41.08h25.39V51.45q8.64-7.29,15.65-10.13a37.82,37.82,0,0,1,14.35-2.85A34.77,34.77,0,0,1,702.83,49q8.82,8.94,8.82,26.42v66.88H686.54V98q0-18.12-1.63-24.06a16.44,16.44,0,0,0-5.66-9.06,15.8,15.8,0,0,0-10-3.11,18.73,18.73,0,0,0-13.23,5.15Q650.53,72,648.4,81.14q-1.12,4.74-1.12,20.54v40.6H621.89Z"/><path class="cls-1" d="M750.71,3.78H776.1v37.3h15.07V62.93H776.1v79.35H750.71V62.93h-13V41.08h13Z"/><path class="cls-1" d="M826.09-.6a15.55,15.55,0,0,1,11.45,4.84A16.08,16.08,0,0,1,842.31,16a15.87,15.87,0,0,1-4.72,11.58,15.34,15.34,0,0,1-11.32,4.79,15.6,15.6,0,0,1-11.55-4.88A16.35,16.35,0,0,1,810,15.59a15.57,15.57,0,0,1,4.73-11.44A15.53,15.53,0,0,1,826.09-.6Z"/><rect class="cls-1" x="813.39" y="41.08" width="25.39" height="101.2"/><path class="cls-1" d="M873.47,2h25.39V82.8l37.39-41.72h31.89l-43.59,48.5,48.81,52.7H941.83l-43-46.64v46.64H873.47Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.7 KiB |
@@ -1 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="c" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 1000"><defs><symbol id="a" viewBox="0 0 998.94 763.82"><path d="M829.67,0h-425.28c-93.1,0-169.27,76.17-169.27,169.27v425.28c0,93.1,76.17,169.27,169.27,169.27h50.18v-165.68h324.96v165.68h50.14c93.1,0,169.27-76.17,169.27-169.27V169.27C998.94,76.17,922.77,0,829.67,0ZM755.98,463.53H235.4v-114.49h268.96v-158.97h43.68v94.7h25.61v-94.7h30.88v69.64h25.61v-69.64h30.88v116.35h25.61v-116.35h43.68v158.97h25.69v114.49Z" style="fill:#fd4b2d;"/><g id="b"><path d="M237.36,342.19h-.02c-25.34-34.27-63.32-69.15-105.42-69.15-48.4.03-92.89,26.58-115.91,69.15-48.08,83.85,18.39,196.94,115.91,194.36,75.46,0,137.69-111.95,137.69-131.75,0-8.76-12.18-35.49-32.25-62.61ZM77.32,342.19c27.16-23.43,66.59-30.27,95.1,0h.02c21.51,19.51,40.28,47.91,47.08,62.35-84.6,176.88-232.87,26.13-142.2-62.35Z" style="fill:#fd4b2d;"/></g></symbol></defs><use width="998.94" height="763.82" transform="translate(1 117.03)" xlink:href="#a"/></svg>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000"><defs><style>.cls-1{fill:#fd4b2d;}</style></defs><rect class="cls-1" x="546.66" y="275.34" width="34.99" height="99.97"/><rect class="cls-1" x="637.66" y="271.13" width="34.99" height="78.19"/><path class="cls-1" d="M127.64,385.31a127.57,127.57,0,0,0-112.13,66.9H74.82c26.27-22.67,64.42-29.28,92,0h62.8C205.11,419.06,168.36,385.31,127.64,385.31Z"/><path class="cls-1" d="M212.39,512.53C130.55,683.65-12.89,537.81,74.82,452.21H15.51C-31,533.33,33.3,642.73,127.64,640.24c73,0,133.2-108.3,133.2-127.46,0-8.47-11.78-34.33-31.2-60.57h-62.8C187.65,471.08,205.81,498.56,212.39,512.53Zm2.17-5h0Z"/><path class="cls-1" d="M999.94,274.11V725.89c0,86.58-70.42,157.06-157.05,157.06H776.22V729.12H457.88V883H391.22c-86.64,0-157.06-70.48-157.06-157.06V583.81H738.87V312.11H495.24V464.76H234.16V274.11a151.29,151.29,0,0,1,1.06-18,154.4,154.4,0,0,1,3.88-21.15c.58-2.23,1.23-4.46,1.88-6.64a13.66,13.66,0,0,1,.52-1.64c.36-1.12.71-2.17,1.06-3.23s.76-2.17,1.18-3.23c.47-1.23.88-2.41,1.35-3.58s1-2.35,1.47-3.53a159,159,0,0,1,14.27-26.49c.06-.06.12-.17.17-.23,1.41-2.06,2.88-4.11,4.41-6.17,1.29-1.7,2.58-3.35,3.88-5,1.52-1.82,3.11-3.7,4.69-5.46s3.12-3.47,4.76-5.11l.18-.18a36.53,36.53,0,0,1,2.64-2.64,159.75,159.75,0,0,1,18.68-15.63c1.76-1.29,3.64-2.52,5.52-3.76,2.11-1.35,4.23-2.64,6.4-3.93,4.11-2.41,8.28-4.64,12.63-6.64,1.35-.64,2.76-1.29,4.11-1.88a152.81,152.81,0,0,1,18.38-6.63c2.41-.71,4.82-1.35,7.29-1.94,1.17-.3,2.35-.59,3.58-.82a158.5,158.5,0,0,1,21.26-3.12l3.12-.17c.52,0,1-.06,1.52-.06,2.35-.12,4.76-.18,7.17-.18H842.89c2.4,0,4.81.06,7.16.18.53,0,1,.06,1.53.06l3.11.17A158.26,158.26,0,0,1,876,120.58c1.24.23,2.41.52,3.59.82,2.46.59,4.87,1.23,7.28,1.94A152.81,152.81,0,0,1,905.2,130c1.35.59,2.76,1.24,4.11,1.88,4.35,2,8.52,4.23,12.63,6.64,2.18,1.29,4.29,2.58,6.4,3.93,1.88,1.24,3.76,2.47,5.52,3.76a157.53,157.53,0,0,1,21.5,18.45c1.65,1.64,3.23,3.34,4.76,5.11s3.17,3.64,4.7,5.46c1.29,1.64,2.58,3.29,3.87,5,1.53,2.06,3,4.11,4.41,6.17.06.06.12.17.18.23a159.71,159.71,0,0,1,14.27,26.49c.47,1.18,1,2.35,1.47,3.53s.88,2.35,1.35,3.58c.41,1.06.82,2.11,1.17,3.23s.71,2.11,1.06,3.23a15.74,15.74,0,0,1,.53,1.64c.64,2.18,1.29,4.41,1.88,6.64a155.92,155.92,0,0,1,3.87,21.15A151.29,151.29,0,0,1,999.94,274.11Z"/><path class="cls-1" d="M973.27,186.59H260.84A157.05,157.05,0,0,1,391.2,117.07H842.9A157.08,157.08,0,0,1,973.27,186.59Z"/><path class="cls-1" d="M998.94,256.1H235.16a155.35,155.35,0,0,1,25.68-69.51H973.27A155.34,155.34,0,0,1,998.94,256.1Z"/><path class="cls-1" d="M1000,274.11v51.51H738.87V312.11H495.24v13.51H234.1V274.11a153.41,153.41,0,0,1,1.06-18H998.94A151.29,151.29,0,0,1,1000,274.11Z"/><rect class="cls-1" x="234.1" y="325.62" width="261.13" height="69.54"/><rect class="cls-1" x="738.87" y="325.62" width="261.13" height="69.54"/><rect class="cls-1" x="234.1" y="395.16" width="261.13" height="69.48"/><rect class="cls-1" x="738.87" y="395.16" width="261.13" height="69.48"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
web/icons/icon_christmas.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
web/icons/icon_discord.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -1 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="i" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 3767.3 592.89"><defs><symbol id="a" viewBox="0 0 998.94 763.82"><path d="M829.67,0h-425.28c-93.1,0-169.27,76.17-169.27,169.27v425.28c0,93.1,76.17,169.27,169.27,169.27h50.18v-165.68h324.96v165.68h50.14c93.1,0,169.27-76.17,169.27-169.27V169.27C998.94,76.17,922.77,0,829.67,0ZM755.98,463.53H235.4v-114.49h268.96v-158.97h43.68v94.7h25.61v-94.7h30.88v69.64h25.61v-69.64h30.88v116.35h25.61v-116.35h43.68v158.97h25.69v114.49Z" style="fill:#fd4b2d;"/><g id="b"><path d="M237.36,342.19h-.02c-25.34-34.27-63.32-69.15-105.42-69.15-48.4.03-92.89,26.58-115.91,69.15-48.08,83.85,18.39,196.94,115.91,194.36,75.46,0,137.69-111.95,137.69-131.75,0-8.76-12.18-35.49-32.25-62.61ZM77.32,342.19c27.16-23.43,66.59-30.27,95.1,0h.02c21.51,19.51,40.28,47.91,47.08,62.35-84.6,176.88-232.87,26.13-142.2-62.35Z" style="fill:#fd4b2d;"/></g></symbol><symbol id="c" viewBox="0 0 2865.3 437.72"><g style="isolation:isolate;"><path d="M238.73,125.38h76.4v304.5h-76.4v-32.18c-14.91,14.18-29.87,24.4-44.87,30.65-15,6.25-31.26,9.37-48.78,9.37-39.32,0-73.33-15.25-102.04-45.76C14.35,361.45,0,323.53,0,278.19s13.89-85.54,41.65-115.58c27.77-30.04,61.5-45.06,101.19-45.06,18.26,0,35.4,3.45,51.43,10.35,16.03,6.91,30.84,17.26,44.45,31.07v-33.58ZM158.41,188.07c-23.62,0-43.24,8.35-58.86,25.05-15.62,16.7-23.43,38.11-23.43,64.23s7.95,47.96,23.84,64.93c15.9,16.98,35.47,25.47,58.72,25.47s43.89-8.35,59.69-25.05c15.8-16.7,23.71-38.57,23.71-65.63s-7.9-47.95-23.71-64.37c-15.81-16.42-35.8-24.63-59.97-24.63Z" style="fill:#fd4b2d;"/><path d="M403.16,125.38h77.24v146.65c0,28.55,1.96,48.37,5.89,59.47,3.93,11.1,10.24,19.73,18.94,25.89,8.69,6.16,19.4,9.24,32.12,9.24s23.52-3.03,32.4-9.1c8.88-6.06,15.47-14.97,19.78-26.73,3.18-8.77,4.77-27.52,4.77-56.25V125.38h76.41v129.02c0,53.18-4.2,89.56-12.59,109.15-10.26,23.88-25.38,42.22-45.34,54.99-19.97,12.78-45.34,19.17-76.13,19.17-33.4,0-60.41-7.46-81.02-22.39-20.62-14.92-35.13-35.73-43.52-62.41-5.97-18.47-8.96-52.06-8.96-100.75v-126.78Z" style="fill:#fd4b2d;"/><path d="M796.76,13.15h76.41v112.23h45.34v65.77h-45.34v238.73h-76.41v-238.73h-39.18v-65.77h39.18V13.15Z" style="fill:#fd4b2d;"/><path d="M999.76,7.84h75.85v148.33c14.93-12.88,29.95-22.53,45.06-28.97,15.11-6.44,30.41-9.65,45.9-9.65,30.23,0,55.7,10.45,76.41,31.34,17.73,18.1,26.59,44.69,26.59,79.76v201.23h-75.29v-133.5c0-35.27-1.68-59.15-5.04-71.65-3.36-12.5-9.09-21.83-17.21-27.99-8.12-6.15-18.15-9.23-30.09-9.23-15.49,0-28.78,5.13-39.88,15.39-11.11,10.26-18.8,24.26-23.09,41.98-2.24,9.14-3.36,30.04-3.36,62.69v122.3h-75.85V7.84Z" style="fill:#fd4b2d;"/><path d="M1688.63,299.74h-245.45c3.54,21.65,13.01,38.86,28.41,51.64,15.39,12.78,35.03,19.17,58.91,19.17,28.55,0,53.08-9.98,73.6-29.95l64.37,30.23c-16.05,22.77-35.26,39.6-57.65,50.52-22.39,10.91-48.98,16.37-79.76,16.37-47.77,0-86.67-15.06-116.71-45.2-30.04-30.13-45.06-67.87-45.06-113.21s14.97-85.03,44.92-115.73c29.95-30.69,67.49-46.04,112.65-46.04,47.95,0,86.95,15.35,116.99,46.04,30.04,30.69,45.06,71.23,45.06,121.61l-.28,14.55ZM1612.22,239.57c-5.05-16.98-15-30.79-29.86-41.42-14.86-10.63-32.1-15.95-51.72-15.95-21.3,0-40,5.98-56.07,17.91-10.09,7.47-19.44,20.62-28.03,39.46h165.68Z" style="fill:#fd4b2d;"/><path d="M1790.6,125.38h76.41v31.21c17.33-14.61,33.02-24.77,47.09-30.48,14.06-5.71,28.46-8.57,43.18-8.57,30.18,0,55.8,10.54,76.85,31.62,17.7,17.91,26.55,44.41,26.55,79.48v201.23h-75.57v-133.35c0-36.34-1.63-60.47-4.89-72.4-3.26-11.93-8.93-21.01-17.03-27.26-8.1-6.24-18.1-9.36-30.01-9.36-15.45,0-28.71,5.17-39.78,15.51-11.08,10.35-18.76,24.65-23.04,42.91-2.24,9.5-3.35,30.1-3.35,61.78v122.16h-76.41V125.38Z" style="fill:#fd4b2d;"/><path d="M2183.92,13.15h76.41v112.23h45.34v65.77h-45.34v238.73h-76.41v-238.73h-39.18v-65.77h39.18V13.15Z" style="fill:#fd4b2d;"/><path d="M2416.46,0c13.39,0,24.88,4.85,34.46,14.55,9.58,9.7,14.38,21.46,14.38,35.27s-4.75,25.24-14.24,34.84c-9.49,9.61-20.84,14.41-34.04,14.41s-25.16-4.9-34.75-14.69c-9.58-9.79-14.37-21.69-14.37-35.68s4.74-24.91,14.23-34.43c9.49-9.51,20.93-14.27,34.33-14.27ZM2378.26,125.38h76.41v304.5h-76.41V125.38Z" style="fill:#fd4b2d;"/><path d="M2564.75,7.84h76.41v243.09l112.51-125.54h95.96l-131.17,145.94,146.86,158.56h-94.85l-129.3-140.34v140.34h-76.41V7.84Z" style="fill:#fd4b2d;"/></g></symbol></defs><use width="998.94" height="763.82" transform="translate(28.54 36.14) scale(.68)" xlink:href="#a"/><use width="2865.3" height="437.72" transform="translate(802.22 67.81)" xlink:href="#c"/></svg>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 994.71 151.65"><defs><style>.cls-1{fill:#fd4b2d;}</style></defs><path class="cls-1" d="M284.72,50.4H305.5v82.84H284.72v-8.76a40.79,40.79,0,0,1-12.21,8.34,34.14,34.14,0,0,1-13.27,2.55q-16.05,0-27.76-12.45T219.77,92q0-19.18,11.33-31.45t27.53-12.26a34.94,34.94,0,0,1,14,2.82,38.32,38.32,0,0,1,12.1,8.45ZM262.87,67.45a21,21,0,0,0-16,6.82q-6.37,6.81-6.38,17.47T247,109.4a21,21,0,0,0,16,6.93,21.42,21.42,0,0,0,16.24-6.81q6.45-6.81,6.45-17.86,0-10.8-6.45-17.51A21.71,21.71,0,0,0,262.87,67.45Z"/><path class="cls-1" d="M335.8,50.4h21V90.29q0,11.65,1.6,16.18a14.16,14.16,0,0,0,5.16,7,14.76,14.76,0,0,0,8.74,2.51,15.25,15.25,0,0,0,8.81-2.48,14.49,14.49,0,0,0,5.38-7.27q1.31-3.57,1.3-15.3V50.4h20.79V85.5q0,21.69-3.43,29.69a32.32,32.32,0,0,1-12.33,15q-8.16,5.22-20.71,5.22-13.64,0-22.05-6.09a32.2,32.2,0,0,1-11.84-17q-2.43-7.55-2.43-27.41Z"/><path class="cls-1" d="M441.32,19.86H462.1V50.4h12.34V68.29H462.1v65H441.32V68.29H430.66V50.4h10.66Z"/><path class="cls-1" d="M495,18.42h20.63V58.77a47.41,47.41,0,0,1,12.26-7.88,31.62,31.62,0,0,1,12.49-2.63,28.13,28.13,0,0,1,20.78,8.53q7.23,7.4,7.24,21.7v54.75H547.9V96.92q0-14.4-1.37-19.49a13.6,13.6,0,0,0-4.68-7.62,13.19,13.19,0,0,0-8.18-2.51,15.43,15.43,0,0,0-10.85,4.19,22.14,22.14,0,0,0-6.28,11.42q-.91,3.72-.92,17v33.28H495Z"/><path class="cls-1" d="M680.84,97.83H614.06a22.25,22.25,0,0,0,7.73,14q6.29,5.22,16,5.21a27.7,27.7,0,0,0,20-8.14l17.51,8.22a41.31,41.31,0,0,1-15.68,13.74q-9.13,4.46-21.7,4.46-19.5,0-31.75-12.3T594,92.27q0-19,12.22-31.48t30.65-12.53q19.56,0,31.82,12.53t12.26,33.08ZM660.05,81.46a20.87,20.87,0,0,0-8.12-11.27,23.61,23.61,0,0,0-14.08-4.34,24.88,24.88,0,0,0-15.25,4.88q-4.11,3-7.62,10.73Z"/><path class="cls-1" d="M707,50.4H727.8v8.49a50.15,50.15,0,0,1,12.81-8.3,31.08,31.08,0,0,1,11.75-2.33,28.44,28.44,0,0,1,20.91,8.61q7.22,7.31,7.22,21.62v54.75H759.93V97q0-14.83-1.33-19.7A13.48,13.48,0,0,0,754,69.85a13,13,0,0,0-8.16-2.55A15.32,15.32,0,0,0,735,71.52a22.6,22.6,0,0,0-6.27,11.67q-.9,3.89-.91,16.81v33.24H707Z"/><path class="cls-1" d="M812.46,19.86h20.79V50.4h12.33V68.29H833.25v65H812.46V68.29H801.8V50.4h10.66Z"/><path class="cls-1" d="M874.16,16.29a12.74,12.74,0,0,1,9.38,3.95,13.18,13.18,0,0,1,3.91,9.6,13,13,0,0,1-3.87,9.48,12.6,12.6,0,0,1-9.27,3.92,12.73,12.73,0,0,1-9.45-4A13.39,13.39,0,0,1,861,29.53a12.78,12.78,0,0,1,3.87-9.36A12.71,12.71,0,0,1,874.16,16.29Z"/><rect class="cls-1" x="863.77" y="50.4" width="20.79" height="82.84"/><path class="cls-1" d="M913,18.42h20.78V84.55L964.34,50.4h26.11L954.76,90.1l40,43.14h-25.8L933.73,95.06v38.18H913Z"/><rect class="cls-1" x="107.1" y="34.93" width="6.37" height="18.2"/><rect class="cls-1" x="123.67" y="34.16" width="6.37" height="14.23"/><path class="cls-1" d="M30.83,55A23.23,23.23,0,0,0,10.41,67.13h10.8C26,63,32.94,61.8,38,67.13H49.39C44.93,61.09,38.24,55,30.83,55Z"/><path class="cls-1" d="M46.25,78.11c-14.89,31.15-41,4.6-25-11H10.41c-8.47,14.76,3.24,34.68,20.42,34.23,13.28,0,24.24-19.72,24.24-23.21,0-1.54-2.14-6.25-5.68-11H38A40.52,40.52,0,0,1,46.25,78.11Zm.4-.91Z"/><path class="cls-1" d="M189.62,34.71V117A28.62,28.62,0,0,1,161,145.54H148.89v-28H90.94v28H78.81A28.62,28.62,0,0,1,50.22,117V91.08h91.87V41.62H97.74V69.41H50.22V34.71a27.43,27.43,0,0,1,.19-3.29,27.09,27.09,0,0,1,.71-3.84c.1-.41.22-.82.34-1.21a2.13,2.13,0,0,1,.09-.3c.07-.21.13-.4.2-.59s.14-.4.21-.59.16-.44.25-.65.18-.43.26-.64a29.35,29.35,0,0,1,2.6-4.82l0-.05c.26-.37.53-.75.81-1.12s.47-.61.7-.91.57-.67.86-1,.56-.63.86-.93l0,0a4.53,4.53,0,0,1,.49-.49,29.23,29.23,0,0,1,3.4-2.84c.32-.24.66-.46,1-.68s.77-.49,1.17-.72a23.78,23.78,0,0,1,2.29-1.21l.75-.34a27.84,27.84,0,0,1,3.35-1.21c.44-.13.88-.24,1.33-.35a6.19,6.19,0,0,1,.65-.15,28.86,28.86,0,0,1,3.87-.57l.56,0h.28c.43,0,.87,0,1.31,0H161c.43,0,.87,0,1.3,0h.28l.56,0a29.25,29.25,0,0,1,3.88.57c.22,0,.43.09.65.15.45.11.88.22,1.32.35a27.23,27.23,0,0,1,3.35,1.21l.75.34a25.19,25.19,0,0,1,2.3,1.21c.39.23.78.47,1.16.72s.69.44,1,.68a29.23,29.23,0,0,1,3.91,3.36q.45.45.87.93c.29.32.57.66.85,1l.71.91c.28.37.54.75.8,1.12l0,.05a28.61,28.61,0,0,1,2.6,4.82l.27.64.24.65c.08.19.15.39.22.59l.19.59c0,.09.06.19.1.3.11.39.23.8.34,1.21a28.56,28.56,0,0,1,.7,3.84A27.42,27.42,0,0,1,189.62,34.71Z"/><path class="cls-1" d="M184.76,18.78H55.07A28.59,28.59,0,0,1,78.8,6.12H161A28.59,28.59,0,0,1,184.76,18.78Z"/><path class="cls-1" d="M189.43,31.43H50.4a28.29,28.29,0,0,1,4.67-12.65H184.76A28.17,28.17,0,0,1,189.43,31.43Z"/><path class="cls-1" d="M189.63,34.71v9.37H142.09V41.62H97.74v2.46H50.21V34.71a27.43,27.43,0,0,1,.19-3.29h139A27.42,27.42,0,0,1,189.63,34.71Z"/><rect class="cls-1" x="50.21" y="44.08" width="47.54" height="12.66"/><rect class="cls-1" x="142.09" y="44.08" width="47.54" height="12.66"/><rect class="cls-1" x="50.21" y="56.74" width="47.54" height="12.65"/><rect class="cls-1" x="142.09" y="56.74" width="47.54" height="12.65"/></svg>
|
||||
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 5.0 KiB |
@@ -63,7 +63,7 @@ const LogLevelColors = /** @type {const} */ ({
|
||||
* Creates a logger with the given prefix.
|
||||
*
|
||||
* @param {string} [prefix]
|
||||
* @param {...string[]} args
|
||||
* @param {...string} args
|
||||
* @returns {Logger}
|
||||
*
|
||||
*/
|
||||
|
||||
2058
web/package-lock.json
generated
@@ -97,7 +97,7 @@
|
||||
"@codemirror/theme-one-dark": "^6.1.3",
|
||||
"@eslint/js": "^9.39.3",
|
||||
"@floating-ui/dom": "^1.7.6",
|
||||
"@formatjs/intl-listformat": "^8.3.5",
|
||||
"@formatjs/intl-listformat": "^8.3.4",
|
||||
"@fortawesome/fontawesome-free": "^7.2.0",
|
||||
"@goauthentik/api": "0.0.0",
|
||||
"@goauthentik/core": "^1.0.0",
|
||||
@@ -127,15 +127,14 @@
|
||||
"@types/codemirror": "^5.60.17",
|
||||
"@types/grecaptcha": "^3.0.9",
|
||||
"@types/guacamole-common-js": "^1.5.5",
|
||||
"@types/node": "^25.6.2",
|
||||
"@types/node": "^25.6.0",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.57.2",
|
||||
"@typescript-eslint/parser": "^8.57.2",
|
||||
"@typescript-eslint/utils": "^8.57.2",
|
||||
"@typescript/native-preview": "^7.0.0-dev.20260421.2",
|
||||
"@vitest/browser": "^4.1.6",
|
||||
"@vitest/browser-playwright": "^4.1.6",
|
||||
"@vitest/browser": "^4.1.5",
|
||||
"@vitest/browser-playwright": "^4.0.15",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"change-case": "^5.4.4",
|
||||
@@ -152,28 +151,28 @@
|
||||
"eslint-plugin-lit": "^2.2.1",
|
||||
"eslint-plugin-wc": "^3.1.0",
|
||||
"fuse.js": "^7.3.0",
|
||||
"globals": "^17.6.0",
|
||||
"globals": "^17.5.0",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"hastscript": "^9.0.1",
|
||||
"knip": "^6.11.0",
|
||||
"knip": "^6.9.0",
|
||||
"lex": "^2025.11.0",
|
||||
"lit": "^3.3.2",
|
||||
"lit-analyzer": "^2.0.3",
|
||||
"lit-element": "^4.2.2",
|
||||
"lit-html": "^3.3.2",
|
||||
"md-front-matter": "^1.0.4",
|
||||
"mermaid": "^11.15.0",
|
||||
"mermaid": "^11.14.0",
|
||||
"node-domexception": "^2025.11.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pino": "^10.3.1",
|
||||
"pino-pretty": "^13.1.2",
|
||||
"playwright": "^1.60.0",
|
||||
"playwright": "^1.58.2",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier-plugin-packagejson": "^3.0.2",
|
||||
"pseudolocale": "^2.2.0",
|
||||
"rapidoc": "^9.3.8",
|
||||
"react": "^19.2.6",
|
||||
"react-dom": "^19.2.6",
|
||||
"react": "^19.2.5",
|
||||
"react-dom": "^19.2.5",
|
||||
"rehype-highlight": "^7.0.2",
|
||||
"rehype-mermaid": "^3.0.0",
|
||||
"rehype-parse": "^9.0.1",
|
||||
@@ -184,7 +183,6 @@
|
||||
"remark-mdx-frontmatter": "^5.2.0",
|
||||
"storybook": "^10.2.1",
|
||||
"style-mod": "^4.1.3",
|
||||
"stylelint": "^17.11.0",
|
||||
"trusted-types": "^2.0.0",
|
||||
"ts-pattern": "^5.9.0",
|
||||
"turnstile-types": "^1.2.3",
|
||||
@@ -192,8 +190,8 @@
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.57.2",
|
||||
"unist-util-visit": "^5.1.0",
|
||||
"vite": "^8.0.12",
|
||||
"vitest": "^4.1.6",
|
||||
"vite": "^8.0.10",
|
||||
"vitest": "^4.1.1",
|
||||
"webcomponent-qr-code": "^1.3.0",
|
||||
"wireit": "^0.14.12",
|
||||
"yaml": "^2.8.4"
|
||||
@@ -204,7 +202,8 @@
|
||||
"@esbuild/linux-x64": "^0.28.0",
|
||||
"@rollup/rollup-darwin-arm64": "^4.57.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "^4.57.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "^4.57.1"
|
||||
"@rollup/rollup-linux-x64-gnu": "^4.57.1",
|
||||
"chromedriver": "^147.0.4"
|
||||
},
|
||||
"workspaces": [
|
||||
"./packages/*"
|
||||
@@ -261,7 +260,10 @@
|
||||
"command": "lit-analyzer src"
|
||||
},
|
||||
"lint:types": {
|
||||
"command": "tsgo -p .",
|
||||
"command": "tsc -p .",
|
||||
"env": {
|
||||
"NODE_OPTIONS": "--max_old_space_size=8192"
|
||||
},
|
||||
"dependencies": [
|
||||
"build-locales"
|
||||
]
|
||||
@@ -290,7 +292,10 @@
|
||||
}
|
||||
},
|
||||
"tsc": {
|
||||
"command": "tsgo -p .",
|
||||
"command": "tsc -p .",
|
||||
"env": {
|
||||
"NODE_OPTIONS": "--max_old_space_size=8192"
|
||||
},
|
||||
"dependencies": [
|
||||
"build-locales"
|
||||
]
|
||||
@@ -327,8 +332,7 @@
|
||||
"typescript": "$typescript"
|
||||
},
|
||||
"@mrmarble/djangoql-completion": {
|
||||
"lex": "$lex",
|
||||
"lodash": "^4.18.1"
|
||||
"lex": "$lex"
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"typescript": "$typescript"
|
||||
@@ -336,9 +340,6 @@
|
||||
"@typescript-eslint/parser": {
|
||||
"typescript": "$typescript"
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"typescript": "$typescript"
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"typescript": "$typescript"
|
||||
},
|
||||
@@ -353,9 +354,6 @@
|
||||
},
|
||||
"typescript-eslint": {
|
||||
"typescript": "$typescript"
|
||||
},
|
||||
"wireit": {
|
||||
"brace-expansion": "^1.1.14"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@goauthentik/tsconfig": "^1.0.9",
|
||||
"@types/node": "^25.6.2",
|
||||
"@types/node": "^25.6.0",
|
||||
"@types/semver": "^7.7.1",
|
||||
"semver": "^7.7.4",
|
||||
"typescript": "^6.0.3"
|
||||
|
||||
2
web/packages/lex/index.js
vendored
@@ -25,7 +25,7 @@
|
||||
*
|
||||
* @callback LexerAction
|
||||
* @this {Lexer}
|
||||
* @param {...string[]} match
|
||||
* @param {...string} match
|
||||
* @returns {Token | Token[] | null | void}
|
||||
*/
|
||||
|
||||
|
||||
@@ -87,10 +87,6 @@ export const ROUTES: Route[] = [
|
||||
await import("#admin/policies/reputation/ReputationListPage");
|
||||
return html`<ak-policy-reputation-list></ak-policy-reputation-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/identity/object-attributes$"), async () => {
|
||||
await import("#admin/object-attributes/ObjectAttributeListPage");
|
||||
return html`<ak-object-attribute-list></ak-object-attribute-list>`;
|
||||
}),
|
||||
new Route(new RegExp("^/identity/groups$"), async () => {
|
||||
await import("#admin/groups/GroupListPage");
|
||||
return html`<ak-group-list></ak-group-list>`;
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import "#elements/CodeMirror";
|
||||
import "#elements/forms/HorizontalFormElement";
|
||||
import "#elements/forms/Radio";
|
||||
import "#elements/forms/SearchSelect/index";
|
||||
|
||||
import { DEFAULT_CONFIG } from "#common/api/config";
|
||||
|
||||
import { ObjectAttributeModelForm } from "#admin/object-attributes/renderAttributes";
|
||||
import { ModelForm } from "#elements/forms/ModelForm";
|
||||
|
||||
import { ApplicationEntitlement, CoreApi, ModelEnum } from "@goauthentik/api";
|
||||
import { ApplicationEntitlement, CoreApi } from "@goauthentik/api";
|
||||
|
||||
import YAML from "yaml";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, html, TemplateResult } from "lit";
|
||||
@@ -15,12 +18,7 @@ import { customElement, property } from "lit/decorators.js";
|
||||
import PFContent from "@patternfly/patternfly/components/Content/content.css";
|
||||
|
||||
@customElement("ak-application-entitlement-form")
|
||||
export class ApplicationEntitlementForm extends ObjectAttributeModelForm<
|
||||
ApplicationEntitlement,
|
||||
string
|
||||
> {
|
||||
public model = ModelEnum.AuthentikCoreApplicationentitlement;
|
||||
|
||||
export class ApplicationEntitlementForm extends ModelForm<ApplicationEntitlement, string> {
|
||||
async loadInstance(pk: string): Promise<ApplicationEntitlement> {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsRetrieve({
|
||||
pbmUuid: pk,
|
||||
@@ -63,7 +61,16 @@ export class ApplicationEntitlementForm extends ObjectAttributeModelForm<
|
||||
required
|
||||
/>
|
||||
</ak-form-element-horizontal>
|
||||
${this.renderObjectAttributes(this.objAttributes, this.instance)}`;
|
||||
<ak-form-element-horizontal label=${msg("Attributes")} name="attributes">
|
||||
<ak-codemirror
|
||||
mode="yaml"
|
||||
value="${YAML.stringify(this.instance?.attributes ?? {})}"
|
||||
>
|
||||
</ak-codemirror>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Set custom attributes using YAML or JSON.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,16 +4,10 @@ import "#elements/forms/HorizontalFormElement";
|
||||
import { DEFAULT_CONFIG } from "#common/api/config";
|
||||
import { PFSize } from "#common/enums";
|
||||
|
||||
import { ModelForm } from "#elements/forms/ModelForm";
|
||||
import { WithBrandConfig } from "#elements/mixins/branding";
|
||||
|
||||
import { ObjectAttributeModelForm } from "#admin/object-attributes/renderAttributes";
|
||||
|
||||
import {
|
||||
DeviceAccessGroup,
|
||||
DeviceAccessGroupRequest,
|
||||
EndpointsApi,
|
||||
ModelEnum,
|
||||
} from "@goauthentik/api";
|
||||
import { DeviceAccessGroup, DeviceAccessGroupRequest, EndpointsApi } from "@goauthentik/api";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { html } from "lit";
|
||||
@@ -26,11 +20,7 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
||||
* @prop {string} instancePk - The primary key of the instance to load.
|
||||
*/
|
||||
@customElement("ak-endpoints-device-access-groups-form")
|
||||
export class DeviceAccessGroupForm extends WithBrandConfig(
|
||||
ObjectAttributeModelForm<DeviceAccessGroup, string>,
|
||||
) {
|
||||
public model = ModelEnum.AuthentikEndpointsDeviceaccessgroup;
|
||||
|
||||
export class DeviceAccessGroupForm extends WithBrandConfig(ModelForm<DeviceAccessGroup, string>) {
|
||||
public static override verboseName = msg("Device Access Group");
|
||||
public static override verboseNamePlural = msg("Device Access Groups");
|
||||
|
||||
@@ -63,14 +53,13 @@ export class DeviceAccessGroupForm extends WithBrandConfig(
|
||||
|
||||
protected override renderForm() {
|
||||
return html`<ak-text-input
|
||||
name="name"
|
||||
autocomplete="off"
|
||||
placeholder=${msg("Type a group name...")}
|
||||
label=${msg("Group Name")}
|
||||
value=${ifDefined(this.instance?.name)}
|
||||
required
|
||||
></ak-text-input>
|
||||
${this.renderObjectAttributes(this.objAttributes, this.instance)}`;
|
||||
name="name"
|
||||
autocomplete="off"
|
||||
placeholder=${msg("Type a group name...")}
|
||||
label=${msg("Group Name")}
|
||||
value=${ifDefined(this.instance?.name)}
|
||||
required
|
||||
></ak-text-input>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import "#admin/groups/ak-group-member-table";
|
||||
import "#components/ak-switch-input";
|
||||
import "#components/ak-text-input";
|
||||
import "#elements/CodeMirror";
|
||||
import "#elements/ak-dual-select/ak-dual-select-provider";
|
||||
import "#elements/chips/Chip";
|
||||
import "#elements/chips/ChipGroup";
|
||||
import "#elements/forms/HorizontalFormElement";
|
||||
import "#elements/forms/SearchSelect/index";
|
||||
import "#components/ak-text-input";
|
||||
import "#components/ak-switch-input";
|
||||
|
||||
import { DEFAULT_CONFIG } from "#common/api/config";
|
||||
|
||||
import { DataProvision, DualSelectPair } from "#elements/ak-dual-select/types";
|
||||
import { ModelForm } from "#elements/forms/ModelForm";
|
||||
|
||||
import { ObjectAttributeModelForm } from "#admin/object-attributes/renderAttributes";
|
||||
import { CoreApi, Group, RbacApi, RelatedGroup, Role } from "@goauthentik/api";
|
||||
|
||||
import { CoreApi, Group, ModelEnum, RbacApi, RelatedGroup, Role } from "@goauthentik/api";
|
||||
import YAML from "yaml";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { css, CSSResult, html, TemplateResult } from "lit";
|
||||
@@ -29,8 +30,7 @@ export function rbacRolePair(item: Role): DualSelectPair {
|
||||
}
|
||||
|
||||
@customElement("ak-group-form")
|
||||
export class GroupForm extends ObjectAttributeModelForm<Group, string> {
|
||||
public model = ModelEnum.AuthentikCoreGroup;
|
||||
export class GroupForm extends ModelForm<Group, string> {
|
||||
static styles: CSSResult[] = [
|
||||
...super.styles,
|
||||
css`
|
||||
@@ -144,7 +144,16 @@ export class GroupForm extends ObjectAttributeModelForm<Group, string> {
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
${this.renderObjectAttributes(this.objAttributes, this.instance)}`;
|
||||
<ak-form-element-horizontal label=${msg("Attributes")} name="attributes">
|
||||
<ak-codemirror
|
||||
mode="yaml"
|
||||
value="${YAML.stringify(this.instance?.attributes ?? {})}"
|
||||
>
|
||||
</ak-codemirror>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg("Set custom attributes using YAML or JSON.")}
|
||||
</p>
|
||||
</ak-form-element-horizontal>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||