Compare commits

...

69 Commits

Author SHA1 Message Date
b0679bb0fa website/docs: Break line. 2025-04-14 17:16:15 +02:00
153fc7cc3b website/docs: Add whitespace. 2025-04-14 17:07:23 +02:00
5eb848e376 core: Bump django from 5.0.14 to 5.1.8 (#14059)
Bump django from 5.0.14 to 5.1.8
2025-04-14 14:54:58 +00:00
61a293daad core: bump django-rest-framework from 3.14.0 to 3.16.0 (#14057)
upgrade `django-rest-framework` to `3.16.0`

The reverted commit is purely an optimization which unfortunately breaks authentik, specifically Blueprints. It adds `getattr(serializer.instance, field)` to a validator. If `field` is a `RelatedObject`, that invocation queries the database.

When authentik creates objects using Blueprints, it doesn't place related objects into the database before the validator tries to get them from there, so with the reverted commit, it produces `RelatedObjectDoesNotExist`.

Perhaps a long-term solution is to revise how Blueprints work, or perhaps it is to change upstream. But in the meantime, Django 5.0 support ended and upgrading to Django 5.1 requires an upgrade of `django-rest-framework` to `3.16.0`, hence this workaround.

See
- https://github.com/encode/django-rest-framework/pull/9154
- https://github.com/encode/django-rest-framework/issues/9358
- https://github.com/encode/django-rest-framework/pull/9482
- https://github.com/encode/django-rest-framework/pull/9483
2025-04-14 16:24:11 +02:00
edf3300944 policies/reputation: limit reputation score (#14008)
* add limits to reputation score

* limit reputation score limits

Upper to non-negative, Lower to non-positive

* simplify tests

* "fix" bandit false-positives

* move magic numbers to constants

Is it too much to ask for a world in which I can just import these
straight from Python?
2025-04-14 14:18:59 +00:00
5d9c40eac8 ci: fix api-py-publish by disabling poetry cache (#14010) 2025-04-14 16:18:31 +02:00
6ebfbcb66e core: bump goauthentik/fips-python from 3.12.9-slim-bookworm-fips to 3.12.10-slim-bookworm-fips (#14044) 2025-04-14 08:15:20 -06:00
bf0235c113 ci: add NPM packages publish (#13974)
Co-authored-by: Teffen Ellis <teffen@nirri.us>
2025-04-14 08:14:17 -06:00
895cd23b57 root: add packages/ to codeowners (#13975) 2025-04-14 08:05:09 -06:00
c908d9e95e providers/oauth2, rac: make sure tokens are revoked after session deletion (#14011) 2025-04-14 15:48:39 +02:00
a07fd8d54b core: bump multidict from 6.4.2 to v6.4.3 (#14051) 2025-04-14 13:26:50 +00:00
39a46a6dc4 core: bump uvicorn from 0.34.0 to v0.34.1 (#14056) 2025-04-14 13:26:10 +00:00
ad71960d77 core: bump typing-extensions from 4.13.1 to v4.13.2 (#14055) 2025-04-14 13:04:16 +00:00
2a384511f5 core: bump ruff from 0.11.4 to v0.11.5 (#14053) 2025-04-14 13:03:52 +00:00
4dcc104947 core: bump boto3 from 1.37.31 to v1.37.33 (#14045) 2025-04-14 09:02:05 -04:00
71fe526e47 core: bump opentelemetry-api from 1.31.1 to v1.32.0 (#14052) 2025-04-14 09:01:39 -04:00
03e3f516ac core: bump httpcore from 1.0.7 to v1.0.8 (#14050) 2025-04-14 13:00:58 +00:00
3b59333246 core: bump google-api-python-client from 2.166.0 to v2.167.0 (#14048) 2025-04-14 13:00:20 +00:00
4e800c14cb core: bump googleapis-common-protos from 1.69.2 to v1.70.0 (#14049) 2025-04-14 12:59:54 +00:00
789b29a3e7 core: bump debugpy from 1.8.13 to v1.8.14 (#14047) 2025-04-14 12:59:21 +00:00
857b6e63a0 root: prevent docker-compose up when secret key is missing (#14043) 2025-04-14 12:56:41 +00:00
edc937dd78 core: bump goauthentik.io/api/v3 from 3.2025024.2 to 3.2025024.4 (#14042)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-14 14:49:32 +02:00
d98b6f29d4 core: bump github.com/sethvargo/go-envconfig from 1.1.1 to 1.2.0 (#14041)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-14 14:49:17 +02:00
53ba2a0ca8 core, web: update translations (#14037)
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-14 14:40:38 +02:00
ae364292e6 website: Port WWW theme to docs site. Prep for package. (#13962)
Update sidebar.css

Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>

website/docs: Update paths.

website/docs: Use package theme.
2025-04-12 01:31:57 +02:00
f15bc2df97 translate: Updates for file locale/en/LC_MESSAGES/django.po in nl [Manual Sync] (#14026)
Translate django.po in nl [Manual Sync]

80% of minimum 75% translated source file: 'django.po'
on 'nl'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 15:55:33 +00:00
b27d49e55f translate: Updates for file web/xliff/en.xlf in fi [Manual Sync] (#14012)
Translate web/xliff/en.xlf in fi [Manual Sync]

95% of minimum 75% translated source file: 'web/xliff/en.xlf'
on 'fi'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:38:37 +02:00
e0d2beb225 translate: Updates for file locale/en/LC_MESSAGES/django.po in de [Manual Sync] (#14020)
Translate django.po in de [Manual Sync]

96% of minimum 75% translated source file: 'django.po'
on 'de'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:38:11 +02:00
2313b4755b translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR [Manual Sync] (#14027)
Translate django.po in pt_BR [Manual Sync]

75% of minimum 75% translated source file: 'django.po'
on 'pt_BR'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:37:55 +02:00
1cffadecb0 translate: Updates for file locale/en/LC_MESSAGES/django.po in it [Manual Sync] (#14024)
Translate django.po in it [Manual Sync]

99% of minimum 75% translated source file: 'django.po'
on 'it'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:37:40 +02:00
5e163d6da1 translate: Updates for file locale/en/LC_MESSAGES/django.po in pl [Manual Sync] (#14025)
Translate django.po in pl [Manual Sync]

82% of minimum 75% translated source file: 'django.po'
on 'pl'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:37:23 +02:00
0626e18674 translate: Updates for file locale/en/LC_MESSAGES/django.po in fi [Manual Sync] (#14023)
Translate django.po in fi [Manual Sync]

94% of minimum 75% translated source file: 'django.po'
on 'fi'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:37:04 +02:00
e986a62a12 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_TW [Manual Sync] (#14031)
Translate django.po in zh_TW [Manual Sync]

79% of minimum 75% translated source file: 'django.po'
on 'zh_TW'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:36:48 +02:00
e25afcb84a translate: Updates for file web/xliff/en.xlf in pl [Manual Sync] (#14015)
Translate web/xliff/en.xlf in pl [Manual Sync]

85% of minimum 75% translated source file: 'web/xliff/en.xlf'
on 'pl'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:36:33 +02:00
bb95613104 translate: Updates for file web/xliff/en.xlf in zh_CN [Manual Sync] (#14017)
Translate web/xliff/en.xlf in zh_CN [Manual Sync]

99% of minimum 75% translated source file: 'web/xliff/en.xlf'
on 'zh_CN'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:36:17 +02:00
89dfac2f57 translate: Updates for file web/xliff/en.xlf in it [Manual Sync] (#14016)
Translate web/xliff/en.xlf in it [Manual Sync]

99% of minimum 75% translated source file: 'web/xliff/en.xlf'
on 'it'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:36:14 +02:00
31462b55e6 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN [Manual Sync] (#14028)
Translate django.po in zh_CN [Manual Sync]

99% of minimum 75% translated source file: 'django.po'
on 'zh_CN'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:36:08 +02:00
60337c1cf0 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans [Manual Sync] (#14029)
Translate django.po in zh-Hans [Manual Sync]

99% of minimum 75% translated source file: 'django.po'
on 'zh-Hans'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 17:36:03 +02:00
343d3bb1fb translate: Updates for file locale/en/LC_MESSAGES/django.po in ru [Manual Sync] (#14032)
Translate django.po in ru [Manual Sync]

91% of minimum 75% translated source file: 'django.po'
on 'ru'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 15:09:01 +00:00
11fe86c4f6 translate: Updates for file locale/en/LC_MESSAGES/django.po in fr [Manual Sync] (#14022)
Translate django.po in fr [Manual Sync]

99% of minimum 75% translated source file: 'django.po'
on 'fr'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 15:07:16 +00:00
963ce085e4 translate: Updates for file locale/en/LC_MESSAGES/django.po in es [Manual Sync] (#14019)
Translate django.po in es [Manual Sync]

95% of minimum 75% translated source file: 'django.po'
on 'es'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 15:06:47 +00:00
3642b89ab0 translate: Updates for file web/xliff/en.xlf in zh-Hans [Manual Sync] (#14021)
Translate en.xlf in zh-Hans [Manual Sync]

99% of minimum 75% translated source file: 'en.xlf'
on 'zh-Hans'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 15:06:07 +00:00
8cfb371ed3 translate: Updates for file web/xliff/en.xlf in ru [Manual Sync] (#14013)
Translate web/xliff/en.xlf in ru [Manual Sync]

90% of minimum 75% translated source file: 'web/xliff/en.xlf'
on 'ru'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 15:05:28 +00:00
6e74edb9f2 web: bump API Client version (#13972)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-04-11 14:32:58 +02:00
397905f8f0 translate: Updates for file web/xliff/en.xlf in fr [Manual Sync] (#13979)
* Translate web/xliff/en.xlf in fr [Manual Sync]

100% translated source file: 'web/xliff/en.xlf'
on 'fr'.

* Removing web/xliff/en.xlf in fr

99% of minimum 100% translated source file: 'web/xliff/en.xlf'
on 'fr'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 14:22:54 +02:00
7fd35b1dfc sources/ldap: add source connections (#13796) 2025-04-11 12:07:18 +00:00
9ba03f5439 core: bump urllib3 from 2.3.0 to 2.4.0 (#14006)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-11 12:00:56 +00:00
1139d6d27c translate: Updates for file web/xliff/en.xlf in zh-Hans [Manual Sync] (#13985)
* Translate en.xlf in zh-Hans [Manual Sync]

100% translated source file: 'en.xlf'
on 'zh-Hans'.

* Removing web/xliff/en.xlf in zh-Hans

99% of minimum 100% translated source file: 'web/xliff/en.xlf'
on 'zh-Hans'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 11:58:56 +00:00
077fd966c2 translate: Updates for file locale/en/LC_MESSAGES/django.po in ru [Manual Sync] (#13992)
Translate django.po in ru [Manual Sync]

91% of minimum 60% translated source file: 'django.po'
on 'ru'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:46:11 +02:00
bd41822a57 translate: Updates for file locale/en/LC_MESSAGES/django.po in de [Manual Sync] (#13986)
Translate django.po in de [Manual Sync]

96% of minimum 60% translated source file: 'django.po'
on 'de'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:45:49 +02:00
dfd3d76434 translate: Updates for file locale/en/LC_MESSAGES/django.po in nl [Manual Sync] (#13991)
Translate django.po in nl [Manual Sync]

81% of minimum 60% translated source file: 'django.po'
on 'nl'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:45:24 +02:00
397e98906d translate: Updates for file locale/en/LC_MESSAGES/django.po in es [Manual Sync] (#13987)
Translate django.po in es [Manual Sync]

95% of minimum 60% translated source file: 'django.po'
on 'es'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:45:12 +02:00
65d8da8c64 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_TW [Manual Sync] (#13994)
Translate django.po in zh_TW [Manual Sync]

79% of minimum 60% translated source file: 'django.po'
on 'zh_TW'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:44:55 +02:00
5b435297c5 translate: Updates for file locale/en/LC_MESSAGES/django.po in fi [Manual Sync] (#13988)
Translate django.po in fi [Manual Sync]

94% of minimum 60% translated source file: 'django.po'
on 'fi'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:44:39 +02:00
f792fd42f6 translate: Updates for file web/xliff/en.xlf in fi [Manual Sync] (#13978)
Translate web/xliff/en.xlf in fi [Manual Sync]

95% of minimum 60% translated source file: 'web/xliff/en.xlf'
on 'fi'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:44:32 +02:00
70c0fdd5fa translate: Updates for file locale/en/LC_MESSAGES/django.po in pl [Manual Sync] (#13989)
Translate django.po in pl [Manual Sync]

82% of minimum 60% translated source file: 'django.po'
on 'pl'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:44:24 +02:00
9b636eba01 translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR [Manual Sync] (#13990)
Translate django.po in pt_BR [Manual Sync]

75% of minimum 60% translated source file: 'django.po'
on 'pt_BR'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:44:19 +02:00
a982224502 translate: Updates for file locale/en/LC_MESSAGES/django.po in tr [Manual Sync] (#13995)
Translate django.po in tr [Manual Sync]

91% of minimum 60% translated source file: 'django.po'
on 'tr'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:44:13 +02:00
6a16cccb40 translate: Updates for file locale/en/LC_MESSAGES/django.po in ko [Manual Sync] (#13993)
Translate django.po in ko [Manual Sync]

68% of minimum 60% translated source file: 'django.po'
on 'ko'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-11 13:43:49 +02:00
6dac91e2b4 core: bump github.com/getsentry/sentry-go from 0.31.1 to 0.32.0 (#14004)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-11 13:43:29 +02:00
3e2d0532d1 core: bump goauthentik.io/api/v3 from 3.2025024.1 to 3.2025024.2 (#14005)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-11 13:42:03 +02:00
4e1300650b core, web: update translations (#13999)
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-11 13:40:50 +02:00
06b3ed0c9c core: fix migrations (#14009) 2025-04-11 13:36:53 +02:00
395ad722b7 core: migrate all sessions to the database (#9736)
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-11 09:10:55 +02:00
9917d81246 website/integrations: add openproject (#13838)
* Added scope mapping section

* Updated formatting

* Bolded UI elements

* Update website/integrations/services/openproject/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/services/openproject/index.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/integrations/services/openproject/index.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/integrations/services/openproject/index.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Indented code block

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-04-10 15:52:00 -05:00
2a87687d34 website/integrations: add wazuh (#13776)
* Document explaining integration between authentik and knocknoc

* Clarified Knocknoc config

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Fixed typos

* Document mostly complete. Work to be done on Wazuh config section

* Completed the Wazuh config section

* Changed URL in Wazuh config

* typo

* Removed knocknoc doc

* Update website/integrations/services/wazuh/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/integrations/services/wazuh/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/integrations/services/wazuh/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/integrations/services/wazuh/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/integrations/services/wazuh/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Multiline codeblocks and moved SAML metadata note to beginning of section.

* Update sidebarsIntegrations.js to remove knoknok

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/integrations/services/wazuh/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/integrations/services/wazuh/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Changed group creation section to cut down on repetition of the word "click"

* Update website/integrations/services/wazuh/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Fixed mistake in the config.yml section and applied various suggestions from Dominic

* Fixed multilinecodeblocks and commands formatting

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Changed multiline codeblocks due to formatting issues.

* Clarified what run_as parameter does

* Update website/integrations/services/wazuh/index.mdx

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/services/wazuh/index.mdx

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/services/wazuh/index.mdx

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/services/wazuh/index.mdx

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/services/wazuh/index.mdx

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/services/wazuh/index.mdx

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Fixed codeblock indenting and prettier issue

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-04-10 15:43:02 -05:00
a726c2260a translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans [Manual Sync] (#13996)
Translate django.po in zh-Hans [Manual Sync]

99% of minimum 60% translated source file: 'django.po'
on 'zh-Hans'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-10 15:38:46 +00:00
44e0bfd4ef website: dev docs: fix upper-case authentik (#13961)
Signed-off-by: Dominic R <dominic@sdko.org>
2025-04-10 16:06:17 +01:00
8d0b362c9c web: elements: Table: Fix table selection clearing behavior (#13959)
web: elements: Table: Fix table selection clearing and modal closing behavior

Closes https://github.com/goauthentik/authentik/issues/13831
2025-04-10 17:03:02 +02:00
164 changed files with 32662 additions and 1876 deletions

View File

@ -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

View 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
View File

@ -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
View 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*

View File

@ -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

View File

@ -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" \

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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:

View 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()

View File

@ -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"""

View 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,
),
]

View File

@ -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",
),
]

View File

@ -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
View 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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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()
)

View File

@ -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())),
),
]

View File

@ -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",

View File

@ -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)

View File

@ -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,

View File

@ -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)

View File

@ -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"""

View File

@ -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)

View 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",
),
]

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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)

View 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",
),
]

View File

@ -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"""

View File

@ -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(

View File

@ -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>/",

View File

@ -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,
)

View File

@ -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"""

View File

@ -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)))

View File

@ -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:
"""

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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",),
),
]

View File

@ -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")

View File

@ -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:

View File

@ -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:

View File

@ -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),
]

View File

@ -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)

View File

@ -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"""

View File

@ -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()

View File

@ -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()

View File

@ -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",

View File

@ -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)],
),
),
]

View File

@ -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,

View File

@ -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",

View File

@ -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
View File

@ -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
View File

@ -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.

View File

@ -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"

View File

@ -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.

View File

@ -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.

View File

@ -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"

View File

@ -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.

View File

@ -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"

View File

@ -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.

View File

@ -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.

View File

@ -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"

View File

@ -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.

View File

@ -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.

View File

@ -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 源"

View File

@ -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 源"

View File

@ -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 WebhookSlack/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
View File

@ -0,0 +1 @@
node_modules

View 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;
}

View 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);
}
}

View 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;
}

View 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");
}

View 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");
}

View 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);
}

View 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";

View 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;
}
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View File

@ -0,0 +1,6 @@
/**
* @file Docusaurus configuration for the authentik website.
*/
export * from "./lib/theme.js";
export * from "./lib/common.js";

View 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

View 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

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