Compare commits
69 Commits
static-con
...
docs-test-
Author | SHA1 | Date | |
---|---|---|---|
b0679bb0fa | |||
153fc7cc3b | |||
5eb848e376 | |||
61a293daad | |||
edf3300944 | |||
5d9c40eac8 | |||
6ebfbcb66e | |||
bf0235c113 | |||
895cd23b57 | |||
c908d9e95e | |||
a07fd8d54b | |||
39a46a6dc4 | |||
ad71960d77 | |||
2a384511f5 | |||
4dcc104947 | |||
71fe526e47 | |||
03e3f516ac | |||
3b59333246 | |||
4e800c14cb | |||
789b29a3e7 | |||
857b6e63a0 | |||
edc937dd78 | |||
d98b6f29d4 | |||
53ba2a0ca8 | |||
ae364292e6 | |||
f15bc2df97 | |||
b27d49e55f | |||
e0d2beb225 | |||
2313b4755b | |||
1cffadecb0 | |||
5e163d6da1 | |||
0626e18674 | |||
e986a62a12 | |||
e25afcb84a | |||
bb95613104 | |||
89dfac2f57 | |||
31462b55e6 | |||
60337c1cf0 | |||
343d3bb1fb | |||
11fe86c4f6 | |||
963ce085e4 | |||
3642b89ab0 | |||
8cfb371ed3 | |||
6e74edb9f2 | |||
397905f8f0 | |||
7fd35b1dfc | |||
9ba03f5439 | |||
1139d6d27c | |||
077fd966c2 | |||
bd41822a57 | |||
dfd3d76434 | |||
397e98906d | |||
65d8da8c64 | |||
5b435297c5 | |||
f792fd42f6 | |||
70c0fdd5fa | |||
9b636eba01 | |||
a982224502 | |||
6a16cccb40 | |||
6dac91e2b4 | |||
3e2d0532d1 | |||
4e1300650b | |||
06b3ed0c9c | |||
395ad722b7 | |||
9917d81246 | |||
2a87687d34 | |||
a726c2260a | |||
44e0bfd4ef | |||
8d0b362c9c |
1
.github/workflows/api-py-publish.yml
vendored
1
.github/workflows/api-py-publish.yml
vendored
@ -30,7 +30,6 @@ jobs:
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version-file: "pyproject.toml"
|
||||
cache: "poetry"
|
||||
- name: Generate API Client
|
||||
run: make gen-client-py
|
||||
- name: Publish package
|
||||
|
45
.github/workflows/packages-npm-publish.yml
vendored
Normal file
45
.github/workflows/packages-npm-publish.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
name: authentik-packages-npm-publish
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- packages/docusaurus-config
|
||||
- packages/eslint-config
|
||||
- packages/prettier-config
|
||||
- packages/tsconfig
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
publish:
|
||||
if: ${{ github.repository != 'goauthentik/authentik-internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
package:
|
||||
- docusaurus-config
|
||||
- eslint-config
|
||||
- prettier-config
|
||||
- tsconfig
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: packages/${{ matrix.package }}/package.json
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
|
||||
with:
|
||||
files: |
|
||||
packages/${{ matrix.package }}/package.json
|
||||
- name: Publish package
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
working-directory: packages/${{ matrix.package}}
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -11,6 +11,10 @@ local_settings.py
|
||||
db.sqlite3
|
||||
media
|
||||
|
||||
# Node
|
||||
|
||||
node_modules
|
||||
|
||||
# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
|
||||
# in your Git repository. Update and uncomment the following line accordingly.
|
||||
# <django-project-name>/staticfiles/
|
||||
|
47
.prettierignore
Normal file
47
.prettierignore
Normal file
@ -0,0 +1,47 @@
|
||||
# Prettier Ignorefile
|
||||
|
||||
## Static Files
|
||||
**/LICENSE
|
||||
|
||||
authentik/stages/**/*
|
||||
|
||||
## Build asset directories
|
||||
coverage
|
||||
dist
|
||||
out
|
||||
.docusaurus
|
||||
website/docs/developer-docs/api/**/*
|
||||
|
||||
## Environment
|
||||
*.env
|
||||
|
||||
## Secrets
|
||||
*.secrets
|
||||
|
||||
## Yarn
|
||||
.yarn/**/*
|
||||
|
||||
## Node
|
||||
node_modules
|
||||
coverage
|
||||
|
||||
## Configs
|
||||
*.log
|
||||
*.yaml
|
||||
*.yml
|
||||
|
||||
# Templates
|
||||
# TODO: Rename affected files to *.template.* or similar.
|
||||
*.html
|
||||
*.mdx
|
||||
*.md
|
||||
|
||||
## Import order matters
|
||||
poly.ts
|
||||
src/locale-codes.ts
|
||||
src/locales/
|
||||
|
||||
# Storybook
|
||||
storybook-static/
|
||||
.storybook/css-import-maps*
|
||||
|
@ -23,6 +23,8 @@ docker-compose.yml @goauthentik/infrastructure
|
||||
Makefile @goauthentik/infrastructure
|
||||
.editorconfig @goauthentik/infrastructure
|
||||
CODEOWNERS @goauthentik/infrastructure
|
||||
# Web packages
|
||||
packages/ @goauthentik/frontend
|
||||
# Web
|
||||
web/ @goauthentik/frontend
|
||||
tests/wdio/ @goauthentik/frontend
|
||||
|
@ -96,7 +96,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
||||
# Stage 5: Download uv
|
||||
FROM ghcr.io/astral-sh/uv:0.6.14 AS uv
|
||||
# Stage 6: Base python image
|
||||
FROM ghcr.io/goauthentik/fips-python:3.12.9-slim-bookworm-fips AS python-base
|
||||
FROM ghcr.io/goauthentik/fips-python:3.12.10-slim-bookworm-fips AS python-base
|
||||
|
||||
ENV VENV_PATH="/ak-root/.venv" \
|
||||
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
|
||||
|
@ -36,6 +36,7 @@ from authentik.core.models import (
|
||||
GroupSourceConnection,
|
||||
PropertyMapping,
|
||||
Provider,
|
||||
Session,
|
||||
Source,
|
||||
User,
|
||||
UserSourceConnection,
|
||||
@ -108,6 +109,7 @@ def excluded_models() -> list[type[Model]]:
|
||||
Policy,
|
||||
PolicyBindingModel,
|
||||
# Classes that have other dependencies
|
||||
Session,
|
||||
AuthenticatedSession,
|
||||
# Classes which are only internally managed
|
||||
# FIXME: these shouldn't need to be explicitly listed, but rather based off of a mixin
|
||||
|
@ -5,6 +5,7 @@ from typing import TypedDict
|
||||
from rest_framework import mixins
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.serializers import CharField, DateTimeField, IPAddressField
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
from ua_parser import user_agent_parser
|
||||
|
||||
@ -54,6 +55,11 @@ class UserAgentDict(TypedDict):
|
||||
class AuthenticatedSessionSerializer(ModelSerializer):
|
||||
"""AuthenticatedSession Serializer"""
|
||||
|
||||
expires = DateTimeField(source="session.expires", read_only=True)
|
||||
last_ip = IPAddressField(source="session.last_ip", read_only=True)
|
||||
last_user_agent = CharField(source="session.last_user_agent", read_only=True)
|
||||
last_used = DateTimeField(source="session.last_used", read_only=True)
|
||||
|
||||
current = SerializerMethodField()
|
||||
user_agent = SerializerMethodField()
|
||||
geo_ip = SerializerMethodField()
|
||||
@ -62,19 +68,19 @@ class AuthenticatedSessionSerializer(ModelSerializer):
|
||||
def get_current(self, instance: AuthenticatedSession) -> bool:
|
||||
"""Check if session is currently active session"""
|
||||
request: Request = self.context["request"]
|
||||
return request._request.session.session_key == instance.session_key
|
||||
return request._request.session.session_key == instance.session.session_key
|
||||
|
||||
def get_user_agent(self, instance: AuthenticatedSession) -> UserAgentDict:
|
||||
"""Get parsed user agent"""
|
||||
return user_agent_parser.Parse(instance.last_user_agent)
|
||||
return user_agent_parser.Parse(instance.session.last_user_agent)
|
||||
|
||||
def get_geo_ip(self, instance: AuthenticatedSession) -> GeoIPDict | None: # pragma: no cover
|
||||
"""Get GeoIP Data"""
|
||||
return GEOIP_CONTEXT_PROCESSOR.city_dict(instance.last_ip)
|
||||
return GEOIP_CONTEXT_PROCESSOR.city_dict(instance.session.last_ip)
|
||||
|
||||
def get_asn(self, instance: AuthenticatedSession) -> ASNDict | None: # pragma: no cover
|
||||
"""Get ASN Data"""
|
||||
return ASN_CONTEXT_PROCESSOR.asn_dict(instance.last_ip)
|
||||
return ASN_CONTEXT_PROCESSOR.asn_dict(instance.session.last_ip)
|
||||
|
||||
class Meta:
|
||||
model = AuthenticatedSession
|
||||
@ -90,6 +96,7 @@ class AuthenticatedSessionSerializer(ModelSerializer):
|
||||
"last_used",
|
||||
"expires",
|
||||
]
|
||||
extra_args = {"uuid": {"read_only": True}}
|
||||
|
||||
|
||||
class AuthenticatedSessionViewSet(
|
||||
@ -101,9 +108,10 @@ class AuthenticatedSessionViewSet(
|
||||
):
|
||||
"""AuthenticatedSession Viewset"""
|
||||
|
||||
queryset = AuthenticatedSession.objects.all()
|
||||
lookup_field = "uuid"
|
||||
queryset = AuthenticatedSession.objects.select_related("session").all()
|
||||
serializer_class = AuthenticatedSessionSerializer
|
||||
search_fields = ["user__username", "last_ip", "last_user_agent"]
|
||||
filterset_fields = ["user__username", "last_ip", "last_user_agent"]
|
||||
search_fields = ["user__username", "session__last_ip", "session__last_user_agent"]
|
||||
filterset_fields = ["user__username", "session__last_ip", "session__last_user_agent"]
|
||||
ordering = ["user__username"]
|
||||
owner_field = "user"
|
||||
|
@ -1,14 +1,11 @@
|
||||
"""User API Views"""
|
||||
|
||||
from datetime import timedelta
|
||||
from importlib import import_module
|
||||
from json import loads
|
||||
from typing import Any
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import update_session_auth_hash
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.sessions.backends.base import SessionBase
|
||||
from django.db.models.functions import ExtractHour
|
||||
from django.db.transaction import atomic
|
||||
from django.db.utils import IntegrityError
|
||||
@ -72,8 +69,8 @@ from authentik.core.middleware import (
|
||||
from authentik.core.models import (
|
||||
USER_ATTRIBUTE_TOKEN_EXPIRING,
|
||||
USER_PATH_SERVICE_ACCOUNT,
|
||||
AuthenticatedSession,
|
||||
Group,
|
||||
Session,
|
||||
Token,
|
||||
TokenIntents,
|
||||
User,
|
||||
@ -92,7 +89,6 @@ from authentik.stages.email.tasks import send_mails
|
||||
from authentik.stages.email.utils import TemplateEmailMessage
|
||||
|
||||
LOGGER = get_logger()
|
||||
SessionStore: SessionBase = import_module(settings.SESSION_ENGINE).SessionStore
|
||||
|
||||
|
||||
class UserGroupSerializer(ModelSerializer):
|
||||
@ -776,10 +772,6 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
||||
response = super().partial_update(request, *args, **kwargs)
|
||||
instance: User = self.get_object()
|
||||
if not instance.is_active:
|
||||
sessions = AuthenticatedSession.objects.filter(user=instance)
|
||||
session_ids = sessions.values_list("session_key", flat=True)
|
||||
for session in session_ids:
|
||||
SessionStore(session).delete()
|
||||
sessions.delete()
|
||||
Session.objects.filter(authenticatedsession__user=instance).delete()
|
||||
LOGGER.debug("Deleted user's sessions", user=instance.username)
|
||||
return response
|
||||
|
@ -24,6 +24,15 @@ class InbuiltBackend(ModelBackend):
|
||||
self.set_method("password", request)
|
||||
return user
|
||||
|
||||
async def aauthenticate(
|
||||
self, request: HttpRequest, username: str | None, password: str | None, **kwargs: Any
|
||||
) -> User | None:
|
||||
user = await super().aauthenticate(request, username=username, password=password, **kwargs)
|
||||
if not user:
|
||||
return None
|
||||
self.set_method("password", request)
|
||||
return user
|
||||
|
||||
def set_method(self, method: str, request: HttpRequest | None, **kwargs):
|
||||
"""Set method data on current flow, if possbiel"""
|
||||
if not request:
|
||||
|
15
authentik/core/management/commands/clearsessions.py
Normal file
15
authentik/core/management/commands/clearsessions.py
Normal file
@ -0,0 +1,15 @@
|
||||
"""Change user type"""
|
||||
|
||||
from importlib import import_module
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from authentik.tenants.management import TenantCommand
|
||||
|
||||
|
||||
class Command(TenantCommand):
|
||||
"""Delete all sessions"""
|
||||
|
||||
def handle_per_tenant(self, **options):
|
||||
engine = import_module(settings.SESSION_ENGINE)
|
||||
engine.SessionStore.clear_expired()
|
@ -2,9 +2,14 @@
|
||||
|
||||
from collections.abc import Callable
|
||||
from contextvars import ContextVar
|
||||
from functools import partial
|
||||
from uuid import uuid4
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
from django.utils.functional import SimpleLazyObject
|
||||
from django.utils.translation import override
|
||||
from sentry_sdk.api import set_tag
|
||||
from structlog.contextvars import STRUCTLOG_KEY_PREFIX
|
||||
@ -20,6 +25,40 @@ CTX_HOST = ContextVar[str | None](STRUCTLOG_KEY_PREFIX + "host", default=None)
|
||||
CTX_AUTH_VIA = ContextVar[str | None](STRUCTLOG_KEY_PREFIX + KEY_AUTH_VIA, default=None)
|
||||
|
||||
|
||||
def get_user(request):
|
||||
if not hasattr(request, "_cached_user"):
|
||||
user = None
|
||||
if (authenticated_session := request.session.get("authenticatedsession", None)) is not None:
|
||||
user = authenticated_session.user
|
||||
request._cached_user = user or AnonymousUser()
|
||||
return request._cached_user
|
||||
|
||||
|
||||
async def aget_user(request):
|
||||
if not hasattr(request, "_cached_user"):
|
||||
user = None
|
||||
if (
|
||||
authenticated_session := await request.session.aget("authenticatedsession", None)
|
||||
) is not None:
|
||||
user = authenticated_session.user
|
||||
request._cached_user = user or AnonymousUser()
|
||||
return request._cached_user
|
||||
|
||||
|
||||
class AuthenticationMiddleware(MiddlewareMixin):
|
||||
def process_request(self, request):
|
||||
if not hasattr(request, "session"):
|
||||
raise ImproperlyConfigured(
|
||||
"The Django authentication middleware requires session "
|
||||
"middleware to be installed. Edit your MIDDLEWARE setting to "
|
||||
"insert "
|
||||
"'authentik.root.middleware.SessionMiddleware' before "
|
||||
"'authentik.core.middleware.AuthenticationMiddleware'."
|
||||
)
|
||||
request.user = SimpleLazyObject(lambda: get_user(request))
|
||||
request.auser = partial(aget_user, request)
|
||||
|
||||
|
||||
class ImpersonateMiddleware:
|
||||
"""Middleware to impersonate users"""
|
||||
|
||||
|
238
authentik/core/migrations/0046_session_and_more.py
Normal file
238
authentik/core/migrations/0046_session_and_more.py
Normal file
@ -0,0 +1,238 @@
|
||||
# Generated by Django 5.0.11 on 2025-01-27 12:58
|
||||
|
||||
import uuid
|
||||
import pickle # nosec
|
||||
from django.core import signing
|
||||
from django.contrib.auth import BACKEND_SESSION_KEY, HASH_SESSION_KEY, SESSION_KEY
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.contrib.sessions.backends.cache import KEY_PREFIX
|
||||
from django.utils.timezone import now, timedelta
|
||||
from authentik.lib.migrations import progress_bar
|
||||
from authentik.root.middleware import ClientIPMiddleware
|
||||
|
||||
|
||||
SESSION_CACHE_ALIAS = "default"
|
||||
|
||||
|
||||
class PickleSerializer:
|
||||
"""
|
||||
Simple wrapper around pickle to be used in signing.dumps()/loads() and
|
||||
cache backends.
|
||||
"""
|
||||
|
||||
def __init__(self, protocol=None):
|
||||
self.protocol = pickle.HIGHEST_PROTOCOL if protocol is None else protocol
|
||||
|
||||
def dumps(self, obj):
|
||||
"""Pickle data to be stored in redis"""
|
||||
return pickle.dumps(obj, self.protocol)
|
||||
|
||||
def loads(self, data):
|
||||
"""Unpickle data to be loaded from redis"""
|
||||
return pickle.loads(data) # nosec
|
||||
|
||||
|
||||
def _migrate_session(
|
||||
apps,
|
||||
db_alias,
|
||||
session_key,
|
||||
session_data,
|
||||
expires,
|
||||
):
|
||||
Session = apps.get_model("authentik_core", "Session")
|
||||
OldAuthenticatedSession = apps.get_model("authentik_core", "OldAuthenticatedSession")
|
||||
AuthenticatedSession = apps.get_model("authentik_core", "AuthenticatedSession")
|
||||
|
||||
old_auth_session = (
|
||||
OldAuthenticatedSession.objects.using(db_alias).filter(session_key=session_key).first()
|
||||
)
|
||||
|
||||
args = {
|
||||
"session_key": session_key,
|
||||
"expires": expires,
|
||||
"last_ip": ClientIPMiddleware.default_ip,
|
||||
"last_user_agent": "",
|
||||
"session_data": {},
|
||||
}
|
||||
for k, v in session_data.items():
|
||||
if k == "authentik/stages/user_login/last_ip":
|
||||
args["last_ip"] = v
|
||||
elif k in ["last_user_agent", "last_used"]:
|
||||
args[k] = v
|
||||
elif args in [SESSION_KEY, BACKEND_SESSION_KEY, HASH_SESSION_KEY]:
|
||||
pass
|
||||
else:
|
||||
args["session_data"][k] = v
|
||||
if old_auth_session:
|
||||
args["last_user_agent"] = old_auth_session.last_user_agent
|
||||
args["last_used"] = old_auth_session.last_used
|
||||
|
||||
args["session_data"] = pickle.dumps(args["session_data"])
|
||||
session = Session.objects.using(db_alias).create(**args)
|
||||
|
||||
if old_auth_session:
|
||||
AuthenticatedSession.objects.using(db_alias).create(
|
||||
session=session,
|
||||
user=old_auth_session.user,
|
||||
)
|
||||
|
||||
|
||||
def migrate_redis_sessions(apps, schema_editor):
|
||||
from django.core.cache import caches
|
||||
|
||||
db_alias = schema_editor.connection.alias
|
||||
cache = caches[SESSION_CACHE_ALIAS]
|
||||
|
||||
# Not a redis cache, skipping
|
||||
if not hasattr(cache, "keys"):
|
||||
return
|
||||
|
||||
print("\nMigrating Redis sessions to database, this might take a couple of minutes...")
|
||||
for key, session_data in progress_bar(cache.get_many(cache.keys(f"{KEY_PREFIX}*")).items()):
|
||||
_migrate_session(
|
||||
apps=apps,
|
||||
db_alias=db_alias,
|
||||
session_key=key.removeprefix(KEY_PREFIX),
|
||||
session_data=session_data,
|
||||
expires=now() + timedelta(seconds=cache.ttl(key)),
|
||||
)
|
||||
|
||||
|
||||
def migrate_database_sessions(apps, schema_editor):
|
||||
DjangoSession = apps.get_model("sessions", "Session")
|
||||
db_alias = schema_editor.connection.alias
|
||||
|
||||
print("\nMigration database sessions, this might take a couple of minutes...")
|
||||
for django_session in progress_bar(DjangoSession.objects.using(db_alias).all()):
|
||||
session_data = signing.loads(
|
||||
django_session.session_data,
|
||||
salt="django.contrib.sessions.SessionStore",
|
||||
serializer=PickleSerializer,
|
||||
)
|
||||
_migrate_session(
|
||||
apps=apps,
|
||||
db_alias=db_alias,
|
||||
session_key=django_session.session_key,
|
||||
session_data=session_data,
|
||||
expires=django_session.expire_date,
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("sessions", "0001_initial"),
|
||||
("authentik_core", "0045_rename_new_identifier_usersourceconnection_identifier_and_more"),
|
||||
("authentik_providers_oauth2", "0027_accesstoken_authentik_p_expires_9f24a5_idx_and_more"),
|
||||
("authentik_providers_rac", "0006_connectiontoken_authentik_p_expires_91f148_idx_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Rename AuthenticatedSession to OldAuthenticatedSession
|
||||
migrations.RenameModel(
|
||||
old_name="AuthenticatedSession",
|
||||
new_name="OldAuthenticatedSession",
|
||||
),
|
||||
migrations.RenameIndex(
|
||||
model_name="oldauthenticatedsession",
|
||||
new_name="authentik_c_expires_cf4f72_idx",
|
||||
old_name="authentik_c_expires_08251d_idx",
|
||||
),
|
||||
migrations.RenameIndex(
|
||||
model_name="oldauthenticatedsession",
|
||||
new_name="authentik_c_expirin_c1f17f_idx",
|
||||
old_name="authentik_c_expirin_9cd839_idx",
|
||||
),
|
||||
migrations.RenameIndex(
|
||||
model_name="oldauthenticatedsession",
|
||||
new_name="authentik_c_expirin_e04f5d_idx",
|
||||
old_name="authentik_c_expirin_195a84_idx",
|
||||
),
|
||||
migrations.RenameIndex(
|
||||
model_name="oldauthenticatedsession",
|
||||
new_name="authentik_c_session_a44819_idx",
|
||||
old_name="authentik_c_session_d0f005_idx",
|
||||
),
|
||||
migrations.RunSQL(
|
||||
sql="ALTER INDEX authentik_core_authenticatedsession_user_id_5055b6cf RENAME TO authentik_core_oldauthenticatedsession_user_id_5055b6cf",
|
||||
reverse_sql="ALTER INDEX authentik_core_oldauthenticatedsession_user_id_5055b6cf RENAME TO authentik_core_authenticatedsession_user_id_5055b6cf",
|
||||
),
|
||||
# Create new Session and AuthenticatedSession models
|
||||
migrations.CreateModel(
|
||||
name="Session",
|
||||
fields=[
|
||||
(
|
||||
"session_key",
|
||||
models.CharField(
|
||||
max_length=40, primary_key=True, serialize=False, verbose_name="session key"
|
||||
),
|
||||
),
|
||||
("expires", models.DateTimeField(default=None, null=True)),
|
||||
("expiring", models.BooleanField(default=True)),
|
||||
("session_data", models.BinaryField(verbose_name="session data")),
|
||||
("last_ip", models.GenericIPAddressField()),
|
||||
("last_user_agent", models.TextField(blank=True)),
|
||||
("last_used", models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
"default_permissions": [],
|
||||
"verbose_name": "Session",
|
||||
"verbose_name_plural": "Sessions",
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="session",
|
||||
index=models.Index(fields=["expires"], name="authentik_c_expires_d2f607_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="session",
|
||||
index=models.Index(fields=["expiring"], name="authentik_c_expirin_7c2cfb_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="session",
|
||||
index=models.Index(
|
||||
fields=["expiring", "expires"], name="authentik_c_expirin_1ab2e4_idx"
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="session",
|
||||
index=models.Index(
|
||||
fields=["expires", "session_key"], name="authentik_c_expires_c49143_idx"
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="AuthenticatedSession",
|
||||
fields=[
|
||||
(
|
||||
"session",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="authentik_core.session",
|
||||
),
|
||||
),
|
||||
("uuid", models.UUIDField(default=uuid.uuid4, unique=True)),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Authenticated Session",
|
||||
"verbose_name_plural": "Authenticated Sessions",
|
||||
},
|
||||
),
|
||||
migrations.RunPython(
|
||||
code=migrate_redis_sessions,
|
||||
reverse_code=migrations.RunPython.noop,
|
||||
),
|
||||
migrations.RunPython(
|
||||
code=migrate_database_sessions,
|
||||
reverse_code=migrations.RunPython.noop,
|
||||
),
|
||||
]
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.11 on 2025-01-27 13:02
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_core", "0046_session_and_more"),
|
||||
("authentik_providers_rac", "0007_migrate_session"),
|
||||
("authentik_providers_oauth2", "0028_migrate_session"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name="OldAuthenticatedSession",
|
||||
),
|
||||
]
|
@ -1,6 +1,7 @@
|
||||
"""authentik core models"""
|
||||
|
||||
from datetime import datetime
|
||||
from enum import StrEnum
|
||||
from hashlib import sha256
|
||||
from typing import Any, Optional, Self
|
||||
from uuid import uuid4
|
||||
@ -9,6 +10,7 @@ from deepmerge import always_merger
|
||||
from django.contrib.auth.hashers import check_password
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
||||
from django.contrib.sessions.base_session import AbstractBaseSession
|
||||
from django.db import models
|
||||
from django.db.models import Q, QuerySet, options
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
@ -646,19 +648,30 @@ class SourceUserMatchingModes(models.TextChoices):
|
||||
"""Different modes a source can handle new/returning users"""
|
||||
|
||||
IDENTIFIER = "identifier", _("Use the source-specific identifier")
|
||||
EMAIL_LINK = "email_link", _(
|
||||
"Link to a user with identical email address. Can have security implications "
|
||||
"when a source doesn't validate email addresses."
|
||||
EMAIL_LINK = (
|
||||
"email_link",
|
||||
_(
|
||||
"Link to a user with identical email address. Can have security implications "
|
||||
"when a source doesn't validate email addresses."
|
||||
),
|
||||
)
|
||||
EMAIL_DENY = "email_deny", _(
|
||||
"Use the user's email address, but deny enrollment when the email address already exists."
|
||||
EMAIL_DENY = (
|
||||
"email_deny",
|
||||
_(
|
||||
"Use the user's email address, but deny enrollment when the email address already "
|
||||
"exists."
|
||||
),
|
||||
)
|
||||
USERNAME_LINK = "username_link", _(
|
||||
"Link to a user with identical username. Can have security implications "
|
||||
"when a username is used with another source."
|
||||
USERNAME_LINK = (
|
||||
"username_link",
|
||||
_(
|
||||
"Link to a user with identical username. Can have security implications "
|
||||
"when a username is used with another source."
|
||||
),
|
||||
)
|
||||
USERNAME_DENY = "username_deny", _(
|
||||
"Use the user's username, but deny enrollment when the username already exists."
|
||||
USERNAME_DENY = (
|
||||
"username_deny",
|
||||
_("Use the user's username, but deny enrollment when the username already exists."),
|
||||
)
|
||||
|
||||
|
||||
@ -666,12 +679,16 @@ class SourceGroupMatchingModes(models.TextChoices):
|
||||
"""Different modes a source can handle new/returning groups"""
|
||||
|
||||
IDENTIFIER = "identifier", _("Use the source-specific identifier")
|
||||
NAME_LINK = "name_link", _(
|
||||
"Link to a group with identical name. Can have security implications "
|
||||
"when a group name is used with another source."
|
||||
NAME_LINK = (
|
||||
"name_link",
|
||||
_(
|
||||
"Link to a group with identical name. Can have security implications "
|
||||
"when a group name is used with another source."
|
||||
),
|
||||
)
|
||||
NAME_DENY = "name_deny", _(
|
||||
"Use the group name, but deny enrollment when the name already exists."
|
||||
NAME_DENY = (
|
||||
"name_deny",
|
||||
_("Use the group name, but deny enrollment when the name already exists."),
|
||||
)
|
||||
|
||||
|
||||
@ -730,8 +747,7 @@ class Source(ManagedModel, SerializerModel, PolicyBindingModel):
|
||||
choices=SourceGroupMatchingModes.choices,
|
||||
default=SourceGroupMatchingModes.IDENTIFIER,
|
||||
help_text=_(
|
||||
"How the source determines if an existing group should be used or "
|
||||
"a new group created."
|
||||
"How the source determines if an existing group should be used or a new group created."
|
||||
),
|
||||
)
|
||||
|
||||
@ -1012,45 +1028,75 @@ class PropertyMapping(SerializerModel, ManagedModel):
|
||||
verbose_name_plural = _("Property Mappings")
|
||||
|
||||
|
||||
class AuthenticatedSession(ExpiringModel):
|
||||
"""Additional session class for authenticated users. Augments the standard django session
|
||||
to achieve the following:
|
||||
- Make it queryable by user
|
||||
- Have a direct connection to user objects
|
||||
- Allow users to view their own sessions and terminate them
|
||||
- Save structured and well-defined information.
|
||||
"""
|
||||
class Session(ExpiringModel, AbstractBaseSession):
|
||||
"""User session with extra fields for fast access"""
|
||||
|
||||
uuid = models.UUIDField(default=uuid4, primary_key=True)
|
||||
# Remove upstream field because we're using our own ExpiringModel
|
||||
expire_date = None
|
||||
session_data = models.BinaryField(_("session data"))
|
||||
|
||||
session_key = models.CharField(max_length=40)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
last_ip = models.TextField()
|
||||
# Keep in sync with Session.Keys
|
||||
last_ip = models.GenericIPAddressField()
|
||||
last_user_agent = models.TextField(blank=True)
|
||||
last_used = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Session")
|
||||
verbose_name_plural = _("Sessions")
|
||||
indexes = ExpiringModel.Meta.indexes + [
|
||||
models.Index(fields=["expires", "session_key"]),
|
||||
]
|
||||
default_permissions = []
|
||||
|
||||
def __str__(self):
|
||||
return self.session_key
|
||||
|
||||
class Keys(StrEnum):
|
||||
"""
|
||||
Keys to be set with the session interface for the fields above to be updated.
|
||||
|
||||
If a field is added here that needs to be initialized when the session is initialized,
|
||||
it must also be reflected in authentik.root.middleware.SessionMiddleware.process_request
|
||||
and in authentik.core.sessions.SessionStore.__init__
|
||||
"""
|
||||
|
||||
LAST_IP = "last_ip"
|
||||
LAST_USER_AGENT = "last_user_agent"
|
||||
LAST_USED = "last_used"
|
||||
|
||||
@classmethod
|
||||
def get_session_store_class(cls):
|
||||
from authentik.core.sessions import SessionStore
|
||||
|
||||
return SessionStore
|
||||
|
||||
def get_decoded(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class AuthenticatedSession(SerializerModel):
|
||||
session = models.OneToOneField(Session, on_delete=models.CASCADE, primary_key=True)
|
||||
# We use the session as primary key, but we need the API to be able to reference
|
||||
# this object uniquely without exposing the session key
|
||||
uuid = models.UUIDField(default=uuid4, unique=True)
|
||||
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Authenticated Session")
|
||||
verbose_name_plural = _("Authenticated Sessions")
|
||||
indexes = ExpiringModel.Meta.indexes + [
|
||||
models.Index(fields=["session_key"]),
|
||||
]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Authenticated Session {self.session_key[:10]}"
|
||||
return f"Authenticated Session {str(self.pk)[:10]}"
|
||||
|
||||
@staticmethod
|
||||
def from_request(request: HttpRequest, user: User) -> Optional["AuthenticatedSession"]:
|
||||
"""Create a new session from a http request"""
|
||||
from authentik.root.middleware import ClientIPMiddleware
|
||||
|
||||
if not hasattr(request, "session") or not request.session.session_key:
|
||||
if not hasattr(request, "session") or not request.session.exists(
|
||||
request.session.session_key
|
||||
):
|
||||
return None
|
||||
return AuthenticatedSession(
|
||||
session_key=request.session.session_key,
|
||||
session=Session.objects.filter(session_key=request.session.session_key).first(),
|
||||
user=user,
|
||||
last_ip=ClientIPMiddleware.get_client_ip(request),
|
||||
last_user_agent=request.META.get("HTTP_USER_AGENT", ""),
|
||||
expires=request.session.get_expiry_date(),
|
||||
)
|
||||
|
168
authentik/core/sessions.py
Normal file
168
authentik/core/sessions.py
Normal file
@ -0,0 +1,168 @@
|
||||
"""authentik sessions engine"""
|
||||
|
||||
import pickle # nosec
|
||||
|
||||
from django.contrib.auth import BACKEND_SESSION_KEY, HASH_SESSION_KEY, SESSION_KEY
|
||||
from django.contrib.sessions.backends.db import SessionStore as SessionBase
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
from django.utils import timezone
|
||||
from django.utils.functional import cached_property
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.root.middleware import ClientIPMiddleware
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
class SessionStore(SessionBase):
|
||||
def __init__(self, session_key=None, last_ip=None, last_user_agent=""):
|
||||
super().__init__(session_key)
|
||||
self._create_kwargs = {
|
||||
"last_ip": last_ip or ClientIPMiddleware.default_ip,
|
||||
"last_user_agent": last_user_agent,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_model_class(cls):
|
||||
from authentik.core.models import Session
|
||||
|
||||
return Session
|
||||
|
||||
@cached_property
|
||||
def model_fields(self):
|
||||
return [k.value for k in self.model.Keys]
|
||||
|
||||
def _get_session_from_db(self):
|
||||
try:
|
||||
return (
|
||||
self.model.objects.select_related(
|
||||
"authenticatedsession",
|
||||
"authenticatedsession__user",
|
||||
)
|
||||
.prefetch_related(
|
||||
"authenticatedsession__user__groups",
|
||||
"authenticatedsession__user__user_permissions",
|
||||
)
|
||||
.get(
|
||||
session_key=self.session_key,
|
||||
expires__gt=timezone.now(),
|
||||
)
|
||||
)
|
||||
except (self.model.DoesNotExist, SuspiciousOperation) as exc:
|
||||
if isinstance(exc, SuspiciousOperation):
|
||||
LOGGER.warning(str(exc))
|
||||
self._session_key = None
|
||||
|
||||
async def _aget_session_from_db(self):
|
||||
try:
|
||||
return (
|
||||
await self.model.objects.select_related(
|
||||
"authenticatedsession",
|
||||
"authenticatedsession__user",
|
||||
)
|
||||
.prefetch_related(
|
||||
"authenticatedsession__user__groups",
|
||||
"authenticatedsession__user__user_permissions",
|
||||
)
|
||||
.aget(
|
||||
session_key=self.session_key,
|
||||
expires__gt=timezone.now(),
|
||||
)
|
||||
)
|
||||
except (self.model.DoesNotExist, SuspiciousOperation) as exc:
|
||||
if isinstance(exc, SuspiciousOperation):
|
||||
LOGGER.warning(str(exc))
|
||||
self._session_key = None
|
||||
|
||||
def encode(self, session_dict):
|
||||
return pickle.dumps(session_dict, protocol=pickle.HIGHEST_PROTOCOL)
|
||||
|
||||
def decode(self, session_data):
|
||||
try:
|
||||
return pickle.loads(session_data) # nosec
|
||||
except pickle.PickleError:
|
||||
# ValueError, unpickling exceptions. If any of these happen, just return an empty
|
||||
# dictionary (an empty session)
|
||||
pass
|
||||
return {}
|
||||
|
||||
def load(self):
|
||||
s = self._get_session_from_db()
|
||||
if s:
|
||||
return {
|
||||
"authenticatedsession": getattr(s, "authenticatedsession", None),
|
||||
**{k: getattr(s, k) for k in self.model_fields},
|
||||
**self.decode(s.session_data),
|
||||
}
|
||||
else:
|
||||
return {}
|
||||
|
||||
async def aload(self):
|
||||
s = await self._aget_session_from_db()
|
||||
if s:
|
||||
return {
|
||||
"authenticatedsession": getattr(s, "authenticatedsession", None),
|
||||
**{k: getattr(s, k) for k in self.model_fields},
|
||||
**self.decode(s.session_data),
|
||||
}
|
||||
else:
|
||||
return {}
|
||||
|
||||
def create_model_instance(self, data):
|
||||
args = {
|
||||
"session_key": self._get_or_create_session_key(),
|
||||
"expires": self.get_expiry_date(),
|
||||
"session_data": {},
|
||||
**self._create_kwargs,
|
||||
}
|
||||
for k, v in data.items():
|
||||
# Don't save:
|
||||
# - unused auth data
|
||||
# - related models
|
||||
if k in [SESSION_KEY, BACKEND_SESSION_KEY, HASH_SESSION_KEY, "authenticatedsession"]:
|
||||
pass
|
||||
elif k in self.model_fields:
|
||||
args[k] = v
|
||||
else:
|
||||
args["session_data"][k] = v
|
||||
args["session_data"] = self.encode(args["session_data"])
|
||||
return self.model(**args)
|
||||
|
||||
async def acreate_model_instance(self, data):
|
||||
args = {
|
||||
"session_key": await self._aget_or_create_session_key(),
|
||||
"expires": await self.aget_expiry_date(),
|
||||
"session_data": {},
|
||||
**self._create_kwargs,
|
||||
}
|
||||
for k, v in data.items():
|
||||
# Don't save:
|
||||
# - unused auth data
|
||||
# - related models
|
||||
if k in [SESSION_KEY, BACKEND_SESSION_KEY, HASH_SESSION_KEY, "authenticatedsession"]:
|
||||
pass
|
||||
elif k in self.model_fields:
|
||||
args[k] = v
|
||||
else:
|
||||
args["session_data"][k] = v
|
||||
args["session_data"] = self.encode(args["session_data"])
|
||||
return self.model(**args)
|
||||
|
||||
@classmethod
|
||||
def clear_expired(cls):
|
||||
cls.get_model_class().objects.filter(expires__lt=timezone.now()).delete()
|
||||
|
||||
@classmethod
|
||||
async def aclear_expired(cls):
|
||||
await cls.get_model_class().objects.filter(expires__lt=timezone.now()).adelete()
|
||||
|
||||
def cycle_key(self):
|
||||
data = self._session
|
||||
key = self.session_key
|
||||
self.create()
|
||||
self._session_cache = data
|
||||
if key:
|
||||
self.delete(key)
|
||||
if (authenticated_session := data.get("authenticatedsession")) is not None:
|
||||
authenticated_session.session_id = self.session_key
|
||||
authenticated_session.save(force_insert=True)
|
@ -1,14 +1,10 @@
|
||||
"""authentik core signals"""
|
||||
|
||||
from importlib import import_module
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.signals import user_logged_in, user_logged_out
|
||||
from django.contrib.sessions.backends.base import SessionBase
|
||||
from django.contrib.auth.signals import user_logged_in
|
||||
from django.core.cache import cache
|
||||
from django.core.signals import Signal
|
||||
from django.db.models import Model
|
||||
from django.db.models.signals import post_save, pre_delete, pre_save
|
||||
from django.db.models.signals import post_delete, post_save, pre_save
|
||||
from django.dispatch import receiver
|
||||
from django.http.request import HttpRequest
|
||||
from structlog.stdlib import get_logger
|
||||
@ -18,6 +14,7 @@ from authentik.core.models import (
|
||||
AuthenticatedSession,
|
||||
BackchannelProvider,
|
||||
ExpiringModel,
|
||||
Session,
|
||||
User,
|
||||
default_token_duration,
|
||||
)
|
||||
@ -28,7 +25,6 @@ password_changed = Signal()
|
||||
login_failed = Signal()
|
||||
|
||||
LOGGER = get_logger()
|
||||
SessionStore: SessionBase = import_module(settings.SESSION_ENGINE).SessionStore
|
||||
|
||||
|
||||
@receiver(post_save, sender=Application)
|
||||
@ -53,18 +49,10 @@ def user_logged_in_session(sender, request: HttpRequest, user: User, **_):
|
||||
session.save()
|
||||
|
||||
|
||||
@receiver(user_logged_out)
|
||||
def user_logged_out_session(sender, request: HttpRequest, user: User, **_):
|
||||
"""Delete AuthenticatedSession if it exists"""
|
||||
if not request.session or not request.session.session_key:
|
||||
return
|
||||
AuthenticatedSession.objects.filter(session_key=request.session.session_key).delete()
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=AuthenticatedSession)
|
||||
@receiver(post_delete, sender=AuthenticatedSession)
|
||||
def authenticated_session_delete(sender: type[Model], instance: "AuthenticatedSession", **_):
|
||||
"""Delete session when authenticated session is deleted"""
|
||||
SessionStore(instance.session_key).delete()
|
||||
Session.objects.filter(session_key=instance.pk).delete()
|
||||
|
||||
|
||||
@receiver(pre_save)
|
||||
|
@ -2,22 +2,16 @@
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from django.conf import ImproperlyConfigured
|
||||
from django.contrib.sessions.backends.cache import KEY_PREFIX
|
||||
from django.contrib.sessions.backends.db import SessionStore as DBSessionStore
|
||||
from django.core.cache import cache
|
||||
from django.utils.timezone import now
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import (
|
||||
USER_ATTRIBUTE_EXPIRES,
|
||||
USER_ATTRIBUTE_GENERATED,
|
||||
AuthenticatedSession,
|
||||
ExpiringModel,
|
||||
User,
|
||||
)
|
||||
from authentik.events.system_tasks import SystemTask, TaskStatus, prefill_task
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.root.celery import CELERY_APP
|
||||
|
||||
LOGGER = get_logger()
|
||||
@ -38,40 +32,6 @@ def clean_expired_models(self: SystemTask):
|
||||
obj.expire_action()
|
||||
LOGGER.debug("Expired models", model=cls, amount=amount)
|
||||
messages.append(f"Expired {amount} {cls._meta.verbose_name_plural}")
|
||||
# Special case
|
||||
amount = 0
|
||||
|
||||
for session in AuthenticatedSession.objects.all():
|
||||
match CONFIG.get("session_storage", "cache"):
|
||||
case "cache":
|
||||
cache_key = f"{KEY_PREFIX}{session.session_key}"
|
||||
value = None
|
||||
try:
|
||||
value = cache.get(cache_key)
|
||||
|
||||
except Exception as exc:
|
||||
LOGGER.debug("Failed to get session from cache", exc=exc)
|
||||
if not value:
|
||||
session.delete()
|
||||
amount += 1
|
||||
case "db":
|
||||
if not (
|
||||
DBSessionStore.get_model_class()
|
||||
.objects.filter(session_key=session.session_key, expire_date__gt=now())
|
||||
.exists()
|
||||
):
|
||||
session.delete()
|
||||
amount += 1
|
||||
case _:
|
||||
# Should never happen, as we check for other values in authentik/root/settings.py
|
||||
raise ImproperlyConfigured(
|
||||
"Invalid session_storage setting, allowed values are db and cache"
|
||||
)
|
||||
if CONFIG.get("session_storage", "cache") == "db":
|
||||
DBSessionStore.clear_expired()
|
||||
LOGGER.debug("Expired sessions", model=AuthenticatedSession, amount=amount)
|
||||
|
||||
messages.append(f"Expired {amount} {AuthenticatedSession._meta.verbose_name_plural}")
|
||||
self.set_status(TaskStatus.SUCCESSFUL, *messages)
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@ from json import loads
|
||||
from django.urls.base import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.core.models import AuthenticatedSession, Session, User
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
|
||||
|
||||
@ -30,3 +30,18 @@ class TestAuthenticatedSessionsAPI(APITestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
body = loads(response.content.decode())
|
||||
self.assertEqual(body["pagination"]["count"], 1)
|
||||
|
||||
def test_delete(self):
|
||||
"""Test deletion"""
|
||||
self.client.force_login(self.user)
|
||||
self.assertEqual(AuthenticatedSession.objects.all().count(), 1)
|
||||
self.assertEqual(Session.objects.all().count(), 1)
|
||||
response = self.client.delete(
|
||||
reverse(
|
||||
"authentik_api:authenticatedsession-detail",
|
||||
kwargs={"uuid": AuthenticatedSession.objects.first().uuid},
|
||||
)
|
||||
)
|
||||
self.assertEqual(response.status_code, 204)
|
||||
self.assertEqual(AuthenticatedSession.objects.all().count(), 0)
|
||||
self.assertEqual(Session.objects.all().count(), 0)
|
||||
|
@ -3,8 +3,6 @@
|
||||
from datetime import datetime
|
||||
from json import loads
|
||||
|
||||
from django.contrib.sessions.backends.cache import KEY_PREFIX
|
||||
from django.core.cache import cache
|
||||
from django.urls.base import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
@ -12,6 +10,7 @@ from authentik.brands.models import Brand
|
||||
from authentik.core.models import (
|
||||
USER_ATTRIBUTE_TOKEN_EXPIRING,
|
||||
AuthenticatedSession,
|
||||
Session,
|
||||
Token,
|
||||
User,
|
||||
UserTypes,
|
||||
@ -381,12 +380,15 @@ class TestUsersAPI(APITestCase):
|
||||
"""Ensure sessions are deleted when a user is deactivated"""
|
||||
user = create_test_admin_user()
|
||||
session_id = generate_id()
|
||||
AuthenticatedSession.objects.create(
|
||||
user=user,
|
||||
session = Session.objects.create(
|
||||
session_key=session_id,
|
||||
last_ip="",
|
||||
last_ip="255.255.255.255",
|
||||
last_user_agent="",
|
||||
)
|
||||
AuthenticatedSession.objects.create(
|
||||
session=session,
|
||||
user=user,
|
||||
)
|
||||
cache.set(KEY_PREFIX + session_id, "foo")
|
||||
|
||||
self.client.force_login(self.admin)
|
||||
response = self.client.patch(
|
||||
@ -397,5 +399,7 @@ class TestUsersAPI(APITestCase):
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
self.assertIsNone(cache.get(KEY_PREFIX + session_id))
|
||||
self.assertFalse(AuthenticatedSession.objects.filter(session_key=session_id).exists())
|
||||
self.assertFalse(Session.objects.filter(session_key=session_id).exists())
|
||||
self.assertFalse(
|
||||
AuthenticatedSession.objects.filter(session__session_key=session_id).exists()
|
||||
)
|
||||
|
@ -1,7 +1,5 @@
|
||||
"""authentik URL Configuration"""
|
||||
|
||||
from channels.auth import AuthMiddleware
|
||||
from channels.sessions import CookieMiddleware
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.urls import path
|
||||
@ -29,7 +27,7 @@ from authentik.core.views.interface import (
|
||||
RootRedirectView,
|
||||
)
|
||||
from authentik.flows.views.interface import FlowInterfaceView
|
||||
from authentik.root.asgi_middleware import SessionMiddleware
|
||||
from authentik.root.asgi_middleware import AuthMiddlewareStack
|
||||
from authentik.root.messages.consumer import MessageConsumer
|
||||
from authentik.root.middleware import ChannelsLoggingMiddleware
|
||||
|
||||
@ -99,9 +97,7 @@ api_urlpatterns = [
|
||||
websocket_urlpatterns = [
|
||||
path(
|
||||
"ws/client/",
|
||||
ChannelsLoggingMiddleware(
|
||||
CookieMiddleware(SessionMiddleware(AuthMiddleware(MessageConsumer.as_asgi())))
|
||||
),
|
||||
ChannelsLoggingMiddleware(AuthMiddlewareStack(MessageConsumer.as_asgi())),
|
||||
),
|
||||
]
|
||||
|
||||
|
@ -102,7 +102,7 @@ def ssf_user_session_delete_session_revoked(sender, instance: AuthenticatedSessi
|
||||
"format": "complex",
|
||||
"session": {
|
||||
"format": "opaque",
|
||||
"id": sha256(instance.session_key.encode("ascii")).hexdigest(),
|
||||
"id": sha256(instance.session.session_key.encode("ascii")).hexdigest(),
|
||||
},
|
||||
"user": {
|
||||
"format": "email",
|
||||
|
@ -59,7 +59,7 @@ def get_login_event(request_or_session: HttpRequest | AuthenticatedSession | Non
|
||||
session = request_or_session.session
|
||||
if isinstance(request_or_session, AuthenticatedSession):
|
||||
SessionStore = _session_engine.SessionStore
|
||||
session = SessionStore(request_or_session.session_key)
|
||||
session = SessionStore(request_or_session.session.session_key)
|
||||
return session.get(SESSION_LOGIN_EVENT, None)
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ from sentry_sdk import start_span
|
||||
from sentry_sdk.tracing import Span
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import AuthenticatedSession, User
|
||||
from authentik.core.models import User
|
||||
from authentik.events.models import Event
|
||||
from authentik.lib.expression.exceptions import ControlFlowException
|
||||
from authentik.lib.utils.http import get_http_session
|
||||
@ -203,9 +203,7 @@ class BaseEvaluator:
|
||||
provider = OAuth2Provider.objects.get(name=provider)
|
||||
session = None
|
||||
if hasattr(request, "session") and request.session.session_key:
|
||||
session = AuthenticatedSession.objects.filter(
|
||||
session_key=request.session.session_key
|
||||
).first()
|
||||
session = request.session["authenticatedsession"]
|
||||
access_token = AccessToken(
|
||||
provider=provider,
|
||||
user=user,
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
from django.contrib.auth.signals import user_logged_in
|
||||
from django.db import transaction
|
||||
from django.db.models import F
|
||||
from django.dispatch import receiver
|
||||
from django.http import HttpRequest
|
||||
from structlog.stdlib import get_logger
|
||||
@ -13,20 +12,29 @@ from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR
|
||||
from authentik.policies.reputation.models import Reputation, reputation_expiry
|
||||
from authentik.root.middleware import ClientIPMiddleware
|
||||
from authentik.stages.identification.signals import identification_failed
|
||||
from authentik.tenants.utils import get_current_tenant
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
def clamp(value, min, max):
|
||||
return sorted([min, value, max])[1]
|
||||
|
||||
|
||||
def update_score(request: HttpRequest, identifier: str, amount: int):
|
||||
"""Update score for IP and User"""
|
||||
remote_ip = ClientIPMiddleware.get_client_ip(request)
|
||||
tenant = get_current_tenant()
|
||||
new_score = clamp(amount, tenant.reputation_lower_limit, tenant.reputation_upper_limit)
|
||||
|
||||
with transaction.atomic():
|
||||
reputation, created = Reputation.objects.select_for_update().get_or_create(
|
||||
ip=remote_ip,
|
||||
identifier=identifier,
|
||||
defaults={
|
||||
"score": amount,
|
||||
"score": clamp(
|
||||
amount, tenant.reputation_lower_limit, tenant.reputation_upper_limit
|
||||
),
|
||||
"ip_geo_data": GEOIP_CONTEXT_PROCESSOR.city_dict(remote_ip) or {},
|
||||
"ip_asn_data": ASN_CONTEXT_PROCESSOR.asn_dict(remote_ip) or {},
|
||||
"expires": reputation_expiry(),
|
||||
@ -34,9 +42,15 @@ def update_score(request: HttpRequest, identifier: str, amount: int):
|
||||
)
|
||||
|
||||
if not created:
|
||||
reputation.score = F("score") + amount
|
||||
new_score = clamp(
|
||||
reputation.score + amount,
|
||||
tenant.reputation_lower_limit,
|
||||
tenant.reputation_upper_limit,
|
||||
)
|
||||
reputation.score = new_score
|
||||
reputation.save()
|
||||
LOGGER.info("Updated score", amount=amount, for_user=identifier, for_ip=remote_ip)
|
||||
|
||||
LOGGER.info("Updated score", amount=new_score, for_user=identifier, for_ip=remote_ip)
|
||||
|
||||
|
||||
@receiver(login_failed)
|
||||
|
@ -6,9 +6,11 @@ from authentik.core.models import User
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.policies.reputation.api import ReputationPolicySerializer
|
||||
from authentik.policies.reputation.models import Reputation, ReputationPolicy
|
||||
from authentik.policies.reputation.signals import update_score
|
||||
from authentik.policies.types import PolicyRequest
|
||||
from authentik.stages.password import BACKEND_INBUILT
|
||||
from authentik.stages.password.stage import authenticate
|
||||
from authentik.tenants.models import DEFAULT_REPUTATION_LOWER_LIMIT, DEFAULT_REPUTATION_UPPER_LIMIT
|
||||
|
||||
|
||||
class TestReputationPolicy(TestCase):
|
||||
@ -17,36 +19,48 @@ class TestReputationPolicy(TestCase):
|
||||
def setUp(self):
|
||||
self.request_factory = RequestFactory()
|
||||
self.request = self.request_factory.get("/")
|
||||
self.test_ip = "127.0.0.1"
|
||||
self.test_username = "test"
|
||||
self.ip = "127.0.0.1"
|
||||
self.username = "username"
|
||||
self.password = generate_id()
|
||||
# We need a user for the one-to-one in userreputation
|
||||
self.user = User.objects.create(username=self.test_username)
|
||||
self.user = User.objects.create(username=self.username)
|
||||
self.user.set_password(self.password)
|
||||
self.backends = [BACKEND_INBUILT]
|
||||
|
||||
def test_ip_reputation(self):
|
||||
"""test IP reputation"""
|
||||
# Trigger negative reputation
|
||||
authenticate(
|
||||
self.request, self.backends, username=self.test_username, password=self.test_username
|
||||
)
|
||||
self.assertEqual(Reputation.objects.get(ip=self.test_ip).score, -1)
|
||||
authenticate(self.request, self.backends, username=self.username, password=self.username)
|
||||
self.assertEqual(Reputation.objects.get(ip=self.ip).score, -1)
|
||||
|
||||
def test_user_reputation(self):
|
||||
"""test User reputation"""
|
||||
# Trigger negative reputation
|
||||
authenticate(
|
||||
self.request, self.backends, username=self.test_username, password=self.test_username
|
||||
)
|
||||
self.assertEqual(Reputation.objects.get(identifier=self.test_username).score, -1)
|
||||
authenticate(self.request, self.backends, username=self.username, password=self.username)
|
||||
self.assertEqual(Reputation.objects.get(identifier=self.username).score, -1)
|
||||
|
||||
def test_update_reputation(self):
|
||||
"""test reputation update"""
|
||||
Reputation.objects.create(identifier=self.test_username, ip=self.test_ip, score=43)
|
||||
Reputation.objects.create(identifier=self.username, ip=self.ip, score=4)
|
||||
# Trigger negative reputation
|
||||
authenticate(
|
||||
self.request, self.backends, username=self.test_username, password=self.test_username
|
||||
authenticate(self.request, self.backends, username=self.username, password=self.username)
|
||||
self.assertEqual(Reputation.objects.get(identifier=self.username).score, 3)
|
||||
|
||||
def test_reputation_lower_limit(self):
|
||||
"""test reputation lower limit"""
|
||||
Reputation.objects.create(identifier=self.username, ip=self.ip)
|
||||
update_score(self.request, identifier=self.username, amount=-1000)
|
||||
self.assertEqual(
|
||||
Reputation.objects.get(identifier=self.username).score, DEFAULT_REPUTATION_LOWER_LIMIT
|
||||
)
|
||||
|
||||
def test_reputation_upper_limit(self):
|
||||
"""test reputation upper limit"""
|
||||
Reputation.objects.create(identifier=self.username, ip=self.ip)
|
||||
update_score(self.request, identifier=self.username, amount=1000)
|
||||
self.assertEqual(
|
||||
Reputation.objects.get(identifier=self.username).score, DEFAULT_REPUTATION_UPPER_LIMIT
|
||||
)
|
||||
self.assertEqual(Reputation.objects.get(identifier=self.test_username).score, 42)
|
||||
|
||||
def test_policy(self):
|
||||
"""Test Policy"""
|
||||
|
@ -126,7 +126,7 @@ class IDToken:
|
||||
id_token.iat = int(now.timestamp())
|
||||
id_token.auth_time = int(token.auth_time.timestamp())
|
||||
if token.session:
|
||||
id_token.sid = hash_session_key(token.session.session_key)
|
||||
id_token.sid = hash_session_key(token.session.session.session_key)
|
||||
|
||||
# We use the timestamp of the user's last successful login (EventAction.LOGIN) for auth_time
|
||||
auth_event = get_login_event(token.session)
|
||||
|
116
authentik/providers/oauth2/migrations/0028_migrate_session.py
Normal file
116
authentik/providers/oauth2/migrations/0028_migrate_session.py
Normal file
@ -0,0 +1,116 @@
|
||||
# Generated by Django 5.0.11 on 2025-01-27 13:00
|
||||
|
||||
from django.db import migrations
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
from functools import partial
|
||||
|
||||
|
||||
def migrate_sessions(apps, schema_editor, model):
|
||||
Model = apps.get_model("authentik_providers_oauth2", model)
|
||||
AuthenticatedSession = apps.get_model("authentik_core", "AuthenticatedSession")
|
||||
db_alias = schema_editor.connection.alias
|
||||
|
||||
for obj in Model.objects.using(db_alias).all():
|
||||
if not obj.old_session:
|
||||
continue
|
||||
obj.session = (
|
||||
AuthenticatedSession.objects.using(db_alias)
|
||||
.filter(session__session_key=obj.old_session.session_key)
|
||||
.first()
|
||||
)
|
||||
if obj.session:
|
||||
obj.save()
|
||||
else:
|
||||
obj.delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_providers_oauth2", "0027_accesstoken_authentik_p_expires_9f24a5_idx_and_more"),
|
||||
("authentik_core", "0046_session_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="accesstoken",
|
||||
old_name="session",
|
||||
new_name="old_session",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="authorizationcode",
|
||||
old_name="session",
|
||||
new_name="old_session",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="devicetoken",
|
||||
old_name="session",
|
||||
new_name="old_session",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="refreshtoken",
|
||||
old_name="session",
|
||||
new_name="old_session",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="accesstoken",
|
||||
name="session",
|
||||
field=models.ForeignKey(
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="authentik_core.authenticatedsession",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="authorizationcode",
|
||||
name="session",
|
||||
field=models.ForeignKey(
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="authentik_core.authenticatedsession",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="devicetoken",
|
||||
name="session",
|
||||
field=models.ForeignKey(
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_DEFAULT,
|
||||
to="authentik_core.authenticatedsession",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="refreshtoken",
|
||||
name="session",
|
||||
field=models.ForeignKey(
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_DEFAULT,
|
||||
to="authentik_core.authenticatedsession",
|
||||
),
|
||||
),
|
||||
migrations.RunPython(code=partial(migrate_sessions, model="AccessToken")),
|
||||
migrations.RunPython(code=partial(migrate_sessions, model="AuthorizationCode")),
|
||||
migrations.RunPython(code=partial(migrate_sessions, model="DeviceToken")),
|
||||
migrations.RunPython(code=partial(migrate_sessions, model="RefreshToken")),
|
||||
migrations.RemoveField(
|
||||
model_name="accesstoken",
|
||||
name="old_session",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="authorizationcode",
|
||||
name="old_session",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="devicetoken",
|
||||
name="old_session",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="refreshtoken",
|
||||
name="old_session",
|
||||
),
|
||||
]
|
@ -1,18 +1,30 @@
|
||||
from django.contrib.auth.signals import user_logged_out
|
||||
from django.db.models.signals import post_save
|
||||
from django.db.models.signals import post_save, pre_delete
|
||||
from django.dispatch import receiver
|
||||
from django.http import HttpRequest
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.core.models import AuthenticatedSession, User
|
||||
from authentik.providers.oauth2.models import AccessToken, DeviceToken, RefreshToken
|
||||
|
||||
|
||||
@receiver(user_logged_out)
|
||||
def user_logged_out_oauth_access_token(sender, request: HttpRequest, user: User, **_):
|
||||
"""Revoke access tokens upon user logout"""
|
||||
def user_logged_out_oauth_tokens_removal(sender, request: HttpRequest, user: User, **_):
|
||||
"""Revoke tokens upon user logout"""
|
||||
if not request.session or not request.session.session_key:
|
||||
return
|
||||
AccessToken.objects.filter(user=user, session__session_key=request.session.session_key).delete()
|
||||
AccessToken.objects.filter(
|
||||
user=user,
|
||||
session__session__session_key=request.session.session_key,
|
||||
).delete()
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=AuthenticatedSession)
|
||||
def user_session_deleted_oauth_tokens_removal(sender, instance: AuthenticatedSession, **_):
|
||||
"""Revoke tokens upon user logout"""
|
||||
AccessToken.objects.filter(
|
||||
user=instance.user,
|
||||
session__session__session_key=instance.session.session_key,
|
||||
).delete()
|
||||
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
@ -20,6 +32,6 @@ def user_deactivated(sender, instance: User, **_):
|
||||
"""Remove user tokens when deactivated"""
|
||||
if instance.is_active:
|
||||
return
|
||||
AccessToken.objects.filter(session__user=instance).delete()
|
||||
RefreshToken.objects.filter(session__user=instance).delete()
|
||||
DeviceToken.objects.filter(session__user=instance).delete()
|
||||
AccessToken.objects.filter(user=instance).delete()
|
||||
RefreshToken.objects.filter(user=instance).delete()
|
||||
DeviceToken.objects.filter(user=instance).delete()
|
||||
|
@ -7,12 +7,13 @@ from dataclasses import asdict
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from authentik.core.models import Application
|
||||
from authentik.core.models import Application, AuthenticatedSession, Session
|
||||
from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.providers.oauth2.models import (
|
||||
AccessToken,
|
||||
ClientTypes,
|
||||
DeviceToken,
|
||||
IDToken,
|
||||
OAuth2Provider,
|
||||
RedirectURI,
|
||||
@ -20,6 +21,7 @@ from authentik.providers.oauth2.models import (
|
||||
RefreshToken,
|
||||
)
|
||||
from authentik.providers.oauth2.tests.utils import OAuthTestCase
|
||||
from authentik.root.middleware import ClientIPMiddleware
|
||||
|
||||
|
||||
class TesOAuth2Revoke(OAuthTestCase):
|
||||
@ -135,3 +137,86 @@ class TesOAuth2Revoke(OAuthTestCase):
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
def test_revoke_logout(self):
|
||||
"""Test revoke on logout"""
|
||||
self.client.force_login(self.user)
|
||||
AccessToken.objects.create(
|
||||
provider=self.provider,
|
||||
user=self.user,
|
||||
session=self.client.session["authenticatedsession"],
|
||||
token=generate_id(),
|
||||
auth_time=timezone.now(),
|
||||
_scope="openid user profile",
|
||||
_id_token=json.dumps(
|
||||
asdict(
|
||||
IDToken("foo", "bar"),
|
||||
)
|
||||
),
|
||||
)
|
||||
self.client.logout()
|
||||
self.assertEqual(AccessToken.objects.all().count(), 0)
|
||||
|
||||
def test_revoke_session_delete(self):
|
||||
"""Test revoke on logout"""
|
||||
session = AuthenticatedSession.objects.create(
|
||||
session=Session.objects.create(
|
||||
session_key=generate_id(),
|
||||
last_ip=ClientIPMiddleware.default_ip,
|
||||
),
|
||||
user=self.user,
|
||||
)
|
||||
AccessToken.objects.create(
|
||||
provider=self.provider,
|
||||
user=self.user,
|
||||
session=session,
|
||||
token=generate_id(),
|
||||
auth_time=timezone.now(),
|
||||
_scope="openid user profile",
|
||||
_id_token=json.dumps(
|
||||
asdict(
|
||||
IDToken("foo", "bar"),
|
||||
)
|
||||
),
|
||||
)
|
||||
session.delete()
|
||||
self.assertEqual(AccessToken.objects.all().count(), 0)
|
||||
|
||||
def test_revoke_user_deactivated(self):
|
||||
"""Test revoke on logout"""
|
||||
AccessToken.objects.create(
|
||||
provider=self.provider,
|
||||
user=self.user,
|
||||
token=generate_id(),
|
||||
auth_time=timezone.now(),
|
||||
_scope="openid user profile",
|
||||
_id_token=json.dumps(
|
||||
asdict(
|
||||
IDToken("foo", "bar"),
|
||||
)
|
||||
),
|
||||
)
|
||||
RefreshToken.objects.create(
|
||||
provider=self.provider,
|
||||
user=self.user,
|
||||
token=generate_id(),
|
||||
auth_time=timezone.now(),
|
||||
_scope="openid user profile",
|
||||
_id_token=json.dumps(
|
||||
asdict(
|
||||
IDToken("foo", "bar"),
|
||||
)
|
||||
),
|
||||
)
|
||||
DeviceToken.objects.create(
|
||||
provider=self.provider,
|
||||
user=self.user,
|
||||
_scope="openid user profile",
|
||||
)
|
||||
|
||||
self.user.is_active = False
|
||||
self.user.save()
|
||||
|
||||
self.assertEqual(AccessToken.objects.all().count(), 0)
|
||||
self.assertEqual(RefreshToken.objects.all().count(), 0)
|
||||
self.assertEqual(DeviceToken.objects.all().count(), 0)
|
||||
|
@ -15,7 +15,7 @@ from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import Application, AuthenticatedSession
|
||||
from authentik.core.models import Application
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.events.signals import get_login_event
|
||||
from authentik.flows.challenge import (
|
||||
@ -316,9 +316,7 @@ class OAuthAuthorizationParams:
|
||||
expires=now + timedelta_from_string(self.provider.access_code_validity),
|
||||
scope=self.scope,
|
||||
nonce=self.nonce,
|
||||
session=AuthenticatedSession.objects.filter(
|
||||
session_key=request.session.session_key
|
||||
).first(),
|
||||
session=request.session["authenticatedsession"],
|
||||
)
|
||||
|
||||
if self.code_challenge and self.code_challenge_method:
|
||||
@ -615,9 +613,7 @@ class OAuthFulfillmentStage(StageView):
|
||||
expires=access_token_expiry,
|
||||
provider=self.provider,
|
||||
auth_time=auth_event.created if auth_event else now,
|
||||
session=AuthenticatedSession.objects.filter(
|
||||
session_key=self.request.session.session_key
|
||||
).first(),
|
||||
session=self.request.session["authenticatedsession"],
|
||||
)
|
||||
|
||||
id_token = IDToken.new(self.provider, token, self.request)
|
||||
|
@ -20,4 +20,4 @@ def logout_proxy_revoke_direct(sender: type[User], request: HttpRequest, **_):
|
||||
@receiver(pre_delete, sender=AuthenticatedSession)
|
||||
def logout_proxy_revoke(sender: type[AuthenticatedSession], instance: AuthenticatedSession, **_):
|
||||
"""Catch logout by expiring sessions being deleted"""
|
||||
proxy_on_logout.delay(instance.session_key)
|
||||
proxy_on_logout.delay(instance.session.session_key)
|
||||
|
60
authentik/providers/rac/migrations/0007_migrate_session.py
Normal file
60
authentik/providers/rac/migrations/0007_migrate_session.py
Normal file
@ -0,0 +1,60 @@
|
||||
# Generated by Django 5.0.11 on 2025-01-27 12:59
|
||||
|
||||
from django.db import migrations
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def migrate_sessions(apps, schema_editor):
|
||||
ConnectionToken = apps.get_model("authentik_providers_rac", "ConnectionToken")
|
||||
AuthenticatedSession = apps.get_model("authentik_core", "AuthenticatedSession")
|
||||
db_alias = schema_editor.connection.alias
|
||||
|
||||
for token in ConnectionToken.objects.using(db_alias).all():
|
||||
token.session = (
|
||||
AuthenticatedSession.objects.using(db_alias)
|
||||
.filter(session_key=token.old_session.session_key)
|
||||
.first()
|
||||
)
|
||||
if token.session:
|
||||
token.save()
|
||||
else:
|
||||
token.delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_providers_rac", "0006_connectiontoken_authentik_p_expires_91f148_idx_and_more"),
|
||||
("authentik_core", "0046_session_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="connectiontoken",
|
||||
old_name="session",
|
||||
new_name="old_session",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="connectiontoken",
|
||||
name="session",
|
||||
field=models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="authentik_core.authenticatedsession",
|
||||
),
|
||||
),
|
||||
migrations.RunPython(code=migrate_sessions),
|
||||
migrations.AlterField(
|
||||
model_name="connectiontoken",
|
||||
name="session",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="authentik_core.authenticatedsession",
|
||||
),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="connectiontoken",
|
||||
name="old_session",
|
||||
),
|
||||
]
|
@ -8,7 +8,7 @@ from django.db.models.signals import post_delete, post_save, pre_delete
|
||||
from django.dispatch import receiver
|
||||
from django.http import HttpRequest
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.core.models import AuthenticatedSession, User
|
||||
from authentik.providers.rac.api.endpoints import user_endpoint_cache_key
|
||||
from authentik.providers.rac.consumer_client import (
|
||||
RAC_CLIENT_GROUP_SESSION,
|
||||
@ -32,6 +32,18 @@ def user_logged_out_session(sender, request: HttpRequest, user: User, **_):
|
||||
)
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=AuthenticatedSession)
|
||||
def user_session_deleted(sender, instance: AuthenticatedSession, **_):
|
||||
layer = get_channel_layer()
|
||||
async_to_sync(layer.group_send)(
|
||||
RAC_CLIENT_GROUP_SESSION
|
||||
% {
|
||||
"session": instance.session.session_key,
|
||||
},
|
||||
{"type": "event.disconnect", "reason": "session_logout"},
|
||||
)
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=ConnectionToken)
|
||||
def pre_delete_connection_token_disconnect(sender, instance: ConnectionToken, **_):
|
||||
"""Disconnect session when connection token is deleted"""
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from django.test import TransactionTestCase
|
||||
|
||||
from authentik.core.models import Application, AuthenticatedSession
|
||||
from authentik.core.models import Application, AuthenticatedSession, Session
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.providers.rac.models import (
|
||||
@ -36,13 +36,15 @@ class TestModels(TransactionTestCase):
|
||||
|
||||
def test_settings_merge(self):
|
||||
"""Test settings merge"""
|
||||
session = Session.objects.create(
|
||||
session_key=generate_id(),
|
||||
last_ip="255.255.255.255",
|
||||
)
|
||||
auth_session = AuthenticatedSession.objects.create(session=session, user=self.user)
|
||||
token = ConnectionToken.objects.create(
|
||||
provider=self.provider,
|
||||
endpoint=self.endpoint,
|
||||
session=AuthenticatedSession.objects.create(
|
||||
user=self.user,
|
||||
session_key=generate_id(),
|
||||
),
|
||||
session=auth_session,
|
||||
)
|
||||
path = f"/tmp/connection/{token.token}" # nosec
|
||||
self.assertEqual(
|
||||
|
@ -1,7 +1,5 @@
|
||||
"""rac urls"""
|
||||
|
||||
from channels.auth import AuthMiddleware
|
||||
from channels.sessions import CookieMiddleware
|
||||
from django.urls import path
|
||||
|
||||
from authentik.outposts.channels import TokenOutpostMiddleware
|
||||
@ -12,7 +10,7 @@ from authentik.providers.rac.api.providers import RACProviderViewSet
|
||||
from authentik.providers.rac.consumer_client import RACClientConsumer
|
||||
from authentik.providers.rac.consumer_outpost import RACOutpostConsumer
|
||||
from authentik.providers.rac.views import RACInterface, RACStartView
|
||||
from authentik.root.asgi_middleware import SessionMiddleware
|
||||
from authentik.root.asgi_middleware import AuthMiddlewareStack
|
||||
from authentik.root.middleware import ChannelsLoggingMiddleware
|
||||
|
||||
urlpatterns = [
|
||||
@ -31,9 +29,7 @@ urlpatterns = [
|
||||
websocket_urlpatterns = [
|
||||
path(
|
||||
"ws/rac/<str:token>/",
|
||||
ChannelsLoggingMiddleware(
|
||||
CookieMiddleware(SessionMiddleware(AuthMiddleware(RACClientConsumer.as_asgi())))
|
||||
),
|
||||
ChannelsLoggingMiddleware(AuthMiddlewareStack(RACClientConsumer.as_asgi())),
|
||||
),
|
||||
path(
|
||||
"ws/outpost_rac/<str:channel>/",
|
||||
|
@ -8,7 +8,7 @@ from django.urls import reverse
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from authentik.core.models import Application, AuthenticatedSession
|
||||
from authentik.core.models import Application
|
||||
from authentik.core.views.interface import InterfaceView
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.challenge import RedirectChallenge
|
||||
@ -113,9 +113,7 @@ class RACFinalStage(RedirectStage):
|
||||
provider=self.provider,
|
||||
endpoint=self.endpoint,
|
||||
settings=self.executor.plan.context.get("connection_settings", {}),
|
||||
session=AuthenticatedSession.objects.filter(
|
||||
session_key=self.request.session.session_key
|
||||
).first(),
|
||||
session=self.request.session["authenticatedsession"],
|
||||
expires=now() + timedelta_from_string(self.provider.connection_expiry),
|
||||
expiring=True,
|
||||
)
|
||||
|
@ -50,7 +50,7 @@ class TestRecovery(TestCase):
|
||||
)
|
||||
token = Token.objects.get(intent=TokenIntents.INTENT_RECOVERY, user=self.user)
|
||||
self.client.get(reverse("authentik_recovery:use-token", kwargs={"key": token.key}))
|
||||
self.assertEqual(int(self.client.session["_auth_user_id"]), token.user.pk)
|
||||
self.assertEqual(self.client.session["authenticatedsession"].user.pk, token.user.pk)
|
||||
|
||||
def test_recovery_view_invalid(self):
|
||||
"""Test recovery view with invalid token"""
|
||||
|
@ -1,8 +1,12 @@
|
||||
"""ASGI middleware"""
|
||||
|
||||
from channels.auth import UserLazyObject
|
||||
from channels.db import database_sync_to_async
|
||||
from channels.middleware import BaseMiddleware
|
||||
from channels.sessions import CookieMiddleware
|
||||
from channels.sessions import InstanceSessionWrapper as UpstreamInstanceSessionWrapper
|
||||
from channels.sessions import SessionMiddleware as UpstreamSessionMiddleware
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
|
||||
from authentik.root.middleware import SessionMiddleware as HTTPSessionMiddleware
|
||||
|
||||
@ -33,3 +37,48 @@ class SessionMiddleware(UpstreamSessionMiddleware):
|
||||
await wrapper.resolve_session()
|
||||
|
||||
return await self.inner(wrapper.scope, receive, wrapper.send)
|
||||
|
||||
|
||||
@database_sync_to_async
|
||||
def get_user(scope):
|
||||
"""
|
||||
Return the user model instance associated with the given scope.
|
||||
If no user is retrieved, return an instance of `AnonymousUser`.
|
||||
"""
|
||||
if "session" not in scope:
|
||||
raise ValueError(
|
||||
"Cannot find session in scope. You should wrap your consumer in SessionMiddleware."
|
||||
)
|
||||
user = None
|
||||
if (authenticated_session := scope["session"].get("authenticated_session", None)) is not None:
|
||||
user = authenticated_session.user
|
||||
return user or AnonymousUser()
|
||||
|
||||
|
||||
class AuthMiddleware(BaseMiddleware):
|
||||
def populate_scope(self, scope):
|
||||
# Make sure we have a session
|
||||
if "session" not in scope:
|
||||
raise ValueError(
|
||||
"AuthMiddleware cannot find session in scope. SessionMiddleware must be above it."
|
||||
)
|
||||
# Add it to the scope if it's not there already
|
||||
if "user" not in scope:
|
||||
scope["user"] = UserLazyObject()
|
||||
|
||||
async def resolve_scope(self, scope):
|
||||
scope["user"]._wrapped = await get_user(scope)
|
||||
|
||||
async def __call__(self, scope, receive, send):
|
||||
scope = dict(scope)
|
||||
# Scope injection/mutation per this middleware's needs.
|
||||
self.populate_scope(scope)
|
||||
# Grab the finalized/resolved scope
|
||||
await self.resolve_scope(scope)
|
||||
|
||||
return await super().__call__(scope, receive, send)
|
||||
|
||||
|
||||
# Handy shortcut for applying all three layers at once
|
||||
def AuthMiddlewareStack(inner):
|
||||
return CookieMiddleware(SessionMiddleware(AuthMiddleware(inner)))
|
||||
|
@ -49,7 +49,7 @@ class SessionMiddleware(UpstreamSessionMiddleware):
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def decode_session_key(key: str) -> str:
|
||||
def decode_session_key(key: str | None) -> str | None:
|
||||
"""Decode raw session cookie, and parse JWT"""
|
||||
# We need to support the standard django format of just a session key
|
||||
# for testing setups, where the session is directly set
|
||||
@ -64,7 +64,11 @@ class SessionMiddleware(UpstreamSessionMiddleware):
|
||||
def process_request(self, request: HttpRequest):
|
||||
raw_session = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
|
||||
session_key = SessionMiddleware.decode_session_key(raw_session)
|
||||
request.session = self.SessionStore(session_key)
|
||||
request.session = self.SessionStore(
|
||||
session_key,
|
||||
last_ip=ClientIPMiddleware.get_client_ip(request),
|
||||
last_user_agent=request.META.get("HTTP_USER_AGENT", ""),
|
||||
)
|
||||
|
||||
def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse:
|
||||
"""
|
||||
|
@ -1,23 +0,0 @@
|
||||
"""
|
||||
Module for abstract serializer/unserializer base classes.
|
||||
"""
|
||||
|
||||
import pickle # nosec
|
||||
|
||||
|
||||
class PickleSerializer:
|
||||
"""
|
||||
Simple wrapper around pickle to be used in signing.dumps()/loads() and
|
||||
cache backends.
|
||||
"""
|
||||
|
||||
def __init__(self, protocol=None):
|
||||
self.protocol = pickle.HIGHEST_PROTOCOL if protocol is None else protocol
|
||||
|
||||
def dumps(self, obj):
|
||||
"""Pickle data to be stored in redis"""
|
||||
return pickle.dumps(obj, self.protocol)
|
||||
|
||||
def loads(self, data):
|
||||
"""Unpickle data to be loaded from redis"""
|
||||
return pickle.loads(data) # nosec
|
@ -7,7 +7,6 @@ from pathlib import Path
|
||||
|
||||
import orjson
|
||||
from celery.schedules import crontab
|
||||
from django.conf import ImproperlyConfigured
|
||||
from sentry_sdk import set_tag
|
||||
from xmlsec import enable_debug_trace
|
||||
|
||||
@ -43,7 +42,6 @@ SESSION_COOKIE_DOMAIN = CONFIG.get("cookie_domain", None)
|
||||
APPEND_SLASH = False
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
BACKEND_INBUILT,
|
||||
BACKEND_APP_PASSWORD,
|
||||
BACKEND_LDAP,
|
||||
@ -229,17 +227,7 @@ CACHES = {
|
||||
DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
||||
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
|
||||
DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
|
||||
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_CACHE_ALIAS = "default"
|
||||
SESSION_ENGINE = "authentik.core.sessions"
|
||||
# Configured via custom SessionMiddleware
|
||||
# SESSION_COOKIE_SAMESITE = "None"
|
||||
# SESSION_COOKIE_SECURE = True
|
||||
@ -256,7 +244,7 @@ MIDDLEWARE = [
|
||||
"django_prometheus.middleware.PrometheusBeforeMiddleware",
|
||||
"authentik.root.middleware.ClientIPMiddleware",
|
||||
"authentik.stages.user_login.middleware.BoundSessionMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"authentik.core.middleware.AuthenticationMiddleware",
|
||||
"authentik.core.middleware.RequestIDMiddleware",
|
||||
"authentik.brands.middleware.BrandMiddleware",
|
||||
"authentik.events.middleware.AuditMiddleware",
|
||||
|
@ -15,11 +15,22 @@ from rest_framework.response import Response
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.property_mappings import PropertyMappingFilterSet, PropertyMappingSerializer
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.sources import (
|
||||
GroupSourceConnectionSerializer,
|
||||
GroupSourceConnectionViewSet,
|
||||
SourceSerializer,
|
||||
UserSourceConnectionSerializer,
|
||||
UserSourceConnectionViewSet,
|
||||
)
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.lib.sync.outgoing.api import SyncStatusSerializer
|
||||
from authentik.sources.ldap.models import LDAPSource, LDAPSourcePropertyMapping
|
||||
from authentik.sources.ldap.models import (
|
||||
GroupLDAPSourceConnection,
|
||||
LDAPSource,
|
||||
LDAPSourcePropertyMapping,
|
||||
UserLDAPSourceConnection,
|
||||
)
|
||||
from authentik.sources.ldap.tasks import CACHE_KEY_STATUS, SYNC_CLASSES
|
||||
|
||||
|
||||
@ -221,3 +232,23 @@ class LDAPSourcePropertyMappingViewSet(UsedByMixin, ModelViewSet):
|
||||
filterset_class = LDAPSourcePropertyMappingFilter
|
||||
search_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
|
||||
|
||||
class UserLDAPSourceConnectionSerializer(UserSourceConnectionSerializer):
|
||||
class Meta(UserSourceConnectionSerializer.Meta):
|
||||
model = UserLDAPSourceConnection
|
||||
|
||||
|
||||
class UserLDAPSourceConnectionViewSet(UserSourceConnectionViewSet, ModelViewSet):
|
||||
queryset = UserLDAPSourceConnection.objects.all()
|
||||
serializer_class = UserLDAPSourceConnectionSerializer
|
||||
|
||||
|
||||
class GroupLDAPSourceConnectionSerializer(GroupSourceConnectionSerializer):
|
||||
class Meta(GroupSourceConnectionSerializer.Meta):
|
||||
model = GroupLDAPSourceConnection
|
||||
|
||||
|
||||
class GroupLDAPSourceConnectionViewSet(GroupSourceConnectionViewSet, ModelViewSet):
|
||||
queryset = GroupLDAPSourceConnection.objects.all()
|
||||
serializer_class = GroupLDAPSourceConnectionSerializer
|
||||
|
@ -0,0 +1,57 @@
|
||||
# Generated by Django 5.0.14 on 2025-04-11 11:46
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_core", "0047_delete_oldauthenticatedsession"),
|
||||
("authentik_sources_ldap", "0007_ldapsource_lookup_groups_from_user"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="GroupLDAPSourceConnection",
|
||||
fields=[
|
||||
(
|
||||
"groupsourceconnection_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="authentik_core.groupsourceconnection",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Group LDAP Source Connection",
|
||||
"verbose_name_plural": "Group LDAP Source Connections",
|
||||
},
|
||||
bases=("authentik_core.groupsourceconnection",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="UserLDAPSourceConnection",
|
||||
fields=[
|
||||
(
|
||||
"usersourceconnection_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="authentik_core.usersourceconnection",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "User LDAP Source Connection",
|
||||
"verbose_name_plural": "User LDAP Source Connections",
|
||||
},
|
||||
bases=("authentik_core.usersourceconnection",),
|
||||
),
|
||||
]
|
@ -15,7 +15,13 @@ from ldap3 import ALL, NONE, RANDOM, Connection, Server, ServerPool, Tls
|
||||
from ldap3.core.exceptions import LDAPException, LDAPInsufficientAccessRightsResult, LDAPSchemaError
|
||||
from rest_framework.serializers import Serializer
|
||||
|
||||
from authentik.core.models import Group, PropertyMapping, Source
|
||||
from authentik.core.models import (
|
||||
Group,
|
||||
GroupSourceConnection,
|
||||
PropertyMapping,
|
||||
Source,
|
||||
UserSourceConnection,
|
||||
)
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.lib.models import DomainlessURLValidator
|
||||
@ -312,3 +318,31 @@ class LDAPSourcePropertyMapping(PropertyMapping):
|
||||
class Meta:
|
||||
verbose_name = _("LDAP Source Property Mapping")
|
||||
verbose_name_plural = _("LDAP Source Property Mappings")
|
||||
|
||||
|
||||
class UserLDAPSourceConnection(UserSourceConnection):
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
from authentik.sources.ldap.api import (
|
||||
UserLDAPSourceConnectionSerializer,
|
||||
)
|
||||
|
||||
return UserLDAPSourceConnectionSerializer
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("User LDAP Source Connection")
|
||||
verbose_name_plural = _("User LDAP Source Connections")
|
||||
|
||||
|
||||
class GroupLDAPSourceConnection(GroupSourceConnection):
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
from authentik.sources.ldap.api import (
|
||||
GroupLDAPSourceConnectionSerializer,
|
||||
)
|
||||
|
||||
return GroupLDAPSourceConnectionSerializer
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Group LDAP Source Connection")
|
||||
verbose_name_plural = _("Group LDAP Source Connections")
|
||||
|
@ -14,7 +14,12 @@ from authentik.core.models import Group
|
||||
from authentik.core.sources.mapper import SourceMapper
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.lib.sync.outgoing.exceptions import StopSync
|
||||
from authentik.sources.ldap.models import LDAP_UNIQUENESS, LDAPSource, flatten
|
||||
from authentik.sources.ldap.models import (
|
||||
LDAP_UNIQUENESS,
|
||||
GroupLDAPSourceConnection,
|
||||
LDAPSource,
|
||||
flatten,
|
||||
)
|
||||
from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer
|
||||
|
||||
|
||||
@ -89,6 +94,12 @@ class GroupLDAPSynchronizer(BaseLDAPSynchronizer):
|
||||
defaults,
|
||||
)
|
||||
self._logger.debug("Created group with attributes", **defaults)
|
||||
if not GroupLDAPSourceConnection.objects.filter(
|
||||
source=self._source, identifier=uniq
|
||||
):
|
||||
GroupLDAPSourceConnection.objects.create(
|
||||
source=self._source, group=ak_group, identifier=uniq
|
||||
)
|
||||
except SkipObjectException:
|
||||
continue
|
||||
except PropertyMappingExpressionException as exc:
|
||||
|
@ -14,7 +14,12 @@ from authentik.core.models import User
|
||||
from authentik.core.sources.mapper import SourceMapper
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.lib.sync.outgoing.exceptions import StopSync
|
||||
from authentik.sources.ldap.models import LDAP_UNIQUENESS, LDAPSource, flatten
|
||||
from authentik.sources.ldap.models import (
|
||||
LDAP_UNIQUENESS,
|
||||
LDAPSource,
|
||||
UserLDAPSourceConnection,
|
||||
flatten,
|
||||
)
|
||||
from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer
|
||||
from authentik.sources.ldap.sync.vendor.freeipa import FreeIPA
|
||||
from authentik.sources.ldap.sync.vendor.ms_ad import MicrosoftActiveDirectory
|
||||
@ -85,6 +90,12 @@ class UserLDAPSynchronizer(BaseLDAPSynchronizer):
|
||||
ak_user, created = User.update_or_create_attributes(
|
||||
{f"attributes__{LDAP_UNIQUENESS}": uniq}, defaults
|
||||
)
|
||||
if not UserLDAPSourceConnection.objects.filter(
|
||||
source=self._source, identifier=uniq
|
||||
):
|
||||
UserLDAPSourceConnection.objects.create(
|
||||
source=self._source, user=ak_user, identifier=uniq
|
||||
)
|
||||
except PropertyMappingExpressionException as exc:
|
||||
raise StopSync(exc, None, exc.mapping) from exc
|
||||
except SkipObjectException:
|
||||
|
@ -1,8 +1,15 @@
|
||||
"""API URLs"""
|
||||
|
||||
from authentik.sources.ldap.api import LDAPSourcePropertyMappingViewSet, LDAPSourceViewSet
|
||||
from authentik.sources.ldap.api import (
|
||||
GroupLDAPSourceConnectionViewSet,
|
||||
LDAPSourcePropertyMappingViewSet,
|
||||
LDAPSourceViewSet,
|
||||
UserLDAPSourceConnectionViewSet,
|
||||
)
|
||||
|
||||
api_urlpatterns = [
|
||||
("propertymappings/source/ldap", LDAPSourcePropertyMappingViewSet),
|
||||
("sources/ldap", LDAPSourceViewSet),
|
||||
("sources/user_connections/ldap", UserLDAPSourceConnectionViewSet),
|
||||
("sources/group_connections/ldap", GroupLDAPSourceConnectionViewSet),
|
||||
]
|
||||
|
@ -255,6 +255,7 @@ class TestAuthenticatorEmailStage(FlowTestCase):
|
||||
)
|
||||
masked_email = mask_email(self.user.email)
|
||||
self.assertEqual(masked_email, response.json()["email"])
|
||||
self.client.logout()
|
||||
|
||||
# Test without email
|
||||
self.client.force_login(self.user_noemail)
|
||||
|
@ -6,14 +6,12 @@ from django.contrib.auth.views import redirect_to_login
|
||||
from django.http.request import HttpRequest
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import AuthenticatedSession
|
||||
from authentik.events.context_processors.asn import ASN_CONTEXT_PROCESSOR
|
||||
from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR
|
||||
from authentik.lib.sentry import SentryIgnoredException
|
||||
from authentik.root.middleware import ClientIPMiddleware, SessionMiddleware
|
||||
from authentik.stages.user_login.models import GeoIPBinding, NetworkBinding
|
||||
|
||||
SESSION_KEY_LAST_IP = "authentik/stages/user_login/last_ip"
|
||||
SESSION_KEY_BINDING_NET = "authentik/stages/user_login/binding/net"
|
||||
SESSION_KEY_BINDING_GEO = "authentik/stages/user_login/binding/geo"
|
||||
LOGGER = get_logger()
|
||||
@ -91,7 +89,7 @@ class BoundSessionMiddleware(SessionMiddleware):
|
||||
|
||||
def recheck_session(self, request: HttpRequest):
|
||||
"""Check if a session is still valid with a changed IP"""
|
||||
last_ip = request.session.get(SESSION_KEY_LAST_IP)
|
||||
last_ip = request.session.get(request.session.model.Keys.LAST_IP)
|
||||
new_ip = ClientIPMiddleware.get_client_ip(request)
|
||||
# Check changed IP
|
||||
if new_ip == last_ip:
|
||||
@ -111,10 +109,7 @@ class BoundSessionMiddleware(SessionMiddleware):
|
||||
if SESSION_KEY_BINDING_NET in request.session or SESSION_KEY_BINDING_GEO in request.session:
|
||||
# Only set the last IP in the session if there's a binding specified
|
||||
# (== basically requires the user to be logged in)
|
||||
request.session[SESSION_KEY_LAST_IP] = new_ip
|
||||
AuthenticatedSession.objects.filter(session_key=request.session.session_key).update(
|
||||
last_ip=new_ip, last_user_agent=request.META.get("HTTP_USER_AGENT", "")
|
||||
)
|
||||
request.session[request.session.model.Keys.LAST_IP] = new_ip
|
||||
|
||||
def recheck_session_net(self, binding: NetworkBinding, last_ip: str, new_ip: str):
|
||||
"""Check network/ASN binding"""
|
||||
|
@ -8,7 +8,7 @@ from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.translation import gettext as _
|
||||
from rest_framework.fields import BooleanField, CharField
|
||||
|
||||
from authentik.core.models import AuthenticatedSession, User
|
||||
from authentik.core.models import Session, User
|
||||
from authentik.events.middleware import audit_ignore
|
||||
from authentik.flows.challenge import ChallengeResponse, WithUserInfoChallenge
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, PLAN_CONTEXT_SOURCE
|
||||
@ -20,7 +20,6 @@ from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||
from authentik.stages.user_login.middleware import (
|
||||
SESSION_KEY_BINDING_GEO,
|
||||
SESSION_KEY_BINDING_NET,
|
||||
SESSION_KEY_LAST_IP,
|
||||
)
|
||||
from authentik.stages.user_login.models import UserLoginStage
|
||||
|
||||
@ -73,7 +72,9 @@ class UserLoginStageView(ChallengeStageView):
|
||||
"""Set the sessions' last IP and session bindings"""
|
||||
stage: UserLoginStage = self.executor.current_stage
|
||||
|
||||
self.request.session[SESSION_KEY_LAST_IP] = ClientIPMiddleware.get_client_ip(self.request)
|
||||
self.request.session[self.request.session.model.Keys.LAST_IP] = (
|
||||
ClientIPMiddleware.get_client_ip(self.request)
|
||||
)
|
||||
self.request.session[SESSION_KEY_BINDING_NET] = stage.network_binding
|
||||
self.request.session[SESSION_KEY_BINDING_GEO] = stage.geoip_binding
|
||||
|
||||
@ -112,7 +113,7 @@ class UserLoginStageView(ChallengeStageView):
|
||||
if not self.executor.plan.context.get(PLAN_CONTEXT_SOURCE, None):
|
||||
messages.success(self.request, _("Successfully logged in!"))
|
||||
if self.executor.current_stage.terminate_other_sessions:
|
||||
AuthenticatedSession.objects.filter(
|
||||
user=user,
|
||||
Session.objects.filter(
|
||||
authenticatedsession__user=user,
|
||||
).exclude(session_key=self.request.session.session_key).delete()
|
||||
return self.executor.stage_ok()
|
||||
|
@ -3,12 +3,10 @@
|
||||
from time import sleep
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.contrib.sessions.backends.cache import KEY_PREFIX
|
||||
from django.core.cache import cache
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import now
|
||||
|
||||
from authentik.core.models import AuthenticatedSession
|
||||
from authentik.core.models import AuthenticatedSession, Session
|
||||
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
|
||||
from authentik.flows.markers import StageMarker
|
||||
from authentik.flows.models import FlowDesignation, FlowStageBinding
|
||||
@ -74,12 +72,13 @@ class TestUserLoginStage(FlowTestCase):
|
||||
session.save()
|
||||
|
||||
key = generate_id()
|
||||
other_session = AuthenticatedSession.objects.create(
|
||||
AuthenticatedSession.objects.create(
|
||||
session=Session.objects.create(
|
||||
session_key=key,
|
||||
last_ip=ClientIPMiddleware.default_ip,
|
||||
),
|
||||
user=self.user,
|
||||
session_key=key,
|
||||
last_ip=ClientIPMiddleware.default_ip,
|
||||
)
|
||||
cache.set(f"{KEY_PREFIX}{other_session.session_key}", "foo")
|
||||
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
|
||||
@ -87,8 +86,8 @@ class TestUserLoginStage(FlowTestCase):
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
||||
self.assertFalse(AuthenticatedSession.objects.filter(session_key=key))
|
||||
self.assertFalse(cache.has_key(f"{KEY_PREFIX}{key}"))
|
||||
self.assertFalse(AuthenticatedSession.objects.filter(session__session_key=key))
|
||||
self.assertFalse(Session.objects.filter(session_key=key).exists())
|
||||
|
||||
def test_expiry(self):
|
||||
"""Test with expiry"""
|
||||
@ -108,7 +107,7 @@ class TestUserLoginStage(FlowTestCase):
|
||||
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
||||
self.assertNotEqual(list(self.client.session.keys()), [])
|
||||
session_key = self.client.session.session_key
|
||||
session = AuthenticatedSession.objects.filter(session_key=session_key).first()
|
||||
session = Session.objects.filter(session_key=session_key).first()
|
||||
self.assertAlmostEqual(
|
||||
session.expires.timestamp() - before_request.timestamp(),
|
||||
timedelta_from_string(self.stage.session_duration).total_seconds(),
|
||||
@ -143,7 +142,7 @@ class TestUserLoginStage(FlowTestCase):
|
||||
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
||||
self.assertNotEqual(list(self.client.session.keys()), [])
|
||||
session_key = self.client.session.session_key
|
||||
session = AuthenticatedSession.objects.filter(session_key=session_key).first()
|
||||
session = Session.objects.filter(session_key=session_key).first()
|
||||
self.assertAlmostEqual(
|
||||
session.expires.timestamp() - _now,
|
||||
timedelta_from_string(self.stage.session_duration).total_seconds()
|
||||
|
@ -20,6 +20,8 @@ class SettingsSerializer(ModelSerializer):
|
||||
"default_user_change_email",
|
||||
"default_user_change_username",
|
||||
"event_retention",
|
||||
"reputation_lower_limit",
|
||||
"reputation_upper_limit",
|
||||
"footer_links",
|
||||
"gdpr_compliance",
|
||||
"impersonation",
|
||||
|
@ -0,0 +1,32 @@
|
||||
# Generated by Django 5.0.14 on 2025-04-14 07:50
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_tenants", "0004_tenant_impersonation_require_reason"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="tenant",
|
||||
name="reputation_lower_limit",
|
||||
field=models.IntegerField(
|
||||
default=-5,
|
||||
help_text="Reputation cannot decrease lower than this value. Zero or negative.",
|
||||
validators=[django.core.validators.MaxValueValidator(0)],
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="tenant",
|
||||
name="reputation_upper_limit",
|
||||
field=models.IntegerField(
|
||||
default=5,
|
||||
help_text="Reputation cannot increase higher than this value. Zero or positive.",
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
),
|
||||
),
|
||||
]
|
@ -5,7 +5,7 @@ from uuid import uuid4
|
||||
|
||||
from django.apps import apps
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models
|
||||
from django.db.utils import IntegrityError
|
||||
from django.dispatch import receiver
|
||||
@ -25,6 +25,8 @@ VALID_SCHEMA_NAME = re.compile(r"^t_[a-z0-9]{1,61}$")
|
||||
|
||||
DEFAULT_TOKEN_DURATION = "days=1" # nosec
|
||||
DEFAULT_TOKEN_LENGTH = 60
|
||||
DEFAULT_REPUTATION_LOWER_LIMIT = -5
|
||||
DEFAULT_REPUTATION_UPPER_LIMIT = 5
|
||||
|
||||
|
||||
def _validate_schema_name(name):
|
||||
@ -70,6 +72,16 @@ class Tenant(TenantMixin, SerializerModel):
|
||||
"Events will be deleted after this duration.(Format: weeks=3;days=2;hours=3,seconds=2)."
|
||||
),
|
||||
)
|
||||
reputation_lower_limit = models.IntegerField(
|
||||
help_text=_("Reputation cannot decrease lower than this value. Zero or negative."),
|
||||
default=DEFAULT_REPUTATION_LOWER_LIMIT,
|
||||
validators=[MaxValueValidator(0)],
|
||||
)
|
||||
reputation_upper_limit = models.IntegerField(
|
||||
help_text=_("Reputation cannot increase higher than this value. Zero or positive."),
|
||||
default=DEFAULT_REPUTATION_UPPER_LIMIT,
|
||||
validators=[MinValueValidator(0)],
|
||||
)
|
||||
footer_links = models.JSONField(
|
||||
help_text=_("The option configures the footer links on the flow executor pages."),
|
||||
default=list,
|
||||
|
@ -1441,6 +1441,86 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"model",
|
||||
"identifiers"
|
||||
],
|
||||
"properties": {
|
||||
"model": {
|
||||
"const": "authentik_sources_ldap.userldapsourceconnection"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"absent",
|
||||
"present",
|
||||
"created",
|
||||
"must_created"
|
||||
],
|
||||
"default": "present"
|
||||
},
|
||||
"conditions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"$ref": "#/$defs/model_authentik_sources_ldap.userldapsourceconnection_permissions"
|
||||
},
|
||||
"attrs": {
|
||||
"$ref": "#/$defs/model_authentik_sources_ldap.userldapsourceconnection"
|
||||
},
|
||||
"identifiers": {
|
||||
"$ref": "#/$defs/model_authentik_sources_ldap.userldapsourceconnection"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"model",
|
||||
"identifiers"
|
||||
],
|
||||
"properties": {
|
||||
"model": {
|
||||
"const": "authentik_sources_ldap.groupldapsourceconnection"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"absent",
|
||||
"present",
|
||||
"created",
|
||||
"must_created"
|
||||
],
|
||||
"default": "present"
|
||||
},
|
||||
"conditions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"$ref": "#/$defs/model_authentik_sources_ldap.groupldapsourceconnection_permissions"
|
||||
},
|
||||
"attrs": {
|
||||
"$ref": "#/$defs/model_authentik_sources_ldap.groupldapsourceconnection"
|
||||
},
|
||||
"identifiers": {
|
||||
"$ref": "#/$defs/model_authentik_sources_ldap.groupldapsourceconnection"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -4754,6 +4834,8 @@
|
||||
"authentik_sources_kerberos.groupkerberossourceconnection",
|
||||
"authentik_sources_ldap.ldapsource",
|
||||
"authentik_sources_ldap.ldapsourcepropertymapping",
|
||||
"authentik_sources_ldap.userldapsourceconnection",
|
||||
"authentik_sources_ldap.groupldapsourceconnection",
|
||||
"authentik_sources_oauth.oauthsource",
|
||||
"authentik_sources_oauth.oauthsourcepropertymapping",
|
||||
"authentik_sources_oauth.useroauthsourceconnection",
|
||||
@ -7112,14 +7194,22 @@
|
||||
"authentik_sources_kerberos.view_kerberossource",
|
||||
"authentik_sources_kerberos.view_kerberossourcepropertymapping",
|
||||
"authentik_sources_kerberos.view_userkerberossourceconnection",
|
||||
"authentik_sources_ldap.add_groupldapsourceconnection",
|
||||
"authentik_sources_ldap.add_ldapsource",
|
||||
"authentik_sources_ldap.add_ldapsourcepropertymapping",
|
||||
"authentik_sources_ldap.add_userldapsourceconnection",
|
||||
"authentik_sources_ldap.change_groupldapsourceconnection",
|
||||
"authentik_sources_ldap.change_ldapsource",
|
||||
"authentik_sources_ldap.change_ldapsourcepropertymapping",
|
||||
"authentik_sources_ldap.change_userldapsourceconnection",
|
||||
"authentik_sources_ldap.delete_groupldapsourceconnection",
|
||||
"authentik_sources_ldap.delete_ldapsource",
|
||||
"authentik_sources_ldap.delete_ldapsourcepropertymapping",
|
||||
"authentik_sources_ldap.delete_userldapsourceconnection",
|
||||
"authentik_sources_ldap.view_groupldapsourceconnection",
|
||||
"authentik_sources_ldap.view_ldapsource",
|
||||
"authentik_sources_ldap.view_ldapsourcepropertymapping",
|
||||
"authentik_sources_ldap.view_userldapsourceconnection",
|
||||
"authentik_sources_oauth.add_groupoauthsourceconnection",
|
||||
"authentik_sources_oauth.add_oauthsource",
|
||||
"authentik_sources_oauth.add_oauthsourcepropertymapping",
|
||||
@ -7971,6 +8061,107 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"model_authentik_sources_ldap.userldapsourceconnection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user": {
|
||||
"type": "integer",
|
||||
"title": "User"
|
||||
},
|
||||
"source": {
|
||||
"type": "integer",
|
||||
"title": "Source"
|
||||
},
|
||||
"identifier": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Identifier"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Icon"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"model_authentik_sources_ldap.userldapsourceconnection_permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"permission"
|
||||
],
|
||||
"properties": {
|
||||
"permission": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"add_userldapsourceconnection",
|
||||
"change_userldapsourceconnection",
|
||||
"delete_userldapsourceconnection",
|
||||
"view_userldapsourceconnection"
|
||||
]
|
||||
},
|
||||
"user": {
|
||||
"type": "integer"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"model_authentik_sources_ldap.groupldapsourceconnection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"title": "Group"
|
||||
},
|
||||
"source": {
|
||||
"type": "integer",
|
||||
"title": "Source"
|
||||
},
|
||||
"identifier": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Identifier"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Icon"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"model_authentik_sources_ldap.groupldapsourceconnection_permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"permission"
|
||||
],
|
||||
"properties": {
|
||||
"permission": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"add_groupldapsourceconnection",
|
||||
"change_groupldapsourceconnection",
|
||||
"delete_groupldapsourceconnection",
|
||||
"view_groupldapsourceconnection"
|
||||
]
|
||||
},
|
||||
"user": {
|
||||
"type": "integer"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"model_authentik_sources_oauth.oauthsource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -13627,14 +13818,22 @@
|
||||
"authentik_sources_kerberos.view_kerberossource",
|
||||
"authentik_sources_kerberos.view_kerberossourcepropertymapping",
|
||||
"authentik_sources_kerberos.view_userkerberossourceconnection",
|
||||
"authentik_sources_ldap.add_groupldapsourceconnection",
|
||||
"authentik_sources_ldap.add_ldapsource",
|
||||
"authentik_sources_ldap.add_ldapsourcepropertymapping",
|
||||
"authentik_sources_ldap.add_userldapsourceconnection",
|
||||
"authentik_sources_ldap.change_groupldapsourceconnection",
|
||||
"authentik_sources_ldap.change_ldapsource",
|
||||
"authentik_sources_ldap.change_ldapsourcepropertymapping",
|
||||
"authentik_sources_ldap.change_userldapsourceconnection",
|
||||
"authentik_sources_ldap.delete_groupldapsourceconnection",
|
||||
"authentik_sources_ldap.delete_ldapsource",
|
||||
"authentik_sources_ldap.delete_ldapsourcepropertymapping",
|
||||
"authentik_sources_ldap.delete_userldapsourceconnection",
|
||||
"authentik_sources_ldap.view_groupldapsourceconnection",
|
||||
"authentik_sources_ldap.view_ldapsource",
|
||||
"authentik_sources_ldap.view_ldapsourcepropertymapping",
|
||||
"authentik_sources_ldap.view_userldapsourceconnection",
|
||||
"authentik_sources_oauth.add_groupoauthsourceconnection",
|
||||
"authentik_sources_oauth.add_oauthsource",
|
||||
"authentik_sources_oauth.add_oauthsourcepropertymapping",
|
||||
|
@ -35,6 +35,7 @@ services:
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||
@ -58,6 +59,7 @@ services:
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||
|
6
go.mod
6
go.mod
@ -5,7 +5,7 @@ go 1.24.0
|
||||
require (
|
||||
beryju.io/ldap v0.1.0
|
||||
github.com/coreos/go-oidc/v3 v3.14.1
|
||||
github.com/getsentry/sentry-go v0.31.1
|
||||
github.com/getsentry/sentry-go v0.32.0
|
||||
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
||||
github.com/go-ldap/ldap/v3 v3.4.10
|
||||
github.com/go-openapi/runtime v0.28.0
|
||||
@ -22,12 +22,12 @@ require (
|
||||
github.com/pires/go-proxyproto v0.8.0
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/redis/go-redis/v9 v9.7.3
|
||||
github.com/sethvargo/go-envconfig v1.1.1
|
||||
github.com/sethvargo/go-envconfig v1.2.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/wwt/guac v1.3.2
|
||||
goauthentik.io/api/v3 v3.2025024.1
|
||||
goauthentik.io/api/v3 v3.2025024.4
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||
golang.org/x/oauth2 v0.29.0
|
||||
golang.org/x/sync v0.13.0
|
||||
|
12
go.sum
12
go.sum
@ -69,8 +69,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/getsentry/sentry-go v0.31.1 h1:ELVc0h7gwyhnXHDouXkhqTFSO5oslsRDk0++eyE0KJ4=
|
||||
github.com/getsentry/sentry-go v0.31.1/go.mod h1:CYNcMMz73YigoHljQRG+qPF+eMq8gG72XcGN/p71BAY=
|
||||
github.com/getsentry/sentry-go v0.32.0 h1:YKs+//QmwE3DcYtfKRH8/KyOOF/I6Qnx7qYGNHCGmCY=
|
||||
github.com/getsentry/sentry-go v0.32.0/go.mod h1:CYNcMMz73YigoHljQRG+qPF+eMq8gG72XcGN/p71BAY=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
@ -255,8 +255,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sethvargo/go-envconfig v1.1.1 h1:JDu8Q9baIzJf47NPkzhIB6aLYL0vQ+pPypoYrejS9QY=
|
||||
github.com/sethvargo/go-envconfig v1.1.1/go.mod h1:JLd0KFWQYzyENqnEPWWZ49i4vzZo/6nRidxI8YvGiHw=
|
||||
github.com/sethvargo/go-envconfig v1.2.0 h1:q3XkOZWkC+G1sMLCrw9oPGTjYexygLOXDmGUit1ti8Q=
|
||||
github.com/sethvargo/go-envconfig v1.2.0/go.mod h1:JLd0KFWQYzyENqnEPWWZ49i4vzZo/6nRidxI8YvGiHw=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
@ -300,8 +300,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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
goauthentik.io/api/v3 v3.2025024.1 h1:wYmpbNW1XptrjS5dlnZj8CrCs+JUGEVJYStrFdWL9aA=
|
||||
goauthentik.io/api/v3 v3.2025024.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
goauthentik.io/api/v3 v3.2025024.4 h1:fD4K6YcCTdwtkqKbYBdJk3POHVzw+LDdJdZSbOAKbX4=
|
||||
goauthentik.io/api/v3 v3.2025024.4/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
Binary file not shown.
@ -19,27 +19,28 @@
|
||||
# Benjamin Böhmke, 2023
|
||||
# Sven S <transifex@versvendet.de>, 2023
|
||||
# Dirk R, 2023
|
||||
# 97cce0ae0cad2a2cc552d3165d04643e_de3d740, 2024
|
||||
# Paul Frey, 2024
|
||||
# Sascha Brockel, 2024
|
||||
# Michael Milz, 2024
|
||||
# Thomas Liske, 2024
|
||||
# Michael Gottinger, 2024
|
||||
# bob4os, 2024
|
||||
# itxworks, 2024
|
||||
# Christian Wichmann <cw1981@gmx.de>, 2024
|
||||
# Stefan Werner, 2024
|
||||
# Alexander Möbius, 2025
|
||||
# Jonas, 2025
|
||||
# Niklas Kroese, 2025
|
||||
# 97cce0ae0cad2a2cc552d3165d04643e_de3d740, 2025
|
||||
# datenschmutz, 2025
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-14 14:49+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Niklas Kroese, 2025\n"
|
||||
"Last-Translator: datenschmutz, 2025\n"
|
||||
"Language-Team: German (https://app.transifex.com/authentik/teams/119923/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -147,6 +148,12 @@ msgstr "Nutzer hat keinen Zugriff auf diese Applikation."
|
||||
msgid "Extra description not available"
|
||||
msgstr "Eine weitergehende Beschreibung ist nicht verfügbar"
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr ""
|
||||
"Es ist nicht möglich, die Gruppe als Übergruppe von sich selbst zu "
|
||||
"definieren."
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
"When not set all providers are returned. When set to true, only backchannel "
|
||||
@ -194,6 +201,14 @@ msgstr "Nutzer zu Gruppe hinzufügen"
|
||||
msgid "Remove user from group"
|
||||
msgstr "Nutzer aus Gruppe entfernen"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Enable superuser status"
|
||||
msgstr "Superuser-Status aktivieren"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Disable superuser status"
|
||||
msgstr "Superuser-Status deaktivieren"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "User's display name."
|
||||
msgstr "Anzeigename"
|
||||
@ -572,60 +587,6 @@ msgstr "Microsoft Entra Provider Zuordnung"
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr "Microsoft Entra Provider Zuordnungen"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Legt fest, wie lange eine Sitzung dauert. Der Standardwert 0 bedeutet, dass "
|
||||
"die Sitzung so lange dauert, bis der Browser geschlossen wird. (Format: "
|
||||
"hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr "Wenn aktiviert, werden Verbindungstoken beim Trennen gelöscht."
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC Anbieter"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC Anbieter"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "RAC Endpunkt"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "RAC Endpunkte"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "RAC Provider Eigenschafts-Zuordnung"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "RAC Provider Eigenschafts-Zuordnungen"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "RAC Verbindungstoken"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "RAC Verbindungstoken"
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Maximale Verbindungsgrenze erreicht."
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Sie sind bereits in einem anderen Tab/Fenster verbunden)"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Signing Key"
|
||||
@ -633,39 +594,39 @@ msgstr "Signaturschlüssel"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "Key used to sign the SSF Events."
|
||||
msgstr ""
|
||||
msgstr "Schlüssel, der zum Signieren der SSF-Ereignisse verwendet wird."
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "Shared Signals Framework Provider"
|
||||
msgstr ""
|
||||
msgstr "Anbieter des Shared Signals Frameworks"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "Shared Signals Framework Providers"
|
||||
msgstr ""
|
||||
msgstr "Shared Signals Frameworks Anbieter"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "Add stream to SSF provider"
|
||||
msgstr ""
|
||||
msgstr "Stream zum SSF-Anbieter hinzufügen."
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "SSF Stream"
|
||||
msgstr ""
|
||||
msgstr "SSF Stream"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "SSF Streams"
|
||||
msgstr ""
|
||||
msgstr "SSF Streams"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "SSF Stream Event"
|
||||
msgstr ""
|
||||
msgstr "SSF Stream Ereignis"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "SSF Stream Events"
|
||||
msgstr ""
|
||||
msgstr "SSF Stream Ereignisse"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/tasks.py
|
||||
msgid "Failed to send request"
|
||||
msgstr ""
|
||||
msgstr "Anfrage konnte nicht gesendet werden."
|
||||
|
||||
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/models.py
|
||||
msgid "Endpoint Authenticator Google Device Trust Connector Stage"
|
||||
@ -729,9 +690,26 @@ msgid "Slack Webhook (Slack/Discord)"
|
||||
msgstr "Slack Webhook (Slack/Discord)"
|
||||
|
||||
#: authentik/events/models.py
|
||||
#: authentik/stages/authenticator_validate/models.py
|
||||
msgid "Email"
|
||||
msgstr "E-Mail"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||
"serializable."
|
||||
msgstr ""
|
||||
"Passen Sie den Inhalt der Anfrage an. Die Zuordnung sollte Daten "
|
||||
"zurückgeben, die JSON-serialisierbar sind."
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Configure additional headers to be sent. Mapping should return a dictionary "
|
||||
"of key-value pairs"
|
||||
msgstr ""
|
||||
"Konfigurieren Sie zusätzliche Header, die gesendet werden sollen. Die "
|
||||
"Zuordnung sollte ein dictionary von Schlüssel-Wert-Paaren zurückgeben."
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Only send notification once, for example when sending a webhook into a chat "
|
||||
@ -1009,6 +987,12 @@ msgstr "Flow-Tokens"
|
||||
msgid "Invalid next URL"
|
||||
msgstr "Ungültige nächste URL"
|
||||
|
||||
#: authentik/lib/sync/outgoing/models.py
|
||||
msgid ""
|
||||
"When enabled, provider will not modify or create objects in the remote "
|
||||
"system."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr "Starte komplette Provider Synchronisation."
|
||||
@ -1023,6 +1007,10 @@ msgstr "Synchonisiere Benutzer Seite {page}"
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr "Synchonisiere Gruppen Seite {page}"
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
@ -1237,6 +1225,14 @@ msgstr "GeoIP: Die Client IP wurde nicht in der Stadt Datenbank gefunden"
|
||||
msgid "Client IP is not in an allowed country."
|
||||
msgstr "GeoIP: Die Client IP befindet sich nicht in einem erlaubten Land."
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance from previous authentication is larger than threshold."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance is further than possible."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "GeoIP Policy"
|
||||
msgstr "GeoIP Richtlinie"
|
||||
@ -1369,6 +1365,20 @@ msgstr "Reputationswert"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "Reputationswert"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "Erlaubnis verweigert"
|
||||
@ -1560,6 +1570,14 @@ msgstr "RS256 (Asymmetrische Verschlüsselung)"
|
||||
msgid "ES256 (Asymmetric Encryption)"
|
||||
msgstr "ES256 (Asymmetrische Verschlüsselung)"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES384 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES512 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Scope used by the client"
|
||||
msgstr "Vom Client verwendeter Scope"
|
||||
@ -1844,6 +1862,59 @@ msgstr "Proxy Anbieter"
|
||||
msgid "Proxy Providers"
|
||||
msgstr "Proxy Anbietern"
|
||||
|
||||
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Legt fest, wie lange eine Sitzung dauert. Der Standardwert 0 bedeutet, dass "
|
||||
"die Sitzung so lange dauert, bis der Browser geschlossen wird. (Format: "
|
||||
"hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr "Wenn aktiviert, werden Verbindungstoken beim Trennen gelöscht."
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC Anbieter"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC Anbieter"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "RAC Endpunkt"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "RAC Endpunkte"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "RAC Provider Eigenschafts-Zuordnung"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "RAC Provider Eigenschafts-Zuordnungen"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "RAC Verbindungstoken"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "RAC Verbindungstoken"
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Maximale Verbindungsgrenze erreicht."
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Sie sind bereits in einem anderen Tab/Fenster verbunden)"
|
||||
|
||||
#: authentik/providers/radius/models.py
|
||||
msgid "Shared secret between clients and server to hash packets."
|
||||
msgstr ""
|
||||
@ -1933,6 +2004,17 @@ msgstr ""
|
||||
"Legen Sie fest, wie der NameID-Wert erstellt werden soll. Bleibt der Wert "
|
||||
"leer, wird die NameIDPolicy der eingehenden Anfrage berücksichtigt"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "AuthnContextClassRef Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Configure how the AuthnContextClassRef value will be created. When left "
|
||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||
"methods the user used to authenticate."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Assertion valid not before current time + this value (Format: "
|
||||
@ -2074,6 +2156,18 @@ msgstr "SAML Anbieter aus Metadaten"
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr "SAML Provider aus Metadaten"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Default"
|
||||
msgstr "Standard"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "AWS"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Slack"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "Basis-URL für SCIM-Anfragen, endet normalerweise auf /v2"
|
||||
@ -2082,6 +2176,14 @@ msgstr "Basis-URL für SCIM-Anfragen, endet normalerweise auf /v2"
|
||||
msgid "Authentication token"
|
||||
msgstr "Authentifizierungstoken"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Compatibility Mode"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "SCIM-Anbieter"
|
||||
@ -2353,6 +2455,13 @@ msgstr ""
|
||||
"Wenn ein Benutzer sein Passwort ändert, wird es zurück zum LDAP "
|
||||
"synchronisiert. Dies kann nur für eine einzige LDAP-Quelle aktiviert werden."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "LDAP Quelle"
|
||||
@ -2764,6 +2873,103 @@ msgstr "Duo Gerät"
|
||||
msgid "Duo Devices"
|
||||
msgstr "Duo Geräte"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email OTP"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Wenn diese Option aktiviert ist, werden die globalen E-Mail "
|
||||
"Verbindungseinstellungen benutzt und die unten angegebenen Einstellungen "
|
||||
"ignoriert"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Beim Rendern der E-Mail-Vorlage ist ein Fehler aufgetreten"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Devices"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Code stimmt nicht überein"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
msgid "Invalid email"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Hallo %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
msgid ""
|
||||
"\n"
|
||||
" Email MFA code.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Hallo %(username)s,"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_sms/models.py
|
||||
msgid ""
|
||||
"When enabled, the Phone number is only used during enrollment to verify the "
|
||||
@ -2802,11 +3008,6 @@ msgstr "SMS Gerät"
|
||||
msgid "SMS Devices"
|
||||
msgstr "SMS Geräte"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Code stimmt nicht überein"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
msgid "Invalid phone number"
|
||||
msgstr "Ungültige Telefonnummer"
|
||||
@ -3041,23 +3242,10 @@ msgstr "Passwort zurücksetzen"
|
||||
msgid "Account Confirmation"
|
||||
msgstr "Konto-Bestätigung"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Wenn diese Option aktiviert ist, werden die globalen E-Mail "
|
||||
"Verbindungseinstellungen benutzt und die unten angegebenen Einstellungen "
|
||||
"ignoriert"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Activate users upon completion of stage."
|
||||
msgstr "Aktivieren Sie die Benutzer nach Abschluss der Stufe."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time in minutes the token sent is valid."
|
||||
msgstr "Zeit in Minuten wie lange der verschickte Token gültig ist"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "E-Mail Stufe"
|
||||
@ -3066,10 +3254,6 @@ msgstr "E-Mail Stufe"
|
||||
msgid "Email Stages"
|
||||
msgstr "E-Mail Stufen"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Beim Rendern der E-Mail-Vorlage ist ein Fehler aufgetreten"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
msgstr "Erfolgreich Mailadresse verifiziert."
|
||||
@ -3153,17 +3337,6 @@ msgstr ""
|
||||
"\n"
|
||||
"Diese E-Mail wurde vom Benachrichtigungsdienst %(name)s gesendet.\n"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Hallo %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -3184,11 +3357,6 @@ msgstr ""
|
||||
"\n"
|
||||
" Wenn Sie keine Passwortänderung beantragt haben, ignorieren Sie bitte diese E-Mail. Der obige Link ist gültig für %(expires)s."
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Hallo %(username)s,"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-03-31 00:10+0000\n"
|
||||
"POT-Creation-Date: 2025-04-14 00:11+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -335,6 +335,18 @@ msgstr ""
|
||||
msgid "Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "session data"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Session"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Sessions"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Authenticated Session"
|
||||
msgstr ""
|
||||
@ -2190,6 +2202,13 @@ msgid ""
|
||||
"enabled on a single LDAP source."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr ""
|
||||
@ -2206,6 +2225,22 @@ msgstr ""
|
||||
msgid "LDAP Source Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "User LDAP Source Connection"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "User LDAP Source Connections"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "Group LDAP Source Connection"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "Group LDAP Source Connections"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/signals.py
|
||||
msgid "Password does not match Active Directory Complexity."
|
||||
msgstr ""
|
||||
|
Binary file not shown.
@ -5,18 +5,19 @@
|
||||
#
|
||||
# Translators:
|
||||
# jcamat, 2022
|
||||
# Jens L. <jens@goauthentik.io>, 2024
|
||||
# Angel, 2024
|
||||
# Iamanaws, 2024
|
||||
# Marcelo Elizeche Landó, 2025
|
||||
# Jens L. <jens@goauthentik.io>, 2025
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-14 14:49+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Iamanaws, 2024\n"
|
||||
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
|
||||
"Language-Team: Spanish (https://app.transifex.com/authentik/teams/119923/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -118,12 +119,16 @@ msgstr "Marcas"
|
||||
|
||||
#: authentik/core/api/application_entitlements.py
|
||||
msgid "User does not have access to application."
|
||||
msgstr ""
|
||||
msgstr "El usuario no tiene acceso a la aplicación"
|
||||
|
||||
#: authentik/core/api/devices.py
|
||||
msgid "Extra description not available"
|
||||
msgstr "Descripción adicional no disponible."
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr "No se puede establecer el grupo como padre de sí mismo."
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
"When not set all providers are returned. When set to true, only backchannel "
|
||||
@ -172,6 +177,14 @@ msgstr "Agrega usuario al grupo"
|
||||
msgid "Remove user from group"
|
||||
msgstr "Remueve usuario del grupo"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Enable superuser status"
|
||||
msgstr "Habiliar estado de \"superusuario\""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Disable superuser status"
|
||||
msgstr "Deshabiliar estado de \"superusuario\""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "User's display name."
|
||||
msgstr "Nombre para mostrar del usuario."
|
||||
@ -548,62 +561,6 @@ msgstr "Asignación de Proveedor de Microsoft Entra"
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr "Asignaciones de Proveedores de Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Determina la duración de una sesión. El valor predeterminado de 0 significa "
|
||||
"que las sesiones duran hasta que se cierra el navegador. (Formato: horas = "
|
||||
"-1; minutos = -2; segundos = -3)"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Cuando es verdadero, los tokens de conexión serán eliminados al "
|
||||
"desconectarse."
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "Proveedor de RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "Proveedores de RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "Punto de Conexión de RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "Puntos de Conexión de RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "Asignación de Propiedades de Proveedor de RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "Asignaciones de Propiedades de Proveedor de RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "Token de Conexión de RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "Tokens de Conexión de RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Límite máximo de conexiones alcanzado."
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Ya estás conectado en otra pestaña/ventana)"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Signing Key"
|
||||
@ -643,7 +600,7 @@ msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/ssf/tasks.py
|
||||
msgid "Failed to send request"
|
||||
msgstr ""
|
||||
msgstr "Falló envio de petición"
|
||||
|
||||
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/models.py
|
||||
msgid "Endpoint Authenticator Google Device Trust Connector Stage"
|
||||
@ -711,9 +668,22 @@ msgid "Slack Webhook (Slack/Discord)"
|
||||
msgstr "Webhook de Slack (Slack/Discord)"
|
||||
|
||||
#: authentik/events/models.py
|
||||
#: authentik/stages/authenticator_validate/models.py
|
||||
msgid "Email"
|
||||
msgstr "Correo"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||
"serializable."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Configure additional headers to be sent. Mapping should return a dictionary "
|
||||
"of key-value pairs"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Only send notification once, for example when sending a webhook into a chat "
|
||||
@ -983,6 +953,12 @@ msgstr "Tokens de flujo"
|
||||
msgid "Invalid next URL"
|
||||
msgstr "Siguiente URL invalida"
|
||||
|
||||
#: authentik/lib/sync/outgoing/models.py
|
||||
msgid ""
|
||||
"When enabled, provider will not modify or create objects in the remote "
|
||||
"system."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr "Iniciando sincronización completa de proveedor"
|
||||
@ -997,6 +973,10 @@ msgstr "Sincronizando página {page} de usuarios"
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr "Sincronizando página {page} de grupos"
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
@ -1210,6 +1190,14 @@ msgstr ""
|
||||
msgid "Client IP is not in an allowed country."
|
||||
msgstr "La IP del cliente no está en un país permitido."
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance from previous authentication is larger than threshold."
|
||||
msgstr "La distancia desde la autenticación previa es mayor que el límite."
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance is further than possible."
|
||||
msgstr "La distancia es mayor de lo posible."
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "GeoIP Policy"
|
||||
msgstr "Política de GeoIP"
|
||||
@ -1344,6 +1332,20 @@ msgstr "Puntuación de Reputacion"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "Puntuaciones de Reputacion"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "Permiso denegado"
|
||||
@ -1535,6 +1537,14 @@ msgstr "RS256 (Encriptación Asimétrica)"
|
||||
msgid "ES256 (Asymmetric Encryption)"
|
||||
msgstr "ES256 (Encriptación Asimétrica)"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES384 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES512 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Scope used by the client"
|
||||
msgstr "Alcance utilizado por el cliente"
|
||||
@ -1818,6 +1828,61 @@ msgstr "Proveedor de Proxy"
|
||||
msgid "Proxy Providers"
|
||||
msgstr "Proveedores de Proxy"
|
||||
|
||||
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Determina la duración de una sesión. El valor predeterminado de 0 significa "
|
||||
"que las sesiones duran hasta que se cierra el navegador. (Formato: horas = "
|
||||
"-1; minutos = -2; segundos = -3)"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Cuando es verdadero, los tokens de conexión serán eliminados al "
|
||||
"desconectarse."
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "Proveedor de RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "Proveedores de RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "Punto de Conexión de RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "Puntos de Conexión de RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "Asignación de Propiedades de Proveedor de RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "Asignaciones de Propiedades de Proveedor de RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "Token de Conexión de RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "Tokens de Conexión de RAC"
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Límite máximo de conexiones alcanzado."
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Ya estás conectado en otra pestaña/ventana)"
|
||||
|
||||
#: authentik/providers/radius/models.py
|
||||
msgid "Shared secret between clients and server to hash packets."
|
||||
msgstr "Secreto compartido entre clientes y servidor para hashear paquetes."
|
||||
@ -1905,6 +1970,17 @@ msgstr ""
|
||||
"Configurar cómo se creará el valor NameID. Si se deja vacío, se considerará "
|
||||
"el NameIDPolicy de la solicitud entrante."
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "AuthnContextClassRef Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Configure how the AuthnContextClassRef value will be created. When left "
|
||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||
"methods the user used to authenticate."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Assertion valid not before current time + this value (Format: "
|
||||
@ -2047,6 +2123,18 @@ msgstr "Proveedor de SAML a partir de Metadatos"
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr "Proveedores de SAML a partir de Metadatos"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Default"
|
||||
msgstr "Predeterminado"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "AWS"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Slack"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "URL base para solicitudes SCIM, generalmente termina en /v2"
|
||||
@ -2055,6 +2143,14 @@ msgstr "URL base para solicitudes SCIM, generalmente termina en /v2"
|
||||
msgid "Authentication token"
|
||||
msgstr "Token de Autenticación"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Compatibility Mode"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "Proveedor de SCIM"
|
||||
@ -2324,6 +2420,13 @@ msgstr ""
|
||||
"Cuando un usuario cambie su contraseña, sincronízala de vuelta con LDAP. "
|
||||
"Esto solo puede habilitarse en una única fuente de LDAP."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "Fuente de LDAP"
|
||||
@ -2733,6 +2836,110 @@ msgstr "Dispositivo Duo"
|
||||
msgid "Duo Devices"
|
||||
msgstr "Dispositivos Duo"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email OTP"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Cuando se habilita, se utilizará la configuración global de conexión de "
|
||||
"correo electrónico y se ignorarán las configuraciones de conexión que se "
|
||||
"indican a continuación"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
|
||||
msgstr ""
|
||||
"Tiempo de validez del token enviado (Formato: "
|
||||
"hours=3,minutes=17,seconds=300)."
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr ""
|
||||
"Se produjo una excepción al procesar la plantilla de correo electrónico"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
msgstr "Dispositivo de Email"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Devices"
|
||||
msgstr "Dispositivos de Email"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "El código no coincide"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
msgid "Invalid email"
|
||||
msgstr "Email Inválido"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Hola %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
msgid ""
|
||||
"\n"
|
||||
" Email MFA code.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Si no solicitaste este código, por favor ignora este correo. El código anterior es válido por %(expires)s."
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Hola %(username)s,"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Si no solicitaste este código, por favor ignora este correo. El código anterior es válido por %(expires)s.\n"
|
||||
|
||||
#: authentik/stages/authenticator_sms/models.py
|
||||
msgid ""
|
||||
"When enabled, the Phone number is only used during enrollment to verify the "
|
||||
@ -2770,11 +2977,6 @@ msgstr "Dispositivo SMS"
|
||||
msgid "SMS Devices"
|
||||
msgstr "Dispositivos SMS"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "El código no coincide"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
msgid "Invalid phone number"
|
||||
msgstr "Número de teléfono inválido"
|
||||
@ -3012,23 +3214,10 @@ msgstr "Restablecimiento de contraseña"
|
||||
msgid "Account Confirmation"
|
||||
msgstr "Confirmación cuenta"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Cuando se habilita, se utilizará la configuración global de conexión de "
|
||||
"correo electrónico y se ignorarán las configuraciones de conexión que se "
|
||||
"indican a continuación"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Activate users upon completion of stage."
|
||||
msgstr "Activar a los usuarios al finalizar la etapa."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time in minutes the token sent is valid."
|
||||
msgstr "El tiempo en minutos que se envía el token es válido."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "Etapa de correo electrónico"
|
||||
@ -3037,11 +3226,6 @@ msgstr "Etapa de correo electrónico"
|
||||
msgid "Email Stages"
|
||||
msgstr "Etapas del correo"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr ""
|
||||
"Se produjo una excepción al procesar la plantilla de correo electrónico"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
msgstr "Correo electrónico verificado correctamente."
|
||||
@ -3126,17 +3310,6 @@ msgstr ""
|
||||
"\n"
|
||||
"Este correo electrónico fue enviado desde el transporte de notificaciones %(name)s.\n"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Hola %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -3154,11 +3327,8 @@ msgid ""
|
||||
" If you did not request a password change, please ignore this email. The link above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Hola %(username)s,"
|
||||
"\n"
|
||||
"Si no solicitaste un cambio de contraseña, por favor ignora este correo. El enlace anterior es válido por %(expires)s."
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
msgid ""
|
||||
@ -3174,6 +3344,8 @@ msgid ""
|
||||
"\n"
|
||||
"If you did not request a password change, please ignore this email. The link above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Si no solicitaste un cambio de contraseña, por favor ignora este correo. El enlace anterior es válido por %(expires)s.\n"
|
||||
|
||||
#: authentik/stages/email/templates/email/setup.html
|
||||
msgid "authentik Test-Email"
|
||||
@ -3493,11 +3665,11 @@ msgstr ""
|
||||
|
||||
#: authentik/stages/redirect/models.py
|
||||
msgid "Redirect Stage"
|
||||
msgstr ""
|
||||
msgstr "Etapa de Redirección"
|
||||
|
||||
#: authentik/stages/redirect/models.py
|
||||
msgid "Redirect Stages"
|
||||
msgstr ""
|
||||
msgstr "Etapas de Redirección"
|
||||
|
||||
#: authentik/stages/user_delete/models.py
|
||||
msgid "User Delete Stage"
|
||||
|
Binary file not shown.
@ -4,20 +4,20 @@
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
# Translators:
|
||||
# Ville Ranki, 2022
|
||||
# Skyler Mäntysaari, 2024
|
||||
# Jani Hast, 2024
|
||||
# MarkoTukiainen, 2025
|
||||
# Marc Schmitt, 2025
|
||||
# Ville Ranki, 2025
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-14 14:49+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Marc Schmitt, 2025\n"
|
||||
"Last-Translator: Ville Ranki, 2025\n"
|
||||
"Language-Team: Finnish (https://app.transifex.com/authentik/teams/119923/fi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -122,6 +122,10 @@ msgstr "Käyttäjällä ei ole pääsyä sovellukseen."
|
||||
msgid "Extra description not available"
|
||||
msgstr "Lisäkuvaus ei ole saatavilla"
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
"When not set all providers are returned. When set to true, only backchannel "
|
||||
@ -169,6 +173,14 @@ msgstr "Lisää käyttäjä ryhmään"
|
||||
msgid "Remove user from group"
|
||||
msgstr "Poista käyttäjä ryhmästä"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Enable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Disable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "User's display name."
|
||||
msgstr "Käyttäjän näytettävä nimi"
|
||||
@ -540,61 +552,6 @@ msgstr "Microsoft Entra -palveluntarjoajan kytkentä"
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr "Microsoft Entra -palveluntarjoajan kytkennät"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Määrittää istunnon keston. Oletusarvo 0 tarkoittaa, että istunto kestää "
|
||||
"kunnes selain suljetaan. (Muoto: hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Kun asetettu arvoon tosi, yhteystunnisteet poistetaan yhteyden katkaisemisen"
|
||||
" yhteydessä."
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC-palveluntarjoaja"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC-palveluntarjoajat"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "RAC-päätepiste"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "RAC-päätepisteet"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "RAC-palveluntarjoajan ominaisuuskytkentä"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "RAC-palveluntarjoajan ominaisuuskytkennät"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "RAC-yhteystunniste"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "RAC-yhteystunnisteet"
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Yhteyksien enimmäismäärä saavutettu."
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Olet jo yhteydessä toisen selainvälilehden tai -ikkunan kautta)"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Signing Key"
|
||||
@ -698,9 +655,22 @@ msgid "Slack Webhook (Slack/Discord)"
|
||||
msgstr "Slack-webhook (Slack/Discord)"
|
||||
|
||||
#: authentik/events/models.py
|
||||
#: authentik/stages/authenticator_validate/models.py
|
||||
msgid "Email"
|
||||
msgstr "Sähköposti"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||
"serializable."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Configure additional headers to be sent. Mapping should return a dictionary "
|
||||
"of key-value pairs"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Only send notification once, for example when sending a webhook into a chat "
|
||||
@ -970,6 +940,12 @@ msgstr "Prosessin tunnisteet"
|
||||
msgid "Invalid next URL"
|
||||
msgstr "Virheellinen seuraava URL"
|
||||
|
||||
#: authentik/lib/sync/outgoing/models.py
|
||||
msgid ""
|
||||
"When enabled, provider will not modify or create objects in the remote "
|
||||
"system."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr "Käynnistetään palveluntarjoajan täysi synkronisointi"
|
||||
@ -984,6 +960,10 @@ msgstr "Synkronoidaan käyttäjien sivua {page}"
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr "Synkronoidaan ryhmien sivua {page}"
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
@ -1194,6 +1174,14 @@ msgstr "GeoIP: asiakkaan IP-osoitetta ei löydy kaupunkitietokannasta."
|
||||
msgid "Client IP is not in an allowed country."
|
||||
msgstr "Asiakkaan IP-osoite ei sijaitse sallitussa maassa."
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance from previous authentication is larger than threshold."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance is further than possible."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "GeoIP Policy"
|
||||
msgstr "GeoIP-käytäntö"
|
||||
@ -1326,6 +1314,20 @@ msgstr "Mainepistemäärä"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "Mainepistemäärät"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "Käyttö evätty"
|
||||
@ -1517,6 +1519,14 @@ msgstr "RS256 (asymmetrinen salaus)"
|
||||
msgid "ES256 (Asymmetric Encryption)"
|
||||
msgstr "ES256 (asymmetrinen salaus)"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES384 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES512 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Scope used by the client"
|
||||
msgstr "Asiakkaan käyttämä käyttöalue"
|
||||
@ -1797,6 +1807,60 @@ msgstr "Välityspalveluntarjoaja"
|
||||
msgid "Proxy Providers"
|
||||
msgstr "Välityspalveluntarjoajat"
|
||||
|
||||
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Määrittää istunnon keston. Oletusarvo 0 tarkoittaa, että istunto kestää "
|
||||
"kunnes selain suljetaan. (Muoto: hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Kun asetettu arvoon tosi, yhteystunnisteet poistetaan yhteyden katkaisemisen"
|
||||
" yhteydessä."
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC-palveluntarjoaja"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC-palveluntarjoajat"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "RAC-päätepiste"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "RAC-päätepisteet"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "RAC-palveluntarjoajan ominaisuuskytkentä"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "RAC-palveluntarjoajan ominaisuuskytkennät"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "RAC-yhteystunniste"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "RAC-yhteystunnisteet"
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Yhteyksien enimmäismäärä saavutettu."
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Olet jo yhteydessä toisen selainvälilehden tai -ikkunan kautta)"
|
||||
|
||||
#: authentik/providers/radius/models.py
|
||||
msgid "Shared secret between clients and server to hash packets."
|
||||
msgstr ""
|
||||
@ -1886,6 +1950,17 @@ msgstr ""
|
||||
"Määritä, kuinka NameID:n arvo luodaan. Jos tämä jätetään tyhjäksi, käytetään"
|
||||
" sisääntulevan pyynnön NameIDPolicy-kentän arvoa."
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "AuthnContextClassRef Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Configure how the AuthnContextClassRef value will be created. When left "
|
||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||
"methods the user used to authenticate."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Assertion valid not before current time + this value (Format: "
|
||||
@ -2028,6 +2103,18 @@ msgstr "SAML-palveluntarjoaja metatiedoista"
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr "SAML-palveluntarjoajat metatiedoista"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Default"
|
||||
msgstr "Oletus"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "AWS"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Slack"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "URL-osoitteen perusosa SCIM-pyyntöjä varten, päättyy yleensä /v2"
|
||||
@ -2036,6 +2123,14 @@ msgstr "URL-osoitteen perusosa SCIM-pyyntöjä varten, päättyy yleensä /v2"
|
||||
msgid "Authentication token"
|
||||
msgstr "Todennustunniste"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Compatibility Mode"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "SCIM-palveluntarjoaja"
|
||||
@ -2302,6 +2397,13 @@ msgstr ""
|
||||
"Kun käyttäjä muuttaa salasanansa, synkronoi se LDAPiin. Tämä voi olla "
|
||||
"käytössä vain yhden LDAP-lähteen kanssa."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "LDAP-lähde"
|
||||
@ -2712,6 +2814,102 @@ msgstr "Duo-laite"
|
||||
msgid "Duo Devices"
|
||||
msgstr "Duo-laitteet"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email OTP"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Kun tämä on käytössä, käytetään globaaleja sähköpostiyhteysasetuksia, ja "
|
||||
"alla olevat yhteysasetukset ohitetaan."
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Sähköpostimallin käytössä tapahtui virhe"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Devices"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Koodi ei täsmää"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
msgid "Invalid email"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Hei %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
msgid ""
|
||||
"\n"
|
||||
" Email MFA code.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Hei %(username)s,"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_sms/models.py
|
||||
msgid ""
|
||||
"When enabled, the Phone number is only used during enrollment to verify the "
|
||||
@ -2749,11 +2947,6 @@ msgstr "SMS-laite"
|
||||
msgid "SMS Devices"
|
||||
msgstr "SMS-laitteet"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Koodi ei täsmää"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
msgid "Invalid phone number"
|
||||
msgstr "Virheellinen puhelinnumero"
|
||||
@ -2992,22 +3185,10 @@ msgstr "Salasanan nollaus"
|
||||
msgid "Account Confirmation"
|
||||
msgstr "Tunnuksen vahvistus"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Kun tämä on käytössä, käytetään globaaleja sähköpostiyhteysasetuksia, ja "
|
||||
"alla olevat yhteysasetukset ohitetaan."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Activate users upon completion of stage."
|
||||
msgstr "Aktivoi käyttäjät tämän vaiheen lopuksi."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time in minutes the token sent is valid."
|
||||
msgstr "Aika minuutteina, jonka verran lähetetty tunniste on voimassa."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "Sähköpostivaihe"
|
||||
@ -3016,10 +3197,6 @@ msgstr "Sähköpostivaihe"
|
||||
msgid "Email Stages"
|
||||
msgstr "Sähköpostivaiheet"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Sähköpostimallin käytössä tapahtui virhe"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
msgstr "Sähköpostiosoite vahvistettu."
|
||||
@ -3102,17 +3279,6 @@ msgstr ""
|
||||
"\n"
|
||||
"Tämä viesti on lähetetty notifikaatiokanavasta %(name)s.\n"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Hei %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -3134,11 +3300,6 @@ msgstr ""
|
||||
" Jos et ole pyytänyt salasanan vaihtoa, jätä tämä viesti huomiotta. Yllä oleva linkki on voimassa %(expires)s.\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Hei %(username)s,"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
|
@ -19,7 +19,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-03-31 00:10+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Marc Schmitt, 2025\n"
|
||||
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
|
||||
@ -2441,6 +2441,13 @@ msgstr ""
|
||||
"Lorsqu'un utilisateur change son mot de passe, le synchroniser à nouveau "
|
||||
"vers LDAP. Ne peut être activé que sur une seule source LDAP."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "Source LDAP"
|
||||
|
Binary file not shown.
@ -20,7 +20,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-03-31 00:10+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025\n"
|
||||
"Language-Team: Italian (https://app.transifex.com/authentik/teams/119923/it/)\n"
|
||||
@ -2429,6 +2429,13 @@ msgstr ""
|
||||
"Quando un utente cambia la propria password, sincronizzala con LDAP. Questo "
|
||||
"può essere abilitato solo su una singola origine LDAP."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "Sorgente LDAP"
|
||||
|
@ -12,7 +12,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-14 14:49+0000\n"
|
||||
"POT-Creation-Date: 2025-03-31 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: NavyStack, 2023\n"
|
||||
"Language-Team: Korean (https://app.transifex.com/authentik/teams/119923/ko/)\n"
|
||||
@ -115,6 +115,10 @@ msgstr ""
|
||||
msgid "Extra description not available"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
"When not set all providers are returned. When set to true, only backchannel "
|
||||
@ -159,6 +163,14 @@ msgstr ""
|
||||
msgid "Remove user from group"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Enable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Disable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "User's display name."
|
||||
msgstr "사용자의 표시 이름"
|
||||
@ -509,59 +521,6 @@ msgstr ""
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"세션이 지속되는 시간을 결정합니다. 기본값인 0초는 브라우저가 닫힐 때까지 세션이 지속된다는 의미입니다. (서식: "
|
||||
"hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Signing Key"
|
||||
@ -663,9 +622,22 @@ msgid "Slack Webhook (Slack/Discord)"
|
||||
msgstr "Slack 웹훅 (Slack/Discord)"
|
||||
|
||||
#: authentik/events/models.py
|
||||
#: authentik/stages/authenticator_validate/models.py
|
||||
msgid "Email"
|
||||
msgstr "이메일"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||
"serializable."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Configure additional headers to be sent. Mapping should return a dictionary "
|
||||
"of key-value pairs"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Only send notification once, for example when sending a webhook into a chat "
|
||||
@ -920,6 +892,12 @@ msgstr "플로우 토큰"
|
||||
msgid "Invalid next URL"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/models.py
|
||||
msgid ""
|
||||
"When enabled, provider will not modify or create objects in the remote "
|
||||
"system."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr ""
|
||||
@ -934,6 +912,10 @@ msgstr ""
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
@ -1126,6 +1108,14 @@ msgstr ""
|
||||
msgid "Client IP is not in an allowed country."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance from previous authentication is larger than threshold."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance is further than possible."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "GeoIP Policy"
|
||||
msgstr ""
|
||||
@ -1250,6 +1240,20 @@ msgstr "평판 점수"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "평판 점수"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "권한 거부됨"
|
||||
@ -1429,6 +1433,14 @@ msgstr "RS256 (비대칭 암호화)"
|
||||
msgid "ES256 (Asymmetric Encryption)"
|
||||
msgstr "ES256 (비대칭 암호화)"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES384 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES512 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Scope used by the client"
|
||||
msgstr "클라이언트에서 사용할 스코프"
|
||||
@ -1680,6 +1692,58 @@ msgstr "프록시 공급자"
|
||||
msgid "Proxy Providers"
|
||||
msgstr "프록시 공급자"
|
||||
|
||||
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"세션이 지속되는 시간을 결정합니다. 기본값인 0초는 브라우저가 닫힐 때까지 세션이 지속된다는 의미입니다. (서식: "
|
||||
"hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/radius/models.py
|
||||
msgid "Shared secret between clients and server to hash packets."
|
||||
msgstr "클라이언트와 서버가 패킷을 해시하기 위해 공유하는 비밀입니다."
|
||||
@ -1758,6 +1822,17 @@ msgid ""
|
||||
"NameIDPolicy of the incoming request will be considered"
|
||||
msgstr "NameID 값이 어떻게 생성될지 구성합니다. 비워 둘 경우, 들어오는 요청의 NameIDPolicy을 고려합니다."
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "AuthnContextClassRef Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Configure how the AuthnContextClassRef value will be created. When left "
|
||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||
"methods the user used to authenticate."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Assertion valid not before current time + this value (Format: "
|
||||
@ -1886,6 +1961,18 @@ msgstr "SAML 공급자 메타데이터"
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "AWS"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Slack"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "SCIM 요청에 대한 기본 URL은, 일반적으로 /v2로 끝납니다"
|
||||
@ -1894,6 +1981,14 @@ msgstr "SCIM 요청에 대한 기본 URL은, 일반적으로 /v2로 끝납니다
|
||||
msgid "Authentication token"
|
||||
msgstr "인증 토큰"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Compatibility Mode"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "SCIM 공급자"
|
||||
@ -2532,6 +2627,100 @@ msgstr "Duo 디바이스"
|
||||
msgid "Duo Devices"
|
||||
msgstr "Duo 디바이스"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email OTP"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr "활성화하면, 전역 이메일 연결 설정이 사용되며 아래의 연결 설정은 무시됩니다."
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "이메일 템플릿 렌더링 중 예외가 발생"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Devices"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "코드가 일치하지 않음"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
msgid "Invalid email"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" %(username)s 님께,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
msgid ""
|
||||
"\n"
|
||||
" Email MFA code.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_sms/models.py
|
||||
msgid ""
|
||||
"When enabled, the Phone number is only used during enrollment to verify the "
|
||||
@ -2566,11 +2755,6 @@ msgstr "SMS 디바이스"
|
||||
msgid "SMS Devices"
|
||||
msgstr "SMS 디바이스"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "코드가 일치하지 않음"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
msgid "Invalid phone number"
|
||||
msgstr "유효하지 않은 전화번호"
|
||||
@ -2795,20 +2979,10 @@ msgstr "비밀번호 초기화"
|
||||
msgid "Account Confirmation"
|
||||
msgstr "계정 확인"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr "활성화하면, 전역 이메일 연결 설정이 사용되며 아래의 연결 설정은 무시됩니다."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Activate users upon completion of stage."
|
||||
msgstr "스테이지가 완료되면 사용자를 활성화합니다."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time in minutes the token sent is valid."
|
||||
msgstr "전송된 토큰이 유효한 시간(분)입니다."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "이메일 스테이지"
|
||||
@ -2817,10 +2991,6 @@ msgstr "이메일 스테이지"
|
||||
msgid "Email Stages"
|
||||
msgstr "이메일 스테이지"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "이메일 템플릿 렌더링 중 예외가 발생"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
msgstr "이메일을 성공적으로 확인했습니다."
|
||||
@ -2899,17 +3069,6 @@ msgid ""
|
||||
"This email was sent from the notification transport %(name)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" %(username)s 님께,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -2928,11 +3087,6 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -7,18 +7,18 @@
|
||||
# Bartosz Karpiński, 2023
|
||||
# Michał Jastrzębski, 2024
|
||||
# Tomci 12 <drizztes@gmail.com>, 2024
|
||||
# Darek “NeroPcStation” NeroPcStation <dareknowacki2001@gmail.com>, 2024
|
||||
# Jens L. <jens@goauthentik.io>, 2024
|
||||
# Marc Schmitt, 2025
|
||||
# Jens L. <jens@goauthentik.io>, 2025
|
||||
# Darek “NeroPcStation” NeroPcStation <dareknowacki2001@gmail.com>, 2025
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-14 14:49+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Marc Schmitt, 2025\n"
|
||||
"Last-Translator: Darek “NeroPcStation” NeroPcStation <dareknowacki2001@gmail.com>, 2025\n"
|
||||
"Language-Team: Polish (https://app.transifex.com/authentik/teams/119923/pl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -125,6 +125,10 @@ msgstr ""
|
||||
msgid "Extra description not available"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
"When not set all providers are returned. When set to true, only backchannel "
|
||||
@ -172,6 +176,14 @@ msgstr "Dodaj użytkownika do grupy"
|
||||
msgid "Remove user from group"
|
||||
msgstr "Usuń użytkownika z grupy"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Enable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Disable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "User's display name."
|
||||
msgstr "Wyświetlana nazwa użytkownika."
|
||||
@ -541,60 +553,6 @@ msgstr "Mapowanie dostawcy Microsoft Entra"
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr "Mapowania dostawcy Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Określa, jak długo trwa sesja. Domyślna wartość 0 sekund oznacza, że sesje "
|
||||
"trwają do zamknięcia przeglądarki. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Gdy ustawione na prawdę, tokeny połączenia zostaną usunięte po rozłączeniu."
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "Dostawca RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "Dostawcy RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "Punkt końcowy RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "Punkty końcowe RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "Token połączenia RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "Tokeny połączenia RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Osiągnięto maksymalny limit połączeń."
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Jesteś już podłączony w innej karcie/oknie)"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Signing Key"
|
||||
@ -698,9 +656,22 @@ msgid "Slack Webhook (Slack/Discord)"
|
||||
msgstr "Slack Webhook (Slack/Discord)"
|
||||
|
||||
#: authentik/events/models.py
|
||||
#: authentik/stages/authenticator_validate/models.py
|
||||
msgid "Email"
|
||||
msgstr "E-mail"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||
"serializable."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Configure additional headers to be sent. Mapping should return a dictionary "
|
||||
"of key-value pairs"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Only send notification once, for example when sending a webhook into a chat "
|
||||
@ -974,6 +945,12 @@ msgstr "Tokeny przepływu"
|
||||
msgid "Invalid next URL"
|
||||
msgstr "Nieprawidłowy następny adres URL"
|
||||
|
||||
#: authentik/lib/sync/outgoing/models.py
|
||||
msgid ""
|
||||
"When enabled, provider will not modify or create objects in the remote "
|
||||
"system."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr "Rozpoczęcie pełnej synchronizacji dostawcy"
|
||||
@ -988,6 +965,10 @@ msgstr ""
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
@ -1200,6 +1181,14 @@ msgstr ""
|
||||
msgid "Client IP is not in an allowed country."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance from previous authentication is larger than threshold."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance is further than possible."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "GeoIP Policy"
|
||||
msgstr ""
|
||||
@ -1330,6 +1319,20 @@ msgstr "Punkty reputacji"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "Punkty reputacji"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr "Oczekiwanie na uwierzytelnienie..."
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "Odmowa uprawnień"
|
||||
@ -1518,6 +1521,14 @@ msgstr "RS256 (szyfrowanie asymetryczne)"
|
||||
msgid "ES256 (Asymmetric Encryption)"
|
||||
msgstr "ES256 (szyfrowanie asymetryczne)"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES384 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES512 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Scope used by the client"
|
||||
msgstr "Zakres używany przez klienta"
|
||||
@ -1793,6 +1804,59 @@ msgstr "Dostawca proxy"
|
||||
msgid "Proxy Providers"
|
||||
msgstr "Dostawcy proxy"
|
||||
|
||||
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Określa, jak długo trwa sesja. Domyślna wartość 0 sekund oznacza, że sesje "
|
||||
"trwają do zamknięcia przeglądarki. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Gdy ustawione na prawdę, tokeny połączenia zostaną usunięte po rozłączeniu."
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "Dostawca RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "Dostawcy RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "Punkt końcowy RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "Punkty końcowe RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "Token połączenia RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "Tokeny połączenia RAC"
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Osiągnięto maksymalny limit połączeń."
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Jesteś już podłączony w innej karcie/oknie)"
|
||||
|
||||
#: authentik/providers/radius/models.py
|
||||
msgid "Shared secret between clients and server to hash packets."
|
||||
msgstr ""
|
||||
@ -1878,6 +1942,17 @@ msgstr ""
|
||||
"Konfiguruje sposób tworzenia wartości NameID. Jeśli pozostanie puste, pod "
|
||||
"uwagę brana będzie wartość NameIDPolicy przychodzącego żądania"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "AuthnContextClassRef Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Configure how the AuthnContextClassRef value will be created. When left "
|
||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||
"methods the user used to authenticate."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Assertion valid not before current time + this value (Format: "
|
||||
@ -2014,6 +2089,18 @@ msgstr "Dostawca SAML z metadanych"
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr "Dostawcy SAML z metadanych"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Default"
|
||||
msgstr "Domyślny"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "AWS"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Slack"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "Podstawowy adres URL dla żądań SCIM, zwykle kończy się na /v2"
|
||||
@ -2022,6 +2109,14 @@ msgstr "Podstawowy adres URL dla żądań SCIM, zwykle kończy się na /v2"
|
||||
msgid "Authentication token"
|
||||
msgstr "Token uwierzytelnienia"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Compatibility Mode"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "Dostawca SCIM"
|
||||
@ -2272,6 +2367,13 @@ msgstr ""
|
||||
"Gdy użytkownik zmieni hasło, zsynchronizuj je z LDAP. Tę funkcję można "
|
||||
"włączyć tylko w jednym źródle LDAP."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "Źródło LDAP"
|
||||
@ -2684,6 +2786,102 @@ msgstr "Urządzenie Duo"
|
||||
msgid "Duo Devices"
|
||||
msgstr "Urządzenia Duo"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email OTP"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Gdy ta opcja jest włączona, będą używane globalne ustawienia połączenia "
|
||||
"poczty e-mail, a poniższe ustawienia połączenia będą ignorowane."
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Wystąpił błąd podczas renderowania szablonu wiadomości e-mail"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Devices"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Kod jest niezgodny"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
msgid "Invalid email"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Cześć %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
msgid ""
|
||||
"\n"
|
||||
" Email MFA code.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Cześć %(username)s,"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_sms/models.py
|
||||
msgid ""
|
||||
"When enabled, the Phone number is only used during enrollment to verify the "
|
||||
@ -2721,11 +2919,6 @@ msgstr "Urządzenie SMS"
|
||||
msgid "SMS Devices"
|
||||
msgstr "Urządzenia SMS"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Kod jest niezgodny"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
msgid "Invalid phone number"
|
||||
msgstr "Nieprawidłowy numer telefonu"
|
||||
@ -2962,22 +3155,10 @@ msgstr "Resetowania hasła"
|
||||
msgid "Account Confirmation"
|
||||
msgstr "Potwierdzenie konta"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Gdy ta opcja jest włączona, będą używane globalne ustawienia połączenia "
|
||||
"poczty e-mail, a poniższe ustawienia połączenia będą ignorowane."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Activate users upon completion of stage."
|
||||
msgstr "Aktywuj użytkowników po zakończeniu etapu."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time in minutes the token sent is valid."
|
||||
msgstr "Czas w minutach, w którym wysłany token jest ważny."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "Etap e-mail"
|
||||
@ -2986,10 +3167,6 @@ msgstr "Etap e-mail"
|
||||
msgid "Email Stages"
|
||||
msgstr "Etapy e-mail"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Wystąpił błąd podczas renderowania szablonu wiadomości e-mail"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
msgstr "Pomyślnie zweryfikowano e-mail."
|
||||
@ -3074,17 +3251,6 @@ msgstr ""
|
||||
"\n"
|
||||
"Ta wiadomość e-mail została wysłana z transportu powiadomień %(name)s.\n"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Cześć %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -3103,11 +3269,6 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Cześć %(username)s,"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
|
Binary file not shown.
@ -5,22 +5,22 @@
|
||||
#
|
||||
# Translators:
|
||||
# Herculino Trotta, 2022
|
||||
# Gil Poiares-Oliveira, 2023
|
||||
# Josenivaldo Benito Junior, 2023
|
||||
# Caio Lima, 2023
|
||||
# Hacklab, 2023
|
||||
# Anderson Silva Andrade <anderson.asa89@gmail.com>, 2024
|
||||
# Wagner Santos, 2024
|
||||
# Rafael Mundel, 2024
|
||||
# Anderson Silva Andrade <anderson.asa89@gmail.com>, 2025
|
||||
# Gil Poiares-Oliveira, 2025
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-14 14:49+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Rafael Mundel, 2024\n"
|
||||
"Last-Translator: Gil Poiares-Oliveira, 2025\n"
|
||||
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/authentik/teams/119923/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -30,7 +30,7 @@ msgstr ""
|
||||
|
||||
#: authentik/admin/models.py
|
||||
msgid "Version history"
|
||||
msgstr ""
|
||||
msgstr "Histórico da versão"
|
||||
|
||||
#: authentik/admin/tasks.py
|
||||
#, python-brace-format
|
||||
@ -90,7 +90,7 @@ msgstr "Export do authentik - {date}"
|
||||
#: authentik/blueprints/v1/tasks.py authentik/crypto/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Successfully imported {count} files."
|
||||
msgstr ""
|
||||
msgstr "{count} arquivos importados com sucesso."
|
||||
|
||||
#: authentik/brands/models.py
|
||||
msgid ""
|
||||
@ -122,11 +122,15 @@ msgstr "Brand"
|
||||
|
||||
#: authentik/core/api/application_entitlements.py
|
||||
msgid "User does not have access to application."
|
||||
msgstr ""
|
||||
msgstr "O usuário não tem acesso ao aplicativo."
|
||||
|
||||
#: authentik/core/api/devices.py
|
||||
msgid "Extra description not available"
|
||||
msgstr ""
|
||||
msgstr "Descrição extra não disponível"
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr "Não é possível definir o grupo como pai de si mesmo."
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
@ -141,7 +145,7 @@ msgstr ""
|
||||
#: authentik/core/api/transactional_applications.py
|
||||
#, python-brace-format
|
||||
msgid "User lacks permission to create {model}"
|
||||
msgstr ""
|
||||
msgstr "O usuário não tem permissão para criar {model}"
|
||||
|
||||
#: authentik/core/api/users.py
|
||||
msgid "No leading or trailing slashes allowed."
|
||||
@ -175,6 +179,14 @@ msgstr "Adicionar usuário ao grupo"
|
||||
msgid "Remove user from group"
|
||||
msgstr "Remover usuário do grupo"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Enable superuser status"
|
||||
msgstr "Habilitar status de superuser"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Disable superuser status"
|
||||
msgstr "Desabilitar status de superuser"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "User's display name."
|
||||
msgstr "Nome de exibição do usuário."
|
||||
@ -546,61 +558,6 @@ msgstr "Mapeamento de Provedor Microsoft Entra"
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr "Mapeamentos de Provedor Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Determina a duração de uma sessão. O padrão de 0 significa que as sessões "
|
||||
"duram até que o navegador seja fechado. (Formato: "
|
||||
"horas=-1;minutos=-2;segundos=-3)"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Quando definido para true, tokens de conexão serão deletados ao desconectar."
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Signing Key"
|
||||
@ -702,9 +659,22 @@ msgid "Slack Webhook (Slack/Discord)"
|
||||
msgstr "Slack Webhook (Slack/Discord)"
|
||||
|
||||
#: authentik/events/models.py
|
||||
#: authentik/stages/authenticator_validate/models.py
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||
"serializable."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Configure additional headers to be sent. Mapping should return a dictionary "
|
||||
"of key-value pairs"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Only send notification once, for example when sending a webhook into a chat "
|
||||
@ -972,6 +942,12 @@ msgstr "Tokens de Fluxo"
|
||||
msgid "Invalid next URL"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/models.py
|
||||
msgid ""
|
||||
"When enabled, provider will not modify or create objects in the remote "
|
||||
"system."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr ""
|
||||
@ -986,6 +962,10 @@ msgstr ""
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
@ -1196,6 +1176,14 @@ msgstr ""
|
||||
msgid "Client IP is not in an allowed country."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance from previous authentication is larger than threshold."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance is further than possible."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "GeoIP Policy"
|
||||
msgstr ""
|
||||
@ -1325,6 +1313,20 @@ msgstr "Pontuação de reputação"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "Pontuações de reputação"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "Permissão negada"
|
||||
@ -1510,6 +1512,14 @@ msgstr "RS256 (criptografia assimétrica)"
|
||||
msgid "ES256 (Asymmetric Encryption)"
|
||||
msgstr "ES256 (criptografia assimétrica)"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES384 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES512 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Scope used by the client"
|
||||
msgstr "Escopo utilizado pelo cliente"
|
||||
@ -1789,6 +1799,60 @@ msgstr "Provedor de proxy"
|
||||
msgid "Proxy Providers"
|
||||
msgstr "Provedores de proxy"
|
||||
|
||||
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Determina a duração de uma sessão. O padrão de 0 significa que as sessões "
|
||||
"duram até que o navegador seja fechado. (Formato: "
|
||||
"horas=-1;minutos=-2;segundos=-3)"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Quando definido para true, tokens de conexão serão deletados ao desconectar."
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/radius/models.py
|
||||
msgid "Shared secret between clients and server to hash packets."
|
||||
msgstr ""
|
||||
@ -1876,6 +1940,17 @@ msgstr ""
|
||||
"Configure como o valor NameID será criado. Quando deixado em branco, o "
|
||||
"NameIDPolicy da solicitação recebida será considerado"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "AuthnContextClassRef Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Configure how the AuthnContextClassRef value will be created. When left "
|
||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||
"methods the user used to authenticate."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Assertion valid not before current time + this value (Format: "
|
||||
@ -2014,6 +2089,18 @@ msgstr "Provedor SAML a partir de Metadados"
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Default"
|
||||
msgstr "Pré-definição"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "AWS"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Slack"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "URL base para solicitações SCIM, geralmente termina em /v2"
|
||||
@ -2022,6 +2109,14 @@ msgstr "URL base para solicitações SCIM, geralmente termina em /v2"
|
||||
msgid "Authentication token"
|
||||
msgstr "Token de autenticação"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Compatibility Mode"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "Provedor SCIM"
|
||||
@ -2269,6 +2364,13 @@ msgstr ""
|
||||
"Quando um usuário alterar sua senha, sincronize-a novamente com o LDAP. Isso"
|
||||
" só pode ser ativado em uma única origem LDAP."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "Fonte LDAP"
|
||||
@ -2677,6 +2779,102 @@ msgstr "Dispositivo Duo"
|
||||
msgid "Duo Devices"
|
||||
msgstr "Dispositivos Duo"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email OTP"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Quando ativado, as configurações globais de conexão de e-mail serão usadas e"
|
||||
" as configurações de conexão abaixo serão ignoradas."
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Houve uma exceção ao renderizar o template de E-mail"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Devices"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "O código não corresponde"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
msgid "Invalid email"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Oi %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
msgid ""
|
||||
"\n"
|
||||
" Email MFA code.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Olá %(username)s,"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_sms/models.py
|
||||
msgid ""
|
||||
"When enabled, the Phone number is only used during enrollment to verify the "
|
||||
@ -2714,11 +2912,6 @@ msgstr "Dispositivo SMS"
|
||||
msgid "SMS Devices"
|
||||
msgstr "Dispositivos SMS"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "O código não corresponde"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
msgid "Invalid phone number"
|
||||
msgstr "Número de telefone inválido"
|
||||
@ -2950,22 +3143,10 @@ msgstr "Redefinição de senha"
|
||||
msgid "Account Confirmation"
|
||||
msgstr "Confirmação de conta"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Quando ativado, as configurações globais de conexão de e-mail serão usadas e"
|
||||
" as configurações de conexão abaixo serão ignoradas."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Activate users upon completion of stage."
|
||||
msgstr "Ative os usuários após a conclusão do estágio."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time in minutes the token sent is valid."
|
||||
msgstr "Tempo em minutos em que o token enviado é válido."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "Etapa de e-mail"
|
||||
@ -2974,10 +3155,6 @@ msgstr "Etapa de e-mail"
|
||||
msgid "Email Stages"
|
||||
msgstr "Etapas de e-mail"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Houve uma exceção ao renderizar o template de E-mail"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
msgstr "E-mail verificado com sucesso."
|
||||
@ -3057,17 +3234,6 @@ msgid ""
|
||||
"This email was sent from the notification transport %(name)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Oi %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -3086,11 +3252,6 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Olá %(username)s,"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
|
@ -10,15 +10,17 @@
|
||||
# Ренат Шарафутдинов, 2023
|
||||
# Stepan Karavaev, 2024
|
||||
# Anton Babenko, 2024
|
||||
# fenix vd, 2025
|
||||
# Marc Schmitt, 2025
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-14 14:49+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Anton Babenko, 2024\n"
|
||||
"Last-Translator: Marc Schmitt, 2025\n"
|
||||
"Language-Team: Russian (https://app.transifex.com/authentik/teams/119923/ru/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -28,12 +30,12 @@ msgstr ""
|
||||
|
||||
#: authentik/admin/models.py
|
||||
msgid "Version history"
|
||||
msgstr ""
|
||||
msgstr "История версий"
|
||||
|
||||
#: authentik/admin/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "New version {version} available!"
|
||||
msgstr ""
|
||||
msgstr "Новая версия доступна {version}"
|
||||
|
||||
#: authentik/api/schema.py
|
||||
msgid "Generic API Error"
|
||||
@ -87,7 +89,7 @@ msgstr "authentik Экспорт - {date}"
|
||||
#: authentik/blueprints/v1/tasks.py authentik/crypto/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Successfully imported {count} files."
|
||||
msgstr ""
|
||||
msgstr "Успешно импортировано {count} файлов."
|
||||
|
||||
#: authentik/brands/models.py
|
||||
msgid ""
|
||||
@ -123,7 +125,11 @@ msgstr ""
|
||||
|
||||
#: authentik/core/api/devices.py
|
||||
msgid "Extra description not available"
|
||||
msgstr ""
|
||||
msgstr "Дополнительное описание недоступно"
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr "Не удается установить группу в качестве родительской для самой себя."
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
@ -172,6 +178,14 @@ msgstr "Добавить пользователя в группу"
|
||||
msgid "Remove user from group"
|
||||
msgstr "Удалить пользователя из группы"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Enable superuser status"
|
||||
msgstr "Включить статус суперпользователя"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Disable superuser status"
|
||||
msgstr "Выключить статус суперпользователя "
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "User's display name."
|
||||
msgstr "Отображаемое имя пользователя."
|
||||
@ -408,7 +422,7 @@ msgstr "Домой"
|
||||
#: authentik/core/templates/login/base_full.html
|
||||
#: authentik/flows/templates/if/flow-sfe.html
|
||||
msgid "Powered by authentik"
|
||||
msgstr "Основано на authentik"
|
||||
msgstr "При поддержке authentik"
|
||||
|
||||
#: authentik/core/views/apps.py authentik/providers/oauth2/views/authorize.py
|
||||
#: authentik/providers/oauth2/views/device_init.py
|
||||
@ -547,61 +561,6 @@ msgstr "Сопоставление провайдера Microsoft Entra"
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr "Сопоставления провайдера Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Определяет время жизни сессии. Значение по умолчанию 0 означает, что сессии "
|
||||
"будут истекать при закрытии браузера. (Формат: часы=-1;минуты=-2;секунды=-3)"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Если установлено значение true, токены соединения будут удалены при "
|
||||
"отключении"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC Провайдер"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC Провайдеры"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "Точка подключения RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "Точки подключения RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "Сопоставление свойства RAC провайдера"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "Сопоставление свойств RAC провайдера"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "Токен соединения RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "Токены соединения RAC"
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Достигнут максимальный лимит соединений."
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Вы уже подключены в другой вкладке/окне)"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Signing Key"
|
||||
@ -621,15 +580,15 @@ msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "Add stream to SSF provider"
|
||||
msgstr ""
|
||||
msgstr "Добавить поток к поставщику SSF"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "SSF Stream"
|
||||
msgstr ""
|
||||
msgstr "SSF поток"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "SSF Streams"
|
||||
msgstr ""
|
||||
msgstr "Потоки SSF"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
msgid "SSF Stream Event"
|
||||
@ -641,27 +600,30 @@ msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/ssf/tasks.py
|
||||
msgid "Failed to send request"
|
||||
msgstr ""
|
||||
msgstr "Не удалось отправить запрос"
|
||||
|
||||
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/models.py
|
||||
msgid "Endpoint Authenticator Google Device Trust Connector Stage"
|
||||
msgstr ""
|
||||
"Этап проверки подлинности конечного устройства Google Device Trust Connector"
|
||||
|
||||
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/models.py
|
||||
msgid "Endpoint Authenticator Google Device Trust Connector Stages"
|
||||
msgstr ""
|
||||
"Этапы проверки подлинности конечного устройства Google Device Trust "
|
||||
"Connector"
|
||||
|
||||
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/models.py
|
||||
msgid "Endpoint Device"
|
||||
msgstr ""
|
||||
msgstr "Конечное устройство"
|
||||
|
||||
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/models.py
|
||||
msgid "Endpoint Devices"
|
||||
msgstr ""
|
||||
msgstr "Конечные устройства"
|
||||
|
||||
#: authentik/enterprise/stages/authenticator_endpoint_gdtc/stage.py
|
||||
msgid "Verifying your browser..."
|
||||
msgstr ""
|
||||
msgstr "Проверка вашего браузера..."
|
||||
|
||||
#: authentik/enterprise/stages/source/models.py
|
||||
msgid ""
|
||||
@ -705,9 +667,22 @@ msgid "Slack Webhook (Slack/Discord)"
|
||||
msgstr "Slack Вебхук (Slack/Discord)"
|
||||
|
||||
#: authentik/events/models.py
|
||||
#: authentik/stages/authenticator_validate/models.py
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||
"serializable."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Configure additional headers to be sent. Mapping should return a dictionary "
|
||||
"of key-value pairs"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Only send notification once, for example when sending a webhook into a chat "
|
||||
@ -977,6 +952,14 @@ msgstr "Токены потока"
|
||||
msgid "Invalid next URL"
|
||||
msgstr "Недопустимый следующий URL-адрес"
|
||||
|
||||
#: authentik/lib/sync/outgoing/models.py
|
||||
msgid ""
|
||||
"When enabled, provider will not modify or create objects in the remote "
|
||||
"system."
|
||||
msgstr ""
|
||||
"Если этот параметр включен, поставщик не будет изменять или создавать "
|
||||
"объекты в удаленной системе."
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr "Запуск полной синхронизации провайдера"
|
||||
@ -991,6 +974,10 @@ msgstr ""
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
@ -1165,6 +1152,8 @@ msgstr "Политики сопоставления событий"
|
||||
#, python-brace-format
|
||||
msgid "Password expired {days} days ago. Please update your password."
|
||||
msgstr ""
|
||||
"Срок действия пароля истек {days} дней назад. Пожалуйста, обновите свой "
|
||||
"пароль."
|
||||
|
||||
#: authentik/policies/expiry/models.py
|
||||
msgid "Password has expired."
|
||||
@ -1202,6 +1191,14 @@ msgstr "GeoIP: IP-адрес клиента не найден в базе дан
|
||||
msgid "Client IP is not in an allowed country."
|
||||
msgstr "IP-адрес клиента находится не в разрешенной стране."
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance from previous authentication is larger than threshold."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance is further than possible."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "GeoIP Policy"
|
||||
msgstr "Политика GeoIP"
|
||||
@ -1292,12 +1289,12 @@ msgstr "Пароль не задан в контексте"
|
||||
|
||||
#: authentik/policies/password/models.py
|
||||
msgid "Invalid password."
|
||||
msgstr ""
|
||||
msgstr "Неправильный пароль"
|
||||
|
||||
#: authentik/policies/password/models.py
|
||||
#, python-brace-format
|
||||
msgid "Password exists on {count} online lists."
|
||||
msgstr ""
|
||||
msgstr "Пароль существует в {count} онлайн-списках."
|
||||
|
||||
#: authentik/policies/password/models.py
|
||||
msgid "Password is too weak."
|
||||
@ -1331,6 +1328,20 @@ msgstr "Оценка репутации"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "Оценка репутации"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "Доступ запрещен"
|
||||
@ -1426,7 +1437,7 @@ msgstr "Поиск по всему каталогу LDAP"
|
||||
#: authentik/providers/oauth2/api/providers.py
|
||||
#, python-brace-format
|
||||
msgid "Invalid Regex Pattern: {url}"
|
||||
msgstr ""
|
||||
msgstr "Неверный шаблон Regex: {url}"
|
||||
|
||||
#: authentik/providers/oauth2/id_token.py
|
||||
msgid "Based on the Hashed User ID"
|
||||
@ -1521,6 +1532,14 @@ msgstr "RS256 (асимметричное шифрование)"
|
||||
msgid "ES256 (Asymmetric Encryption)"
|
||||
msgstr "ES256 (асимметричное шифрование)"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES384 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES512 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Scope used by the client"
|
||||
msgstr "Область, используемая клиентом"
|
||||
@ -1612,7 +1631,7 @@ msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Encryption Key"
|
||||
msgstr ""
|
||||
msgstr "Ключ шифрования"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid ""
|
||||
@ -1800,6 +1819,60 @@ msgstr "Прокси провайдер"
|
||||
msgid "Proxy Providers"
|
||||
msgstr "Прокси провайдеры"
|
||||
|
||||
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Определяет время жизни сессии. Значение по умолчанию 0 означает, что сессии "
|
||||
"будут истекать при закрытии браузера. (Формат: часы=-1;минуты=-2;секунды=-3)"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"Если установлено значение true, токены соединения будут удалены при "
|
||||
"отключении"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC Провайдер"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC Провайдеры"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "Точка подключения RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "Точки подключения RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "Сопоставление свойства RAC провайдера"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "Сопоставление свойств RAC провайдера"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "Токен соединения RAC"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "Токены соединения RAC"
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Достигнут максимальный лимит соединений."
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Вы уже подключены в другой вкладке/окне)"
|
||||
|
||||
#: authentik/providers/radius/models.py
|
||||
msgid "Shared secret between clients and server to hash packets."
|
||||
msgstr "Общий секрет между клиентами и сервером для хэширования пакетов."
|
||||
@ -1886,6 +1959,17 @@ msgstr ""
|
||||
"Настройте, как будет создаваться значение NameID. Если оставить пустым, "
|
||||
"будет рассматриваться NameIDPolicy входящего запроса"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "AuthnContextClassRef Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Configure how the AuthnContextClassRef value will be created. When left "
|
||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||
"methods the user used to authenticate."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Assertion valid not before current time + this value (Format: "
|
||||
@ -2028,6 +2112,18 @@ msgstr "Провайдер SAML из метаданных"
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr "Провайдеры SAML из метаданных"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Default"
|
||||
msgstr "По умолчанию"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "AWS"
|
||||
msgstr "AWS"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Slack"
|
||||
msgstr "Slack"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "Базовый URL для запросов SCIM, обычно заканчивается на /v2"
|
||||
@ -2036,6 +2132,14 @@ msgstr "Базовый URL для запросов SCIM, обычно закан
|
||||
msgid "Authentication token"
|
||||
msgstr "Токен аутентификации"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Compatibility Mode"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "SCIM Провайдер"
|
||||
@ -2106,6 +2210,8 @@ msgstr ""
|
||||
#: authentik/sources/kerberos/models.py
|
||||
msgid "Custom krb5.conf to use. Uses the system one by default"
|
||||
msgstr ""
|
||||
"Пользовательский krb5.conf для использования. По умолчанию используется "
|
||||
"системный."
|
||||
|
||||
#: authentik/sources/kerberos/models.py
|
||||
msgid "KAdmin server type"
|
||||
@ -2113,19 +2219,20 @@ msgstr ""
|
||||
|
||||
#: authentik/sources/kerberos/models.py
|
||||
msgid "Sync users from Kerberos into authentik"
|
||||
msgstr ""
|
||||
msgstr "Синхронизация пользователей из Kerberos в authentik"
|
||||
|
||||
#: authentik/sources/kerberos/models.py
|
||||
msgid "When a user changes their password, sync it back to Kerberos"
|
||||
msgstr ""
|
||||
"Когда пользователь меняет свой пароль, синхронизируйте его с Kerberos."
|
||||
|
||||
#: authentik/sources/kerberos/models.py
|
||||
msgid "Principal to authenticate to kadmin for sync."
|
||||
msgstr ""
|
||||
msgstr "Участник должен пройти аутентификацию в kadmin для синхронизации."
|
||||
|
||||
#: authentik/sources/kerberos/models.py
|
||||
msgid "Password to authenticate to kadmin for sync"
|
||||
msgstr ""
|
||||
msgstr "Пароль для авторизации в kadmin для синхронизации"
|
||||
|
||||
#: authentik/sources/kerberos/models.py
|
||||
msgid ""
|
||||
@ -2138,6 +2245,8 @@ msgid ""
|
||||
"Credentials cache to authenticate to kadmin for sync. Must be in the form "
|
||||
"TYPE:residual"
|
||||
msgstr ""
|
||||
"Кэш учетных данных для аутентификации в kadmin для синхронизации. Должен "
|
||||
"быть в форме TYPE:residual"
|
||||
|
||||
#: authentik/sources/kerberos/models.py
|
||||
msgid ""
|
||||
@ -2158,6 +2267,8 @@ msgid ""
|
||||
"If enabled, the authentik-stored password will be updated upon login with "
|
||||
"the Kerberos password backend"
|
||||
msgstr ""
|
||||
"Если этот параметр включен, сохраненный в authentik пароль будет обновлен "
|
||||
"при входе в систему с помощью серверной части Kerberos "
|
||||
|
||||
#: authentik/sources/kerberos/models.py
|
||||
msgid "Kerberos Source"
|
||||
@ -2287,6 +2398,13 @@ msgstr ""
|
||||
"При изменении пользовательского пароля синхронизировать его обратно в LDAP. "
|
||||
"Это можно включить только для одного источника LDAP."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "Источник LDAP"
|
||||
@ -2701,6 +2819,103 @@ msgstr "Устройство Duo"
|
||||
msgid "Duo Devices"
|
||||
msgstr "Устройства Duo"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email OTP"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Если эта функция включена, будут использоваться глобальные настройки "
|
||||
"подключения к электронной почте, а настройки подключения, указанные ниже, "
|
||||
"будут игнорироваться."
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Возникло исключение при рендеринге шаблона электронной почты"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Devices"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Код не соответствует"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
msgid "Invalid email"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Привет %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
msgid ""
|
||||
"\n"
|
||||
" Email MFA code.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Привет %(username)s,"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_sms/models.py
|
||||
msgid ""
|
||||
"When enabled, the Phone number is only used during enrollment to verify the "
|
||||
@ -2737,11 +2952,6 @@ msgstr "СМС устройство"
|
||||
msgid "SMS Devices"
|
||||
msgstr "СМС устройства"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Код не соответствует"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
msgid "Invalid phone number"
|
||||
msgstr "Невереый номер телефона"
|
||||
@ -2978,23 +3188,10 @@ msgstr "Сброс пароля"
|
||||
msgid "Account Confirmation"
|
||||
msgstr "Подтверждение аккаунта"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Если эта функция включена, будут использоваться глобальные настройки "
|
||||
"подключения к электронной почте, а настройки подключения, указанные ниже, "
|
||||
"будут игнорироваться."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Activate users upon completion of stage."
|
||||
msgstr "Активировать пользователей по завершении этапа."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time in minutes the token sent is valid."
|
||||
msgstr "Время валидности отправленного токена в минутах."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "Этап электронной почты"
|
||||
@ -3003,10 +3200,6 @@ msgstr "Этап электронной почты"
|
||||
msgid "Email Stages"
|
||||
msgstr "Этапы электронной почты"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "Возникло исключение при рендеринге шаблона электронной почты"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
msgstr "Почта успешно подтверждена."
|
||||
@ -3091,17 +3284,6 @@ msgstr ""
|
||||
"\n"
|
||||
"Это письмо было отправлено с помощью поставщика уведомления %(name)s.\n"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Привет %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -3120,11 +3302,6 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Привет %(username)s,"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -3459,11 +3636,11 @@ msgstr ""
|
||||
|
||||
#: authentik/stages/redirect/models.py
|
||||
msgid "Redirect Stage"
|
||||
msgstr ""
|
||||
msgstr "Этап переадресации"
|
||||
|
||||
#: authentik/stages/redirect/models.py
|
||||
msgid "Redirect Stages"
|
||||
msgstr ""
|
||||
msgstr "Этапы переадресации"
|
||||
|
||||
#: authentik/stages/user_delete/models.py
|
||||
msgid "User Delete Stage"
|
||||
|
Binary file not shown.
@ -5,17 +5,17 @@
|
||||
#
|
||||
# Translators:
|
||||
# Oktay, 2022
|
||||
# Jens L. <jens@goauthentik.io>, 2024
|
||||
# Yusuf KOŞAN <yusufkosan@gmail.com>, 2024
|
||||
# Jens L. <jens@goauthentik.io>, 2025
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-14 14:49+0000\n"
|
||||
"POT-Creation-Date: 2025-03-31 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Yusuf KOŞAN <yusufkosan@gmail.com>, 2024\n"
|
||||
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
|
||||
"Language-Team: Turkish (https://app.transifex.com/authentik/teams/119923/tr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -123,6 +123,10 @@ msgstr ""
|
||||
msgid "Extra description not available"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
"When not set all providers are returned. When set to true, only backchannel "
|
||||
@ -170,6 +174,14 @@ msgstr "Gruba kullanıcı ekleme"
|
||||
msgid "Remove user from group"
|
||||
msgstr "Kullanıcıyı gruptan çıkarma"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Enable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Disable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "User's display name."
|
||||
msgstr "Kullanıcının görünen adı."
|
||||
@ -541,62 +553,6 @@ msgstr "Microsoft Entra Sağlayıcı Eşlemesi"
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr "Microsoft Entra Sağlayıcı Eşlemeleri"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Bir oturumun ne kadar süreceğini belirler. Varsayılan 0 değeri, oturumların "
|
||||
"tarayıcı kapatılana kadar süreceği anlamına gelir. (Biçim: "
|
||||
"saat=-1;dakika=-2;saniye=-3)"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"true olarak ayarlandığında, bağlantı kesildiğinde bağlantı jetonları "
|
||||
"silinecektir."
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC Sağlayıcısı"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC Sağlayıcıları"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "RAC Uç Noktası"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "RAC Uç Noktaları"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "RAC Sağlayıcı Özellik Eşlemesi"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "RAC Sağlayıcı Özellik Eşlemeleri"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "RAC Bağlantı jetonu"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "RAC Bağlantı jetonları"
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Maksimum bağlantı sınırına ulaşıldı."
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Zaten başka bir sekmede/pencerede bağlısınız)"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Signing Key"
|
||||
@ -700,9 +656,22 @@ msgid "Slack Webhook (Slack/Discord)"
|
||||
msgstr "Slack Web kancası (Slack/Discord)"
|
||||
|
||||
#: authentik/events/models.py
|
||||
#: authentik/stages/authenticator_validate/models.py
|
||||
msgid "Email"
|
||||
msgstr "E-posta"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||
"serializable."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Configure additional headers to be sent. Mapping should return a dictionary "
|
||||
"of key-value pairs"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Only send notification once, for example when sending a webhook into a chat "
|
||||
@ -975,6 +944,12 @@ msgstr "Akış Jetonları"
|
||||
msgid "Invalid next URL"
|
||||
msgstr "Sonraki URL geçersiz"
|
||||
|
||||
#: authentik/lib/sync/outgoing/models.py
|
||||
msgid ""
|
||||
"When enabled, provider will not modify or create objects in the remote "
|
||||
"system."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr "Tam sağlayıcı senkronizasyonunu başlatma"
|
||||
@ -989,6 +964,10 @@ msgstr ""
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
@ -1198,6 +1177,14 @@ msgstr "GeoIP: istemci IP adresi Şehir veritabanında bulunamadı."
|
||||
msgid "Client IP is not in an allowed country."
|
||||
msgstr "İstemci IP'si izin verilen bir ülkede değil."
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance from previous authentication is larger than threshold."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance is further than possible."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "GeoIP Policy"
|
||||
msgstr "GeoIP İlkesi"
|
||||
@ -1329,6 +1316,20 @@ msgstr "İtibar Puanı"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "İtibar Puanları"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "İzin reddedildi"
|
||||
@ -1516,6 +1517,14 @@ msgstr "RS256 (Asimetrik Şifreleme)"
|
||||
msgid "ES256 (Asymmetric Encryption)"
|
||||
msgstr "ES256 (Asimetrik Şifreleme)"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES384 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES512 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Scope used by the client"
|
||||
msgstr "İstemci tarafından kullanılan kapsam"
|
||||
@ -1798,6 +1807,61 @@ msgstr "Vekil Sağlayıcı"
|
||||
msgid "Proxy Providers"
|
||||
msgstr "Vekil Sağlayıcılar"
|
||||
|
||||
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr ""
|
||||
"Bir oturumun ne kadar süreceğini belirler. Varsayılan 0 değeri, oturumların "
|
||||
"tarayıcı kapatılana kadar süreceği anlamına gelir. (Biçim: "
|
||||
"saat=-1;dakika=-2;saniye=-3)"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr ""
|
||||
"true olarak ayarlandığında, bağlantı kesildiğinde bağlantı jetonları "
|
||||
"silinecektir."
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC Sağlayıcısı"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC Sağlayıcıları"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "RAC Uç Noktası"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "RAC Uç Noktaları"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr "RAC Sağlayıcı Özellik Eşlemesi"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr "RAC Sağlayıcı Özellik Eşlemeleri"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "RAC Bağlantı jetonu"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "RAC Bağlantı jetonları"
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "Maksimum bağlantı sınırına ulaşıldı."
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(Zaten başka bir sekmede/pencerede bağlısınız)"
|
||||
|
||||
#: authentik/providers/radius/models.py
|
||||
msgid "Shared secret between clients and server to hash packets."
|
||||
msgstr ""
|
||||
@ -1886,6 +1950,17 @@ msgstr ""
|
||||
"NameID değerinin nasıl oluşturulacağını yapılandırın. Boş bırakıldığında, "
|
||||
"gelen isteğin NameIDPolicy'si dikkate alınacaktır"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "AuthnContextClassRef Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Configure how the AuthnContextClassRef value will be created. When left "
|
||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||
"methods the user used to authenticate."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Assertion valid not before current time + this value (Format: "
|
||||
@ -2028,6 +2103,18 @@ msgstr "Meta Verilerden SAML Sağlayıcısı"
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr "Meta Verilerden SAML Sağlayıcıları"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Default"
|
||||
msgstr "Varsayılan"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "AWS"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Slack"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "SCIM istekleri için temel URL, genellikle /v2 ile biter"
|
||||
@ -2036,6 +2123,14 @@ msgstr "SCIM istekleri için temel URL, genellikle /v2 ile biter"
|
||||
msgid "Authentication token"
|
||||
msgstr "Kimlik doğrulama jetonu"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Compatibility Mode"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "SCIM Sağlayıcısı"
|
||||
@ -2712,6 +2807,102 @@ msgstr "Duo Cihazı"
|
||||
msgid "Duo Devices"
|
||||
msgstr "Duo Cihazları"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email OTP"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Etkinleştirildiğinde, genel E-posta bağlantısı ayarları kullanılır ve "
|
||||
"aşağıdaki bağlantı ayarları yoksayılır."
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "E-posta şablonu oluşturulurken istisna oluştu"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Devices"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Kod eşleşmiyor"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
msgid "Invalid email"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Merhaba, %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
msgid ""
|
||||
"\n"
|
||||
" Email MFA code.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Merhaba %(username)s,"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_sms/models.py
|
||||
msgid ""
|
||||
"When enabled, the Phone number is only used during enrollment to verify the "
|
||||
@ -2748,11 +2939,6 @@ msgstr "SMS Cihazı"
|
||||
msgid "SMS Devices"
|
||||
msgstr "SMS Cihazları"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "Kod eşleşmiyor"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
msgid "Invalid phone number"
|
||||
msgstr "Geçersiz telefon numarası"
|
||||
@ -2987,22 +3173,10 @@ msgstr "Parola Sıfırlama"
|
||||
msgid "Account Confirmation"
|
||||
msgstr "Hesap Onayı"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr ""
|
||||
"Etkinleştirildiğinde, genel E-posta bağlantısı ayarları kullanılır ve "
|
||||
"aşağıdaki bağlantı ayarları yoksayılır."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Activate users upon completion of stage."
|
||||
msgstr "Aşama aşaması tamamlandığında kullanıcıları etkinleştirin."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time in minutes the token sent is valid."
|
||||
msgstr "Gönderilen belirteç dakikalar olarak geçerlidir."
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "E-posta Aşaması"
|
||||
@ -3011,10 +3185,6 @@ msgstr "E-posta Aşaması"
|
||||
msgid "Email Stages"
|
||||
msgstr "E-posta Aşamaları"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr "E-posta şablonu oluşturulurken istisna oluştu"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
msgstr "Başarıyla doğrulanmış E-posta."
|
||||
@ -3099,17 +3269,6 @@ msgstr ""
|
||||
"\n"
|
||||
"Bu e-posta bildirim aktarımından gönderilmiştir %(name)s.\n"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Merhaba, %(username)s,\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -3128,11 +3287,6 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "Merhaba %(username)s,"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
|
Binary file not shown.
@ -15,7 +15,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-03-22 00:10+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: deluxghost, 2025\n"
|
||||
"Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n"
|
||||
@ -1235,6 +1235,20 @@ msgstr "信誉分数"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "信誉分数"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr "正在等待身份验证…"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "权限被拒绝"
|
||||
@ -2208,6 +2222,13 @@ msgid ""
|
||||
"enabled on a single LDAP source."
|
||||
msgstr "当用户修改密码时,将其同步回 LDAP。仅可在单点 LDAP 源时启用。"
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "LDAP 源"
|
||||
|
@ -14,7 +14,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-03-31 00:10+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: deluxghost, 2025\n"
|
||||
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n"
|
||||
@ -2221,6 +2221,13 @@ msgid ""
|
||||
"enabled on a single LDAP source."
|
||||
msgstr "当用户修改密码时,将其同步回 LDAP。仅可在单点 LDAP 源时启用。"
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "LDAP 源"
|
||||
|
@ -7,16 +7,16 @@
|
||||
# Chen Zhikai, 2022
|
||||
# Passerby Dreamer, 2023
|
||||
# Phreeman33, 2024
|
||||
# 刘松, 2024
|
||||
# 刘松, 2025
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-14 14:49+0000\n"
|
||||
"POT-Creation-Date: 2025-04-11 00:10+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: 刘松, 2024\n"
|
||||
"Last-Translator: 刘松, 2025\n"
|
||||
"Language-Team: Chinese (Taiwan) (https://app.transifex.com/authentik/teams/119923/zh_TW/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -117,6 +117,10 @@ msgstr ""
|
||||
msgid "Extra description not available"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid ""
|
||||
"When not set all providers are returned. When set to true, only backchannel "
|
||||
@ -161,6 +165,14 @@ msgstr "將使用者加入群組"
|
||||
msgid "Remove user from group"
|
||||
msgstr "將使用者移出群組"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Enable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Disable superuser status"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "User's display name."
|
||||
msgstr "使用者的顯示名稱。"
|
||||
@ -509,57 +521,6 @@ msgstr "Microsoft Entra 供應程式映射"
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr "Microsoft Entra 供應程式映射"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr "確定會談持續多久。預設值為 0 表示會談會持續到關閉瀏覽器為止。(格式:hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr "啟用後,連線權杖將在斷開連線時刪除。"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC 供應程式"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC 供應程式"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "RAC 端點"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "RAC 端點"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "RAC 連線權杖"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "RAC 連線權杖"
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "已達到最大連線限制。"
|
||||
|
||||
#: authentik/enterprise/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(您已在另一個分頁/窗口中連線了)"
|
||||
|
||||
#: authentik/enterprise/providers/ssf/models.py
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Signing Key"
|
||||
@ -661,9 +622,22 @@ msgid "Slack Webhook (Slack/Discord)"
|
||||
msgstr "Slack Webhook(Slack/Discord)"
|
||||
|
||||
#: authentik/events/models.py
|
||||
#: authentik/stages/authenticator_validate/models.py
|
||||
msgid "Email"
|
||||
msgstr "電子郵件"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Customize the body of the request. Mapping should return data that is JSON-"
|
||||
"serializable."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Configure additional headers to be sent. Mapping should return a dictionary "
|
||||
"of key-value pairs"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"Only send notification once, for example when sending a webhook into a chat "
|
||||
@ -915,6 +889,12 @@ msgstr "流程權杖"
|
||||
msgid "Invalid next URL"
|
||||
msgstr "無效的下一步網址"
|
||||
|
||||
#: authentik/lib/sync/outgoing/models.py
|
||||
msgid ""
|
||||
"When enabled, provider will not modify or create objects in the remote "
|
||||
"system."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr "開始同步所有提供程式"
|
||||
@ -929,6 +909,10 @@ msgstr ""
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
@ -1118,6 +1102,14 @@ msgstr ""
|
||||
msgid "Client IP is not in an allowed country."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance from previous authentication is larger than threshold."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "Distance is further than possible."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/geoip/models.py
|
||||
msgid "GeoIP Policy"
|
||||
msgstr ""
|
||||
@ -1242,6 +1234,20 @@ msgstr "信譽分數"
|
||||
msgid "Reputation Scores"
|
||||
msgstr "信譽分數"
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Waiting for authentication..."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid ""
|
||||
"You're already authenticating in another tab. This page will refresh once "
|
||||
"authentication is completed."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/buffer.html
|
||||
msgid "Authenticate in this tab"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/policies/templates/policies/denied.html
|
||||
msgid "Permission denied"
|
||||
msgstr "權限不足。"
|
||||
@ -1417,6 +1423,14 @@ msgstr "RS256(非對稱加密)"
|
||||
msgid "ES256 (Asymmetric Encryption)"
|
||||
msgstr "ES256(非對稱加密)"
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES384 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "ES512 (Asymmetric Encryption)"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/oauth2/models.py
|
||||
msgid "Scope used by the client"
|
||||
msgstr "用戶端使用的範疇"
|
||||
@ -1667,6 +1681,56 @@ msgstr "代理伺服器供應商"
|
||||
msgid "Proxy Providers"
|
||||
msgstr "代理伺服器供應商"
|
||||
|
||||
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
"Determines how long a session lasts. Default of 0 means that the sessions "
|
||||
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
|
||||
msgstr "確定會談持續多久。預設值為 0 表示會談會持續到關閉瀏覽器為止。(格式:hours=-1;minutes=-2;seconds=-3)"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "When set to true, connection tokens will be deleted upon disconnect."
|
||||
msgstr "啟用後,連線權杖將在斷開連線時刪除。"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider"
|
||||
msgstr "RAC 供應程式"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Providers"
|
||||
msgstr "RAC 供應程式"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoint"
|
||||
msgstr "RAC 端點"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Endpoints"
|
||||
msgstr "RAC 端點"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Provider Property Mappings"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection token"
|
||||
msgstr "RAC 連線權杖"
|
||||
|
||||
#: authentik/providers/rac/models.py
|
||||
msgid "RAC Connection tokens"
|
||||
msgstr "RAC 連線權杖"
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "Maximum connection limit reached."
|
||||
msgstr "已達到最大連線限制。"
|
||||
|
||||
#: authentik/providers/rac/views.py
|
||||
msgid "(You are already connected in another tab/window)"
|
||||
msgstr "(您已在另一個分頁/窗口中連線了)"
|
||||
|
||||
#: authentik/providers/radius/models.py
|
||||
msgid "Shared secret between clients and server to hash packets."
|
||||
msgstr "用於用戶端與伺服器之間封包雜湊處理的共享金鑰。"
|
||||
@ -1745,6 +1809,17 @@ msgid ""
|
||||
"NameIDPolicy of the incoming request will be considered"
|
||||
msgstr "設定 NameID 值建立的方式。如果未設定則會使用傳入請求中的 NameIDPolicy。"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "AuthnContextClassRef Property Mapping"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Configure how the AuthnContextClassRef value will be created. When left "
|
||||
"empty, the AuthnContextClassRef will be set based on which authentication "
|
||||
"methods the user used to authenticate."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid ""
|
||||
"Assertion valid not before current time + this value (Format: "
|
||||
@ -1872,6 +1947,18 @@ msgstr "從中繼資料取得 SAML 供應商"
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr "來自詮釋資料的 SAML 提供程式"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Default"
|
||||
msgstr "默认"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "AWS"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Slack"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "SCIM 要求中的基礎網址,通常以 /v2 結尾。"
|
||||
@ -1880,6 +1967,14 @@ msgstr "SCIM 要求中的基礎網址,通常以 /v2 結尾。"
|
||||
msgid "Authentication token"
|
||||
msgstr "認證權杖"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Compatibility Mode"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Alter authentik behavior for vendor-specific SCIM implementations."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "SCIM 供應商"
|
||||
@ -2122,6 +2217,13 @@ msgid ""
|
||||
"enabled on a single LDAP source."
|
||||
msgstr "當使用者更改密碼時,將其同步回 LDAP。這只能在只有單一 LDAP 來源上啟用。"
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid ""
|
||||
"Lookup group membership based on a user attribute instead of a group "
|
||||
"attribute. This allows nested group resolution on systems like FreeIPA and "
|
||||
"Active Directory"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
msgstr "LDAP 來源"
|
||||
@ -2517,6 +2619,100 @@ msgstr "Duo 設備"
|
||||
msgid "Duo Devices"
|
||||
msgstr "Duo 設備"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email OTP"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr "啟用時,將使用全域電子郵件連線設定,在此之下的連線設定將被忽略。"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stage"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Authenticator Setup Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Devices"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "授權碼不符"
|
||||
|
||||
#: authentik/stages/authenticator_email/stage.py
|
||||
msgid "Invalid email"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" 嗨!%(username)s。\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
msgid ""
|
||||
"\n"
|
||||
" Email MFA code.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "%(username)s 您好,"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/authenticator_sms/models.py
|
||||
msgid ""
|
||||
"When enabled, the Phone number is only used during enrollment to verify the "
|
||||
@ -2549,11 +2745,6 @@ msgstr "簡訊設備"
|
||||
msgid "SMS Devices"
|
||||
msgstr "簡訊設備"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
#: authentik/stages/authenticator_totp/stage.py
|
||||
msgid "Code does not match"
|
||||
msgstr "授權碼不符"
|
||||
|
||||
#: authentik/stages/authenticator_sms/stage.py
|
||||
msgid "Invalid phone number"
|
||||
msgstr "無效的電話號碼"
|
||||
@ -2776,20 +2967,10 @@ msgstr "重設密碼"
|
||||
msgid "Account Confirmation"
|
||||
msgstr "帳戶認證"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid ""
|
||||
"When enabled, global Email connection settings will be used and connection "
|
||||
"settings below will be ignored."
|
||||
msgstr "啟用時,將使用全域電子郵件連線設定,在此之下的連線設定將被忽略。"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Activate users upon completion of stage."
|
||||
msgstr "完成階段後啟用使用者。"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Time in minutes the token sent is valid."
|
||||
msgstr "發送權杖的有效時間(以分鐘為單位)。"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stage"
|
||||
msgstr "電子郵件階段"
|
||||
@ -2798,10 +2979,6 @@ msgstr "電子郵件階段"
|
||||
msgid "Email Stages"
|
||||
msgstr "電子郵件階段"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
msgstr "已成功認證電子郵件。"
|
||||
@ -2882,17 +3059,6 @@ msgstr ""
|
||||
"\n"
|
||||
"此電子郵件來自通知:1%(name)s。\n"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" Hi %(username)s,\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" 嗨!%(username)s。\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.html
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -2911,11 +3077,6 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
#, python-format
|
||||
msgid "Hi %(username)s,"
|
||||
msgstr "%(username)s 您好,"
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
msgid ""
|
||||
"\n"
|
||||
|
1
packages/docusaurus-config/.gitignore
vendored
Normal file
1
packages/docusaurus-config/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
56
packages/docusaurus-config/css/badges.css
Normal file
56
packages/docusaurus-config/css/badges.css
Normal file
@ -0,0 +1,56 @@
|
||||
.anchor > .badge {
|
||||
font-size: 0.75rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.anchor > .badge {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.badge {
|
||||
--ifm-font-weight-bold: 900;
|
||||
}
|
||||
|
||||
.badge--support-vendor {
|
||||
--ifm-badge-background-color: var(--ifm-color-warning-contrast-background);
|
||||
--ifm-badge-color: var(--ifm-color-warning-contrast-foreground);
|
||||
--ifm-badge-border-color: var(--ifm-color-warning-contrast-foreground);
|
||||
}
|
||||
|
||||
.badge--support-community {
|
||||
--ifm-badge-background-color: var(
|
||||
--ifm-color-secondary-contrast-foreground
|
||||
);
|
||||
--ifm-badge-border-color: var(--ifm-color-secondary-dark);
|
||||
--ifm-badge-color: var(--ifm-color-secondary-contrast-background);
|
||||
}
|
||||
|
||||
.badge--support-deprecated {
|
||||
--ifm-badge-background-color: var(--ifm-color-danger);
|
||||
--ifm-badge-border-color: var(--ifm-color-danger-contrast-background);
|
||||
--ifm-badge-color: var(--ifm-color-danger-contrast-foreground);
|
||||
}
|
||||
|
||||
.badge--support-authentik {
|
||||
--ifm-badge-background-color: var(--ifm-color-primary);
|
||||
--ifm-badge-border-color: var(--ifm-color-secondary);
|
||||
--ifm-badge-color: var(--ifm-color-secondary);
|
||||
}
|
||||
|
||||
.badge--version {
|
||||
--ifm-badge-background-color: var(--ifm-color-primary-contrast-background);
|
||||
--ifm-badge-border-color: var(--ifm-color-primary-contrast-foreground);
|
||||
--ifm-badge-color: var(--ifm-color-primary-contrast-foreground);
|
||||
}
|
||||
|
||||
.badge--preview {
|
||||
--ifm-badge-background-color: rgb(115, 188, 247);
|
||||
--ifm-badge-border-color: var(--ifm-badge-background-color);
|
||||
--ifm-badge-color: var(--ifm-color-primary-contrast-foreground);
|
||||
}
|
||||
|
||||
.badge-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
21
packages/docusaurus-config/css/buttons.css
Normal file
21
packages/docusaurus-config/css/buttons.css
Normal file
@ -0,0 +1,21 @@
|
||||
:root {
|
||||
--ifm-button-color: var(--white);
|
||||
}
|
||||
|
||||
.button-row {
|
||||
gap: var(--ifm-global-spacing);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.button--outline {
|
||||
--ifm-button-color: var(--white);
|
||||
--ifm-button-border-color: var(--white);
|
||||
|
||||
&:hover {
|
||||
--ifm-button-color: var(--ifm-color-primary);
|
||||
}
|
||||
}
|
12
packages/docusaurus-config/css/code.css
Normal file
12
packages/docusaurus-config/css/code.css
Normal file
@ -0,0 +1,12 @@
|
||||
:root {
|
||||
--docusaurus-highlighted-code-line-bg: #efefef;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] {
|
||||
/* Color which works with dark mode syntax highlighting theme */
|
||||
--docusaurus-highlighted-code-line-bg: #3f3f3f;
|
||||
}
|
||||
|
||||
.theme-code-block pre code {
|
||||
font-weight: 500;
|
||||
}
|
93
packages/docusaurus-config/css/fonts.css
Normal file
93
packages/docusaurus-config/css/fonts.css
Normal file
@ -0,0 +1,93 @@
|
||||
:root {
|
||||
--ifm-font-family-base:
|
||||
RedHatVF, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell,
|
||||
Noto Sans, sans-serif, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial,
|
||||
sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
|
||||
--ifm-font-family-monospace:
|
||||
RedHatMonoVF, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||
"Liberation Mono", "Courier New", monospace;
|
||||
|
||||
--ifm-heading-font-family: RedHatDisplayVF, var(--ifm-font-family-base);
|
||||
|
||||
--ifm-h5-font-size: 0.88rem;
|
||||
--ifm-code-font-size: 100%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayVF";
|
||||
font-style: normal;
|
||||
font-weight: 300 900;
|
||||
font-display: fallback;
|
||||
src:
|
||||
local("Red Hat Display"),
|
||||
url("/fonts/RedHatFont-updated/modified/RedHatDisplayVFModified-updated.woff2")
|
||||
format("woff2-variations"),
|
||||
url("https://goauthentik.io/fonts/RedHatFont-updated/modified/RedHatDisplayVFModified-updated.woff2")
|
||||
format("woff2-variations");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatDisplayVF";
|
||||
font-style: italic;
|
||||
font-weight: 300 900;
|
||||
font-display: fallback;
|
||||
src:
|
||||
local("Red Hat Display"),
|
||||
url("/fonts/RedHatFont-updated/modified/RedHatDisplayVF-updated-ItalicModified.woff2")
|
||||
format("woff2-variations"),
|
||||
url("https://goauthentik.io/fonts/RedHatFont-updated/modified/RedHatDisplayVF-updated-ItalicModified.woff2")
|
||||
format("woff2-variations");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatTextVF";
|
||||
font-style: normal;
|
||||
font-weight: 400 500;
|
||||
font-display: fallback;
|
||||
src:
|
||||
local("Red Hat Display"),
|
||||
url("/fonts/RedHatFont-updated/modified/RedHatTextVFModified-updated.woff2")
|
||||
format("woff2-variations"),
|
||||
url("https://goauthentik.io/fonts/RedHatFont-updated/modified/RedHatTextVFModified-updated.woff2")
|
||||
format("woff2-variations");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatTextVF";
|
||||
font-style: italic;
|
||||
font-weight: 400 500;
|
||||
font-display: fallback;
|
||||
src:
|
||||
local("Red Hat Display"),
|
||||
url("/fonts/RedHatFont-updated/modified/RedHatTextVF-updated-ItalicModified.woff2")
|
||||
format("woff2-variations")
|
||||
url("https://goauthentik.io/fonts/RedHatFont-updated/modified/RedHatTextVF-updated-ItalicModified.woff2")
|
||||
format("woff2-variations");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatMonoVF";
|
||||
font-style: normal;
|
||||
font-weight: 300 700;
|
||||
font-display: fallback;
|
||||
src:
|
||||
local("Red Hat Mono"),
|
||||
url("/fonts/RedHatFont-updated/RedHatMono/RedHatMonoVF-updated.woff2")
|
||||
format("woff2-variations"),
|
||||
url("https://goauthentik.io/fonts/RedHatFont-updated/RedHatMono/RedHatMonoVF-updated.woff2")
|
||||
format("woff2-variations");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "RedHatMonoVF";
|
||||
font-style: italic;
|
||||
font-weight: 300 700;
|
||||
font-display: fallback;
|
||||
src:
|
||||
local("Red Hat Mono"),
|
||||
url("/fonts/RedHatFont-updated/RedHatMono/RedHatMonoVF-updated-Italic.woff2")
|
||||
format("woff2-variations"),
|
||||
url("https://goauthentik.io/fonts/RedHatFont-updated/RedHatMono/RedHatMonoVF-updated-Italic.woff2")
|
||||
format("woff2-variations");
|
||||
}
|
44
packages/docusaurus-config/css/header.css
Normal file
44
packages/docusaurus-config/css/header.css
Normal file
@ -0,0 +1,44 @@
|
||||
a[data-icon] {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
align-items: center;
|
||||
border-radius: var(--ifm-badge-border-radius);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--ifm-hover-overlay);
|
||||
}
|
||||
}
|
||||
|
||||
a[data-icon]::before {
|
||||
display: block;
|
||||
content: "";
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
a[data-icon]::after {
|
||||
display: block;
|
||||
content: attr(aria-label);
|
||||
}
|
||||
|
||||
@media (max-width: 1300px) {
|
||||
.navbar--fixed-top .navbar__items a[data-icon]::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 998px) {
|
||||
.navbar--fixed-top .navbar__items a[data-icon] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
a[data-icon="github"]::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
a[data-icon="discord"]::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20127.14%2096.36%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23fff%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22%E5%9B%BE%E5%B1%82_2%22%20data-name%3D%22%E5%9B%BE%E5%B1%82%202%22%3E%3Cg%20id%3D%22Discord_Logos%22%20data-name%3D%22Discord%20Logos%22%3E%3Cg%20id%3D%22Discord_Logo_-_Large_-_White%22%20data-name%3D%22Discord%20Logo%20-%20Large%20-%20White%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M107.7%2C8.07A105.15%2C105.15%2C0%2C0%2C0%2C81.47%2C0a72.06%2C72.06%2C0%2C0%2C0-3.36%2C6.83A97.68%2C97.68%2C0%2C0%2C0%2C49%2C6.83%2C72.37%2C72.37%2C0%2C0%2C0%2C45.64%2C0%2C105.89%2C105.89%2C0%2C0%2C0%2C19.39%2C8.09C2.79%2C32.65-1.71%2C56.6.54%2C80.21h0A105.73%2C105.73%2C0%2C0%2C0%2C32.71%2C96.36%2C77.7%2C77.7%2C0%2C0%2C0%2C39.6%2C85.25a68.42%2C68.42%2C0%2C0%2C1-10.85-5.18c.91-.66%2C1.8-1.34%2C2.66-2a75.57%2C75.57%2C0%2C0%2C0%2C64.32%2C0c.87.71%2C1.76%2C1.39%2C2.66%2C2a68.68%2C68.68%2C0%2C0%2C1-10.87%2C5.19%2C77%2C77%2C0%2C0%2C0%2C6.89%2C11.1A105.25%2C105.25%2C0%2C0%2C0%2C126.6%2C80.22h0C129.24%2C52.84%2C122.09%2C29.11%2C107.7%2C8.07ZM42.45%2C65.69C36.18%2C65.69%2C31%2C60%2C31%2C53s5-12.74%2C11.43-12.74S54%2C46%2C53.89%2C53%2C48.84%2C65.69%2C42.45%2C65.69Zm42.24%2C0C78.41%2C65.69%2C73.25%2C60%2C73.25%2C53s5-12.74%2C11.44-12.74S96.23%2C46%2C96.12%2C53%2C91.08%2C65.69%2C84.69%2C65.69Z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
}
|
40
packages/docusaurus-config/css/homepage.css
Normal file
40
packages/docusaurus-config/css/homepage.css
Normal file
@ -0,0 +1,40 @@
|
||||
/* TODO: Determine just how global these styles are. */
|
||||
|
||||
/* The parent div centers, but the inner paragraph needs its own centering while its size changes. */
|
||||
.homepage_hero__subtitle {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.homepage_hero__subtitle p {
|
||||
font-size: clamp(
|
||||
1.125rem,
|
||||
0.9946rem + 0.6522vi,
|
||||
1.5rem
|
||||
); /* Adjust font as page scales */
|
||||
max-width: 28ch; /* Apply a maximum to keep everything in the box */
|
||||
text-wrap: balance; /* Prevent widows, orphans, and runts. Doesn't work in Safari */
|
||||
}
|
||||
|
||||
.hero--primary {
|
||||
background: radial-gradient(
|
||||
at right bottom,
|
||||
rgba(47, 6, 75, 1) 0%,
|
||||
var(--ifm-color-primary) 50%
|
||||
);
|
||||
padding-bottom: 5.3rem !important;
|
||||
/* fix aliasing at the edge */
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
-webkit-clip-path: polygon(0 0, 100% 0, 100% 100%, 0 calc(100% - 3vw));
|
||||
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 calc(100% - 3vw));
|
||||
}
|
||||
|
||||
.hero-banner {
|
||||
padding: 4rem 0;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
overflow-wrap: normal;
|
||||
color: var(--white);
|
||||
}
|
11
packages/docusaurus-config/css/index.css
Normal file
11
packages/docusaurus-config/css/index.css
Normal file
@ -0,0 +1,11 @@
|
||||
@import "../css/root.css";
|
||||
@import "../css/fonts.css";
|
||||
@import "../css/code.css";
|
||||
@import "../css/navbar.css";
|
||||
@import "../css/header.css";
|
||||
@import "../css/sidebar.css";
|
||||
@import "../css/markdown.css";
|
||||
@import "../css/badges.css";
|
||||
@import "../css/menu.css";
|
||||
@import "../css/buttons.css";
|
||||
@import "../css/homepage.css";
|
27
packages/docusaurus-config/css/markdown.css
Normal file
27
packages/docusaurus-config/css/markdown.css
Normal file
@ -0,0 +1,27 @@
|
||||
.docusaurus-mermaid-container {
|
||||
/* Improve contrast. */
|
||||
& .messageText {
|
||||
stroke: var(--ifm-background-color) !important;
|
||||
stroke-width: 4;
|
||||
fill: var(--ifm-color-content) !important;
|
||||
paint-order: stroke;
|
||||
}
|
||||
}
|
||||
|
||||
.markdown {
|
||||
/* Remove empty table headers. */
|
||||
& table > thead:has(> tr > th:empty):not(:has(> tr > th:not(:empty))) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.contains-task-list {
|
||||
input[type="checkbox"] {
|
||||
appearance: none;
|
||||
}
|
||||
input[type="checkbox"]::after {
|
||||
content: "✓";
|
||||
color: var(--ifm-color-success-dark);
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
22
packages/docusaurus-config/css/menu.css
Normal file
22
packages/docusaurus-config/css/menu.css
Normal file
@ -0,0 +1,22 @@
|
||||
:root {
|
||||
--ifm-menu-link-padding-vertical: 1em;
|
||||
}
|
||||
|
||||
.menu__list-item {
|
||||
font-family: var(--ifm-heading-font-family);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.navbar-sidebar__items:not(.navbar-sidebar__items--show-secondary) {
|
||||
--ifm-menu-color: var(--white);
|
||||
--ifm-menu-color-active: var(--white);
|
||||
|
||||
.menu__list-item {
|
||||
font-size: var(--ifm-h3-font-size);
|
||||
filter: drop-shadow(0px -1px var(--ifm-color-primary-darker));
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumbs__link {
|
||||
font-weight: 400;
|
||||
}
|
191
packages/docusaurus-config/css/navbar.css
Normal file
191
packages/docusaurus-config/css/navbar.css
Normal file
@ -0,0 +1,191 @@
|
||||
:root {
|
||||
--ifm-navbar-item-padding-horizontal: 0.5rem;
|
||||
--ifm-navbar-link-color: var(--white);
|
||||
--ifm-navbar-link-hover-color: var(--white);
|
||||
|
||||
--ifm-navbar-link-color: var(--white);
|
||||
--ifm-navbar-link-hover-color: var(--white);
|
||||
}
|
||||
|
||||
.navbar--fixed-top {
|
||||
background-color: var(--ifm-color-primary);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.navbar .navbar__inner {
|
||||
margin: 0 auto;
|
||||
max-width: 1600px;
|
||||
}
|
||||
|
||||
/* Nav header background color on mobile */
|
||||
.navbar-sidebar__brand,
|
||||
.navbar-sidebar__items {
|
||||
background-color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
.navbar__toggle,
|
||||
.navbar-sidebar__brand .clean-btn,
|
||||
.navbar__items--right .clean-btn {
|
||||
color: var(--white);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--ifm-hover-overlay);
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-sidebar__brand .navbar-sidebar__close {
|
||||
--ifm-color-emphasis-600: var(--white);
|
||||
}
|
||||
|
||||
.navbar__item.navbar__link {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.navbar__items:not(.navbar__items--right) {
|
||||
.navbar__item.navbar__link {
|
||||
margin-block-start: 0.1em;
|
||||
border-radius: var(--ifm-badge-border-radius);
|
||||
}
|
||||
|
||||
.navbar__item.navbar__link.navbar__link--active {
|
||||
background: #fff;
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
.navbar__item.navbar__link:not(.navbar__link--active):hover {
|
||||
background: var(--ifm-hover-overlay);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.navbar__item.navbar__link + .navbar__item.navbar__link {
|
||||
margin-inline-start: calc(var(--ifm-navbar-padding-horizontal) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
.navbar__item.navbar__link {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.navbar--fixed-top .navbar__inner .navbar__item {
|
||||
filter: drop-shadow(0px -1px var(--ifm-color-primary-darker));
|
||||
}
|
||||
|
||||
@media (min-width: 1120px) {
|
||||
.navbar--fixed-top .navbar__items:not(.navbar__items--right) {
|
||||
--ifm-navbar-item-padding-horizontal: 1rem;
|
||||
}
|
||||
|
||||
.docs-wrapper .navbar {
|
||||
margin: 0;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
|
||||
.navbar__brand {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.docs-wrapper .navbar__brand {
|
||||
width: var(--doc-sidebar-width);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar__item.navbar__link {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar__logo {
|
||||
margin: 0 0.75rem 0.2rem 0;
|
||||
}
|
||||
|
||||
.navbar__items--right {
|
||||
display: grid;
|
||||
|
||||
--ifm-hover-overlay: hsl(0deg 0% 100% / 25%);
|
||||
--ifm-navbar-item-padding-horizontal: 0.75rem;
|
||||
|
||||
.navbar__item.navbar__link {
|
||||
grid-row: 1;
|
||||
|
||||
&:first-child {
|
||||
grid-column: 1 / span 1;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
grid-column: 2 / span 1;
|
||||
}
|
||||
}
|
||||
|
||||
div:has(.DocSearch) {
|
||||
grid-column: 5 / span 1;
|
||||
grid-row: 1;
|
||||
|
||||
@media (min-width: 999px) {
|
||||
border-inline-start: 1px solid var(--ifm-hover-overlay);
|
||||
margin-inline-start: calc(
|
||||
var(--ifm-navbar-item-padding-horizontal) / 2
|
||||
);
|
||||
padding-inline-start: calc(
|
||||
var(--ifm-navbar-item-padding-horizontal) / 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
div:has(.clean-btn) {
|
||||
grid-column: 6 / span 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.DocSearch-Button {
|
||||
--docsearch-primary-color: var(--ifm-color-primary-darkest);
|
||||
--docsearch-text-color: var(--ifm-navbar-link-color);
|
||||
--docsearch-searchbox-shadow: unset;
|
||||
--docsearch-searchbox-background: transparent;
|
||||
--docsearch-searchbox-focus-background: var(--ifm-hover-overlay);
|
||||
|
||||
--docsearch-muted-color: hsl(0 0% 85% / 1);
|
||||
--docsearch-key-gradient: linear-gradient(
|
||||
-26.5deg,
|
||||
hsl(236.47deg 43.59% 77.06%),
|
||||
hsl(236.84deg 34.55% 10.78%)
|
||||
);
|
||||
--docsearch-key-shadow:
|
||||
inset 0 -2px 0 0 hsl(233.33deg 36% 24.51%),
|
||||
inset 0 0 1px 1px hsl(232.11deg 34.86% 57.25%),
|
||||
0 2px 2px 0 rgba(3, 4, 9, 0.3);
|
||||
--docsearch-key-pressed-shadow:
|
||||
inset 0 -2px 0 0 #282d55,
|
||||
inset 0 0 1px 1px hsl(231.82deg 21.36% 40.39%),
|
||||
0 1px 1px 0 hsl(230deg 50% 2.35% / 30.2%);
|
||||
|
||||
padding: var(--ifm-navbar-item-padding-vertical)
|
||||
var(--ifm-navbar-item-padding-horizontal) !important;
|
||||
padding-inline-end: calc(
|
||||
var(--ifm-navbar-item-padding-horizontal) * 1.25
|
||||
) !important;
|
||||
|
||||
.DocSearch-Button-Placeholder {
|
||||
font-family: var(--ifm-heading-font-family);
|
||||
color: var(--ifm-navbar-link-color);
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.DocSearch-Button-Container {
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.DocSearch-Search-Icon {
|
||||
stroke-width: 1.75;
|
||||
}
|
||||
|
||||
.DocSearch-Button-Keys {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.DocSearch-Button-Key {
|
||||
font-weight: 500;
|
||||
}
|
19
packages/docusaurus-config/css/root.css
Normal file
19
packages/docusaurus-config/css/root.css
Normal file
@ -0,0 +1,19 @@
|
||||
:root {
|
||||
--white: hsl(0deg 0% 95%);
|
||||
|
||||
--ifm-color-primary: #fd4b2d;
|
||||
--ifm-color-primary-dark: #fd320f;
|
||||
--ifm-color-primary-darker: #fb2602;
|
||||
--ifm-color-primary-darkest: #cf1f02;
|
||||
--ifm-color-primary-light: #fd644b;
|
||||
--ifm-color-primary-lighter: #fd7159;
|
||||
--ifm-color-primary-lightest: #fe9786;
|
||||
|
||||
--ifm-hover-overlay: hsl(0deg 0% 100% / 25%);
|
||||
|
||||
--ifm-color-content: hsl(216 35% 3%);
|
||||
}
|
||||
|
||||
body {
|
||||
overscroll-behavior-x: none;
|
||||
}
|
20
packages/docusaurus-config/css/sidebar.css
Normal file
20
packages/docusaurus-config/css/sidebar.css
Normal file
@ -0,0 +1,20 @@
|
||||
.theme-doc-sidebar-menu .dropdown {
|
||||
display: block;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.theme-doc-sidebar-menu .navbar__link {
|
||||
color: var(--ifm-menu-color);
|
||||
}
|
||||
|
||||
.theme-doc-sidebar-menu .dropdown__menu {
|
||||
left: 0;
|
||||
}
|
||||
.theme-doc-sidebar-menu hr {
|
||||
margin-top: calc(var(--ifm-hr-margin-vertical) / 2);
|
||||
margin-right: -0.5rem;
|
||||
}
|
||||
|
||||
.clean-list {
|
||||
font-weight: 500;
|
||||
}
|
6
packages/docusaurus-config/index.js
Normal file
6
packages/docusaurus-config/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @file Docusaurus configuration for the authentik website.
|
||||
*/
|
||||
|
||||
export * from "./lib/theme.js";
|
||||
export * from "./lib/common.js";
|
70
packages/docusaurus-config/lib/common.js
Normal file
70
packages/docusaurus-config/lib/common.js
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @file Common Docusaurus configuration utilities.
|
||||
*
|
||||
* @import { Config as DocusaurusConfig } from "@docusaurus/types"
|
||||
* @import { UserThemeConfig } from "./theme.js"
|
||||
*/
|
||||
|
||||
import { deepmerge } from "deepmerge-ts";
|
||||
import { createThemeConfig } from "./theme.js";
|
||||
|
||||
//#region Types
|
||||
|
||||
/**
|
||||
* @typedef {Omit<DocusaurusConfig, 'themeConfig'>} DocusaurusConfigBase
|
||||
*
|
||||
* Represents the base configuration for Docusaurus, excluding the theme configuration.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef DocusaurusConfigBaseTheme
|
||||
* @property {UserThemeConfig} themeConfig The theme configuration.
|
||||
*
|
||||
* Represents a configuration object, only including the theme configuration.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Partial<DocusaurusConfigBase & DocusaurusConfigBaseTheme>} DocusaurusConfigInit
|
||||
*
|
||||
* The initial configuration for Docusaurus.
|
||||
*
|
||||
* @remarks
|
||||
* This type is the result of Docusaurs's less than ideal type definitions.
|
||||
* Much of the configuration is not strictly typed, however, this type
|
||||
* is a good starting point.
|
||||
*/
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Functions
|
||||
|
||||
/**
|
||||
* Create a Docusaurus configuration.
|
||||
*
|
||||
* @param {DocusaurusConfigInit} [overrides] The options to override.
|
||||
* @returns {DocusaurusConfig}
|
||||
*/
|
||||
export function createDocusaurusConfig({ themeConfig, ...overrides } = {}) {
|
||||
/**
|
||||
* @type {DocusaurusConfig}
|
||||
*/
|
||||
const config = {
|
||||
title: "authentik",
|
||||
tagline: "Bring all of your authentication into a unified platform.",
|
||||
url: "https://docs.goauthentik.io",
|
||||
baseUrl: "/",
|
||||
onBrokenLinks: "throw",
|
||||
onBrokenAnchors: "throw",
|
||||
favicon: "img/icon.png",
|
||||
organizationName: "Authentik Security Inc.",
|
||||
projectName: "authentik",
|
||||
markdown: {
|
||||
mermaid: true,
|
||||
},
|
||||
themeConfig: createThemeConfig(themeConfig),
|
||||
};
|
||||
|
||||
return deepmerge(config, overrides);
|
||||
}
|
||||
|
||||
//#endregion
|
85
packages/docusaurus-config/lib/theme.js
Normal file
85
packages/docusaurus-config/lib/theme.js
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @file Docusaurus theme configuration for the authentik website.
|
||||
*
|
||||
* @import { UserThemeConfig as UserThemeConfigCommon } from "@docusaurus/theme-common";
|
||||
* @import { UserThemeConfig as UserThemeConfigAlgolia } from "@docusaurus/theme-search-algolia";
|
||||
*/
|
||||
|
||||
import { deepmerge } from "deepmerge-ts";
|
||||
import { themes as prismThemes } from "prism-react-renderer";
|
||||
|
||||
//#region Types
|
||||
|
||||
/**
|
||||
* Combined theme configuration for Docusaurus and Algolia.
|
||||
*
|
||||
* @typedef {UserThemeConfigCommon & UserThemeConfigAlgolia} UserThemeConfig
|
||||
*/
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Functions
|
||||
|
||||
/**
|
||||
* @returns {string} The copyright string.
|
||||
*/
|
||||
export function formatCopyright() {
|
||||
return `Copyright © ${new Date().getFullYear()} Authentik Security Inc. Built with Docusaurus.`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Prisma configuration for Docusaurus.
|
||||
*
|
||||
* @param {Partial<UserThemeConfigCommon['prism']>} overrides - Overrides for the default Prisma configuration.
|
||||
* @returns {UserThemeConfigCommon['prism']}
|
||||
*/
|
||||
export function createPrismConfig(overrides = {}) {
|
||||
/**
|
||||
* @type {UserThemeConfigCommon['prism']}
|
||||
*/
|
||||
const prismConfig = {
|
||||
theme: prismThemes.oneLight,
|
||||
darkTheme: prismThemes.oneDark,
|
||||
additionalLanguages: [
|
||||
// ---
|
||||
"apacheconf",
|
||||
"diff",
|
||||
"http",
|
||||
"json",
|
||||
"nginx",
|
||||
"python",
|
||||
"bash",
|
||||
],
|
||||
};
|
||||
|
||||
return deepmerge(prismConfig, overrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a theme configuration for Docusaurus.
|
||||
*
|
||||
* @param {Partial<UserThemeConfig>} overrides - Overrides for the default theme configuration.
|
||||
* @returns {UserThemeConfig}
|
||||
*/
|
||||
export function createThemeConfig({ prism, ...overrides } = {}) {
|
||||
/**
|
||||
* @type {UserThemeConfig}
|
||||
*/
|
||||
const themeConfig = {
|
||||
image: "img/social.png",
|
||||
tableOfContents: {
|
||||
minHeadingLevel: 2,
|
||||
maxHeadingLevel: 3,
|
||||
},
|
||||
colorMode: {
|
||||
respectPrefersColorScheme: true,
|
||||
},
|
||||
algolia: {
|
||||
appId: "36ROD0O0FV",
|
||||
apiKey: "727db511300ca9aec5425645bbbddfb5",
|
||||
},
|
||||
prism: createPrismConfig(prism),
|
||||
};
|
||||
|
||||
return deepmerge(themeConfig, overrides);
|
||||
}
|
20973
packages/docusaurus-config/package-lock.json
generated
Normal file
20973
packages/docusaurus-config/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user