Compare commits
49 Commits
benchmarks
...
version/20
Author | SHA1 | Date | |
---|---|---|---|
c8072579c8 | |||
378a701fb9 | |||
bba793d94c | |||
53f8699deb | |||
6f3dc2eafd | |||
567ed07fe8 | |||
2999e9d006 | |||
b32a228e3a | |||
5a2dfb23c6 | |||
8ebce479bd | |||
81589e835e | |||
22b1f39b91 | |||
c25e982f1f | |||
d5c09fae8a | |||
bf15e04053 | |||
0932622567 | |||
0a5b8bea5d | |||
64d4a19ccf | |||
82875cfc0e | |||
83776b9f08 | |||
a742331484 | |||
2e9df96a62 | |||
9f5d7089c3 | |||
ddc78cc297 | |||
cb9b3407d8 | |||
d7b872c1e0 | |||
c35217f581 | |||
3b73a2eb9d | |||
3b94ffa705 | |||
936102f6d9 | |||
8c687d81aa | |||
01d7263484 | |||
49ac0eb662 | |||
8935ca65a7 | |||
58a374d1f1 | |||
f409831921 | |||
951acb26dd | |||
2df0c95806 | |||
f8d1b7b9b7 | |||
e092aabb21 | |||
48c59a815d | |||
9f40716a87 | |||
39da241298 | |||
a71a87fa3e | |||
176fe2f6fc | |||
4544f475c9 | |||
5bbf59b2bd | |||
1b2f1db711 | |||
14fab991b4 |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 2024.2.2
|
current_version = 2024.4.0-rc1
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
||||||
@ -21,6 +21,8 @@ optional_value = final
|
|||||||
|
|
||||||
[bumpversion:file:schema.yml]
|
[bumpversion:file:schema.yml]
|
||||||
|
|
||||||
|
[bumpversion:file:blueprints/schema.json]
|
||||||
|
|
||||||
[bumpversion:file:authentik/__init__.py]
|
[bumpversion:file:authentik/__init__.py]
|
||||||
|
|
||||||
[bumpversion:file:internal/constants/constants.go]
|
[bumpversion:file:internal/constants/constants.go]
|
||||||
|
20
SECURITY.md
20
SECURITY.md
@ -18,10 +18,10 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni
|
|||||||
|
|
||||||
(.x being the latest patch release for each version)
|
(.x being the latest patch release for each version)
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| --- | --- |
|
| --------- | --------- |
|
||||||
| 2023.6.x | ✅ |
|
| 2023.10.x | ✅ |
|
||||||
| 2023.8.x | ✅ |
|
| 2024.2.x | ✅ |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
@ -31,12 +31,12 @@ To report a vulnerability, send an email to [security@goauthentik.io](mailto:se
|
|||||||
|
|
||||||
authentik reserves the right to reclassify CVSS as necessary. To determine severity, we will use the CVSS calculator from NVD (https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator). The calculated CVSS score will then be translated into one of the following categories:
|
authentik reserves the right to reclassify CVSS as necessary. To determine severity, we will use the CVSS calculator from NVD (https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator). The calculated CVSS score will then be translated into one of the following categories:
|
||||||
|
|
||||||
| Score | Severity |
|
| Score | Severity |
|
||||||
| --- | --- |
|
| ---------- | -------- |
|
||||||
| 0.0 | None |
|
| 0.0 | None |
|
||||||
| 0.1 – 3.9 | Low |
|
| 0.1 – 3.9 | Low |
|
||||||
| 4.0 – 6.9 | Medium |
|
| 4.0 – 6.9 | Medium |
|
||||||
| 7.0 – 8.9 | High |
|
| 7.0 – 8.9 | High |
|
||||||
| 9.0 – 10.0 | Critical |
|
| 9.0 – 10.0 | Critical |
|
||||||
|
|
||||||
## Disclosure process
|
## Disclosure process
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
||||||
__version__ = "2024.2.2"
|
__version__ = "2024.4.0"
|
||||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 5.0.4 on 2024-04-18 18:56
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_brands", "0005_tenantuuid_to_branduuid"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name="brand",
|
||||||
|
index=models.Index(fields=["domain"], name="authentik_b_domain_b9b24a_idx"),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name="brand",
|
||||||
|
index=models.Index(fields=["default"], name="authentik_b_default_3ccf12_idx"),
|
||||||
|
),
|
||||||
|
]
|
@ -84,3 +84,7 @@ class Brand(SerializerModel):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Brand")
|
verbose_name = _("Brand")
|
||||||
verbose_name_plural = _("Brands")
|
verbose_name_plural = _("Brands")
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["domain"]),
|
||||||
|
models.Index(fields=["default"]),
|
||||||
|
]
|
||||||
|
@ -54,9 +54,6 @@ options.DEFAULT_NAMES = options.DEFAULT_NAMES + (
|
|||||||
# used_by API that allows models to specify if they shadow an object
|
# used_by API that allows models to specify if they shadow an object
|
||||||
# for example the proxy provider which is built on top of an oauth provider
|
# for example the proxy provider which is built on top of an oauth provider
|
||||||
"authentik_used_by_shadows",
|
"authentik_used_by_shadows",
|
||||||
# List fields for which changes are not logged (due to them having dedicated objects)
|
|
||||||
# for example user's password and last_login
|
|
||||||
"authentik_signals_ignored_fields",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -335,14 +332,6 @@ class User(SerializerModel, GuardianUserMixin, AbstractUser):
|
|||||||
models.Index(fields=["path"]),
|
models.Index(fields=["path"]),
|
||||||
models.Index(fields=["type"]),
|
models.Index(fields=["type"]),
|
||||||
]
|
]
|
||||||
authentik_signals_ignored_fields = [
|
|
||||||
# Logged by the events `password_set`
|
|
||||||
# the `password_set` action/signal doesn't currently convey which user
|
|
||||||
# initiated the password change, so for now we'll log two actions
|
|
||||||
# ("password", "password_change_date"),
|
|
||||||
# Logged by `login`
|
|
||||||
("last_login",),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class Provider(SerializerModel):
|
class Provider(SerializerModel):
|
||||||
|
@ -102,9 +102,4 @@ class EnterpriseAuditMiddleware(AuditMiddleware):
|
|||||||
new_state = self.serialize_simple(instance)
|
new_state = self.serialize_simple(instance)
|
||||||
diff = self.diff(prev_state, new_state)
|
diff = self.diff(prev_state, new_state)
|
||||||
thread_kwargs["diff"] = diff
|
thread_kwargs["diff"] = diff
|
||||||
if not created:
|
|
||||||
ignored_field_sets = getattr(instance._meta, "authentik_signals_ignored_fields", [])
|
|
||||||
for field_set in ignored_field_sets:
|
|
||||||
if set(diff.keys()) == set(field_set):
|
|
||||||
return None
|
|
||||||
return super().post_save_handler(request, sender, instance, created, thread_kwargs, **_)
|
return super().post_save_handler(request, sender, instance, created, thread_kwargs, **_)
|
||||||
|
@ -14,7 +14,7 @@ from pathlib import Path
|
|||||||
from sys import argv, stderr
|
from sys import argv, stderr
|
||||||
from time import time
|
from time import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import quote_plus, urlparse
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from django.conf import ImproperlyConfigured
|
from django.conf import ImproperlyConfigured
|
||||||
@ -331,6 +331,26 @@ class ConfigLoader:
|
|||||||
CONFIG = ConfigLoader()
|
CONFIG = ConfigLoader()
|
||||||
|
|
||||||
|
|
||||||
|
def redis_url(db: int) -> str:
|
||||||
|
"""Helper to create a Redis URL for a specific database"""
|
||||||
|
_redis_protocol_prefix = "redis://"
|
||||||
|
_redis_tls_requirements = ""
|
||||||
|
if CONFIG.get_bool("redis.tls", False):
|
||||||
|
_redis_protocol_prefix = "rediss://"
|
||||||
|
_redis_tls_requirements = f"?ssl_cert_reqs={CONFIG.get('redis.tls_reqs')}"
|
||||||
|
if _redis_ca := CONFIG.get("redis.tls_ca_cert", None):
|
||||||
|
_redis_tls_requirements += f"&ssl_ca_certs={_redis_ca}"
|
||||||
|
_redis_url = (
|
||||||
|
f"{_redis_protocol_prefix}"
|
||||||
|
f"{quote_plus(CONFIG.get('redis.username'))}:"
|
||||||
|
f"{quote_plus(CONFIG.get('redis.password'))}@"
|
||||||
|
f"{quote_plus(CONFIG.get('redis.host'))}:"
|
||||||
|
f"{CONFIG.get_int('redis.port')}"
|
||||||
|
f"/{db}{_redis_tls_requirements}"
|
||||||
|
)
|
||||||
|
return _redis_url
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if len(argv) < 2: # noqa: PLR2004
|
if len(argv) < 2: # noqa: PLR2004
|
||||||
print(dumps(CONFIG.raw, indent=4, cls=AttrEncoder))
|
print(dumps(CONFIG.raw, indent=4, cls=AttrEncoder))
|
||||||
|
@ -35,6 +35,7 @@ redis:
|
|||||||
password: ""
|
password: ""
|
||||||
tls: false
|
tls: false
|
||||||
tls_reqs: "none"
|
tls_reqs: "none"
|
||||||
|
tls_ca_cert: null
|
||||||
|
|
||||||
# broker:
|
# broker:
|
||||||
# url: ""
|
# url: ""
|
||||||
@ -58,6 +59,8 @@ remote_debug: false
|
|||||||
|
|
||||||
log_level: info
|
log_level: info
|
||||||
|
|
||||||
|
session_storage: cache
|
||||||
|
|
||||||
error_reporting:
|
error_reporting:
|
||||||
enabled: false
|
enabled: false
|
||||||
sentry_dsn: https://151ba72610234c4c97c5bcff4e1cffd8@authentik.error-reporting.a7k.io/4504163677503489
|
sentry_dsn: https://151ba72610234c4c97c5bcff4e1cffd8@authentik.error-reporting.a7k.io/4504163677503489
|
||||||
|
@ -5,13 +5,13 @@ import os
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from hashlib import sha512
|
from hashlib import sha512
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib.parse import quote_plus
|
|
||||||
|
|
||||||
from celery.schedules import crontab
|
from celery.schedules import crontab
|
||||||
|
from django.conf import ImproperlyConfigured
|
||||||
from sentry_sdk import set_tag
|
from sentry_sdk import set_tag
|
||||||
|
|
||||||
from authentik import ENV_GIT_HASH_KEY, __version__
|
from authentik import ENV_GIT_HASH_KEY, __version__
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG, redis_url
|
||||||
from authentik.lib.logging import get_logger_config, structlog_configure
|
from authentik.lib.logging import get_logger_config, structlog_configure
|
||||||
from authentik.lib.sentry import sentry_init
|
from authentik.lib.sentry import sentry_init
|
||||||
from authentik.lib.utils.reflection import get_env
|
from authentik.lib.utils.reflection import get_env
|
||||||
@ -195,25 +195,15 @@ REST_FRAMEWORK = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_redis_protocol_prefix = "redis://"
|
|
||||||
_redis_celery_tls_requirements = ""
|
|
||||||
if CONFIG.get_bool("redis.tls", False):
|
|
||||||
_redis_protocol_prefix = "rediss://"
|
|
||||||
_redis_celery_tls_requirements = f"?ssl_cert_reqs={CONFIG.get('redis.tls_reqs')}"
|
|
||||||
_redis_url = (
|
|
||||||
f"{_redis_protocol_prefix}"
|
|
||||||
f"{quote_plus(CONFIG.get('redis.username'))}:"
|
|
||||||
f"{quote_plus(CONFIG.get('redis.password'))}@"
|
|
||||||
f"{quote_plus(CONFIG.get('redis.host'))}:"
|
|
||||||
f"{CONFIG.get_int('redis.port')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
CACHES = {
|
CACHES = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "django_redis.cache.RedisCache",
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
"LOCATION": CONFIG.get("cache.url") or f"{_redis_url}/{CONFIG.get('redis.db')}",
|
"LOCATION": CONFIG.get("cache.url") or redis_url(CONFIG.get("redis.db")),
|
||||||
"TIMEOUT": CONFIG.get_int("cache.timeout", 300),
|
"TIMEOUT": CONFIG.get_int("cache.timeout", 300),
|
||||||
"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
|
"OPTIONS": {
|
||||||
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||||
|
},
|
||||||
"KEY_PREFIX": "authentik_cache",
|
"KEY_PREFIX": "authentik_cache",
|
||||||
"KEY_FUNCTION": "django_tenants.cache.make_key",
|
"KEY_FUNCTION": "django_tenants.cache.make_key",
|
||||||
"REVERSE_KEY_FUNCTION": "django_tenants.cache.reverse_key",
|
"REVERSE_KEY_FUNCTION": "django_tenants.cache.reverse_key",
|
||||||
@ -222,7 +212,15 @@ CACHES = {
|
|||||||
DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
||||||
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
|
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
|
||||||
DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
|
DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
|
||||||
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
|
match CONFIG.get("session_storage", "cache"):
|
||||||
|
case "cache":
|
||||||
|
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
|
||||||
|
case "db":
|
||||||
|
SESSION_ENGINE = "django.contrib.sessions.backends.db"
|
||||||
|
case _:
|
||||||
|
raise ImproperlyConfigured(
|
||||||
|
"Invalid session_storage setting, allowed values are db and cache"
|
||||||
|
)
|
||||||
SESSION_SERIALIZER = "authentik.root.sessions.pickle.PickleSerializer"
|
SESSION_SERIALIZER = "authentik.root.sessions.pickle.PickleSerializer"
|
||||||
SESSION_CACHE_ALIAS = "default"
|
SESSION_CACHE_ALIAS = "default"
|
||||||
# Configured via custom SessionMiddleware
|
# Configured via custom SessionMiddleware
|
||||||
@ -276,7 +274,7 @@ CHANNEL_LAYERS = {
|
|||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "channels_redis.pubsub.RedisPubSubChannelLayer",
|
"BACKEND": "channels_redis.pubsub.RedisPubSubChannelLayer",
|
||||||
"CONFIG": {
|
"CONFIG": {
|
||||||
"hosts": [CONFIG.get("channel.url", f"{_redis_url}/{CONFIG.get('redis.db')}")],
|
"hosts": [CONFIG.get("channel.url") or redis_url(CONFIG.get("redis.db"))],
|
||||||
"prefix": "authentik_channels_",
|
"prefix": "authentik_channels_",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -376,11 +374,9 @@ CELERY = {
|
|||||||
"beat_scheduler": "authentik.tenants.scheduler:TenantAwarePersistentScheduler",
|
"beat_scheduler": "authentik.tenants.scheduler:TenantAwarePersistentScheduler",
|
||||||
"task_create_missing_queues": True,
|
"task_create_missing_queues": True,
|
||||||
"task_default_queue": "authentik",
|
"task_default_queue": "authentik",
|
||||||
"broker_url": CONFIG.get("broker.url")
|
"broker_url": CONFIG.get("broker.url") or redis_url(CONFIG.get("redis.db")),
|
||||||
or f"{_redis_url}/{CONFIG.get('redis.db')}{_redis_celery_tls_requirements}",
|
"result_backend": CONFIG.get("result_backend.url") or redis_url(CONFIG.get("redis.db")),
|
||||||
"broker_transport_options": CONFIG.get_dict_from_b64_json("broker.transport_options"),
|
"broker_transport_options": CONFIG.get_dict_from_b64_json("broker.transport_options"),
|
||||||
"result_backend": CONFIG.get("result_backend.url")
|
|
||||||
or f"{_redis_url}/{CONFIG.get('redis.db')}{_redis_celery_tls_requirements}",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Sentry integration
|
# Sentry integration
|
||||||
|
@ -34,7 +34,7 @@ def mock_ad_connection(password: str) -> Connection:
|
|||||||
"objectSid": "unique-test-group",
|
"objectSid": "unique-test-group",
|
||||||
"objectClass": "group",
|
"objectClass": "group",
|
||||||
"distinguishedName": "cn=group1,ou=groups,dc=goauthentik,dc=io",
|
"distinguishedName": "cn=group1,ou=groups,dc=goauthentik,dc=io",
|
||||||
"member": ["cn=user0,ou=users,dc=goauthentik,dc=io"],
|
"member": ["cn=user,ou=users,dc=goauthentik,dc=io"],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
# Group without SID
|
# Group without SID
|
||||||
@ -47,7 +47,7 @@ def mock_ad_connection(password: str) -> Connection:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
connection.strategy.add_entry(
|
connection.strategy.add_entry(
|
||||||
"cn=user0,ou=users,dc=goauthentik,dc=io",
|
"cn=user0,ou=foo,ou=users,dc=goauthentik,dc=io",
|
||||||
{
|
{
|
||||||
"userPassword": password,
|
"userPassword": password,
|
||||||
"sAMAccountName": "user0_sn",
|
"sAMAccountName": "user0_sn",
|
||||||
|
@ -55,7 +55,7 @@ class LDAPSyncTests(TestCase):
|
|||||||
)
|
)
|
||||||
connection.assert_called_with(
|
connection.assert_called_with(
|
||||||
connection_kwargs={
|
connection_kwargs={
|
||||||
"user": "cn=user0,ou=users,dc=goauthentik,dc=io",
|
"user": "cn=user0,ou=foo,ou=users,dc=goauthentik,dc=io",
|
||||||
"password": LDAP_PASSWORD,
|
"password": LDAP_PASSWORD,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -7,7 +7,6 @@ from rest_framework.viewsets import ModelViewSet
|
|||||||
from authentik.core.api.sources import SourceSerializer
|
from authentik.core.api.sources import SourceSerializer
|
||||||
from authentik.core.api.tokens import TokenSerializer
|
from authentik.core.api.tokens import TokenSerializer
|
||||||
from authentik.core.api.used_by import UsedByMixin
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
from authentik.core.models import Token, TokenIntents, User, UserTypes
|
|
||||||
from authentik.sources.scim.models import SCIMSource
|
from authentik.sources.scim.models import SCIMSource
|
||||||
|
|
||||||
|
|
||||||
@ -27,25 +26,6 @@ class SCIMSourceSerializer(SourceSerializer):
|
|||||||
return relative_url
|
return relative_url
|
||||||
return self.context["request"].build_absolute_uri(relative_url)
|
return self.context["request"].build_absolute_uri(relative_url)
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
instance: SCIMSource = super().create(validated_data)
|
|
||||||
identifier = f"ak-source-scim-{instance.pk}"
|
|
||||||
user = User.objects.create(
|
|
||||||
username=identifier,
|
|
||||||
name=f"SCIM Source {instance.name} Service-Account",
|
|
||||||
type=UserTypes.SERVICE_ACCOUNT,
|
|
||||||
)
|
|
||||||
token = Token.objects.create(
|
|
||||||
user=user,
|
|
||||||
identifier=identifier,
|
|
||||||
intent=TokenIntents.INTENT_API,
|
|
||||||
expiring=False,
|
|
||||||
managed=f"goauthentik.io/sources/scim/{instance.pk}",
|
|
||||||
)
|
|
||||||
instance.token = token
|
|
||||||
instance.save()
|
|
||||||
return instance
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = SCIMSource
|
model = SCIMSource
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
"""Authentik SCIM app config"""
|
"""Authentik SCIM app config"""
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from authentik.blueprints.apps import ManagedAppConfig
|
||||||
|
|
||||||
|
|
||||||
class AuthentikSourceSCIMConfig(AppConfig):
|
class AuthentikSourceSCIMConfig(ManagedAppConfig):
|
||||||
"""authentik SCIM Source app config"""
|
"""authentik SCIM Source app config"""
|
||||||
|
|
||||||
name = "authentik.sources.scim"
|
name = "authentik.sources.scim"
|
||||||
label = "authentik_sources_scim"
|
label = "authentik_sources_scim"
|
||||||
verbose_name = "authentik Sources.SCIM"
|
verbose_name = "authentik Sources.SCIM"
|
||||||
mountpoint = "source/scim/"
|
mountpoint = "source/scim/"
|
||||||
|
default = True
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
"""SCIM Source"""
|
"""SCIM Source"""
|
||||||
|
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework.serializers import BaseSerializer
|
from rest_framework.serializers import BaseSerializer
|
||||||
@ -14,6 +16,12 @@ class SCIMSource(Source):
|
|||||||
|
|
||||||
token = models.ForeignKey(Token, on_delete=models.CASCADE, null=True, default=None)
|
token = models.ForeignKey(Token, on_delete=models.CASCADE, null=True, default=None)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_account_identifier(self) -> str:
|
||||||
|
if not self.pk:
|
||||||
|
self.pk = uuid4()
|
||||||
|
return f"ak-source-scim-{self.pk}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def component(self) -> str:
|
def component(self) -> str:
|
||||||
"""Return component used to edit this object"""
|
"""Return component used to edit this object"""
|
||||||
|
38
authentik/sources/scim/signals.py
Normal file
38
authentik/sources/scim/signals.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from django.db.models import Model
|
||||||
|
from django.db.models.signals import pre_delete, pre_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from authentik.core.models import Token, TokenIntents, User, UserTypes
|
||||||
|
from authentik.sources.scim.models import SCIMSource
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(pre_save, sender=SCIMSource)
|
||||||
|
def scim_source_pre_save(sender: type[Model], instance: SCIMSource, **_):
|
||||||
|
"""Create service account before source is saved"""
|
||||||
|
# .service_account_identifier will auto-assign a primary key uuid to the source
|
||||||
|
# if none is set yet, just so we can get the identifier before we save
|
||||||
|
identifier = instance.service_account_identifier
|
||||||
|
user = User.objects.create(
|
||||||
|
username=identifier,
|
||||||
|
name=f"SCIM Source {instance.name} Service-Account",
|
||||||
|
type=UserTypes.INTERNAL_SERVICE_ACCOUNT,
|
||||||
|
)
|
||||||
|
token = Token.objects.create(
|
||||||
|
user=user,
|
||||||
|
identifier=identifier,
|
||||||
|
intent=TokenIntents.INTENT_API,
|
||||||
|
expiring=False,
|
||||||
|
managed=f"goauthentik.io/sources/scim/{instance.pk}",
|
||||||
|
)
|
||||||
|
instance.token = token
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(pre_delete, sender=SCIMSource)
|
||||||
|
def scim_source_pre_delete(sender: type[Model], instance: SCIMSource, **_):
|
||||||
|
"""Delete SCIM Source service account before deleting source"""
|
||||||
|
Token.objects.filter(
|
||||||
|
identifier=instance.service_account_identifier, intent=TokenIntents.INTENT_API
|
||||||
|
).delete()
|
||||||
|
User.objects.filter(
|
||||||
|
username=instance.service_account_identifier, type=UserTypes.INTERNAL_SERVICE_ACCOUNT
|
||||||
|
).delete()
|
@ -14,27 +14,13 @@ class TestSCIMAuth(APITestCase):
|
|||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.user = create_test_admin_user()
|
self.user = create_test_admin_user()
|
||||||
self.token = Token.objects.create(
|
|
||||||
user=self.user,
|
|
||||||
identifier=generate_id(),
|
|
||||||
intent=TokenIntents.INTENT_API,
|
|
||||||
)
|
|
||||||
self.token2 = Token.objects.create(
|
|
||||||
user=self.user,
|
|
||||||
identifier=generate_id(),
|
|
||||||
intent=TokenIntents.INTENT_API,
|
|
||||||
)
|
|
||||||
self.token3 = Token.objects.create(
|
self.token3 = Token.objects.create(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
identifier=generate_id(),
|
identifier=generate_id(),
|
||||||
intent=TokenIntents.INTENT_API,
|
intent=TokenIntents.INTENT_API,
|
||||||
)
|
)
|
||||||
self.source = SCIMSource.objects.create(
|
self.source = SCIMSource.objects.create(name=generate_id(), slug=generate_id())
|
||||||
name=generate_id(), slug=generate_id(), token=self.token
|
self.source2 = SCIMSource.objects.create(name=generate_id(), slug=generate_id())
|
||||||
)
|
|
||||||
self.source2 = SCIMSource.objects.create(
|
|
||||||
name=generate_id(), slug=generate_id(), token=self.token2
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_auth_ok(self):
|
def test_auth_ok(self):
|
||||||
"""Test successful auth"""
|
"""Test successful auth"""
|
||||||
@ -45,7 +31,7 @@ class TestSCIMAuth(APITestCase):
|
|||||||
"source_slug": self.source.slug,
|
"source_slug": self.source.slug,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
@ -71,7 +57,7 @@ class TestSCIMAuth(APITestCase):
|
|||||||
"source_slug": self.source.slug,
|
"source_slug": self.source.slug,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token2.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source2.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
# Token for no source
|
# Token for no source
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
from authentik.core.models import Token, TokenIntents
|
|
||||||
from authentik.core.tests.utils import create_test_admin_user
|
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.sources.scim.models import SCIMSource
|
from authentik.sources.scim.models import SCIMSource
|
||||||
|
|
||||||
@ -13,14 +11,9 @@ class TestSCIMResourceTypes(APITestCase):
|
|||||||
"""Test SCIM ResourceTypes view"""
|
"""Test SCIM ResourceTypes view"""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.user = create_test_admin_user()
|
|
||||||
self.token = Token.objects.create(
|
|
||||||
user=self.user,
|
|
||||||
identifier=generate_id(),
|
|
||||||
intent=TokenIntents.INTENT_API,
|
|
||||||
)
|
|
||||||
self.source = SCIMSource.objects.create(
|
self.source = SCIMSource.objects.create(
|
||||||
name=generate_id(), slug=generate_id(), token=self.token
|
name=generate_id(),
|
||||||
|
slug=generate_id(),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_resource_type(self):
|
def test_resource_type(self):
|
||||||
@ -32,7 +25,7 @@ class TestSCIMResourceTypes(APITestCase):
|
|||||||
"source_slug": self.source.slug,
|
"source_slug": self.source.slug,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
@ -46,7 +39,7 @@ class TestSCIMResourceTypes(APITestCase):
|
|||||||
"resource_type": "ServiceProviderConfig",
|
"resource_type": "ServiceProviderConfig",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
@ -60,6 +53,6 @@ class TestSCIMResourceTypes(APITestCase):
|
|||||||
"resource_type": "foo",
|
"resource_type": "foo",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
from authentik.core.models import Token, TokenIntents
|
|
||||||
from authentik.core.tests.utils import create_test_admin_user
|
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.sources.scim.models import SCIMSource
|
from authentik.sources.scim.models import SCIMSource
|
||||||
|
|
||||||
@ -13,15 +11,7 @@ class TestSCIMSchemas(APITestCase):
|
|||||||
"""Test SCIM Schema view"""
|
"""Test SCIM Schema view"""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.user = create_test_admin_user()
|
self.source = SCIMSource.objects.create(name=generate_id(), slug=generate_id())
|
||||||
self.token = Token.objects.create(
|
|
||||||
user=self.user,
|
|
||||||
identifier=generate_id(),
|
|
||||||
intent=TokenIntents.INTENT_API,
|
|
||||||
)
|
|
||||||
self.source = SCIMSource.objects.create(
|
|
||||||
name=generate_id(), slug=generate_id(), token=self.token
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_schema(self):
|
def test_schema(self):
|
||||||
"""Test full schema view"""
|
"""Test full schema view"""
|
||||||
@ -32,7 +22,7 @@ class TestSCIMSchemas(APITestCase):
|
|||||||
"source_slug": self.source.slug,
|
"source_slug": self.source.slug,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
@ -46,7 +36,7 @@ class TestSCIMSchemas(APITestCase):
|
|||||||
"schema_uri": "urn:ietf:params:scim:schemas:core:2.0:Meta",
|
"schema_uri": "urn:ietf:params:scim:schemas:core:2.0:Meta",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
@ -60,6 +50,6 @@ class TestSCIMSchemas(APITestCase):
|
|||||||
"schema_uri": "foo",
|
"schema_uri": "foo",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
from authentik.core.models import Token, TokenIntents
|
|
||||||
from authentik.core.tests.utils import create_test_admin_user
|
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.sources.scim.models import SCIMSource
|
from authentik.sources.scim.models import SCIMSource
|
||||||
|
|
||||||
@ -13,14 +11,9 @@ class TestSCIMServiceProviderConfig(APITestCase):
|
|||||||
"""Test SCIM ServiceProviderConfig view"""
|
"""Test SCIM ServiceProviderConfig view"""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.user = create_test_admin_user()
|
|
||||||
self.token = Token.objects.create(
|
|
||||||
user=self.user,
|
|
||||||
identifier=generate_id(),
|
|
||||||
intent=TokenIntents.INTENT_API,
|
|
||||||
)
|
|
||||||
self.source = SCIMSource.objects.create(
|
self.source = SCIMSource.objects.create(
|
||||||
name=generate_id(), slug=generate_id(), token=self.token
|
name=generate_id(),
|
||||||
|
slug=generate_id(),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_config(self):
|
def test_config(self):
|
||||||
@ -32,6 +25,6 @@ class TestSCIMServiceProviderConfig(APITestCase):
|
|||||||
"source_slug": self.source.slug,
|
"source_slug": self.source.slug,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
27
authentik/sources/scim/tests/test_signals.py
Normal file
27
authentik/sources/scim/tests/test_signals.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
"""Test SCIM Source creation"""
|
||||||
|
|
||||||
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
|
from authentik.core.models import Token, User
|
||||||
|
from authentik.lib.generators import generate_id
|
||||||
|
from authentik.sources.scim.models import SCIMSource
|
||||||
|
|
||||||
|
|
||||||
|
class TestSCIMSignals(APITestCase):
|
||||||
|
"""Test SCIM Signals view"""
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.uid = generate_id()
|
||||||
|
|
||||||
|
def test_create(self) -> None:
|
||||||
|
source = SCIMSource.objects.create(name=self.uid, slug=self.uid)
|
||||||
|
self.assertIsNotNone(source.token)
|
||||||
|
self.assertIsNotNone(source.token.user)
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
self.test_create()
|
||||||
|
source = SCIMSource.objects.filter(slug=self.uid).first()
|
||||||
|
identifier = source.service_account_identifier
|
||||||
|
source.delete()
|
||||||
|
self.assertFalse(User.objects.filter(username=identifier).exists())
|
||||||
|
self.assertFalse(Token.objects.filter(identifier=identifier).exists())
|
@ -6,8 +6,8 @@ from uuid import uuid4
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
from authentik.core.models import Token, TokenIntents
|
from authentik.core.tests.utils import create_test_user
|
||||||
from authentik.core.tests.utils import create_test_admin_user
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.providers.scim.clients.schema import User as SCIMUserSchema
|
from authentik.providers.scim.clients.schema import User as SCIMUserSchema
|
||||||
from authentik.sources.scim.models import SCIMSource, SCIMSourceUser
|
from authentik.sources.scim.models import SCIMSource, SCIMSourceUser
|
||||||
@ -18,15 +18,7 @@ class TestSCIMUsers(APITestCase):
|
|||||||
"""Test SCIM User view"""
|
"""Test SCIM User view"""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.user = create_test_admin_user()
|
self.source = SCIMSource.objects.create(name=generate_id(), slug=generate_id())
|
||||||
self.token = Token.objects.create(
|
|
||||||
user=self.user,
|
|
||||||
identifier=generate_id(),
|
|
||||||
intent=TokenIntents.INTENT_API,
|
|
||||||
)
|
|
||||||
self.source = SCIMSource.objects.create(
|
|
||||||
name=generate_id(), slug=generate_id(), token=self.token
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_user_list(self):
|
def test_user_list(self):
|
||||||
"""Test full user list"""
|
"""Test full user list"""
|
||||||
@ -37,15 +29,16 @@ class TestSCIMUsers(APITestCase):
|
|||||||
"source_slug": self.source.slug,
|
"source_slug": self.source.slug,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_user_list_single(self):
|
def test_user_list_single(self):
|
||||||
"""Test full user list (single user)"""
|
"""Test full user list (single user)"""
|
||||||
|
user = create_test_user()
|
||||||
SCIMSourceUser.objects.create(
|
SCIMSourceUser.objects.create(
|
||||||
source=self.source,
|
source=self.source,
|
||||||
user=self.user,
|
user=user,
|
||||||
id=str(uuid4()),
|
id=str(uuid4()),
|
||||||
)
|
)
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
@ -53,16 +46,17 @@ class TestSCIMUsers(APITestCase):
|
|||||||
"authentik_sources_scim:v2-users",
|
"authentik_sources_scim:v2-users",
|
||||||
kwargs={
|
kwargs={
|
||||||
"source_slug": self.source.slug,
|
"source_slug": self.source.slug,
|
||||||
"user_id": str(self.user.uuid),
|
"user_id": str(user.uuid),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
SCIMUserSchema.model_validate_json(response.content, strict=True)
|
SCIMUserSchema.model_validate_json(response.content, strict=True)
|
||||||
|
|
||||||
def test_user_create(self):
|
def test_user_create(self):
|
||||||
"""Test user create"""
|
"""Test user create"""
|
||||||
|
user = create_test_user()
|
||||||
ext_id = generate_id()
|
ext_id = generate_id()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse(
|
reverse(
|
||||||
@ -78,13 +72,18 @@ class TestSCIMUsers(APITestCase):
|
|||||||
"emails": [
|
"emails": [
|
||||||
{
|
{
|
||||||
"primary": True,
|
"primary": True,
|
||||||
"value": self.user.email,
|
"value": user.email,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
content_type=SCIM_CONTENT_TYPE,
|
content_type=SCIM_CONTENT_TYPE,
|
||||||
HTTP_AUTHORIZATION=f"Bearer {self.token.key}",
|
HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}",
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, 201)
|
||||||
self.assertTrue(SCIMSourceUser.objects.filter(source=self.source, id=ext_id).exists())
|
self.assertTrue(SCIMSourceUser.objects.filter(source=self.source, id=ext_id).exists())
|
||||||
|
self.assertTrue(
|
||||||
|
Event.objects.filter(
|
||||||
|
action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username
|
||||||
|
).exists()
|
||||||
|
)
|
||||||
|
@ -20,7 +20,10 @@ class WebAuthnDeviceSerializer(ModelSerializer):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WebAuthnDevice
|
model = WebAuthnDevice
|
||||||
fields = ["pk", "name", "created_on", "device_type"]
|
fields = ["pk", "name", "created_on", "device_type", "aaguid"]
|
||||||
|
extra_kwargs = {
|
||||||
|
"aaguid": {"read_only": True},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class WebAuthnDeviceViewSet(
|
class WebAuthnDeviceViewSet(
|
||||||
|
@ -0,0 +1,168 @@
|
|||||||
|
# Generated by Django 5.0.4 on 2024-04-18 11:29
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
replaces = [
|
||||||
|
("authentik_stages_authenticator_webauthn", "0001_initial"),
|
||||||
|
("authentik_stages_authenticator_webauthn", "0002_default_setup_flow"),
|
||||||
|
("authentik_stages_authenticator_webauthn", "0003_webauthndevice_confirmed"),
|
||||||
|
("authentik_stages_authenticator_webauthn", "0004_auto_20210304_1850"),
|
||||||
|
(
|
||||||
|
"authentik_stages_authenticator_webauthn",
|
||||||
|
"0005_authenticatewebauthnstage_user_verification",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"authentik_stages_authenticator_webauthn",
|
||||||
|
"0006_authenticatewebauthnstage_authenticator_attachment_and_more",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"authentik_stages_authenticator_webauthn",
|
||||||
|
"0007_rename_last_used_on_webauthndevice_last_t",
|
||||||
|
),
|
||||||
|
("authentik_stages_authenticator_webauthn", "0008_alter_webauthndevice_credential_id"),
|
||||||
|
("authentik_stages_authenticator_webauthn", "0009_authenticatewebauthnstage_friendly_name"),
|
||||||
|
(
|
||||||
|
"authentik_stages_authenticator_webauthn",
|
||||||
|
"0010_webauthndevicetype_authenticatorwebauthnstage_and_more",
|
||||||
|
),
|
||||||
|
("authentik_stages_authenticator_webauthn", "0011_webauthndevice_aaguid"),
|
||||||
|
]
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_flows", "0016_auto_20201202_1307"),
|
||||||
|
("authentik_flows", "0027_auto_20231028_1424"),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="WebAuthnDeviceType",
|
||||||
|
fields=[
|
||||||
|
("aaguid", models.UUIDField(primary_key=True, serialize=False, unique=True)),
|
||||||
|
("description", models.TextField()),
|
||||||
|
("icon", models.TextField(null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "WebAuthn Device type",
|
||||||
|
"verbose_name_plural": "WebAuthn Device types",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="AuthenticatorWebAuthnStage",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"stage_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="authentik_flows.stage",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"configure_flow",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
help_text="Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage.",
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to="authentik_flows.flow",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_verification",
|
||||||
|
models.TextField(
|
||||||
|
choices=[
|
||||||
|
("required", "Required"),
|
||||||
|
("preferred", "Preferred"),
|
||||||
|
("discouraged", "Discouraged"),
|
||||||
|
],
|
||||||
|
default="preferred",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"authenticator_attachment",
|
||||||
|
models.TextField(
|
||||||
|
choices=[("platform", "Platform"), ("cross-platform", "Cross Platform")],
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"resident_key_requirement",
|
||||||
|
models.TextField(
|
||||||
|
choices=[
|
||||||
|
("discouraged", "Discouraged"),
|
||||||
|
("preferred", "Preferred"),
|
||||||
|
("required", "Required"),
|
||||||
|
],
|
||||||
|
default="preferred",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("friendly_name", models.TextField(null=True)),
|
||||||
|
(
|
||||||
|
"device_type_restrictions",
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True, to="authentik_stages_authenticator_webauthn.webauthndevicetype"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "WebAuthn Authenticator Setup Stage",
|
||||||
|
"verbose_name_plural": "WebAuthn Authenticator Setup Stages",
|
||||||
|
},
|
||||||
|
bases=("authentik_flows.stage", models.Model),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="WebAuthnDevice",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.TextField(max_length=200)),
|
||||||
|
("credential_id", models.TextField(unique=True)),
|
||||||
|
("public_key", models.TextField()),
|
||||||
|
("sign_count", models.IntegerField(default=0)),
|
||||||
|
("rp_id", models.CharField(max_length=253)),
|
||||||
|
("created_on", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("last_t", models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"confirmed",
|
||||||
|
models.BooleanField(default=True, help_text="Is this device ready for use?"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"device_type",
|
||||||
|
models.ForeignKey(
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_DEFAULT,
|
||||||
|
to="authentik_stages_authenticator_webauthn.webauthndevicetype",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("aaguid", models.TextField(default="00000000-0000-0000-0000-000000000000")),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "WebAuthn Device",
|
||||||
|
"verbose_name_plural": "WebAuthn Devices",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 5.0.4 on 2024-04-18 11:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
(
|
||||||
|
"authentik_stages_authenticator_webauthn",
|
||||||
|
"0010_webauthndevicetype_authenticatorwebauthnstage_and_more",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="webauthndevice",
|
||||||
|
name="aaguid",
|
||||||
|
field=models.TextField(default="00000000-0000-0000-0000-000000000000"),
|
||||||
|
),
|
||||||
|
]
|
@ -132,6 +132,7 @@ class WebAuthnDevice(SerializerModel, Device):
|
|||||||
created_on = models.DateTimeField(auto_now_add=True)
|
created_on = models.DateTimeField(auto_now_add=True)
|
||||||
last_t = models.DateTimeField(default=now)
|
last_t = models.DateTimeField(default=now)
|
||||||
|
|
||||||
|
aaguid = models.TextField(default=UNKNOWN_DEVICE_TYPE_AAGUID)
|
||||||
device_type = models.ForeignKey(
|
device_type = models.ForeignKey(
|
||||||
"WebAuthnDeviceType", on_delete=models.SET_DEFAULT, null=True, default=None
|
"WebAuthnDeviceType", on_delete=models.SET_DEFAULT, null=True, default=None
|
||||||
)
|
)
|
||||||
|
@ -126,10 +126,6 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
|||||||
if authenticator_attachment:
|
if authenticator_attachment:
|
||||||
authenticator_attachment = AuthenticatorAttachment(str(authenticator_attachment))
|
authenticator_attachment = AuthenticatorAttachment(str(authenticator_attachment))
|
||||||
|
|
||||||
attestation = AttestationConveyancePreference.DIRECT
|
|
||||||
if stage.device_type_restrictions.exists():
|
|
||||||
attestation = AttestationConveyancePreference.ENTERPRISE
|
|
||||||
|
|
||||||
registration_options: PublicKeyCredentialCreationOptions = generate_registration_options(
|
registration_options: PublicKeyCredentialCreationOptions = generate_registration_options(
|
||||||
rp_id=get_rp_id(self.request),
|
rp_id=get_rp_id(self.request),
|
||||||
rp_name=self.request.brand.branding_title,
|
rp_name=self.request.brand.branding_title,
|
||||||
@ -141,7 +137,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
|||||||
user_verification=UserVerificationRequirement(str(stage.user_verification)),
|
user_verification=UserVerificationRequirement(str(stage.user_verification)),
|
||||||
authenticator_attachment=authenticator_attachment,
|
authenticator_attachment=authenticator_attachment,
|
||||||
),
|
),
|
||||||
attestation=attestation,
|
attestation=AttestationConveyancePreference.DIRECT,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.request.session[SESSION_KEY_WEBAUTHN_CHALLENGE] = registration_options.challenge
|
self.request.session[SESSION_KEY_WEBAUTHN_CHALLENGE] = registration_options.challenge
|
||||||
@ -180,6 +176,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
|||||||
sign_count=webauthn_credential.sign_count,
|
sign_count=webauthn_credential.sign_count,
|
||||||
rp_id=get_rp_id(self.request),
|
rp_id=get_rp_id(self.request),
|
||||||
device_type=device_type,
|
device_type=device_type,
|
||||||
|
aaguid=webauthn_credential.aaguid,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return self.executor.stage_invalid("Device with Credential ID already exists.")
|
return self.executor.stage_invalid("Device with Credential ID already exists.")
|
||||||
|
@ -150,22 +150,26 @@ class PromptChallengeResponse(ChallengeResponse):
|
|||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
def username_field_validator_factory() -> Callable[[PromptChallenge, str], Any]:
|
def username_field_validator_factory() -> Callable[[PromptChallengeResponse, str], Any]:
|
||||||
"""Return a `clean_` method for `field`. Clean method checks if username is taken already."""
|
"""Return a `clean_` method for `field`. Clean method checks if username is taken already."""
|
||||||
|
|
||||||
def username_field_validator(_: PromptChallenge, value: str) -> Any:
|
def username_field_validator(self: PromptChallengeResponse, value: str) -> Any:
|
||||||
"""Check for duplicate usernames"""
|
"""Check for duplicate usernames"""
|
||||||
if User.objects.filter(username=value).exists():
|
pending_user = self.stage.get_pending_user()
|
||||||
|
query = User.objects.all()
|
||||||
|
if pending_user.pk:
|
||||||
|
query = query.exclude(username=pending_user.username)
|
||||||
|
if query.filter(username=value).exists():
|
||||||
raise ValidationError("Username is already taken.")
|
raise ValidationError("Username is already taken.")
|
||||||
return value
|
return value
|
||||||
|
|
||||||
return username_field_validator
|
return username_field_validator
|
||||||
|
|
||||||
|
|
||||||
def password_single_validator_factory() -> Callable[[PromptChallenge, str], Any]:
|
def password_single_validator_factory() -> Callable[[PromptChallengeResponse, str], Any]:
|
||||||
"""Return a `clean_` method for `field`. Clean method checks if username is taken already."""
|
"""Return a `clean_` method for `field`. Clean method checks if username is taken already."""
|
||||||
|
|
||||||
def password_single_clean(self: PromptChallenge, value: str) -> Any:
|
def password_single_clean(self: PromptChallengeResponse, value: str) -> Any:
|
||||||
"""Send password validation signals for e.g. LDAP Source"""
|
"""Send password validation signals for e.g. LDAP Source"""
|
||||||
password_validate.send(sender=self, password=value, plan_context=self.plan.context)
|
password_validate.send(sender=self, password=value, plan_context=self.plan.context)
|
||||||
return value
|
return value
|
||||||
|
@ -9,6 +9,7 @@ from django.utils.translation import gettext as _
|
|||||||
from rest_framework.fields import BooleanField, CharField
|
from rest_framework.fields import BooleanField, CharField
|
||||||
|
|
||||||
from authentik.core.models import AuthenticatedSession, User
|
from authentik.core.models import AuthenticatedSession, User
|
||||||
|
from authentik.events.middleware import audit_ignore
|
||||||
from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge
|
from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, PLAN_CONTEXT_SOURCE
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, PLAN_CONTEXT_SOURCE
|
||||||
from authentik.flows.stage import ChallengeStageView
|
from authentik.flows.stage import ChallengeStageView
|
||||||
@ -95,11 +96,14 @@ class UserLoginStageView(ChallengeStageView):
|
|||||||
self.logger.warning("User is not active, login will not work.")
|
self.logger.warning("User is not active, login will not work.")
|
||||||
delta = self.set_session_duration(remember)
|
delta = self.set_session_duration(remember)
|
||||||
self.set_session_ip()
|
self.set_session_ip()
|
||||||
login(
|
# the `user_logged_in` signal will update the user to write the `last_login` field
|
||||||
self.request,
|
# which we don't want to log as we already have a dedicated login event
|
||||||
user,
|
with audit_ignore():
|
||||||
backend=backend,
|
login(
|
||||||
)
|
self.request,
|
||||||
|
user,
|
||||||
|
backend=backend,
|
||||||
|
)
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
"Logged in",
|
"Logged in",
|
||||||
backend=backend,
|
backend=backend,
|
||||||
|
@ -16,7 +16,7 @@ entries:
|
|||||||
placeholder: Username
|
placeholder: Username
|
||||||
placeholder_expression: false
|
placeholder_expression: false
|
||||||
required: true
|
required: true
|
||||||
type: text
|
type: username
|
||||||
field_key: username
|
field_key: username
|
||||||
label: Username
|
label: Username
|
||||||
identifiers:
|
identifiers:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"$schema": "http://json-schema.org/draft-07/schema",
|
"$schema": "http://json-schema.org/draft-07/schema",
|
||||||
"$id": "https://goauthentik.io/blueprints/schema.json",
|
"$id": "https://goauthentik.io/blueprints/schema.json",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "authentik 2024.2.2 Blueprint schema",
|
"title": "authentik 2024.4.0 Blueprint schema",
|
||||||
"required": [
|
"required": [
|
||||||
"version",
|
"version",
|
||||||
"entries"
|
"entries"
|
||||||
|
@ -11,7 +11,6 @@ entries:
|
|||||||
name: "authentik default LDAP Mapping: DN to User Path"
|
name: "authentik default LDAP Mapping: DN to User Path"
|
||||||
object_field: "path"
|
object_field: "path"
|
||||||
expression: |
|
expression: |
|
||||||
dn = ldap.get("distinguishedName")
|
|
||||||
path_elements = []
|
path_elements = []
|
||||||
for pair in dn.split(","):
|
for pair in dn.split(","):
|
||||||
attr, _, value = pair.partition("=")
|
attr, _, value = pair.partition("=")
|
||||||
|
@ -32,7 +32,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- redis:/data
|
- redis:/data
|
||||||
server:
|
server:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.2.2}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.4.0}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: server
|
command: server
|
||||||
environment:
|
environment:
|
||||||
@ -53,7 +53,7 @@ services:
|
|||||||
- postgresql
|
- postgresql
|
||||||
- redis
|
- redis
|
||||||
worker:
|
worker:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.2.2}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.4.0}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: worker
|
command: worker
|
||||||
environment:
|
environment:
|
||||||
|
10
go.mod
10
go.mod
@ -1,15 +1,13 @@
|
|||||||
module goauthentik.io
|
module goauthentik.io
|
||||||
|
|
||||||
go 1.22
|
go 1.22.2
|
||||||
|
|
||||||
toolchain go1.22.0
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
beryju.io/ldap v0.1.0
|
beryju.io/ldap v0.1.0
|
||||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||||
github.com/getsentry/sentry-go v0.27.0
|
github.com/getsentry/sentry-go v0.27.0
|
||||||
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
||||||
github.com/go-ldap/ldap/v3 v3.4.7
|
github.com/go-ldap/ldap/v3 v3.4.8
|
||||||
github.com/go-openapi/runtime v0.28.0
|
github.com/go-openapi/runtime v0.28.0
|
||||||
github.com/go-openapi/strfmt v0.23.0
|
github.com/go-openapi/strfmt v0.23.0
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
@ -30,7 +28,7 @@ require (
|
|||||||
github.com/spf13/cobra v1.8.0
|
github.com/spf13/cobra v1.8.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/wwt/guac v1.3.2
|
github.com/wwt/guac v1.3.2
|
||||||
goauthentik.io/api/v3 v3.2024022.11
|
goauthentik.io/api/v3 v3.2024023.2
|
||||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||||
golang.org/x/oauth2 v0.19.0
|
golang.org/x/oauth2 v0.19.0
|
||||||
golang.org/x/sync v0.7.0
|
golang.org/x/sync v0.7.0
|
||||||
@ -75,7 +73,7 @@ require (
|
|||||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||||
golang.org/x/crypto v0.21.0 // indirect
|
golang.org/x/crypto v0.21.0 // indirect
|
||||||
golang.org/x/net v0.22.0 // indirect
|
golang.org/x/net v0.23.0 // indirect
|
||||||
golang.org/x/sys v0.18.0 // indirect
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
google.golang.org/protobuf v1.33.0 // indirect
|
google.golang.org/protobuf v1.33.0 // indirect
|
||||||
|
11
go.sum
11
go.sum
@ -84,8 +84,8 @@ github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 h1:O6yi4xa9b2D
|
|||||||
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27/go.mod h1:AYvN8omj7nKLmbcXS2dyABYU6JB1Lz1bHmkkq1kf4I4=
|
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27/go.mod h1:AYvN8omj7nKLmbcXS2dyABYU6JB1Lz1bHmkkq1kf4I4=
|
||||||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno=
|
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno=
|
||||||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw=
|
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.7 h1:3Hbd7mIB1qjd3Ra59fI3JYea/t5kykFu2CVHBca9koE=
|
github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.7/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk=
|
github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
@ -294,8 +294,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
|
|||||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||||
goauthentik.io/api/v3 v3.2024022.11 h1:MlsaBwyMM9NtDvZcoaWvuNznPHXA0a5olnDLyr24REA=
|
goauthentik.io/api/v3 v3.2024023.2 h1:lSVaZAKTpsDhtw11wnkGjPalkDzv9H2VKEJllBi2aXs=
|
||||||
goauthentik.io/api/v3 v3.2024022.11/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
goauthentik.io/api/v3 v3.2024023.2/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@ -373,8 +373,9 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
|
||||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
|
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||||
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -25,13 +25,14 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RedisConfig struct {
|
type RedisConfig struct {
|
||||||
Host string `yaml:"host" env:"HOST, overwrite"`
|
Host string `yaml:"host" env:"HOST, overwrite"`
|
||||||
Port int `yaml:"port" env:"PORT, overwrite"`
|
Port int `yaml:"port" env:"PORT, overwrite"`
|
||||||
DB int `yaml:"db" env:"DB, overwrite"`
|
DB int `yaml:"db" env:"DB, overwrite"`
|
||||||
Username string `yaml:"username" env:"USERNAME, overwrite"`
|
Username string `yaml:"username" env:"USERNAME, overwrite"`
|
||||||
Password string `yaml:"password" env:"PASSWORD, overwrite"`
|
Password string `yaml:"password" env:"PASSWORD, overwrite"`
|
||||||
TLS bool `yaml:"tls" env:"TLS, overwrite"`
|
TLS bool `yaml:"tls" env:"TLS, overwrite"`
|
||||||
TLSReqs string `yaml:"tls_reqs" env:"TLS_REQS, overwrite"`
|
TLSReqs string `yaml:"tls_reqs" env:"TLS_REQS, overwrite"`
|
||||||
|
TLSCaCert *string `yaml:"tls_ca_certs" env:"TLS_CA_CERT, overwrite"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListenConfig struct {
|
type ListenConfig struct {
|
||||||
|
@ -29,4 +29,4 @@ func UserAgent() string {
|
|||||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSION = "2024.2.2"
|
const VERSION = "2024.4.0"
|
||||||
|
@ -2,6 +2,8 @@ package application
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -19,6 +21,7 @@ import (
|
|||||||
"goauthentik.io/internal/outpost/proxyv2/codecs"
|
"goauthentik.io/internal/outpost/proxyv2/codecs"
|
||||||
"goauthentik.io/internal/outpost/proxyv2/constants"
|
"goauthentik.io/internal/outpost/proxyv2/constants"
|
||||||
"goauthentik.io/internal/outpost/proxyv2/redisstore"
|
"goauthentik.io/internal/outpost/proxyv2/redisstore"
|
||||||
|
"goauthentik.io/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const RedisKeyPrefix = "authentik_proxy_session_"
|
const RedisKeyPrefix = "authentik_proxy_session_"
|
||||||
@ -31,11 +34,40 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL)
|
|||||||
maxAge = int(*t) + 1
|
maxAge = int(*t) + 1
|
||||||
}
|
}
|
||||||
if a.isEmbedded {
|
if a.isEmbedded {
|
||||||
|
var tls *tls.Config
|
||||||
|
if config.Get().Redis.TLS {
|
||||||
|
tls = utils.GetTLSConfig()
|
||||||
|
switch strings.ToLower(config.Get().Redis.TLSReqs) {
|
||||||
|
case "none":
|
||||||
|
case "false":
|
||||||
|
tls.InsecureSkipVerify = true
|
||||||
|
case "required":
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ca := config.Get().Redis.TLSCaCert
|
||||||
|
if ca != nil {
|
||||||
|
// Get the SystemCertPool, continue with an empty pool on error
|
||||||
|
rootCAs, _ := x509.SystemCertPool()
|
||||||
|
if rootCAs == nil {
|
||||||
|
rootCAs = x509.NewCertPool()
|
||||||
|
}
|
||||||
|
certs, err := os.ReadFile(*ca)
|
||||||
|
if err != nil {
|
||||||
|
a.log.WithError(err).Fatalf("Failed to append %s to RootCAs", *ca)
|
||||||
|
}
|
||||||
|
// Append our cert to the system pool
|
||||||
|
if ok := rootCAs.AppendCertsFromPEM(certs); !ok {
|
||||||
|
a.log.Println("No certs appended, using system certs only")
|
||||||
|
}
|
||||||
|
tls.RootCAs = rootCAs
|
||||||
|
}
|
||||||
|
}
|
||||||
client := redis.NewClient(&redis.Options{
|
client := redis.NewClient(&redis.Options{
|
||||||
Addr: fmt.Sprintf("%s:%d", config.Get().Redis.Host, config.Get().Redis.Port),
|
Addr: fmt.Sprintf("%s:%d", config.Get().Redis.Host, config.Get().Redis.Port),
|
||||||
Username: config.Get().Redis.Username,
|
Username: config.Get().Redis.Username,
|
||||||
Password: config.Get().Redis.Password,
|
Password: config.Get().Redis.Password,
|
||||||
DB: config.Get().Redis.DB,
|
DB: config.Get().Redis.DB,
|
||||||
|
TLSConfig: tls,
|
||||||
})
|
})
|
||||||
|
|
||||||
// New default RedisStore
|
// New default RedisStore
|
||||||
|
@ -54,7 +54,7 @@ function cleanup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function prepare_debug {
|
function prepare_debug {
|
||||||
poetry install --no-ansi --no-interaction
|
VIRTUAL_ENV=/ak-root/venv poetry install --no-ansi --no-interaction
|
||||||
touch /unittest.xml
|
touch /unittest.xml
|
||||||
chown authentik:authentik /unittest.xml
|
chown authentik:authentik /unittest.xml
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ from psycopg import OperationalError, connect
|
|||||||
from redis import Redis
|
from redis import Redis
|
||||||
from redis.exceptions import RedisError
|
from redis.exceptions import RedisError
|
||||||
|
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG, redis_url
|
||||||
|
|
||||||
|
|
||||||
def check_postgres():
|
def check_postgres():
|
||||||
@ -35,24 +35,18 @@ def check_postgres():
|
|||||||
|
|
||||||
|
|
||||||
def check_redis():
|
def check_redis():
|
||||||
REDIS_PROTOCOL_PREFIX = "redis://"
|
url = redis_url(CONFIG.get("redis.db"))
|
||||||
if CONFIG.get_bool("redis.tls", False):
|
|
||||||
REDIS_PROTOCOL_PREFIX = "rediss://"
|
|
||||||
REDIS_URL = (
|
|
||||||
f"{REDIS_PROTOCOL_PREFIX}"
|
|
||||||
f"{quote_plus(CONFIG.get('redis.username'))}:"
|
|
||||||
f"{quote_plus(CONFIG.get('redis.password'))}@"
|
|
||||||
f"{quote_plus(CONFIG.get('redis.host'))}:"
|
|
||||||
f"{CONFIG.get_int('redis.port')}/{CONFIG.get('redis.db')}"
|
|
||||||
)
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
redis = Redis.from_url(REDIS_URL)
|
redis = Redis.from_url(url)
|
||||||
redis.ping()
|
redis.ping()
|
||||||
break
|
break
|
||||||
except RedisError as exc:
|
except RedisError as exc:
|
||||||
sleep(1)
|
sleep(1)
|
||||||
CONFIG.log("info", f"Redis Connection failed, retrying... ({exc})", redis_url=REDIS_URL)
|
sanitized_url = url.replace(quote_plus(CONFIG.get("redis.password")), "******")
|
||||||
|
CONFIG.log(
|
||||||
|
"info", f"Redis Connection failed, retrying... ({exc})", redis_url=sanitized_url
|
||||||
|
)
|
||||||
CONFIG.log("info", "Redis Connection successful")
|
CONFIG.log("info", "Redis Connection successful")
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-05 00:07+0000\n"
|
"POT-Creation-Date: 2024-04-16 00:07+0000\n"
|
||||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||||
"Last-Translator: Marc Schmitt, 2024\n"
|
"Last-Translator: Marc Schmitt, 2024\n"
|
||||||
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
|
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
|
||||||
@ -138,6 +138,14 @@ msgstr "Group"
|
|||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
msgstr "Groupes"
|
msgstr "Groupes"
|
||||||
|
|
||||||
|
#: authentik/core/models.py
|
||||||
|
msgid "Add user to group"
|
||||||
|
msgstr "Ajouter un utilisateur au groupe"
|
||||||
|
|
||||||
|
#: authentik/core/models.py
|
||||||
|
msgid "Remove user from group"
|
||||||
|
msgstr "Retirer l'utilisateur du groupe"
|
||||||
|
|
||||||
#: authentik/core/models.py
|
#: authentik/core/models.py
|
||||||
msgid "User's display name."
|
msgid "User's display name."
|
||||||
msgstr "Nom d'affichage de l'utilisateur"
|
msgstr "Nom d'affichage de l'utilisateur"
|
||||||
@ -505,6 +513,22 @@ msgstr "Limite maximum de connection atteinte."
|
|||||||
msgid "(You are already connected in another tab/window)"
|
msgid "(You are already connected in another tab/window)"
|
||||||
msgstr "(Vous êtes déjà connecté dans un autre onglet/une autre fenêtre)"
|
msgstr "(Vous êtes déjà connecté dans un autre onglet/une autre fenêtre)"
|
||||||
|
|
||||||
|
#: authentik/enterprise/stages/source/models.py
|
||||||
|
msgid ""
|
||||||
|
"Amount of time a user can take to return from the source to continue the "
|
||||||
|
"flow (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||||
|
msgstr ""
|
||||||
|
"Durée que l'utilisateur peut prendre pour revenir de la source pour "
|
||||||
|
"continuer le flux (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||||
|
|
||||||
|
#: authentik/enterprise/stages/source/models.py
|
||||||
|
msgid "Source Stage"
|
||||||
|
msgstr "Étape Source"
|
||||||
|
|
||||||
|
#: authentik/enterprise/stages/source/models.py
|
||||||
|
msgid "Source Stages"
|
||||||
|
msgstr "Étapes Source"
|
||||||
|
|
||||||
#: authentik/events/api/tasks.py
|
#: authentik/events/api/tasks.py
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Successfully started task {name}."
|
msgid "Successfully started task {name}."
|
||||||
@ -1944,6 +1968,12 @@ msgstr "Les objets appliqués à ce filtre seront des groupes."
|
|||||||
msgid "Field which contains a unique Identifier."
|
msgid "Field which contains a unique Identifier."
|
||||||
msgstr "Champ qui contient un identifiant unique."
|
msgstr "Champ qui contient un identifiant unique."
|
||||||
|
|
||||||
|
#: authentik/sources/ldap/models.py
|
||||||
|
msgid "Update internal authentik password when login succeeds with LDAP"
|
||||||
|
msgstr ""
|
||||||
|
"Mettre à jour le mot de passe interne à authentik lorsque la connexion avec "
|
||||||
|
"LDAP réussi"
|
||||||
|
|
||||||
#: authentik/sources/ldap/models.py
|
#: authentik/sources/ldap/models.py
|
||||||
msgid ""
|
msgid ""
|
||||||
"When a user changes their password, sync it back to LDAP. This can only be "
|
"When a user changes their password, sync it back to LDAP. This can only be "
|
||||||
@ -2282,6 +2312,14 @@ msgstr "Connexion de l'utilisateur à la source SAML"
|
|||||||
msgid "User SAML Source Connections"
|
msgid "User SAML Source Connections"
|
||||||
msgstr "Connexion de l'utilisateur aux sources SAML"
|
msgstr "Connexion de l'utilisateur aux sources SAML"
|
||||||
|
|
||||||
|
#: authentik/sources/scim/models.py
|
||||||
|
msgid "SCIM Source"
|
||||||
|
msgstr "Source SCIM"
|
||||||
|
|
||||||
|
#: authentik/sources/scim/models.py
|
||||||
|
msgid "SCIM Sources"
|
||||||
|
msgstr "Sources SCIM"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_duo/models.py
|
#: authentik/stages/authenticator_duo/models.py
|
||||||
msgid "Duo Authenticator Setup Stage"
|
msgid "Duo Authenticator Setup Stage"
|
||||||
msgstr "Étape de configuration du Duo Authenticator"
|
msgstr "Étape de configuration du Duo Authenticator"
|
||||||
@ -2395,8 +2433,20 @@ msgid "TOTP Devices"
|
|||||||
msgstr "Équipements TOTP"
|
msgstr "Équipements TOTP"
|
||||||
|
|
||||||
#: authentik/stages/authenticator_validate/challenge.py
|
#: authentik/stages/authenticator_validate/challenge.py
|
||||||
msgid "Invalid Token"
|
msgid ""
|
||||||
msgstr "Jeton Invalide"
|
"Invalid Token. Please ensure the time on your device is accurate and try "
|
||||||
|
"again."
|
||||||
|
msgstr ""
|
||||||
|
"Jeton invalide. Merci de vous assurer que le temps défini sur votre appareil"
|
||||||
|
" est juste et de réessayer,"
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_validate/challenge.py
|
||||||
|
#: authentik/stages/authenticator_webauthn/stage.py
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Invalid device type. Contact your {brand} administrator for help."
|
||||||
|
msgstr ""
|
||||||
|
"Type d'appareil invalide. Merci de contacter l'administrateur de {brand} "
|
||||||
|
"pour de l'assistance."
|
||||||
|
|
||||||
#: authentik/stages/authenticator_validate/models.py
|
#: authentik/stages/authenticator_validate/models.py
|
||||||
msgid "Static"
|
msgid "Static"
|
||||||
@ -2452,6 +2502,10 @@ msgstr "Étape de validation de l'authentificateur"
|
|||||||
msgid "Authenticator Validation Stages"
|
msgid "Authenticator Validation Stages"
|
||||||
msgstr "Étapes de validation de l'authentificateur"
|
msgstr "Étapes de validation de l'authentificateur"
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_validate/stage.py
|
||||||
|
msgid "No (allowed) MFA authenticator configured."
|
||||||
|
msgstr "Pas d'authentificateur MFA (autorisé) configuré."
|
||||||
|
|
||||||
#: authentik/stages/authenticator_webauthn/models.py
|
#: authentik/stages/authenticator_webauthn/models.py
|
||||||
msgid "WebAuthn Authenticator Setup Stage"
|
msgid "WebAuthn Authenticator Setup Stage"
|
||||||
msgstr "Étape de validation de l'authentificateur WebAuthn"
|
msgstr "Étape de validation de l'authentificateur WebAuthn"
|
||||||
@ -2468,6 +2522,14 @@ msgstr "Appareil WebAuthn"
|
|||||||
msgid "WebAuthn Devices"
|
msgid "WebAuthn Devices"
|
||||||
msgstr "Équipements WebAuthn"
|
msgstr "Équipements WebAuthn"
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_webauthn/models.py
|
||||||
|
msgid "WebAuthn Device type"
|
||||||
|
msgstr "Type d'appareil WebAuthn"
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_webauthn/models.py
|
||||||
|
msgid "WebAuthn Device types"
|
||||||
|
msgstr "Types d'appareil WebAuthn"
|
||||||
|
|
||||||
#: authentik/stages/captcha/models.py
|
#: authentik/stages/captcha/models.py
|
||||||
msgid "Public key, acquired your captcha Provider."
|
msgid "Public key, acquired your captcha Provider."
|
||||||
msgstr "Clé publique, acquise auprès de votre fournisseur captcha."
|
msgstr "Clé publique, acquise auprès de votre fournisseur captcha."
|
||||||
@ -3129,6 +3191,14 @@ msgstr ""
|
|||||||
msgid "Globally enable/disable impersonation."
|
msgid "Globally enable/disable impersonation."
|
||||||
msgstr "Activer/désactiver l'appropriation utilisateur de manière globale."
|
msgstr "Activer/désactiver l'appropriation utilisateur de manière globale."
|
||||||
|
|
||||||
|
#: authentik/tenants/models.py
|
||||||
|
msgid "Default token duration"
|
||||||
|
msgstr "Durée par défaut des jetons"
|
||||||
|
|
||||||
|
#: authentik/tenants/models.py
|
||||||
|
msgid "Default token length"
|
||||||
|
msgstr "Longueur par défaut des jetons"
|
||||||
|
|
||||||
#: authentik/tenants/models.py
|
#: authentik/tenants/models.py
|
||||||
msgid "Tenant"
|
msgid "Tenant"
|
||||||
msgstr "Tenant"
|
msgstr "Tenant"
|
||||||
|
Binary file not shown.
226
poetry.lock
generated
226
poetry.lock
generated
@ -2,87 +2,87 @@
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aiohttp"
|
name = "aiohttp"
|
||||||
version = "3.9.2"
|
version = "3.9.4"
|
||||||
description = "Async http client/server framework (asyncio)"
|
description = "Async http client/server framework (asyncio)"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:772fbe371788e61c58d6d3d904268e48a594ba866804d08c995ad71b144f94cb"},
|
{file = "aiohttp-3.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:76d32588ef7e4a3f3adff1956a0ba96faabbdee58f2407c122dd45aa6e34f372"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:edd4f1af2253f227ae311ab3d403d0c506c9b4410c7fc8d9573dec6d9740369f"},
|
{file = "aiohttp-3.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:56181093c10dbc6ceb8a29dfeea1e815e1dfdc020169203d87fd8d37616f73f9"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cfee9287778399fdef6f8a11c9e425e1cb13cc9920fd3a3df8f122500978292b"},
|
{file = "aiohttp-3.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7a5b676d3c65e88b3aca41816bf72831898fcd73f0cbb2680e9d88e819d1e4d"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cc158466f6a980a6095ee55174d1de5730ad7dec251be655d9a6a9dd7ea1ff9"},
|
{file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1df528a85fb404899d4207a8d9934cfd6be626e30e5d3a5544a83dbae6d8a7e"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54ec82f45d57c9a65a1ead3953b51c704f9587440e6682f689da97f3e8defa35"},
|
{file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f595db1bceabd71c82e92df212dd9525a8a2c6947d39e3c994c4f27d2fe15b11"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abeb813a18eb387f0d835ef51f88568540ad0325807a77a6e501fed4610f864e"},
|
{file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c0b09d76e5a4caac3d27752027fbd43dc987b95f3748fad2b924a03fe8632ad"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc91d07280d7d169f3a0f9179d8babd0ee05c79d4d891447629ff0d7d8089ec2"},
|
{file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:689eb4356649ec9535b3686200b231876fb4cab4aca54e3bece71d37f50c1d13"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b65e861f4bebfb660f7f0f40fa3eb9f2ab9af10647d05dac824390e7af8f75b7"},
|
{file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3666cf4182efdb44d73602379a66f5fdfd5da0db5e4520f0ac0dcca644a3497"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:04fd8ffd2be73d42bcf55fd78cde7958eeee6d4d8f73c3846b7cba491ecdb570"},
|
{file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b65b0f8747b013570eea2f75726046fa54fa8e0c5db60f3b98dd5d161052004a"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3d8d962b439a859b3ded9a1e111a4615357b01620a546bc601f25b0211f2da81"},
|
{file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1885d2470955f70dfdd33a02e1749613c5a9c5ab855f6db38e0b9389453dce7"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:8ceb658afd12b27552597cf9a65d9807d58aef45adbb58616cdd5ad4c258c39e"},
|
{file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0593822dcdb9483d41f12041ff7c90d4d1033ec0e880bcfaf102919b715f47f1"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:0e4ee4df741670560b1bc393672035418bf9063718fee05e1796bf867e995fad"},
|
{file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:47f6eb74e1ecb5e19a78f4a4228aa24df7fbab3b62d4a625d3f41194a08bd54f"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2dec87a556f300d3211decf018bfd263424f0690fcca00de94a837949fbcea02"},
|
{file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c8b04a3dbd54de6ccb7604242fe3ad67f2f3ca558f2d33fe19d4b08d90701a89"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-win32.whl", hash = "sha256:3e1a800f988ce7c4917f34096f81585a73dbf65b5c39618b37926b1238cf9bc4"},
|
{file = "aiohttp-3.9.4-cp310-cp310-win32.whl", hash = "sha256:8a78dfb198a328bfb38e4308ca8167028920fb747ddcf086ce706fbdd23b2926"},
|
||||||
{file = "aiohttp-3.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:ea510718a41b95c236c992b89fdfc3d04cc7ca60281f93aaada497c2b4e05c46"},
|
{file = "aiohttp-3.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:e78da6b55275987cbc89141a1d8e75f5070e577c482dd48bd9123a76a96f0bbb"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6aaa6f99256dd1b5756a50891a20f0d252bd7bdb0854c5d440edab4495c9f973"},
|
{file = "aiohttp-3.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c111b3c69060d2bafc446917534150fd049e7aedd6cbf21ba526a5a97b4402a5"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a27d8c70ad87bcfce2e97488652075a9bdd5b70093f50b10ae051dfe5e6baf37"},
|
{file = "aiohttp-3.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:efbdd51872cf170093998c87ccdf3cb5993add3559341a8e5708bcb311934c94"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:54287bcb74d21715ac8382e9de146d9442b5f133d9babb7e5d9e453faadd005e"},
|
{file = "aiohttp-3.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bfdb41dc6e85d8535b00d73947548a748e9534e8e4fddd2638109ff3fb081df"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb3d05569aa83011fcb346b5266e00b04180105fcacc63743fc2e4a1862a891"},
|
{file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bd9d334412961125e9f68d5b73c1d0ab9ea3f74a58a475e6b119f5293eee7ba"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8534e7d69bb8e8d134fe2be9890d1b863518582f30c9874ed7ed12e48abe3c4"},
|
{file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35d78076736f4a668d57ade00c65d30a8ce28719d8a42471b2a06ccd1a2e3063"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bd9d5b989d57b41e4ff56ab250c5ddf259f32db17159cce630fd543376bd96b"},
|
{file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:824dff4f9f4d0f59d0fa3577932ee9a20e09edec8a2f813e1d6b9f89ced8293f"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa6904088e6642609981f919ba775838ebf7df7fe64998b1a954fb411ffb4663"},
|
{file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52b8b4e06fc15519019e128abedaeb56412b106ab88b3c452188ca47a25c4093"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bda42eb410be91b349fb4ee3a23a30ee301c391e503996a638d05659d76ea4c2"},
|
{file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eae569fb1e7559d4f3919965617bb39f9e753967fae55ce13454bec2d1c54f09"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:193cc1ccd69d819562cc7f345c815a6fc51d223b2ef22f23c1a0f67a88de9a72"},
|
{file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:69b97aa5792428f321f72aeb2f118e56893371f27e0b7d05750bcad06fc42ca1"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b9f1cb839b621f84a5b006848e336cf1496688059d2408e617af33e3470ba204"},
|
{file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4d79aad0ad4b980663316f26d9a492e8fab2af77c69c0f33780a56843ad2f89e"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:d22a0931848b8c7a023c695fa2057c6aaac19085f257d48baa24455e67df97ec"},
|
{file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:d6577140cd7db19e430661e4b2653680194ea8c22c994bc65b7a19d8ec834403"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4112d8ba61fbd0abd5d43a9cb312214565b446d926e282a6d7da3f5a5aa71d36"},
|
{file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:9860d455847cd98eb67897f5957b7cd69fbcb436dd3f06099230f16a66e66f79"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c4ad4241b52bb2eb7a4d2bde060d31c2b255b8c6597dd8deac2f039168d14fd7"},
|
{file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:69ff36d3f8f5652994e08bd22f093e11cfd0444cea310f92e01b45a4e46b624e"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-win32.whl", hash = "sha256:ee2661a3f5b529f4fc8a8ffee9f736ae054adfb353a0d2f78218be90617194b3"},
|
{file = "aiohttp-3.9.4-cp311-cp311-win32.whl", hash = "sha256:e27d3b5ed2c2013bce66ad67ee57cbf614288bda8cdf426c8d8fe548316f1b5f"},
|
||||||
{file = "aiohttp-3.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:4deae2c165a5db1ed97df2868ef31ca3cc999988812e82386d22937d9d6fed52"},
|
{file = "aiohttp-3.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d6a67e26daa686a6fbdb600a9af8619c80a332556245fa8e86c747d226ab1a1e"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6f4cdba12539215aaecf3c310ce9d067b0081a0795dd8a8805fdb67a65c0572a"},
|
{file = "aiohttp-3.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c5ff8ff44825736a4065d8544b43b43ee4c6dd1530f3a08e6c0578a813b0aa35"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:84e843b33d5460a5c501c05539809ff3aee07436296ff9fbc4d327e32aa3a326"},
|
{file = "aiohttp-3.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d12a244627eba4e9dc52cbf924edef905ddd6cafc6513849b4876076a6f38b0e"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8008d0f451d66140a5aa1c17e3eedc9d56e14207568cd42072c9d6b92bf19b52"},
|
{file = "aiohttp-3.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dcad56c8d8348e7e468899d2fb3b309b9bc59d94e6db08710555f7436156097f"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61c47ab8ef629793c086378b1df93d18438612d3ed60dca76c3422f4fbafa792"},
|
{file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7e69a7fd4b5ce419238388e55abd220336bd32212c673ceabc57ccf3d05b55"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc71f748e12284312f140eaa6599a520389273174b42c345d13c7e07792f4f57"},
|
{file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4870cb049f10d7680c239b55428916d84158798eb8f353e74fa2c98980dcc0b"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a1c3a4d0ab2f75f22ec80bca62385db2e8810ee12efa8c9e92efea45c1849133"},
|
{file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2feaf1b7031ede1bc0880cec4b0776fd347259a723d625357bb4b82f62687b"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a87aa0b13bbee025faa59fa58861303c2b064b9855d4c0e45ec70182bbeba1b"},
|
{file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939393e8c3f0a5bcd33ef7ace67680c318dc2ae406f15e381c0054dd658397de"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2cc0d04688b9f4a7854c56c18aa7af9e5b0a87a28f934e2e596ba7e14783192"},
|
{file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d2334e387b2adcc944680bebcf412743f2caf4eeebd550f67249c1c3696be04"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1956e3ac376b1711c1533266dec4efd485f821d84c13ce1217d53e42c9e65f08"},
|
{file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e0198ea897680e480845ec0ffc5a14e8b694e25b3f104f63676d55bf76a82f1a"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:114da29f39eccd71b93a0fcacff178749a5c3559009b4a4498c2c173a6d74dff"},
|
{file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e40d2cd22914d67c84824045861a5bb0fb46586b15dfe4f046c7495bf08306b2"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3f17999ae3927d8a9a823a1283b201344a0627272f92d4f3e3a4efe276972fe8"},
|
{file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:aba80e77c227f4234aa34a5ff2b6ff30c5d6a827a91d22ff6b999de9175d71bd"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:f31df6a32217a34ae2f813b152a6f348154f948c83213b690e59d9e84020925c"},
|
{file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:fb68dc73bc8ac322d2e392a59a9e396c4f35cb6fdbdd749e139d1d6c985f2527"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7a75307ffe31329928a8d47eae0692192327c599113d41b278d4c12b54e1bd11"},
|
{file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f3460a92638dce7e47062cf088d6e7663adb135e936cb117be88d5e6c48c9d53"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-win32.whl", hash = "sha256:972b63d589ff8f305463593050a31b5ce91638918da38139b9d8deaba9e0fed7"},
|
{file = "aiohttp-3.9.4-cp312-cp312-win32.whl", hash = "sha256:32dc814ddbb254f6170bca198fe307920f6c1308a5492f049f7f63554b88ef36"},
|
||||||
{file = "aiohttp-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:200dc0246f0cb5405c80d18ac905c8350179c063ea1587580e3335bfc243ba6a"},
|
{file = "aiohttp-3.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:63f41a909d182d2b78fe3abef557fcc14da50c7852f70ae3be60e83ff64edba5"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:158564d0d1020e0d3fe919a81d97aadad35171e13e7b425b244ad4337fc6793a"},
|
{file = "aiohttp-3.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c3770365675f6be220032f6609a8fbad994d6dcf3ef7dbcf295c7ee70884c9af"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:da1346cd0ccb395f0ed16b113ebb626fa43b7b07fd7344fce33e7a4f04a8897a"},
|
{file = "aiohttp-3.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:305edae1dea368ce09bcb858cf5a63a064f3bff4767dec6fa60a0cc0e805a1d3"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:eaa9256de26ea0334ffa25f1913ae15a51e35c529a1ed9af8e6286dd44312554"},
|
{file = "aiohttp-3.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f121900131d116e4a93b55ab0d12ad72573f967b100e49086e496a9b24523ea"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1543e7fb00214fb4ccead42e6a7d86f3bb7c34751ec7c605cca7388e525fd0b4"},
|
{file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b71e614c1ae35c3d62a293b19eface83d5e4d194e3eb2fabb10059d33e6e8cbf"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:186e94570433a004e05f31f632726ae0f2c9dee4762a9ce915769ce9c0a23d89"},
|
{file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:419f009fa4cfde4d16a7fc070d64f36d70a8d35a90d71aa27670bba2be4fd039"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d52d20832ac1560f4510d68e7ba8befbc801a2b77df12bd0cd2bcf3b049e52a4"},
|
{file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b39476ee69cfe64061fd77a73bf692c40021f8547cda617a3466530ef63f947"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c45e4e815ac6af3b72ca2bde9b608d2571737bb1e2d42299fc1ffdf60f6f9a1"},
|
{file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b33f34c9c7decdb2ab99c74be6443942b730b56d9c5ee48fb7df2c86492f293c"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa906b9bdfd4a7972dd0628dbbd6413d2062df5b431194486a78f0d2ae87bd55"},
|
{file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c78700130ce2dcebb1a8103202ae795be2fa8c9351d0dd22338fe3dac74847d9"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:68bbee9e17d66f17bb0010aa15a22c6eb28583edcc8b3212e2b8e3f77f3ebe2a"},
|
{file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:268ba22d917655d1259af2d5659072b7dc11b4e1dc2cb9662fdd867d75afc6a4"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4c189b64bd6d9a403a1a3f86a3ab3acbc3dc41a68f73a268a4f683f89a4dec1f"},
|
{file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:17e7c051f53a0d2ebf33013a9cbf020bb4e098c4bc5bce6f7b0c962108d97eab"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:8a7876f794523123bca6d44bfecd89c9fec9ec897a25f3dd202ee7fc5c6525b7"},
|
{file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:7be99f4abb008cb38e144f85f515598f4c2c8932bf11b65add0ff59c9c876d99"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:d23fba734e3dd7b1d679b9473129cd52e4ec0e65a4512b488981a56420e708db"},
|
{file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:d58a54d6ff08d2547656356eea8572b224e6f9bbc0cf55fa9966bcaac4ddfb10"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b141753be581fab842a25cb319f79536d19c2a51995d7d8b29ee290169868eab"},
|
{file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7673a76772bda15d0d10d1aa881b7911d0580c980dbd16e59d7ba1422b2d83cd"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-win32.whl", hash = "sha256:103daf41ff3b53ba6fa09ad410793e2e76c9d0269151812e5aba4b9dd674a7e8"},
|
{file = "aiohttp-3.9.4-cp38-cp38-win32.whl", hash = "sha256:e4370dda04dc8951012f30e1ce7956a0a226ac0714a7b6c389fb2f43f22a250e"},
|
||||||
{file = "aiohttp-3.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:328918a6c2835861ff7afa8c6d2c70c35fdaf996205d5932351bdd952f33fa2f"},
|
{file = "aiohttp-3.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:eb30c4510a691bb87081192a394fb661860e75ca3896c01c6d186febe7c88530"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5264d7327c9464786f74e4ec9342afbbb6ee70dfbb2ec9e3dfce7a54c8043aa3"},
|
{file = "aiohttp-3.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:84e90494db7df3be5e056f91412f9fa9e611fbe8ce4aaef70647297f5943b276"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07205ae0015e05c78b3288c1517afa000823a678a41594b3fdc870878d645305"},
|
{file = "aiohttp-3.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7d4845f8501ab28ebfdbeab980a50a273b415cf69e96e4e674d43d86a464df9d"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae0a1e638cffc3ec4d4784b8b4fd1cf28968febc4bd2718ffa25b99b96a741bd"},
|
{file = "aiohttp-3.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:69046cd9a2a17245c4ce3c1f1a4ff8c70c7701ef222fce3d1d8435f09042bba1"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d43302a30ba1166325974858e6ef31727a23bdd12db40e725bec0f759abce505"},
|
{file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b73a06bafc8dcc508420db43b4dd5850e41e69de99009d0351c4f3007960019"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16a967685907003765855999af11a79b24e70b34dc710f77a38d21cd9fc4f5fe"},
|
{file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:418bb0038dfafeac923823c2e63226179976c76f981a2aaad0ad5d51f2229bca"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6fa3ee92cd441d5c2d07ca88d7a9cef50f7ec975f0117cd0c62018022a184308"},
|
{file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71a8f241456b6c2668374d5d28398f8e8cdae4cce568aaea54e0f39359cd928d"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b500c5ad9c07639d48615a770f49618130e61be36608fc9bc2d9bae31732b8f"},
|
{file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:935c369bf8acc2dc26f6eeb5222768aa7c62917c3554f7215f2ead7386b33748"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c07327b368745b1ce2393ae9e1aafed7073d9199e1dcba14e035cc646c7941bf"},
|
{file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74e4e48c8752d14ecfb36d2ebb3d76d614320570e14de0a3aa7a726ff150a03c"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cc7d6502c23a0ec109687bf31909b3fb7b196faf198f8cff68c81b49eb316ea9"},
|
{file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:916b0417aeddf2c8c61291238ce25286f391a6acb6f28005dd9ce282bd6311b6"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:07be2be7071723c3509ab5c08108d3a74f2181d4964e869f2504aaab68f8d3e8"},
|
{file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9b6787b6d0b3518b2ee4cbeadd24a507756ee703adbac1ab6dc7c4434b8c572a"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:122468f6fee5fcbe67cb07014a08c195b3d4c41ff71e7b5160a7bcc41d585a5f"},
|
{file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:221204dbda5ef350e8db6287937621cf75e85778b296c9c52260b522231940ed"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:00a9abcea793c81e7f8778ca195a1714a64f6d7436c4c0bb168ad2a212627000"},
|
{file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:10afd99b8251022ddf81eaed1d90f5a988e349ee7d779eb429fb07b670751e8c"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a9825fdd64ecac5c670234d80bb52bdcaa4139d1f839165f548208b3779c6c6"},
|
{file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2506d9f7a9b91033201be9ffe7d89c6a54150b0578803cce5cb84a943d075bc3"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-win32.whl", hash = "sha256:5422cd9a4a00f24c7244e1b15aa9b87935c85fb6a00c8ac9b2527b38627a9211"},
|
{file = "aiohttp-3.9.4-cp39-cp39-win32.whl", hash = "sha256:e571fdd9efd65e86c6af2f332e0e95dad259bfe6beb5d15b3c3eca3a6eb5d87b"},
|
||||||
{file = "aiohttp-3.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:7d579dcd5d82a86a46f725458418458fa43686f6a7b252f2966d359033ffc8ab"},
|
{file = "aiohttp-3.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:7d29dd5319d20aa3b7749719ac9685fbd926f71ac8c77b2477272725f882072d"},
|
||||||
{file = "aiohttp-3.9.2.tar.gz", hash = "sha256:b0ad0a5e86ce73f5368a164c10ada10504bf91869c05ab75d982c6048217fbf7"},
|
{file = "aiohttp-3.9.4.tar.gz", hash = "sha256:6ff71ede6d9a5a58cfb7b6fffc83ab5d4a63138276c771ac91ceaaddf5459644"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -547,13 +547,13 @@ test = ["coverage (>=7)", "hypothesis", "pytest"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "celery"
|
name = "celery"
|
||||||
version = "5.3.6"
|
version = "5.4.0"
|
||||||
description = "Distributed Task Queue."
|
description = "Distributed Task Queue."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "celery-5.3.6-py3-none-any.whl", hash = "sha256:9da4ea0118d232ce97dff5ed4974587fb1c0ff5c10042eb15278487cdd27d1af"},
|
{file = "celery-5.4.0-py3-none-any.whl", hash = "sha256:369631eb580cf8c51a82721ec538684994f8277637edde2dfc0dacd73ed97f64"},
|
||||||
{file = "celery-5.3.6.tar.gz", hash = "sha256:870cc71d737c0200c397290d730344cc991d13a057534353d124c9380267aab9"},
|
{file = "celery-5.4.0.tar.gz", hash = "sha256:504a19140e8d3029d5acad88330c541d4c3f64c789d85f94756762d8bca7e706"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -569,7 +569,7 @@ vine = ">=5.1.0,<6.0"
|
|||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
arangodb = ["pyArango (>=2.0.2)"]
|
arangodb = ["pyArango (>=2.0.2)"]
|
||||||
auth = ["cryptography (==41.0.5)"]
|
auth = ["cryptography (==42.0.5)"]
|
||||||
azureblockblob = ["azure-storage-blob (>=12.15.0)"]
|
azureblockblob = ["azure-storage-blob (>=12.15.0)"]
|
||||||
brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"]
|
brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"]
|
||||||
cassandra = ["cassandra-driver (>=3.25.0,<4)"]
|
cassandra = ["cassandra-driver (>=3.25.0,<4)"]
|
||||||
@ -579,22 +579,23 @@ couchbase = ["couchbase (>=3.0.0)"]
|
|||||||
couchdb = ["pycouchdb (==1.14.2)"]
|
couchdb = ["pycouchdb (==1.14.2)"]
|
||||||
django = ["Django (>=2.2.28)"]
|
django = ["Django (>=2.2.28)"]
|
||||||
dynamodb = ["boto3 (>=1.26.143)"]
|
dynamodb = ["boto3 (>=1.26.143)"]
|
||||||
elasticsearch = ["elastic-transport (<=8.10.0)", "elasticsearch (<=8.11.0)"]
|
elasticsearch = ["elastic-transport (<=8.13.0)", "elasticsearch (<=8.13.0)"]
|
||||||
eventlet = ["eventlet (>=0.32.0)"]
|
eventlet = ["eventlet (>=0.32.0)"]
|
||||||
|
gcs = ["google-cloud-storage (>=2.10.0)"]
|
||||||
gevent = ["gevent (>=1.5.0)"]
|
gevent = ["gevent (>=1.5.0)"]
|
||||||
librabbitmq = ["librabbitmq (>=2.0.0)"]
|
librabbitmq = ["librabbitmq (>=2.0.0)"]
|
||||||
memcache = ["pylibmc (==1.6.3)"]
|
memcache = ["pylibmc (==1.6.3)"]
|
||||||
mongodb = ["pymongo[srv] (>=4.0.2)"]
|
mongodb = ["pymongo[srv] (>=4.0.2)"]
|
||||||
msgpack = ["msgpack (==1.0.7)"]
|
msgpack = ["msgpack (==1.0.8)"]
|
||||||
pymemcache = ["python-memcached (==1.59)"]
|
pymemcache = ["python-memcached (>=1.61)"]
|
||||||
pyro = ["pyro4 (==4.82)"]
|
pyro = ["pyro4 (==4.82)"]
|
||||||
pytest = ["pytest-celery (==0.0.0)"]
|
pytest = ["pytest-celery[all] (>=1.0.0)"]
|
||||||
redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"]
|
redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"]
|
||||||
s3 = ["boto3 (>=1.26.143)"]
|
s3 = ["boto3 (>=1.26.143)"]
|
||||||
slmq = ["softlayer-messaging (>=1.0.3)"]
|
slmq = ["softlayer-messaging (>=1.0.3)"]
|
||||||
solar = ["ephem (==4.1.5)"]
|
solar = ["ephem (==4.1.5)"]
|
||||||
sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"]
|
sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"]
|
||||||
sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.0)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"]
|
sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.4)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"]
|
||||||
tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"]
|
tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"]
|
||||||
yaml = ["PyYAML (>=3.10)"]
|
yaml = ["PyYAML (>=3.10)"]
|
||||||
zookeeper = ["kazoo (>=1.3.1)"]
|
zookeeper = ["kazoo (>=1.3.1)"]
|
||||||
@ -1612,22 +1613,23 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gunicorn"
|
name = "gunicorn"
|
||||||
version = "21.2.0"
|
version = "22.0.0"
|
||||||
description = "WSGI HTTP Server for UNIX"
|
description = "WSGI HTTP Server for UNIX"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"},
|
{file = "gunicorn-22.0.0-py3-none-any.whl", hash = "sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9"},
|
||||||
{file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"},
|
{file = "gunicorn-22.0.0.tar.gz", hash = "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
packaging = "*"
|
packaging = "*"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
eventlet = ["eventlet (>=0.24.1)"]
|
eventlet = ["eventlet (>=0.24.1,!=0.36.0)"]
|
||||||
gevent = ["gevent (>=1.4.0)"]
|
gevent = ["gevent (>=1.4.0)"]
|
||||||
setproctitle = ["setproctitle"]
|
setproctitle = ["setproctitle"]
|
||||||
|
testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"]
|
||||||
tornado = ["tornado (>=0.2)"]
|
tornado = ["tornado (>=0.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3525,28 +3527,28 @@ pyasn1 = ">=0.1.3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.3.7"
|
version = "0.4.0"
|
||||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e8377cccb2f07abd25e84fc5b2cbe48eeb0fea9f1719cad7caedb061d70e5ce"},
|
{file = "ruff-0.4.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:70b8c620cf2212744eabd6d69c4f839f2be0d8880d27beaeb0adb6aa0b316aa8"},
|
||||||
{file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:15a4d1cc1e64e556fa0d67bfd388fed416b7f3b26d5d1c3e7d192c897e39ba4b"},
|
{file = "ruff-0.4.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfa3e3ff53be05a8c5570c1585ea1e089f6b399ca99fcb78598d4a8234f248db"},
|
||||||
{file = "ruff-0.3.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28bdf3d7dc71dd46929fafeec98ba89b7c3550c3f0978e36389b5631b793663"},
|
{file = "ruff-0.4.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5616cca501d1d16b932b7e607d7e1fd1b8c8c51d6ee484b7940fc1adc5bea541"},
|
||||||
{file = "ruff-0.3.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:379b67d4f49774ba679593b232dcd90d9e10f04d96e3c8ce4a28037ae473f7bb"},
|
{file = "ruff-0.4.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46eff08dd480b5d9b540846159fe134d70e3c45a3c913c600047cbf7f0e4e308"},
|
||||||
{file = "ruff-0.3.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c060aea8ad5ef21cdfbbe05475ab5104ce7827b639a78dd55383a6e9895b7c51"},
|
{file = "ruff-0.4.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d546f511431fff2b17adcf7110f3b2c2c0c8d33b0e10e5fd27fd340bc617efc"},
|
||||||
{file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ebf8f615dde968272d70502c083ebf963b6781aacd3079081e03b32adfe4d58a"},
|
{file = "ruff-0.4.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c7b6b6b38e216036284c5779b6aa14acbf5664e3b5872533219cf93daf40ddfb"},
|
||||||
{file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48098bd8f5c38897b03604f5428901b65e3c97d40b3952e38637b5404b739a2"},
|
{file = "ruff-0.4.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e1cf8b064bb2a6b4922af7274fe2dffcb552d96ba716b2fbe5e2c970ed7de18"},
|
||||||
{file = "ruff-0.3.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da8a4fda219bf9024692b1bc68c9cff4b80507879ada8769dc7e985755d662ea"},
|
{file = "ruff-0.4.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9911c9046b94253e1fa844c0192bb764b86866a881502dee324686474d498c17"},
|
||||||
{file = "ruff-0.3.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c44e0149f1d8b48c4d5c33d88c677a4aa22fd09b1683d6a7ff55b816b5d074f"},
|
{file = "ruff-0.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ca7a971c8f1a0b6f5ff4a819c0d1c2619536530bbd5a289af725d8b2ef1013d"},
|
||||||
{file = "ruff-0.3.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3050ec0af72b709a62ecc2aca941b9cd479a7bf2b36cc4562f0033d688e44fa1"},
|
{file = "ruff-0.4.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:752e0f77f421141dd470a0b1bed4fd8f763aebabe32c80ed3580f740ef4ba807"},
|
||||||
{file = "ruff-0.3.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a29cc38e4c1ab00da18a3f6777f8b50099d73326981bb7d182e54a9a21bb4ff7"},
|
{file = "ruff-0.4.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:84f2a5dd8f33964d826c5377e094f7ce11e55e432cd42d3bf64efe4384224a03"},
|
||||||
{file = "ruff-0.3.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b15cc59c19edca917f51b1956637db47e200b0fc5e6e1878233d3a938384b0b"},
|
{file = "ruff-0.4.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0b20e7db4a672495320a8a18149b7febf4e4f97509a4657367144569ce0915fd"},
|
||||||
{file = "ruff-0.3.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e491045781b1e38b72c91247cf4634f040f8d0cb3e6d3d64d38dcf43616650b4"},
|
{file = "ruff-0.4.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0b0eddd339e24dc4f7719b1cde4967f6b6bc0ad948cc183711ba8910f14aeafe"},
|
||||||
{file = "ruff-0.3.7-py3-none-win32.whl", hash = "sha256:bc931de87593d64fad3a22e201e55ad76271f1d5bfc44e1a1887edd0903c7d9f"},
|
{file = "ruff-0.4.0-py3-none-win32.whl", hash = "sha256:e70befd488271a2c28c80bd427f73d8855dd222fc549fa1e9967d287c5cfe781"},
|
||||||
{file = "ruff-0.3.7-py3-none-win_amd64.whl", hash = "sha256:5ef0e501e1e39f35e03c2acb1d1238c595b8bb36cf7a170e7c1df1b73da00e74"},
|
{file = "ruff-0.4.0-py3-none-win_amd64.whl", hash = "sha256:8584b9361900997ccf8d7aaa4dc4ab43e258a853ca7189d98ac929dc9ee50875"},
|
||||||
{file = "ruff-0.3.7-py3-none-win_arm64.whl", hash = "sha256:789e144f6dc7019d1f92a812891c645274ed08af6037d11fc65fcbc183b7d59f"},
|
{file = "ruff-0.4.0-py3-none-win_arm64.whl", hash = "sha256:fea4ec813c965e40af29ee627a1579ee1d827d77e81d54b85bdd7b42d1540cdd"},
|
||||||
{file = "ruff-0.3.7.tar.gz", hash = "sha256:d5c1aebee5162c2226784800ae031f660c350e7a3402c4d1f8ea4e97e232e3ba"},
|
{file = "ruff-0.4.0.tar.gz", hash = "sha256:7457308d9ebf00d6a1c9a26aa755e477787a636c90b823f91cd7d4bea9e89260"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3963,13 +3965,13 @@ wsproto = ">=0.14"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "twilio"
|
name = "twilio"
|
||||||
version = "9.0.4"
|
version = "9.0.5"
|
||||||
description = "Twilio API client and TwiML generator"
|
description = "Twilio API client and TwiML generator"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.0"
|
python-versions = ">=3.7.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "twilio-9.0.4-py2.py3-none-any.whl", hash = "sha256:086abae1a575a0ee89a72c0792d814ee349fe55c8df76b563ecfc49463c3c533"},
|
{file = "twilio-9.0.5-py2.py3-none-any.whl", hash = "sha256:5e09e910b9368f50f23cb3c3dd5ba77164d80a81e9d97db955cbac322deb2a4e"},
|
||||||
{file = "twilio-9.0.4.tar.gz", hash = "sha256:d493d5bde6361bb713dffec00b9465ff84978b71334dd75002152e79604688ba"},
|
{file = "twilio-9.0.5.tar.gz", hash = "sha256:e9b5727943584d25d618fe502f0100fc5283215f31c863f80b5c64581b4702b0"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "authentik"
|
name = "authentik"
|
||||||
version = "2024.2.2"
|
version = "2024.4.0"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["authentik Team <hello@goauthentik.io>"]
|
authors = ["authentik Team <hello@goauthentik.io>"]
|
||||||
|
|
||||||
|
26
schema.yml
26
schema.yml
@ -1,7 +1,7 @@
|
|||||||
openapi: 3.0.3
|
openapi: 3.0.3
|
||||||
info:
|
info:
|
||||||
title: authentik
|
title: authentik
|
||||||
version: 2024.2.2
|
version: 2024.4.0
|
||||||
description: Making authentication simple.
|
description: Making authentication simple.
|
||||||
contact:
|
contact:
|
||||||
email: hello@goauthentik.io
|
email: hello@goauthentik.io
|
||||||
@ -44714,6 +44714,26 @@ components:
|
|||||||
- num_pk
|
- num_pk
|
||||||
- parent_name
|
- parent_name
|
||||||
- pk
|
- pk
|
||||||
|
UserGroupRequest:
|
||||||
|
type: object
|
||||||
|
description: Simplified Group Serializer for user's groups
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
maxLength: 80
|
||||||
|
is_superuser:
|
||||||
|
type: boolean
|
||||||
|
description: Users added to this group will be superusers.
|
||||||
|
parent:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
attributes:
|
||||||
|
type: object
|
||||||
|
additionalProperties: {}
|
||||||
|
required:
|
||||||
|
- name
|
||||||
UserLoginChallenge:
|
UserLoginChallenge:
|
||||||
type: object
|
type: object
|
||||||
description: Empty challenge
|
description: Empty challenge
|
||||||
@ -45400,7 +45420,11 @@ components:
|
|||||||
- $ref: '#/components/schemas/WebAuthnDeviceType'
|
- $ref: '#/components/schemas/WebAuthnDeviceType'
|
||||||
readOnly: true
|
readOnly: true
|
||||||
nullable: true
|
nullable: true
|
||||||
|
aaguid:
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
required:
|
required:
|
||||||
|
- aaguid
|
||||||
- created_on
|
- created_on
|
||||||
- device_type
|
- device_type
|
||||||
- name
|
- name
|
||||||
|
@ -6,7 +6,6 @@ from typing import Any
|
|||||||
|
|
||||||
from docker.types import Healthcheck
|
from docker.types import Healthcheck
|
||||||
|
|
||||||
from authentik.core.models import Token, TokenIntents, User
|
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
from authentik.lib.utils.http import get_http_session
|
from authentik.lib.utils.http import get_http_session
|
||||||
from authentik.sources.scim.models import SCIMSource
|
from authentik.sources.scim.models import SCIMSource
|
||||||
@ -40,18 +39,9 @@ class TestSourceSCIM(SeleniumTestCase):
|
|||||||
|
|
||||||
@retry()
|
@retry()
|
||||||
def test_scim_conformance(self):
|
def test_scim_conformance(self):
|
||||||
user = User.objects.create(
|
|
||||||
username=generate_id(),
|
|
||||||
)
|
|
||||||
token = Token.objects.create(
|
|
||||||
user=user,
|
|
||||||
intent=TokenIntents.INTENT_API,
|
|
||||||
expiring=False,
|
|
||||||
)
|
|
||||||
source = SCIMSource.objects.create(
|
source = SCIMSource.objects.create(
|
||||||
name=generate_id(),
|
name=generate_id(),
|
||||||
slug=generate_id(),
|
slug=generate_id(),
|
||||||
token=token,
|
|
||||||
)
|
)
|
||||||
session = get_http_session()
|
session = get_http_session()
|
||||||
test_launch = session.post(
|
test_launch = session.post(
|
||||||
@ -59,7 +49,7 @@ class TestSourceSCIM(SeleniumTestCase):
|
|||||||
data={
|
data={
|
||||||
"endPoint": self.live_server_url + f"/source/scim/{source.slug}/v2",
|
"endPoint": self.live_server_url + f"/source/scim/{source.slug}/v2",
|
||||||
"username": "foo",
|
"username": "foo",
|
||||||
"password": token.key,
|
"password": source.token.key,
|
||||||
"jwtToken": None,
|
"jwtToken": None,
|
||||||
"usersCheck": 1,
|
"usersCheck": 1,
|
||||||
"groupsCheck": 1,
|
"groupsCheck": 1,
|
||||||
|
8
tests/wdio/package-lock.json
generated
8
tests/wdio/package-lock.json
generated
@ -6,7 +6,7 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "@goauthentik/web-tests",
|
"name": "@goauthentik/web-tests",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chromedriver": "^123.0.3"
|
"chromedriver": "^123.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
@ -2084,9 +2084,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chromedriver": {
|
"node_modules/chromedriver": {
|
||||||
"version": "123.0.3",
|
"version": "123.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-123.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-123.0.4.tgz",
|
||||||
"integrity": "sha512-35IeTqDLcVR0htF9nD/Lh+g24EG088WHVKXBXiFyWq+2lelnoM0B3tKTBiUEjLng0GnELI4QyQPFK7i97Fz1fQ==",
|
"integrity": "sha512-3Yi7y7q35kkSAOTbRisiww/SL2w+DqafDPAaUShpSuLMmPaOvHQR0i3bm2/33QBiQ8fUb1J/MzppzVL6IDqvhA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@testim/chrome-version": "^1.1.4",
|
"@testim/chrome-version": "^1.1.4",
|
||||||
|
@ -32,6 +32,6 @@
|
|||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chromedriver": "^123.0.3"
|
"chromedriver": "^123.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5051
web/package-lock.json
generated
5051
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -38,22 +38,22 @@
|
|||||||
"@codemirror/theme-one-dark": "^6.1.2",
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
"@formatjs/intl-listformat": "^7.5.5",
|
"@formatjs/intl-listformat": "^7.5.5",
|
||||||
"@fortawesome/fontawesome-free": "^6.5.2",
|
"@fortawesome/fontawesome-free": "^6.5.2",
|
||||||
"@goauthentik/api": "^2024.2.2-1713289394",
|
"@goauthentik/api": "^2024.2.3-1713441634",
|
||||||
"@lit-labs/task": "^3.1.0",
|
"@lit-labs/task": "^3.1.0",
|
||||||
"@lit/context": "^1.1.1",
|
"@lit/context": "^1.1.1",
|
||||||
"@lit/localize": "^0.12.1",
|
"@lit/localize": "^0.12.1",
|
||||||
"@lit/reactive-element": "^2.0.4",
|
"@lit/reactive-element": "^2.0.4",
|
||||||
"@open-wc/lit-helpers": "^0.7.0",
|
"@open-wc/lit-helpers": "^0.7.0",
|
||||||
"@patternfly/elements": "^3.0.0",
|
"@patternfly/elements": "^3.0.1",
|
||||||
"@patternfly/patternfly": "^4.224.2",
|
"@patternfly/patternfly": "^4.224.2",
|
||||||
"@sentry/browser": "^7.110.1",
|
"@sentry/browser": "^7.111.0",
|
||||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"chart.js": "^4.4.2",
|
"chart.js": "^4.4.2",
|
||||||
"chartjs-adapter-moment": "^1.0.1",
|
"chartjs-adapter-moment": "^1.0.1",
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"construct-style-sheets-polyfill": "^3.1.0",
|
"construct-style-sheets-polyfill": "^3.1.0",
|
||||||
"core-js": "^3.36.1",
|
"core-js": "^3.37.0",
|
||||||
"country-flag-icons": "^1.5.11",
|
"country-flag-icons": "^1.5.11",
|
||||||
"fuse.js": "^7.0.0",
|
"fuse.js": "^7.0.0",
|
||||||
"guacamole-common-js": "^1.5.0",
|
"guacamole-common-js": "^1.5.0",
|
||||||
@ -81,13 +81,13 @@
|
|||||||
"@lit/localize-tools": "^0.7.2",
|
"@lit/localize-tools": "^0.7.2",
|
||||||
"@rollup/plugin-replace": "^5.0.5",
|
"@rollup/plugin-replace": "^5.0.5",
|
||||||
"@spotlightjs/spotlight": "^1.2.17",
|
"@spotlightjs/spotlight": "^1.2.17",
|
||||||
"@storybook/addon-essentials": "^7.6.17",
|
"@storybook/addon-essentials": "^8.0.8",
|
||||||
"@storybook/addon-links": "^7.6.17",
|
"@storybook/addon-links": "^8.0.8",
|
||||||
"@storybook/api": "^7.6.17",
|
"@storybook/api": "^7.6.17",
|
||||||
"@storybook/blocks": "^7.6.4",
|
"@storybook/blocks": "^8.0.8",
|
||||||
"@storybook/manager-api": "^7.6.17",
|
"@storybook/manager-api": "^8.0.8",
|
||||||
"@storybook/web-components": "^7.6.17",
|
"@storybook/web-components": "^8.0.8",
|
||||||
"@storybook/web-components-vite": "^7.6.17",
|
"@storybook/web-components-vite": "^8.0.8",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
"@types/chart.js": "^2.9.41",
|
"@types/chart.js": "^2.9.41",
|
||||||
"@types/codemirror": "5.60.15",
|
"@types/codemirror": "5.60.15",
|
||||||
@ -117,8 +117,8 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"rollup-plugin-modify": "^3.0.0",
|
"rollup-plugin-modify": "^3.0.0",
|
||||||
"rollup-plugin-postcss-lit": "^2.1.0",
|
"rollup-plugin-postcss-lit": "^2.1.0",
|
||||||
"storybook": "^7.6.17",
|
"storybook": "^8.0.8",
|
||||||
"storybook-addon-mock": "^4.3.0",
|
"storybook-addon-mock": "^5.0.0",
|
||||||
"ts-lit-plugin": "^2.0.2",
|
"ts-lit-plugin": "^2.0.2",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
"turnstile-types": "^1.2.1",
|
"turnstile-types": "^1.2.1",
|
||||||
|
@ -166,7 +166,7 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(AKElement) {
|
|||||||
${this.renderNewVersionMessage()}
|
${this.renderNewVersionMessage()}
|
||||||
${this.renderImpersonationMessage()}
|
${this.renderImpersonationMessage()}
|
||||||
${map(sidebarContent, renderOneSidebarItem)}
|
${map(sidebarContent, renderOneSidebarItem)}
|
||||||
${this.renderEnterpriseMessage()}
|
${this.renderEnterpriseMenu()}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(AKElement) {
|
|||||||
: nothing;
|
: nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEnterpriseMessage() {
|
renderEnterpriseMenu() {
|
||||||
return this.can(CapabilitiesEnum.IsEnterprise)
|
return this.can(CapabilitiesEnum.IsEnterprise)
|
||||||
? html`
|
? html`
|
||||||
<ak-sidebar-item>
|
<ak-sidebar-item>
|
||||||
|
@ -3,6 +3,8 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
|||||||
import { first } from "@goauthentik/common/utils";
|
import { first } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/elements/CodeMirror";
|
import "@goauthentik/elements/CodeMirror";
|
||||||
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider";
|
||||||
|
import { DataProvision, DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
|
||||||
import "@goauthentik/elements/chips/Chip";
|
import "@goauthentik/elements/chips/Chip";
|
||||||
import "@goauthentik/elements/chips/ChipGroup";
|
import "@goauthentik/elements/chips/ChipGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
@ -12,22 +14,17 @@ import YAML from "yaml";
|
|||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||||
import { customElement, state } from "lit/decorators.js";
|
import { customElement } from "lit/decorators.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
import {
|
import { CoreApi, CoreGroupsListRequest, Group, RbacApi, Role } from "@goauthentik/api";
|
||||||
CoreApi,
|
|
||||||
CoreGroupsListRequest,
|
export function rbacRolePair(item: Role): DualSelectPair {
|
||||||
Group,
|
return [item.pk, html`<div class="selection-main">${item.name}</div>`, item.name];
|
||||||
PaginatedRoleList,
|
}
|
||||||
RbacApi,
|
|
||||||
} from "@goauthentik/api";
|
|
||||||
|
|
||||||
@customElement("ak-group-form")
|
@customElement("ak-group-form")
|
||||||
export class GroupForm extends ModelForm<Group, string> {
|
export class GroupForm extends ModelForm<Group, string> {
|
||||||
@state()
|
|
||||||
roles?: PaginatedRoleList;
|
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return super.styles.concat(css`
|
return super.styles.concat(css`
|
||||||
.pf-c-button.pf-m-control {
|
.pf-c-button.pf-m-control {
|
||||||
@ -51,12 +48,6 @@ export class GroupForm extends ModelForm<Group, string> {
|
|||||||
: msg("Successfully created group.");
|
: msg("Successfully created group.");
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(): Promise<void> {
|
|
||||||
this.roles = await new RbacApi(DEFAULT_CONFIG).rbacRolesList({
|
|
||||||
ordering: "name",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async send(data: Group): Promise<Group> {
|
async send(data: Group): Promise<Group> {
|
||||||
if (this.instance?.pk) {
|
if (this.instance?.pk) {
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreGroupsPartialUpdate({
|
return new CoreApi(DEFAULT_CONFIG).coreGroupsPartialUpdate({
|
||||||
@ -127,24 +118,29 @@ export class GroupForm extends ModelForm<Group, string> {
|
|||||||
</ak-search-select>
|
</ak-search-select>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Roles")} name="roles">
|
<ak-form-element-horizontal label=${msg("Roles")} name="roles">
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-provider
|
||||||
${this.roles?.results.map((role) => {
|
.provider=${(page: number, search?: string): Promise<DataProvision> => {
|
||||||
const selected = Array.from(this.instance?.roles || []).some((sp) => {
|
return new RbacApi(DEFAULT_CONFIG)
|
||||||
return sp == role.pk;
|
.rbacRolesList({
|
||||||
});
|
page: page,
|
||||||
return html`<option value=${role.pk} ?selected=${selected}>
|
search: search,
|
||||||
${role.name}
|
})
|
||||||
</option>`;
|
.then((results) => {
|
||||||
})}
|
return {
|
||||||
</select>
|
pagination: results.pagination,
|
||||||
|
options: results.results.map(rbacRolePair),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
.selected=${(this.instance?.rolesObj ?? []).map(rbacRolePair)}
|
||||||
|
available-label="${msg("Available Roles")}"
|
||||||
|
selected-label="${msg("Selected Roles")}"
|
||||||
|
></ak-dual-select-provider>
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg(
|
${msg(
|
||||||
"Select roles to grant this groups' users' permissions from the selected roles.",
|
"Select roles to grant this groups' users' permissions from the selected roles.",
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${msg("Attributes")}
|
label=${msg("Attributes")}
|
||||||
|
@ -110,10 +110,7 @@ export class UserWriteStageForm extends BaseStageForm<UserWriteStage> {
|
|||||||
${msg("Mark newly created users as inactive.")}
|
${msg("Mark newly created users as inactive.")}
|
||||||
</p>
|
</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal label=${msg("User type")} name="userType">
|
||||||
label=${msg("User path template")}
|
|
||||||
name="userPathTemplate"
|
|
||||||
>
|
|
||||||
<ak-radio
|
<ak-radio
|
||||||
.options=${[
|
.options=${[
|
||||||
{
|
{
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 699 KiB After Width: | Height: | Size: 1.0 MiB |
@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
|
|||||||
export const ERROR_CLASS = "pf-m-danger";
|
export const ERROR_CLASS = "pf-m-danger";
|
||||||
export const PROGRESS_CLASS = "pf-m-in-progress";
|
export const PROGRESS_CLASS = "pf-m-in-progress";
|
||||||
export const CURRENT_CLASS = "pf-m-current";
|
export const CURRENT_CLASS = "pf-m-current";
|
||||||
export const VERSION = "2024.2.2";
|
export const VERSION = "2024.4.0";
|
||||||
export const TITLE_DEFAULT = "authentik";
|
export const TITLE_DEFAULT = "authentik";
|
||||||
export const ROUTE_SEPARATOR = ";";
|
export const ROUTE_SEPARATOR = ";";
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { EVENT_REFRESH } from "@goauthentik/authentik/common/constants";
|
import { EVENT_REFRESH } from "@goauthentik/authentik/common/constants";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
|
import { globalAK } from "@goauthentik/common/global";
|
||||||
import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts";
|
import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts";
|
||||||
|
|
||||||
import { ContextProvider } from "@lit/context";
|
import { ContextProvider } from "@lit/context";
|
||||||
@ -23,6 +24,9 @@ export class ConfigContextController implements ReactiveController {
|
|||||||
context: authentikConfigContext,
|
context: authentikConfigContext,
|
||||||
initialValue: undefined,
|
initialValue: undefined,
|
||||||
});
|
});
|
||||||
|
// Pre-hydrate from template-embedded config
|
||||||
|
this.context.setValue(globalAK().config);
|
||||||
|
this.host.config = globalAK().config;
|
||||||
this.fetch = this.fetch.bind(this);
|
this.fetch = this.fetch.bind(this);
|
||||||
this.fetch();
|
this.fetch();
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
import { EVENT_LOCALE_CHANGE } from "@goauthentik/common/constants";
|
import { EVENT_LOCALE_CHANGE, EVENT_LOCALE_REQUEST } from "@goauthentik/common/constants";
|
||||||
import { EVENT_LOCALE_REQUEST } from "@goauthentik/common/constants";
|
import { customEvent } from "@goauthentik/elements/utils/customEvents";
|
||||||
import { customEvent, isCustomEvent } from "@goauthentik/elements/utils/customEvents";
|
|
||||||
|
|
||||||
import { LitElement, html } from "lit";
|
import { LitElement, html } from "lit";
|
||||||
import { customElement, property } from "lit/decorators.js";
|
import { customElement, property, state } from "lit/decorators.js";
|
||||||
|
|
||||||
|
import { WithBrandConfig } from "../Interface/brandProvider";
|
||||||
import { initializeLocalization } from "./configureLocale";
|
import { initializeLocalization } from "./configureLocale";
|
||||||
import type { LocaleGetter, LocaleSetter } from "./configureLocale";
|
import type { LocaleGetter, LocaleSetter } from "./configureLocale";
|
||||||
import {
|
import { DEFAULT_LOCALE, autoDetectLanguage, getBestMatchLocale } from "./helpers";
|
||||||
DEFAULT_LOCALE,
|
|
||||||
autoDetectLanguage,
|
const LocaleContextBase = WithBrandConfig(LitElement);
|
||||||
getBestMatchLocale,
|
|
||||||
localeCodeFromUrl,
|
|
||||||
} from "./helpers";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component to manage your locale settings.
|
* A component to manage your locale settings.
|
||||||
@ -28,7 +25,7 @@ import {
|
|||||||
* @fires ak-locale-change - When a valid locale has been swapped in
|
* @fires ak-locale-change - When a valid locale has been swapped in
|
||||||
*/
|
*/
|
||||||
@customElement("ak-locale-context")
|
@customElement("ak-locale-context")
|
||||||
export class LocaleContext extends LitElement {
|
export class LocaleContext extends LocaleContextBase {
|
||||||
/// @attribute The text representation of the current locale */
|
/// @attribute The text representation of the current locale */
|
||||||
@property({ attribute: true, type: String })
|
@property({ attribute: true, type: String })
|
||||||
locale = DEFAULT_LOCALE;
|
locale = DEFAULT_LOCALE;
|
||||||
@ -41,6 +38,9 @@ export class LocaleContext extends LitElement {
|
|||||||
|
|
||||||
setLocale: LocaleSetter;
|
setLocale: LocaleSetter;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
userLocale = "";
|
||||||
|
|
||||||
constructor(code = DEFAULT_LOCALE) {
|
constructor(code = DEFAULT_LOCALE) {
|
||||||
super();
|
super();
|
||||||
this.notifyApplication = this.notifyApplication.bind(this);
|
this.notifyApplication = this.notifyApplication.bind(this);
|
||||||
@ -59,8 +59,15 @@ export class LocaleContext extends LitElement {
|
|||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
const localeRequest = autoDetectLanguage(this.locale);
|
// Commenting out until we can come up with a better way of separating the
|
||||||
this.updateLocale(localeRequest);
|
// "request user identity" with the session expiration heartbeat.
|
||||||
|
/*
|
||||||
|
new CoreApi(DEFAULT_CONFIG)
|
||||||
|
.coreUsersMeRetrieve()
|
||||||
|
.then((user) => (this.userLocale = user?.user?.settings?.locale ?? ""))
|
||||||
|
.catch(() => {});
|
||||||
|
*/
|
||||||
|
this.updateLocale();
|
||||||
window.addEventListener(EVENT_LOCALE_REQUEST, this.updateLocaleHandler);
|
window.addEventListener(EVENT_LOCALE_REQUEST, this.updateLocaleHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,28 +76,19 @@ export class LocaleContext extends LitElement {
|
|||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLocaleHandler(ev: Event) {
|
updateLocaleHandler(_ev: Event) {
|
||||||
if (!isCustomEvent(ev)) {
|
|
||||||
console.warn(`Received a non-custom event at EVENT_LOCALE_REQUEST: ${ev}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.debug("authentik/locale: Locale update request received.");
|
console.debug("authentik/locale: Locale update request received.");
|
||||||
this.updateLocale(ev.detail.locale);
|
this.updateLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLocale(code: string) {
|
updateLocale() {
|
||||||
const urlCode = localeCodeFromUrl(this.param);
|
const localeRequest = autoDetectLanguage(this.userLocale, this.brand?.defaultLocale);
|
||||||
const requestedLocale = urlCode ? urlCode : code;
|
const locale = getBestMatchLocale(localeRequest);
|
||||||
const locale = getBestMatchLocale(requestedLocale);
|
|
||||||
if (!locale) {
|
if (!locale) {
|
||||||
console.warn(`authentik/locale: failed to find locale for code ${code}`);
|
console.warn(`authentik/locale: failed to find locale for code ${localeRequest}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
locale.locale().then(() => {
|
locale.locale().then(() => {
|
||||||
console.debug(`authentik/locale: Loaded locale '${code}'`);
|
|
||||||
if (this.getLocale() === code) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.debug(`Setting Locale to ... ${locale.label()} (${locale.code})`);
|
console.debug(`Setting Locale to ... ${locale.label()} (${locale.code})`);
|
||||||
this.setLocale(locale.code).then(() => {
|
this.setLocale(locale.code).then(() => {
|
||||||
window.setTimeout(this.notifyApplication, 0);
|
window.setTimeout(this.notifyApplication, 0);
|
||||||
|
@ -45,12 +45,13 @@ export function localeCodeFromUrl(param = "locale") {
|
|||||||
const isLocaleCandidate = (v: unknown): v is string =>
|
const isLocaleCandidate = (v: unknown): v is string =>
|
||||||
typeof v === "string" && v !== "" && v !== TOMBSTONE;
|
typeof v === "string" && v !== "" && v !== TOMBSTONE;
|
||||||
|
|
||||||
export function autoDetectLanguage(requestedCode?: string): string {
|
export function autoDetectLanguage(userReq = TOMBSTONE, brandReq = TOMBSTONE): string {
|
||||||
const localeCandidates: string[] = [
|
const localeCandidates: string[] = [
|
||||||
globalAK()?.locale ?? TOMBSTONE,
|
|
||||||
localeCodeFromUrl("locale"),
|
localeCodeFromUrl("locale"),
|
||||||
requestedCode ?? TOMBSTONE,
|
userReq,
|
||||||
window.navigator?.language ?? TOMBSTONE,
|
window.navigator?.language ?? TOMBSTONE,
|
||||||
|
brandReq,
|
||||||
|
globalAK()?.locale ?? TOMBSTONE,
|
||||||
DEFAULT_LOCALE,
|
DEFAULT_LOCALE,
|
||||||
].filter(isLocaleCandidate);
|
].filter(isLocaleCandidate);
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@ export class LogViewer extends Table<LogEvent> {
|
|||||||
pagination: {
|
pagination: {
|
||||||
next: 0,
|
next: 0,
|
||||||
previous: 0,
|
previous: 0,
|
||||||
count: 1,
|
count: this.logs?.length || 0,
|
||||||
current: 1,
|
current: 1,
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
startIndex: 1,
|
startIndex: 1,
|
||||||
endIndex: 1,
|
endIndex: this.logs?.length || 0,
|
||||||
},
|
},
|
||||||
results: this.logs || [],
|
results: this.logs || [],
|
||||||
};
|
};
|
||||||
|
@ -208,7 +208,7 @@ export class SidebarItem extends AKElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderWithLabel() {
|
renderWithLabel() {
|
||||||
html`
|
return html`
|
||||||
<span class="pf-c-nav__link">
|
<span class="pf-c-nav__link">
|
||||||
<slot name="label"></slot>
|
<slot name="label"></slot>
|
||||||
</span>
|
</span>
|
||||||
|
@ -516,7 +516,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
? html`
|
? html`
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://unsplash.com/@theforestbirds"
|
href="https://unsplash.com/@sorasagano"
|
||||||
>${msg("Background image")}</a
|
>${msg("Background image")}</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
|
@ -6531,6 +6531,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -6800,6 +6800,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -6448,6 +6448,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -8447,117 +8447,158 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s00bcaadd620a11f8">
|
<trans-unit id="s00bcaadd620a11f8">
|
||||||
<source>Latest version unknown</source>
|
<source>Latest version unknown</source>
|
||||||
|
<target>Dernière version inconnue</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s10fedec3a779ea63">
|
<trans-unit id="s10fedec3a779ea63">
|
||||||
<source>Timestamp</source>
|
<source>Timestamp</source>
|
||||||
|
<target>Horodatage</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s48e186fb300e5464">
|
<trans-unit id="s48e186fb300e5464">
|
||||||
<source>Time</source>
|
<source>Time</source>
|
||||||
|
<target>Temps</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="saa8aa81ad6f055fd">
|
<trans-unit id="saa8aa81ad6f055fd">
|
||||||
<source>Level</source>
|
<source>Level</source>
|
||||||
|
<target>Niveau</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd0ea7366ebc403ff">
|
<trans-unit id="sd0ea7366ebc403ff">
|
||||||
<source>Event</source>
|
<source>Event</source>
|
||||||
|
<target>Évènement</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s225f3e57c6a0d635">
|
<trans-unit id="s225f3e57c6a0d635">
|
||||||
<source>Logger</source>
|
<source>Logger</source>
|
||||||
|
<target>Logger</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s39d6971531a270b6">
|
<trans-unit id="s39d6971531a270b6">
|
||||||
<source>Update internal password on login</source>
|
<source>Update internal password on login</source>
|
||||||
|
<target>Mettre à jour le mot de passe interne à la connexion</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sefe04e319223a3d6">
|
<trans-unit id="sefe04e319223a3d6">
|
||||||
<source>When the user logs in to authentik using this source password backend, update their credentials in authentik.</source>
|
<source>When the user logs in to authentik using this source password backend, update their credentials in authentik.</source>
|
||||||
|
<target>Lorsqu'un utilisateur se connecte à authentik en utilisant le backend de mot de passe de cette source, mettre à jour ses identifiants dans authentik.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s5f43af3669b1e098">
|
<trans-unit id="s5f43af3669b1e098">
|
||||||
<source>Source</source>
|
<source>Source</source>
|
||||||
|
<target>Source</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd9f752de8448bcc9">
|
<trans-unit id="sd9f752de8448bcc9">
|
||||||
<source>Resume timeout</source>
|
<source>Resume timeout</source>
|
||||||
|
<target>Délai de reprise</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s517954806d7610f2">
|
<trans-unit id="s517954806d7610f2">
|
||||||
<source>Amount of time a user can take to return from the source to continue the flow.</source>
|
<source>Amount of time a user can take to return from the source to continue the flow.</source>
|
||||||
|
<target>Durée que l'utilisateur peut prendre pour revenir de la source pour continuer le flux.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s8c4bc6e515949112">
|
<trans-unit id="s8c4bc6e515949112">
|
||||||
<source>Your Install ID</source>
|
<source>Your Install ID</source>
|
||||||
|
<target>Votre ID d'installation</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s8cc0075913c67566">
|
<trans-unit id="s8cc0075913c67566">
|
||||||
<source>Enter the email associated with your account, and we'll send you a link to reset your password.</source>
|
<source>Enter the email associated with your account, and we'll send you a link to reset your password.</source>
|
||||||
|
<target>Entrer l'email associé à votre compte, et nous vous enverrons un lien pour réinitialiser votre mot de passe.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s06bfe45ffef2cf60">
|
<trans-unit id="s06bfe45ffef2cf60">
|
||||||
<source>Stage name: <x id="0" equiv-text="${this.challenge.name}"/></source>
|
<source>Stage name: <x id="0" equiv-text="${this.challenge.name}"/></source>
|
||||||
|
<target>Nom de l'étape : <x id="0" equiv-text="${this.challenge.name}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s90064dd5c4dde2c6">
|
<trans-unit id="s90064dd5c4dde2c6">
|
||||||
<source>Please scan the QR code above using the Microsoft Authenticator, Google Authenticator, or other authenticator apps on your device, and enter the code the device displays below to finish setting up the MFA device.</source>
|
<source>Please scan the QR code above using the Microsoft Authenticator, Google Authenticator, or other authenticator apps on your device, and enter the code the device displays below to finish setting up the MFA device.</source>
|
||||||
|
<target>Merci de scanner le QR code ci-dessus avec Microsoft Authenticator, Google Authenticator ou une autre application d'authentification à deux facteurs sur votre appareil, et entrer le code que l'appareil affiche ci-dessous pour finir la configuration de votre appareil MFA.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s02160dc6adba3456">
|
<trans-unit id="s02160dc6adba3456">
|
||||||
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
|
<source>Inject an OAuth or SAML Source into the flow execution. This allows for additional user verification, or to dynamically access different sources for different user identifiers (username, email address, etc).</source>
|
||||||
|
<target>Injecte une source OAuth ou SAML dans l’exécution du flux. Cela permet d'effectuer des vérifications additionnelles sur l'utilisateur, ou d'accéder dynamiquement à plusieurs sources pour des identifiants utilisateurs différents (nom d'utilisateur, adresse courriel, etc).</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sc7d071fb5cc1f6bf">
|
<trans-unit id="sc7d071fb5cc1f6bf">
|
||||||
<source>A selection is required</source>
|
<source>A selection is required</source>
|
||||||
|
<target>Une sélection est requise</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sa64fb483becc9c2c">
|
<trans-unit id="sa64fb483becc9c2c">
|
||||||
<source>Device type restrictions</source>
|
<source>Device type restrictions</source>
|
||||||
|
<target>Restrictions de type d'appareil</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sbb928551c84cd63f">
|
<trans-unit id="sbb928551c84cd63f">
|
||||||
<source>Available Device types</source>
|
<source>Available Device types</source>
|
||||||
|
<target>Types d'appareil disponibles</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s6446c35d6b411e53">
|
<trans-unit id="s6446c35d6b411e53">
|
||||||
<source>Selected Device types</source>
|
<source>Selected Device types</source>
|
||||||
|
<target>Types d'appareil sélectionnés</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s1f4df216b56de4ac">
|
<trans-unit id="s1f4df216b56de4ac">
|
||||||
<source>Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed.</source>
|
<source>Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed.</source>
|
||||||
|
<target>Optionnel, restreindre quels types d'appareil WebAuthn peuvent être utilisés. Lorsqu'aucun type d'appareil n'est sélectionné, tout les appareils sont autorisés.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s23ed998c51cbe38f">
|
<trans-unit id="s23ed998c51cbe38f">
|
||||||
<source>If the user has successfully authenticated with a device in the classes listed above within this configured duration, this stage will be skipped.</source>
|
<source>If the user has successfully authenticated with a device in the classes listed above within this configured duration, this stage will be skipped.</source>
|
||||||
|
<target>Si un utilisateur s'est authentifié avec succès avec un type d'appareil contenu dans ceux listés ci-dessus dans le temps configuré ici, cette étape sera passée.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4d4f52ccfd9d6adf">
|
<trans-unit id="s4d4f52ccfd9d6adf">
|
||||||
<source>WebAuthn-specific settings</source>
|
<source>WebAuthn-specific settings</source>
|
||||||
|
<target>Réglages spécifiques à WebAuthn</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sb46d2e64f64c6284">
|
<trans-unit id="sb46d2e64f64c6284">
|
||||||
<source>WebAuthn Device type restrictions</source>
|
<source>WebAuthn Device type restrictions</source>
|
||||||
|
<target>Restrictions de type d'appareil WebAuthn</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s11274960b13cf21a">
|
<trans-unit id="s11274960b13cf21a">
|
||||||
<source>This restriction only applies to devices created in authentik 2024.4 or later.</source>
|
<source>This restriction only applies to devices created in authentik 2024.4 or later.</source>
|
||||||
|
<target>Les restrictions ne s'appliquent qu'aux appareils créés dans authentik 2024.4 ou ultérieur.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4888252cbd785175">
|
<trans-unit id="s4888252cbd785175">
|
||||||
<source>Default token duration</source>
|
<source>Default token duration</source>
|
||||||
|
<target>Durée par défaut des jetons</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s25c80a16a07871ba">
|
<trans-unit id="s25c80a16a07871ba">
|
||||||
<source>Default duration for generated tokens</source>
|
<source>Default duration for generated tokens</source>
|
||||||
|
<target>Durée par défaut des jetons générés</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="se5c9ffc025fdf61d">
|
<trans-unit id="se5c9ffc025fdf61d">
|
||||||
<source>Default token length</source>
|
<source>Default token length</source>
|
||||||
|
<target>Longueur par défaut des jetons</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sa6b2c110466d1754">
|
<trans-unit id="sa6b2c110466d1754">
|
||||||
<source>Default length of generated tokens</source>
|
<source>Default length of generated tokens</source>
|
||||||
|
<target>Longueur par défaut des jetons générés</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s1f25e1e20469a9ea">
|
<trans-unit id="s1f25e1e20469a9ea">
|
||||||
<source>deleted</source>
|
<source>deleted</source>
|
||||||
|
<target>supprimé</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s0ca04e397298bc43">
|
<trans-unit id="s0ca04e397298bc43">
|
||||||
<source>Select permissions to assign</source>
|
<source>Select permissions to assign</source>
|
||||||
|
<target>Sélectionner les permissions à assigner</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s676d94e7e31a8075">
|
<trans-unit id="s676d94e7e31a8075">
|
||||||
<source>SCIM Source is in preview.</source>
|
<source>SCIM Source is in preview.</source>
|
||||||
|
<target>La source SCIM est en aperçu.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s31f1afc0a81977c1">
|
<trans-unit id="s31f1afc0a81977c1">
|
||||||
<source>Update SCIM Source</source>
|
<source>Update SCIM Source</source>
|
||||||
|
<target>Mettre à jour la source SCIM</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s4bb356adc8a7f85b">
|
<trans-unit id="s4bb356adc8a7f85b">
|
||||||
<source>SCIM Base URL</source>
|
<source>SCIM Base URL</source>
|
||||||
|
<target>URL de base SCIM</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sb23304fc42c5d6d9">
|
<trans-unit id="sb23304fc42c5d6d9">
|
||||||
<source>Provisioned Users</source>
|
<source>Provisioned Users</source>
|
||||||
|
<target>Utilisateurs provisionnés</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s6a81ee82b2e5ecbb">
|
<trans-unit id="s6a81ee82b2e5ecbb">
|
||||||
<source>Provisioned Groups</source>
|
<source>Provisioned Groups</source>
|
||||||
|
<target>Groupes provisionnés</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s10154dbd4fbc697b">
|
<trans-unit id="s10154dbd4fbc697b">
|
||||||
<source>removed</source>
|
<source>removed</source>
|
||||||
|
<target>supprimé</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
<target>Vérification...</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -8386,6 +8386,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -8230,6 +8230,9 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -6652,6 +6652,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -8502,4 +8502,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
|
</trans-unit>
|
||||||
</body></file></xliff>
|
</body></file></xliff>
|
||||||
|
@ -6441,6 +6441,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -5359,6 +5359,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" ?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
<?xml version="1.0"?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
<file target-language="zh-Hans" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
<file target-language="zh-Hans" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
||||||
<body>
|
<body>
|
||||||
<trans-unit id="s4caed5b7a7e5d89b">
|
<trans-unit id="s4caed5b7a7e5d89b">
|
||||||
@ -596,9 +596,9 @@
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="saa0e2675da69651b">
|
<trans-unit id="saa0e2675da69651b">
|
||||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||||
<target>未找到 URL "
|
<target>未找到 URL "
|
||||||
<x id="0" equiv-text="${this.url}"/>"。</target>
|
<x id="0" equiv-text="${this.url}"/>"。</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s58cd9c2fe836d9c6">
|
<trans-unit id="s58cd9c2fe836d9c6">
|
||||||
@ -1040,8 +1040,8 @@
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sa8384c9c26731f83">
|
<trans-unit id="sa8384c9c26731f83">
|
||||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||||
<target>要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。</target>
|
<target>要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s55787f4dfcdce52b">
|
<trans-unit id="s55787f4dfcdce52b">
|
||||||
@ -1782,8 +1782,8 @@
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sa90b7809586c35ce">
|
<trans-unit id="sa90b7809586c35ce">
|
||||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||||
<target>输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。</target>
|
<target>输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s0410779cb47de312">
|
<trans-unit id="s0410779cb47de312">
|
||||||
@ -2961,8 +2961,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s76768bebabb7d543">
|
<trans-unit id="s76768bebabb7d543">
|
||||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||||
<target>包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'</target>
|
<target>包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s026555347e589f0e">
|
<trans-unit id="s026555347e589f0e">
|
||||||
@ -3739,8 +3739,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s7b1fba26d245cb1c">
|
<trans-unit id="s7b1fba26d245cb1c">
|
||||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||||
<target>使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。</target>
|
<target>使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s44536d20bb5c8257">
|
<trans-unit id="s44536d20bb5c8257">
|
||||||
@ -3916,10 +3916,10 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sa95a538bfbb86111">
|
<trans-unit id="sa95a538bfbb86111">
|
||||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||||
<target>您确定要更新
|
<target>您确定要更新
|
||||||
<x id="0" equiv-text="${this.objectLabel}"/>"
|
<x id="0" equiv-text="${this.objectLabel}"/>"
|
||||||
<x id="1" equiv-text="${this.obj?.name}"/>" 吗?</target>
|
<x id="1" equiv-text="${this.obj?.name}"/>" 吗?</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sc92d7cfb6ee1fec6">
|
<trans-unit id="sc92d7cfb6ee1fec6">
|
||||||
@ -4995,7 +4995,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sdf1d8edef27236f0">
|
<trans-unit id="sdf1d8edef27236f0">
|
||||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||||
<target>像 YubiKey 这样的“漫游”身份验证器</target>
|
<target>像 YubiKey 这样的“漫游”身份验证器</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -5330,10 +5330,10 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s2d5f69929bb7221d">
|
<trans-unit id="s2d5f69929bb7221d">
|
||||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||||
<target>
|
<target>
|
||||||
<x id="0" equiv-text="${prompt.name}"/>("
|
<x id="0" equiv-text="${prompt.name}"/>("
|
||||||
<x id="1" equiv-text="${prompt.fieldKey}"/>",类型为
|
<x id="1" equiv-text="${prompt.fieldKey}"/>",类型为
|
||||||
<x id="2" equiv-text="${prompt.type}"/>)</target>
|
<x id="2" equiv-text="${prompt.type}"/>)</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -5382,7 +5382,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s1608b2f94fa0dbd4">
|
<trans-unit id="s1608b2f94fa0dbd4">
|
||||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||||
<target>如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。</target>
|
<target>如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -7830,7 +7830,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<target>成功创建用户并添加到组 <x id="0" equiv-text="${this.group.name}"/></target>
|
<target>成功创建用户并添加到组 <x id="0" equiv-text="${this.group.name}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s824e0943a7104668">
|
<trans-unit id="s824e0943a7104668">
|
||||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||||
<target>此用户将会被添加到组 &quot;<x id="0" equiv-text="${this.targetGroup.name}"/>&quot;。</target>
|
<target>此用户将会被添加到组 &quot;<x id="0" equiv-text="${this.targetGroup.name}"/>&quot;。</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s62e7f6ed7d9cb3ca">
|
<trans-unit id="s62e7f6ed7d9cb3ca">
|
||||||
@ -8598,7 +8598,10 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
<target>正在验证...</target>
|
<target>正在验证...</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
@ -6489,6 +6489,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -8347,6 +8347,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s30d6ff9e15e0a40a">
|
<trans-unit id="s30d6ff9e15e0a40a">
|
||||||
<source>Verifying...</source>
|
<source>Verifying...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc1673c93148583ba">
|
||||||
|
<source>Request failed. Please try again later.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
15
website/developer-docs/api/clients.md
Normal file
15
website/developer-docs/api/clients.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: API Clients
|
||||||
|
---
|
||||||
|
|
||||||
|
These API clients are officially supported and maintained.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
These API clients are primarily built around creating/updating/deleting configuration objects in authentik, and in most cases can **not** be used to implemented SSO into your application.
|
||||||
|
:::
|
||||||
|
|
||||||
|
| Language | Package name | URL |
|
||||||
|
| --------------------- | ----------------------- | ---------------------------------------------- |
|
||||||
|
| JavaScript/Typescript | `@goauthentik/api` | https://www.npmjs.com/package/@goauthentik/api |
|
||||||
|
| Go | `goauthentik.io/api/v3` | https://pkg.go.dev/goauthentik.io/api/v3 |
|
||||||
|
| Python | `authentik_client` | https://pypi.org/project/authentik-client/ |
|
@ -58,3 +58,11 @@ When enabled, all the events caused by a user will be deleted upon the user's de
|
|||||||
### Impersonation
|
### Impersonation
|
||||||
|
|
||||||
Globally enable/disable impersonation. Defaults to `true`.
|
Globally enable/disable impersonation. Defaults to `true`.
|
||||||
|
|
||||||
|
### Default token duration
|
||||||
|
|
||||||
|
Default duration for generated tokens. Defaults to `minutes=30`.
|
||||||
|
|
||||||
|
### Default token length
|
||||||
|
|
||||||
|
Default length of generated tokens. Defaults to 60.
|
||||||
|
@ -21,7 +21,9 @@ Using the `Not configured action`, you can choose what happens when a user does
|
|||||||
By default, authenticator validation is required every time the flow containing this stage is executed. To only change this behavior, set _Last validation threshold_ to a non-zero value. (Requires authentik 2022.5)
|
By default, authenticator validation is required every time the flow containing this stage is executed. To only change this behavior, set _Last validation threshold_ to a non-zero value. (Requires authentik 2022.5)
|
||||||
Keep in mind that when using Code-based devices (TOTP, Static and SMS), values lower than `seconds=30` cannot be used, as with the way TOTP devices are saved, there is no exact timestamp.
|
Keep in mind that when using Code-based devices (TOTP, Static and SMS), values lower than `seconds=30` cannot be used, as with the way TOTP devices are saved, there is no exact timestamp.
|
||||||
|
|
||||||
### Less-frequent validation
|
### Options
|
||||||
|
|
||||||
|
#### Less-frequent validation
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
Requires authentik 2022.5.1
|
Requires authentik 2022.5.1
|
||||||
@ -29,12 +31,13 @@ Requires authentik 2022.5.1
|
|||||||
|
|
||||||
You can configure this stage to only ask for MFA validation if the user hasn't authenticated themselves within a defined time period. To configure this, set _Last validation threshold_ to any non-zero value. Any of the users devices within the selected classes are checked.
|
You can configure this stage to only ask for MFA validation if the user hasn't authenticated themselves within a defined time period. To configure this, set _Last validation threshold_ to any non-zero value. Any of the users devices within the selected classes are checked.
|
||||||
|
|
||||||
### Passwordless authentication
|
#### Passwordless authentication
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
Requires authentik 2021.12.4
|
Requires authentik 2021.12.4
|
||||||
:::
|
:::
|
||||||
:::danger
|
|
||||||
|
:::caution
|
||||||
Firefox has some known issues regarding FIDO (see https://bugzilla.mozilla.org/show_bug.cgi?id=1530370) and TouchID (see https://bugzilla.mozilla.org/show_bug.cgi?id=1536482)
|
Firefox has some known issues regarding FIDO (see https://bugzilla.mozilla.org/show_bug.cgi?id=1530370) and TouchID (see https://bugzilla.mozilla.org/show_bug.cgi?id=1536482)
|
||||||
:::
|
:::
|
||||||
|
|
||||||
@ -48,7 +51,7 @@ As final stage, bind a _User login_ stage.
|
|||||||
|
|
||||||
Users can either access this flow directly via its URL, or you can modify any Identification stage's _Passwordless flow_ setting to add a direct link to this flow.
|
Users can either access this flow directly via its URL, or you can modify any Identification stage's _Passwordless flow_ setting to add a direct link to this flow.
|
||||||
|
|
||||||
### Logging
|
#### Logging
|
||||||
|
|
||||||
Logins which used Passwordless authentication have the _auth_method_ context variable set to `auth_webauthn_pwl`, and the device used is saved in the arguments. Example:
|
Logins which used Passwordless authentication have the _auth_method_ context variable set to `auth_webauthn_pwl`, and the device used is saved in the arguments. Example:
|
||||||
|
|
||||||
@ -73,7 +76,7 @@ Logins which used Passwordless authentication have the _auth_method_ context var
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### `WebAuthn Device type restrictions`
|
#### WebAuthn Device type restrictions
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
Requires authentik 2024.4
|
Requires authentik 2024.4
|
||||||
|
@ -4,19 +4,21 @@ title: WebAuthn authenticator setup stage
|
|||||||
|
|
||||||
This stage configures a WebAuthn-based Authenticator. This can either be a browser, biometrics or a Security stick like a YubiKey.
|
This stage configures a WebAuthn-based Authenticator. This can either be a browser, biometrics or a Security stick like a YubiKey.
|
||||||
|
|
||||||
### `User verification`
|
### Options
|
||||||
|
|
||||||
|
#### User verification
|
||||||
|
|
||||||
Configure if authentik should require, prefer or discourage user verification for the authenticator. For example when using a virtual authenticator like Windows Hello, this setting controls if a PIN is required.
|
Configure if authentik should require, prefer or discourage user verification for the authenticator. For example when using a virtual authenticator like Windows Hello, this setting controls if a PIN is required.
|
||||||
|
|
||||||
### `Resident key requirement`
|
#### Resident key requirement
|
||||||
|
|
||||||
Configure if the created authenticator is stored in the encrypted memory on the device or in persistent memory. When configuring [passwordless login](../identification/index.md#passwordless-flow), this should be set to either _Preferred_ or _Required_, otherwise the authenticator cannot be used for passwordless authentication.
|
Configure if the created authenticator is stored in the encrypted memory on the device or in persistent memory. When configuring [passwordless login](../identification/index.md#passwordless-flow), this should be set to either _Preferred_ or _Required_, otherwise the authenticator cannot be used for passwordless authentication.
|
||||||
|
|
||||||
### `Authenticator Attachment`
|
#### Authenticator Attachment
|
||||||
|
|
||||||
Configure if authentik will require either a removable device (like a YubiKey, Google Titan, etc) or a non-removable device (like Windows Hello, TouchID or password managers), or not send a requirement.
|
Configure if authentik will require either a removable device (like a YubiKey, Google Titan, etc) or a non-removable device (like Windows Hello, TouchID or password managers), or not send a requirement.
|
||||||
|
|
||||||
### `Device type restrictions`
|
#### Device type restrictions
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
Requires authentik 2024.4
|
Requires authentik 2024.4
|
||||||
|
@ -98,8 +98,8 @@ Templates are rendered using Django's templating engine. The following variables
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="alert alert-success">
|
<td class="alert alert-success">
|
||||||
{% blocktrans with username=user.username %} Hi {{ username }}, {%
|
{% blocktrans with username=user.username %} Hi {{ username }},
|
||||||
endblocktrans %}
|
{% endblocktrans %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -38,12 +38,20 @@ It is very important that the configured source's authentication and enrollment
|
|||||||
|
|
||||||
This is because the Source stage works by appending a [dynamic in-memory](../../../core/terminology.md#dynamic-in-memory-stage) stage to the source's flow, so having a [User login stage](../user_login/index.md) bound will cause the source's flow to not resume the original flow it was started from, and instead directly authenticating the pending user.
|
This is because the Source stage works by appending a [dynamic in-memory](../../../core/terminology.md#dynamic-in-memory-stage) stage to the source's flow, so having a [User login stage](../user_login/index.md) bound will cause the source's flow to not resume the original flow it was started from, and instead directly authenticating the pending user.
|
||||||
|
|
||||||
|
### Example use case
|
||||||
|
|
||||||
|
This stage can be used to leverage an external OAuth/SAML identity provider.
|
||||||
|
|
||||||
|
For example, you can authenticate users by routing them through a custom device-health solution.
|
||||||
|
|
||||||
|
Another use case is to route users to authenticate with your legacy (Okta, etc) IdP and then use the returned identity and attributes within authentik as part of an authorization flow, for example as part of an IdP migration. For authentication/enrollment this is also possible with an [OAuth](../../../../integrations/sources/oauth/)/[SAML](../../../../integrations/sources/saml/) source by itself.
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
#### `source`
|
#### Source
|
||||||
|
|
||||||
The source the user is redirected to. Must be a web-based source, such as [OAuth](../../../../integrations/sources/oauth/) or [SAML](../../../../integrations/sources/saml/). Sources like [LDAP](../../../../integrations/sources/ldap/) are _not_ compatible.
|
The source the user is redirected to. Must be a web-based source, such as [OAuth](../../../../integrations/sources/oauth/) or [SAML](../../../../integrations/sources/saml/). Sources like [LDAP](../../../../integrations/sources/ldap/) are _not_ compatible.
|
||||||
|
|
||||||
#### `resume_timeout`
|
#### Resume timeout
|
||||||
|
|
||||||
Because the execution of the current flow is suspended before the user is redirected to the configured source, this option configures how long the suspended flow is saved. If this timeout is exceeded, upon return from the configured source, the suspended flow will restart from the beginning.
|
Because the execution of the current flow is suspended before the user is redirected to the configured source, this option configures how long the suspended flow is saved. If this timeout is exceeded, upon return from the configured source, the suspended flow will restart from the beginning.
|
||||||
|
@ -72,7 +72,7 @@ To check if your config has been applied correctly, you can run the following co
|
|||||||
- `AUTHENTIK_POSTGRESQL__PASSWORD`: Database password, defaults to the environment variable `POSTGRES_PASSWORD`
|
- `AUTHENTIK_POSTGRESQL__PASSWORD`: Database password, defaults to the environment variable `POSTGRES_PASSWORD`
|
||||||
- `AUTHENTIK_POSTGRESQL__USE_PGBOUNCER`: Adjust configuration to support connection to PgBouncer
|
- `AUTHENTIK_POSTGRESQL__USE_PGBOUNCER`: Adjust configuration to support connection to PgBouncer
|
||||||
- `AUTHENTIK_POSTGRESQL__USE_PGPOOL`: Adjust configuration to support connection to Pgpool
|
- `AUTHENTIK_POSTGRESQL__USE_PGPOOL`: Adjust configuration to support connection to Pgpool
|
||||||
- `AUTHENTIK_POSTGRESQL__SSLMODE`: Strictness of ssl verification. Defaults to `verify-ca`
|
- `AUTHENTIK_POSTGRESQL__SSLMODE`: Strictness of ssl verification. Defaults to `"verify-ca"`
|
||||||
- `AUTHENTIK_POSTGRESQL__SSLROOTCERT`: CA root for server ssl verification
|
- `AUTHENTIK_POSTGRESQL__SSLROOTCERT`: CA root for server ssl verification
|
||||||
- `AUTHENTIK_POSTGRESQL__SSLCERT`: Path to x509 client certificate to authenticate to server
|
- `AUTHENTIK_POSTGRESQL__SSLCERT`: Path to x509 client certificate to authenticate to server
|
||||||
- `AUTHENTIK_POSTGRESQL__SSLKEY`: Path to private key of `SSLCERT` certificate
|
- `AUTHENTIK_POSTGRESQL__SSLKEY`: Path to private key of `SSLCERT` certificate
|
||||||
@ -85,7 +85,8 @@ To check if your config has been applied correctly, you can run the following co
|
|||||||
- `AUTHENTIK_REDIS__USERNAME`: Redis server username when not using configuration URL
|
- `AUTHENTIK_REDIS__USERNAME`: Redis server username when not using configuration URL
|
||||||
- `AUTHENTIK_REDIS__PASSWORD`: Redis server password when not using configuration URL
|
- `AUTHENTIK_REDIS__PASSWORD`: Redis server password when not using configuration URL
|
||||||
- `AUTHENTIK_REDIS__TLS`: Redis server connection using TLS when not using configuration URL
|
- `AUTHENTIK_REDIS__TLS`: Redis server connection using TLS when not using configuration URL
|
||||||
- `AUTHENTIK_REDIS__TLS_REQS`: Redis server TLS connection requirements when not using configuration URL
|
- `AUTHENTIK_REDIS__TLS_REQS`: Redis server TLS connection requirements when not using configuration URL. Defaults to `"none"`. Allowed values are `"none"` and `"required"`.
|
||||||
|
- `AUTHENTIK_REDIS__TLS_CA_CERT`: Path to the Redis server TLS CA root when not using configuration URL. Defaults to `null`.
|
||||||
|
|
||||||
## Result Backend Settings
|
## Result Backend Settings
|
||||||
|
|
||||||
@ -312,6 +313,14 @@ Configure how long reputation scores should be saved for in seconds. Note that t
|
|||||||
|
|
||||||
Defaults to `86400`.
|
Defaults to `86400`.
|
||||||
|
|
||||||
|
### `AUTHENTIK_SESSION_STORAGE`
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Requires authentik 2024.4
|
||||||
|
:::
|
||||||
|
|
||||||
|
Configure if the sessions are stored in the cache or the database. Defaults to `cache`. Allowed values are `cache` and `db`. Note that changing this value will invalidate all previous sessions.
|
||||||
|
|
||||||
### `AUTHENTIK_WEB__WORKERS`
|
### `AUTHENTIK_WEB__WORKERS`
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
@ -51,7 +51,7 @@ Run the following commands to generate a password and secret key and write them
|
|||||||
{/* prettier-ignore */}
|
{/* prettier-ignore */}
|
||||||
```shell
|
```shell
|
||||||
echo "PG_PASS=$(openssl rand -base64 36)" >> .env
|
echo "PG_PASS=$(openssl rand -base64 36)" >> .env
|
||||||
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 36)" >> .env
|
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60)" >> .env
|
||||||
```
|
```
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
@ -23,9 +23,9 @@ password=my-token
|
|||||||
|
|
||||||
This will return a JSON response with an `access_token`, which is a signed JWT token. This token can be sent along requests to other hosts, which can then validate the JWT based on the signing key configured in authentik.
|
This will return a JSON response with an `access_token`, which is a signed JWT token. This token can be sent along requests to other hosts, which can then validate the JWT based on the signing key configured in authentik.
|
||||||
|
|
||||||
Starting with authentik 2024.next, it is also possible to encode the username and token of the user to authenticate with, separated with a colon, into a base64 string and pass it as `client_secret` value.
|
Starting with authentik 2024.4, it is also possible to encode the username and token of the user to authenticate with, separated with a colon, into a base64 string and pass it as `client_secret` value.
|
||||||
|
|
||||||
In addition to that, with authentik 2024.next it is also possible to pass the configured `client_secret` value, which will automatically generate a service account user for which the JWT token will be issued.
|
In addition to that, with authentik 2024.4 it is also possible to pass the configured `client_secret` value, which will automatically generate a service account user for which the JWT token will be issued.
|
||||||
|
|
||||||
### JWT-authentication
|
### JWT-authentication
|
||||||
|
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
---
|
|
||||||
title: Release next
|
|
||||||
slug: /releases/next
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- ## Breaking changes -->
|
|
||||||
|
|
||||||
## Breaking changes
|
|
||||||
|
|
||||||
### Manual action is required
|
|
||||||
|
|
||||||
### Manual action may be required
|
|
||||||
|
|
||||||
- **Configuration options migrated to the Admin interface**
|
|
||||||
|
|
||||||
The following config options have been moved from the config file and can now be set using the Admin interface (under **System** -> **Settings**) or the API:
|
|
||||||
|
|
||||||
- `AUTHENTIK_DEFAULT_TOKEN_LENGTH`
|
|
||||||
|
|
||||||
When upgrading to 2024.next, the currently configured options will be automatically migrated to the database, and can be removed from the `.env` or helm values file afterwards.
|
|
||||||
|
|
||||||
## New features
|
|
||||||
|
|
||||||
- Configurable app password token expiring
|
|
||||||
|
|
||||||
Thanks @jmdilly for contributing this feature!
|
|
||||||
|
|
||||||
Admins can now configure the default token duration (which defaults to `minutes=30`) in the admin interface as specified above. This value can also be overridden per-user with the `goauthentik.io/user/token-maximum-lifetime` attribute.
|
|
||||||
|
|
||||||
## Upgrading
|
|
||||||
|
|
||||||
This release does not introduce any new requirements.
|
|
||||||
|
|
||||||
### docker-compose
|
|
||||||
|
|
||||||
To upgrade, download the new docker-compose file and update the Docker stack with the new version, using these commands:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
wget -O docker-compose.yml https://goauthentik.io/version/xxxx.x/docker-compose.yml
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
The `-O` flag retains the downloaded file's name, overwriting any existing local file with the same name.
|
|
||||||
|
|
||||||
### Kubernetes
|
|
||||||
|
|
||||||
Upgrade the Helm Chart to the new version, using the following commands:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
helm repo update
|
|
||||||
helm upgrade authentik authentik/authentik -f values.yaml --version ^xxxx.x
|
|
||||||
```
|
|
||||||
|
|
||||||
## Minor changes/fixes
|
|
||||||
|
|
||||||
<!-- _Insert the output of `make gen-changelog` here_ -->
|
|
||||||
|
|
||||||
## API Changes
|
|
||||||
|
|
||||||
<!-- _Insert output of `make gen-diff` here_ -->
|
|
@ -321,10 +321,6 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2024.2
|
|||||||
|
|
||||||
## Fixed in 2024.2.2
|
## Fixed in 2024.2.2
|
||||||
|
|
||||||
- ci: do not push docker image if fork (#8724)
|
|
||||||
- ci: fix missing DOCKER_USERNAME secret (#8730)
|
|
||||||
- ci: fix missing DOCKER_USERNAME secret (cherry-pick #8730) (#8733)
|
|
||||||
- ci: fix missing output on composite action (cherry-pick #8741) (#8742)
|
|
||||||
- core: fix blueprint export (cherry-pick #8695) (#8696)
|
- core: fix blueprint export (cherry-pick #8695) (#8696)
|
||||||
- enterprise: fix read_only activating when no license is installed (cherry-pick #8697) (#8698)
|
- enterprise: fix read_only activating when no license is installed (cherry-pick #8697) (#8698)
|
||||||
- enterprise: force license usage update after change to license (cherry-pick #8723) (#8725)
|
- enterprise: force license usage update after change to license (cherry-pick #8723) (#8725)
|
||||||
@ -338,6 +334,19 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2024.2
|
|||||||
- web/admin: don't mark property mappings as required anywhere (cherry-pick #8752) (#8755)
|
- web/admin: don't mark property mappings as required anywhere (cherry-pick #8752) (#8755)
|
||||||
- web/admin: don't mark remaining property mappings as required (cherry-pick #8772) (#8773)
|
- web/admin: don't mark remaining property mappings as required (cherry-pick #8772) (#8773)
|
||||||
|
|
||||||
|
## Fixed in 2024.2.3
|
||||||
|
|
||||||
|
- api: capabilities: properly set can_save_media when s3 is enabled (cherry-pick #8896) (#8897)
|
||||||
|
- enterprise: only check for valid license existing for creating Enterprise objects (cherry-pick #8813) (#8822)
|
||||||
|
- enterprise/rac: fix connection token management (cherry-pick #8909) (#8912)
|
||||||
|
- events: discard notification if user has empty email (cherry-pick #8938) (#8951)
|
||||||
|
- events: fix incorrect user logged when using API token authentication (#9302)
|
||||||
|
- lifecycle: migrate: ensure template schema exists before migrating (cherry-pick #8952) (#9022)
|
||||||
|
- stages/email: Disable autoescape for text templates (cherry-pick #8812) (#8824)
|
||||||
|
- stages/email: fix issue when sending emails to users with same display as email (cherry-pick #8850) (#8852)
|
||||||
|
- stages/user_write: ensure user data is json-serializable (cherry-pick #8926) (#8928)
|
||||||
|
- tenants: really ensure default tenant cannot be deleted (cherry-pick #8875) (#8876)
|
||||||
|
|
||||||
## API Changes
|
## API Changes
|
||||||
|
|
||||||
#### What's New
|
#### What's New
|
||||||
|
104
website/docs/releases/2024/v2024.4.md
Normal file
104
website/docs/releases/2024/v2024.4.md
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
---
|
||||||
|
title: Release 2024.4
|
||||||
|
slug: /releases/2024.4
|
||||||
|
---
|
||||||
|
|
||||||
|
:::::note
|
||||||
|
2024.4 has not been released yet! We're publishing these release notes as a preview of what's to come, and for our awesome beta testers trying out release candidates.
|
||||||
|
|
||||||
|
To try out the release candidate, replace your Docker image tag with the latest release candidate number, such as 2024.4.0-rc1. You can find the latest one in [the latest releases on GitHub](https://github.com/goauthentik/authentik/releases). If you don't find any, it means we haven't released one yet.
|
||||||
|
:::::
|
||||||
|
|
||||||
|
## Highlights
|
||||||
|
|
||||||
|
- **OAuth/SAML as authentication factor** <span class="badge badge--primary">Enterprise</span> Use an external provider as part of an MFA authentication flow, including custom implementations
|
||||||
|
|
||||||
|
- **SCIM Source** <span class="badge badge--info">Preview</span> Provision users and groups in authentik using an SCIM API
|
||||||
|
|
||||||
|
- **Configurable WebAuthn device restrictions** Configure which types of WebAuthn devices can be used to enroll and validate for different authorization levels.
|
||||||
|
|
||||||
|
- **Performance improvements** The API Endpoints to list Users, Groups, and Events have been optimized by 100%, y% and z% respectively
|
||||||
|
|
||||||
|
## Breaking changes
|
||||||
|
|
||||||
|
### Manual action may be required
|
||||||
|
|
||||||
|
- **Configuration options migrated to the Admin interface**
|
||||||
|
|
||||||
|
The following config options have been moved from the config file and can now be set using the Admin interface (under **System** -> **Settings**) or the API:
|
||||||
|
|
||||||
|
- `AUTHENTIK_DEFAULT_TOKEN_LENGTH`
|
||||||
|
|
||||||
|
When upgrading to 2024.4, the currently configured options will be automatically migrated to the database, and can be removed from the `.env` or helm values file afterwards.
|
||||||
|
|
||||||
|
## New features
|
||||||
|
|
||||||
|
- **Source stage** <span class="badge badge--primary">Enterprise</span>
|
||||||
|
|
||||||
|
The source stage allows for an inclusion of a source as part of a flow. This can be used to link a user to a source as part of their authentication/enrollment, or it can be used as an external multi-factor to provide device health attestation for example.
|
||||||
|
|
||||||
|
For details refer to [Source stage](../../flow/stages/source/index.md)
|
||||||
|
|
||||||
|
- **SCIM Source** <span class="badge badge--info">Preview</span>
|
||||||
|
|
||||||
|
Provision users and groups in authentik using an SCIM API.
|
||||||
|
|
||||||
|
For details refer to [SCIM Source](../../../integrations/sources/scim/)
|
||||||
|
|
||||||
|
- **Configurable WebAuthn device restrictions**
|
||||||
|
|
||||||
|
Configure which types of WebAuthn devices can be used to enroll and validate for different authorization levels.
|
||||||
|
|
||||||
|
For details refer to [WebAuthn authenticator setup stage](../../flow/stages/authenticator_webauthn/index.md)
|
||||||
|
|
||||||
|
- **Revamped UI for log messages**
|
||||||
|
|
||||||
|
Log messages from several API endpoints are now shown with much greater detail, which helps with implementing custom policies and property mappings.
|
||||||
|
|
||||||
|
- **Python API Client**
|
||||||
|
|
||||||
|
There's now an official API Client for Python: https://pypi.org/project/authentik-client/. This API Client can be used to create/update/delete objects within authentik as well as using the Flow executor to authenticate.
|
||||||
|
|
||||||
|
- **Configure LDAP sources to not store hashed password in authentik**
|
||||||
|
|
||||||
|
When authentik is configured to federate with an LDAP source, upon authentication, authentik hashed the password and stored it in its own database. This allows authentication to function when LDAP is unreachable. Admins can now configure this behavior for when this is not desirable.
|
||||||
|
|
||||||
|
For details refer to [LDAP Source](../../../integrations/sources/ldap/)
|
||||||
|
|
||||||
|
- **Configurable app password token expiring**
|
||||||
|
|
||||||
|
Thanks @jmdilly for contributing this feature!
|
||||||
|
|
||||||
|
Admins can now configure the default token duration (which defaults to `minutes=30`) in the admin interface as specified above. This value can also be overridden per-user with the `goauthentik.io/user/token-maximum-lifetime` attribute.
|
||||||
|
|
||||||
|
## Upgrading
|
||||||
|
|
||||||
|
This release does not introduce any new requirements.
|
||||||
|
|
||||||
|
### docker-compose
|
||||||
|
|
||||||
|
To upgrade, download the new docker-compose file and update the Docker stack with the new version, using these commands:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
wget -O docker-compose.yml https://goauthentik.io/version/2024.4/docker-compose.yml
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
The `-O` flag retains the downloaded file's name, overwriting any existing local file with the same name.
|
||||||
|
|
||||||
|
### Kubernetes
|
||||||
|
|
||||||
|
Upgrade the Helm Chart to the new version, using the following commands:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
helm repo update
|
||||||
|
helm upgrade authentik authentik/authentik -f values.yaml --version ^2024.4
|
||||||
|
```
|
||||||
|
|
||||||
|
## Minor changes/fixes
|
||||||
|
|
||||||
|
<!-- _Insert the output of `make gen-changelog` here_ -->
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
<!-- _Insert output of `make gen-diff` here_ -->
|
@ -3,6 +3,12 @@ title: Release xxxx.x
|
|||||||
slug: "/releases/xxxx.x"
|
slug: "/releases/xxxx.x"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
:::::note
|
||||||
|
xxxx.x has not been released yet! We're publishing these release notes as a preview of what's to come, and for our awesome beta testers trying out release candidates.
|
||||||
|
|
||||||
|
To try out the release candidate, replace your Docker image tag with the latest release candidate number, such as xxxx.x.0-rc1. You can find the latest one in [the latest releases on GitHub](https://github.com/goauthentik/authentik/releases). If you don't find any, it means we haven't released one yet.
|
||||||
|
:::::
|
||||||
|
|
||||||
<!-- ## Breaking changes -->
|
<!-- ## Breaking changes -->
|
||||||
|
|
||||||
## New features
|
## New features
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
---
|
---
|
||||||
title: LDAP
|
title: LDAP Source
|
||||||
---
|
---
|
||||||
|
|
||||||
Sources allow you to connect authentik to an existing user directory. They can also be used for social logins, using external providers such as Facebook, Twitter, etc.
|
Sources allow you to connect authentik to an existing user directory. They can also be used for social logins, using external providers such as Facebook, Twitter, etc.
|
||||||
|
|
||||||
## LDAP Source
|
|
||||||
|
|
||||||
This source allows you to import users and groups from an LDAP Server.
|
This source allows you to import users and groups from an LDAP Server.
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
@ -54,7 +52,7 @@ Be aware of the following security considerations when turning on this functiona
|
|||||||
|
|
||||||
- Updating the LDAP password does not invalid the password stored in authentik, however for LDAP Servers like FreeIPA and Active Directory, authentik will lock its internal password during the next LDAP sync. For other LDAP servers, the old passwords will still be valid indefinitely.
|
- Updating the LDAP password does not invalid the password stored in authentik, however for LDAP Servers like FreeIPA and Active Directory, authentik will lock its internal password during the next LDAP sync. For other LDAP servers, the old passwords will still be valid indefinitely.
|
||||||
- Logging in via LDAP credentials overwrites the password stored in authentik if users have different passwords in LDAP and authentik.
|
- Logging in via LDAP credentials overwrites the password stored in authentik if users have different passwords in LDAP and authentik.
|
||||||
- Custom security measures used to secure the password in LDAP may differ from the ones used in authentik. Depending on thread model and security requirements this could lead to unknowingly being non-compliant.
|
- Custom security measures used to secure the password in LDAP may differ from the ones used in authentik. Depending on threat model and security requirements this could lead to unknowingly being non-compliant.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: OAuth
|
title: OAuth Source
|
||||||
---
|
---
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: SCIM source
|
title: SCIM Source
|
||||||
---
|
---
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
@ -10,14 +10,20 @@ The SCIM source allows other applications to directly create users and groups wi
|
|||||||
|
|
||||||
The base SCIM URL is in the format of `https://authentik.company/source/scim/<source-slug>/v2`. Authentication is done via Bearer tokens that are generated by authentik. When an SCIM source is created, a service account is created and a matching token is provided.
|
The base SCIM URL is in the format of `https://authentik.company/source/scim/<source-slug>/v2`. Authentication is done via Bearer tokens that are generated by authentik. When an SCIM source is created, a service account is created and a matching token is provided.
|
||||||
|
|
||||||
|
## First steps
|
||||||
|
|
||||||
|
To set up an SCIM source, log in as an administrator into authentik. Navigate to **Directory->Federation & Social login**, and click on **Create**. Select the **SCIM Source** type in the wizard, and give the source a name.
|
||||||
|
|
||||||
|
After the source is created, click on the name of the source in the list, and you will see the **SCIM Base URL** which is used by the SCIM client. Use the **Click to copy token** button to copy the token which is used by the client to authenticate SCIM requests.
|
||||||
|
|
||||||
## Supported Options & Resource types
|
## Supported Options & Resource types
|
||||||
|
|
||||||
### `/v2/Users`
|
### `/v2/Users`
|
||||||
|
|
||||||
Endpoint to list, create, patch, and delete users.
|
Endpoint to list, create, update and delete users.
|
||||||
|
|
||||||
### `/v2/Groups`
|
### `/v2/Groups`
|
||||||
|
|
||||||
Endpoint to list, create, patch, and delete groups.
|
Endpoint to list, create, update and delete groups.
|
||||||
|
|
||||||
There is also the `/v2/ServiceProviderConfig` and `/v2/ResourceTypes`, which is used by SCIM-enabled applications to find out which features authentik supports.
|
There is also the `/v2/ServiceProviderConfig` and `/v2/ResourceTypes`, which is used by SCIM-enabled applications to find out which features authentik supports.
|
||||||
|
@ -343,13 +343,14 @@ const docsSidebar = {
|
|||||||
description: "Release notes for recent authentik versions",
|
description: "Release notes for recent authentik versions",
|
||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
|
"releases/2024/v2024.4",
|
||||||
"releases/2024/v2024.2",
|
"releases/2024/v2024.2",
|
||||||
"releases/2023/v2023.10",
|
"releases/2023/v2023.10",
|
||||||
"releases/2023/v2023.8",
|
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
label: "Previous versions",
|
label: "Previous versions",
|
||||||
items: [
|
items: [
|
||||||
|
"releases/2023/v2023.8",
|
||||||
"releases/2023/v2023.6",
|
"releases/2023/v2023.6",
|
||||||
"releases/2023/v2023.5",
|
"releases/2023/v2023.5",
|
||||||
"releases/2023/v2023.4",
|
"releases/2023/v2023.4",
|
||||||
|
@ -47,6 +47,7 @@ module.exports = {
|
|||||||
"api/making-schema-changes",
|
"api/making-schema-changes",
|
||||||
"api/websocket",
|
"api/websocket",
|
||||||
"api/browser",
|
"api/browser",
|
||||||
|
"api/clients",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user