Compare commits

..

358 Commits

Author SHA1 Message Date
Connor Peshek
6155b9c8bc providers/saml: fix signature verification order for encrypted saml responses 2026-01-19 16:39:58 -06:00
Connor Peshek
578f8726f3 sources/saml: Fix signature verificaiton order on encrypted responses 2026-01-19 16:32:44 -06:00
Connor Peshek
c49006c8bf providers/saml: fix structure of encrypted saml assertion 2026-01-16 21:07:20 -05:00
Connor Peshek
56c6913f05 fix back-end to support cert only 2026-01-16 19:45:13 -05:00
Connor Peshek
7c22845cf0 providers/saml: allow selection of certificates without private keys for saml encryption 2026-01-16 11:03:09 -05:00
Jens L.
cbff6b1eeb web/admin: fix switches (#19493)
* web/admin: fix switches

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update all forms

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* Apply suggestions from code review

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Jens L. <jens@beryju.org>

* fix lint

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2026-01-15 21:31:46 +01:00
Teffen Ellis
0f11ad6df0 web: Z-Index Fixes, Mobile Sidebar Behavior. (#19460)
web: Fix Z-Index issues, mobile sidebar behavior.

Co-authored-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
2026-01-15 16:03:36 -03:00
Jens L.
2c29698415 endpoints/connectors/agent: add tests for IA endpoint stage (#19487)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-15 18:03:33 +01:00
Dewi Roberts
8ead09851d website/docs: limiting permissions of AD service account (#19483)
* Add info about limiting permissions

* Simplified instructions

* OU > organizational unit
2026-01-15 16:14:20 +00:00
Jens L.
41c24c6381 endpoints/connectors/agent: Skip Endpoint stage on device IA & fix confusing identification subtext (#19482)
* when doing device interactive auth, let the endpoint stage continue as we already know the device based on the DTH header

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* only show "continuing to device xyz" when using device IA flow, not when using an endpoint stage with browser extension

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-15 16:53:50 +01:00
Jens L.
244962dbff root: adjust makefile for non-brew macos (#19479)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-15 14:14:27 +01:00
Jean-Marc Le Roux
3e37821eb7 providers/oauth2: allow property mappings to override scope claim in access tokens (#19226)
* test(oauth2): add failing test for scope claim override via property mapping

Reproduces issue #19224 where property mappings cannot override the scope claim.

* fix(oauth2): allow property mappings to override scope claim in access tokens

Previously, the scope claim in access tokens was unconditionally set to
the requested scopes, ignoring any custom scope value returned by
property mappings.

This change uses setdefault() instead of direct assignment, so the
default scope is only set if no custom scope was provided by property
mappings.

Fixes #19224
2026-01-15 14:06:15 +01:00
Jens L.
4f5b65bb2f revert: lib: use orjson for structlog json (#19478)
Revert "lib: use orjson for structlog json (#19462)"

This reverts commit 51a7eb96fb.
2026-01-15 13:59:21 +01:00
authentik-automation[bot]
d4f3bb1d41 stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#19464)
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>
2026-01-15 13:47:49 +01:00
dependabot[bot]
41e99b5d16 core: bump library/nginx from e3a22a7 to c881927 in /website (#19469)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-15 12:18:40 +00:00
dependabot[bot]
6e46b1ff3b core: bump library/node from 25.2.1-trixie to 25.3.0-trixie in /website (#19468)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-15 12:56:21 +01:00
dependabot[bot]
807399d4a7 web: bump prettier from 3.7.4 to 3.8.0 in /web (#19471)
Bumps [prettier](https://github.com/prettier/prettier) from 3.7.4 to 3.8.0.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.0)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-15 12:51:20 +01:00
Fredouye
adee431d64 website/integrations: add MinIO AIStor configuration via environment variables (#19337)
* Add MinIO AIStor configuration via environment variables

Signed-off-by: Fredouye <frederic.mangeant@gmail.com>

* Minor changes

* Change website URL

* Apply suggestions

---------

Signed-off-by: Fredouye <frederic.mangeant@gmail.com>
Co-authored-by: dewi-tik <dewi@goauthentik.io>
2026-01-15 02:22:44 +00:00
Jens L.
06ed43002f root: upgrade ruff lint for 3.14 (#19461)
* root: upgrade ruff lint for 3.14

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* redo makefile

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-15 03:15:02 +01:00
Jens L.
51a7eb96fb lib: use orjson for structlog json (#19462)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-15 02:55:08 +01:00
Simonyi Gergő
37a18645fe ci: fix checkout stable (for 2025.12) (#19448)
* ci: fix checkout stable (again)

Fixes the fix at https://github.com/goauthentik/authentik/pull/18303

This fails on version branches that already have releases, because the
version tag is named `version/${numbers}`, not just `${numbers}`.

* lint by human

Thank you <3

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>

---------

Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>
Co-authored-by: Jens L. <jens@goauthentik.io>
2026-01-15 02:12:18 +01:00
Jens L.
885f3b68b2 root: Python 3.14 (#17313)
* root: Python 3.14

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update pydantic

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* bump kadmin

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add krb5 stuff to compile on macos?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* re-lock

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* trigger build

* lock uv

* bump to 3.14.2

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* output container logs if it failed to start

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* relock

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* target black and ruff to python 3.14

* upgrade pydatic from 2.11.7 to 2.12.5

* revert ruff to python 3.13 ruff checks

* bump docs

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix makefile

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
Co-authored-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
2026-01-15 02:08:17 +01:00
dependabot[bot]
5f4ba1a4ac core: bump channels from 4.3.1 to 4.3.2 (#19458)
Bumps [channels](https://github.com/django/channels) from 4.3.1 to 4.3.2.
- [Changelog](https://github.com/django/channels/blob/main/CHANGELOG.txt)
- [Commits](https://github.com/django/channels/compare/4.3.1...4.3.2)

---
updated-dependencies:
- dependency-name: channels
  dependency-version: 4.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-15 00:31:50 +01:00
dependabot[bot]
c9f82984ba core: bump mypy from 1.18.2 to 1.19.1 (#19457)
Bumps [mypy](https://github.com/python/mypy) from 1.18.2 to 1.19.1.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.18.2...v1.19.1)

---
updated-dependencies:
- dependency-name: mypy
  dependency-version: 1.19.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-15 00:31:36 +01:00
dependabot[bot]
2e4747a68f core: bump google-api-python-client from 2.177.0 to 2.188.0 (#19443)
Bumps [google-api-python-client](https://github.com/googleapis/google-api-python-client) from 2.177.0 to 2.188.0.
- [Release notes](https://github.com/googleapis/google-api-python-client/releases)
- [Commits](https://github.com/googleapis/google-api-python-client/compare/v2.177.0...v2.188.0)

---
updated-dependencies:
- dependency-name: google-api-python-client
  dependency-version: 2.188.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:57:53 +01:00
dependabot[bot]
d081514317 core: bump selenium from 4.32.0 to 4.39.0 (#19455)
Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.32.0 to 4.39.0.
- [Release notes](https://github.com/SeleniumHQ/Selenium/releases)
- [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.32.0...selenium-4.39.0)

---
updated-dependencies:
- dependency-name: selenium
  dependency-version: 4.39.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:57:38 +01:00
dependabot[bot]
afde3b2ff4 core: bump msgraph-sdk from 1.39.0 to 1.52.0 (#19454)
Bumps [msgraph-sdk](https://github.com/microsoftgraph/msgraph-sdk-python) from 1.39.0 to 1.52.0.
- [Release notes](https://github.com/microsoftgraph/msgraph-sdk-python/releases)
- [Changelog](https://github.com/microsoftgraph/msgraph-sdk-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoftgraph/msgraph-sdk-python/compare/v1.39.0...v1.52.0)

---
updated-dependencies:
- dependency-name: msgraph-sdk
  dependency-version: 1.52.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:57:27 +01:00
dependabot[bot]
f7fb04fd51 core: bump constructs from 10.4.2 to 10.4.4 (#19451)
Bumps [constructs](https://github.com/aws/constructs) from 10.4.2 to 10.4.4.
- [Release notes](https://github.com/aws/constructs/releases)
- [Commits](https://github.com/aws/constructs/compare/v10.4.2...v10.4.4)

---
updated-dependencies:
- dependency-name: constructs
  dependency-version: 10.4.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:57:17 +01:00
dependabot[bot]
a60cc68f94 core: bump structlog from 25.4.0 to 25.5.0 (#19450)
Bumps [structlog](https://github.com/hynek/structlog) from 25.4.0 to 25.5.0.
- [Release notes](https://github.com/hynek/structlog/releases)
- [Changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hynek/structlog/compare/25.4.0...25.5.0)

---
updated-dependencies:
- dependency-name: structlog
  dependency-version: 25.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:55:42 +01:00
dependabot[bot]
21ee3fdd64 core: bump pytest-randomly from 3.16.0 to 4.0.1 (#19456)
Bumps [pytest-randomly](https://github.com/pytest-dev/pytest-randomly) from 3.16.0 to 4.0.1.
- [Changelog](https://github.com/pytest-dev/pytest-randomly/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-randomly/compare/3.16.0...4.0.1)

---
updated-dependencies:
- dependency-name: pytest-randomly
  dependency-version: 4.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:55:27 +01:00
dependabot[bot]
de15279c53 core: bump djangorestframework-stubs[compatible-mypy] from 3.16.3 to 3.16.7 (#19449)
core: bump djangorestframework-stubs[compatible-mypy]

Bumps [djangorestframework-stubs[compatible-mypy]](https://github.com/sponsors/typeddjango) from 3.16.3 to 3.16.7.
- [Commits](https://github.com/sponsors/typeddjango/commits)

---
updated-dependencies:
- dependency-name: djangorestframework-stubs[compatible-mypy]
  dependency-version: 3.16.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:54:49 +01:00
dependabot[bot]
138910e36e core: bump psycopg[c,pool] from 3.2.9 to 3.3.2 (#19452)
Bumps [psycopg[c,pool]](https://github.com/psycopg/psycopg) from 3.2.9 to 3.3.2.
- [Changelog](https://github.com/psycopg/psycopg/blob/master/docs/news.rst)
- [Commits](https://github.com/psycopg/psycopg/compare/3.2.9...3.3.2)

---
updated-dependencies:
- dependency-name: psycopg[c,pool]
  dependency-version: 3.3.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:54:39 +01:00
dependabot[bot]
fa4616bbe5 core: bump uvicorn[standard] from 0.35.0 to 0.40.0 (#19453)
Bumps [uvicorn[standard]](https://github.com/Kludex/uvicorn) from 0.35.0 to 0.40.0.
- [Release notes](https://github.com/Kludex/uvicorn/releases)
- [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md)
- [Commits](https://github.com/Kludex/uvicorn/compare/0.35.0...0.40.0)

---
updated-dependencies:
- dependency-name: uvicorn[standard]
  dependency-version: 0.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:54:25 +01:00
dependabot[bot]
7ab875767c core: bump webauthn from 2.6.0 to 2.7.0 (#19442)
Bumps [webauthn](https://github.com/duo-labs/py_webauthn) from 2.6.0 to 2.7.0.
- [Release notes](https://github.com/duo-labs/py_webauthn/releases)
- [Changelog](https://github.com/duo-labs/py_webauthn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/duo-labs/py_webauthn/compare/v2.6.0...v2.7.0)

---
updated-dependencies:
- dependency-name: webauthn
  dependency-version: 2.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:27:56 +01:00
dependabot[bot]
44d718f51f core: bump fido2 from 2.0.0 to 2.1.0 (#19445)
Bumps [fido2](https://github.com/Yubico/python-fido2) from 2.0.0 to 2.1.0.
- [Release notes](https://github.com/Yubico/python-fido2/releases)
- [Changelog](https://github.com/Yubico/python-fido2/blob/main/NEWS)
- [Commits](https://github.com/Yubico/python-fido2/compare/2.0.0...2.1.0)

---
updated-dependencies:
- dependency-name: fido2
  dependency-version: 2.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:27:07 +01:00
dependabot[bot]
0f3138d8bc core: bump gssapi from 1.9.0 to 1.10.1 (#19436)
Bumps [gssapi](https://github.com/pythongssapi/python-gssapi) from 1.9.0 to 1.10.1.
- [Release notes](https://github.com/pythongssapi/python-gssapi/releases)
- [Commits](https://github.com/pythongssapi/python-gssapi/compare/v1.9.0...v1.10.1)

---
updated-dependencies:
- dependency-name: gssapi
  dependency-version: 1.10.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 23:26:54 +01:00
dependabot[bot]
1dfcea086e core: bump paramiko from 3.5.1 to 4.0.0 (#19440) 2026-01-14 22:37:00 +01:00
dependabot[bot]
3f4dab1b67 core: bump django-filter from 25.1 to 25.2 (#19444) 2026-01-14 22:32:39 +01:00
dependabot[bot]
4b11432add core: bump setproctitle from 1.3.6 to 1.3.7 (#19447) 2026-01-14 22:31:25 +01:00
dependabot[bot]
6e9067a2be core: bump coverage[toml] from 7.8.0 to 7.13.1 (#19446) 2026-01-14 22:30:42 +01:00
dependabot[bot]
0ceb02a525 core: bump sentry-sdk from 2.33.2 to 2.49.0 (#19441)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.33.2 to 2.49.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.33.2...2.49.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-version: 2.49.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 21:35:59 +01:00
dependabot[bot]
9e4243570e core: bump twilio from 9.7.0 to 9.9.1 (#19434)
Bumps [twilio](https://github.com/twilio/twilio-python) from 9.7.0 to 9.9.1.
- [Release notes](https://github.com/twilio/twilio-python/releases)
- [Changelog](https://github.com/twilio/twilio-python/blob/main/CHANGES.md)
- [Commits](https://github.com/twilio/twilio-python/compare/9.7.0...9.9.1)

---
updated-dependencies:
- dependency-name: twilio
  dependency-version: 9.9.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 21:26:41 +01:00
dependabot[bot]
46401eeec9 core: bump pydantic from 2.11.7 to 2.12.5 (#19435)
Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.11.7 to 2.12.5.
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.11.7...v2.12.5)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-version: 2.12.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 21:26:29 +01:00
dependabot[bot]
5c3f3303e1 core: bump cryptography from 45.0.5 to 46.0.3 (#19439)
Bumps [cryptography](https://github.com/pyca/cryptography) from 45.0.5 to 46.0.3.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/45.0.5...46.0.3)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 46.0.3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 21:25:02 +01:00
dependabot[bot]
89c8f570ec core: bump django-pglock from 1.7.2 to 1.8.0 (#19437)
Bumps [django-pglock](https://github.com/AmbitionEng/django-pglock) from 1.7.2 to 1.8.0.
- [Release notes](https://github.com/AmbitionEng/django-pglock/releases)
- [Changelog](https://github.com/AmbitionEng/django-pglock/blob/main/CHANGELOG.md)
- [Commits](https://github.com/AmbitionEng/django-pglock/compare/1.7.2...1.8.0)

---
updated-dependencies:
- dependency-name: django-pglock
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 21:23:35 +01:00
dependabot[bot]
7c276b368a core: bump types-ldap3 from 2.9.13.20250622 to 2.9.13.20251121 (#19438)
Bumps [types-ldap3](https://github.com/typeshed-internal/stub_uploader) from 2.9.13.20250622 to 2.9.13.20251121.
- [Commits](https://github.com/typeshed-internal/stub_uploader/commits)

---
updated-dependencies:
- dependency-name: types-ldap3
  dependency-version: 2.9.13.20251121
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 21:23:24 +01:00
dependabot[bot]
937736ac5e core: bump pytest from 8.3.5 to 9.0.2 (#19425)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.5 to 9.0.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.5...9.0.2)

---
updated-dependencies:
- dependency-name: pytest
  dependency-version: 9.0.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 21:23:05 +01:00
dependabot[bot]
5f433b2623 core: bump aws-cdk-lib from 2.188.0 to 2.234.1 (#19427)
Bumps [aws-cdk-lib](https://github.com/aws/aws-cdk) from 2.188.0 to 2.234.1.
- [Release notes](https://github.com/aws/aws-cdk/releases)
- [Changelog](https://github.com/aws/aws-cdk/blob/main/CHANGELOG.v2.alpha.md)
- [Commits](https://github.com/aws/aws-cdk/compare/v2.188.0...v2.234.1)

---
updated-dependencies:
- dependency-name: aws-cdk-lib
  dependency-version: 2.234.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 21:22:59 +01:00
dependabot[bot]
6a618688e0 core: bump django-pgtrigger from 4.15.2 to 4.17.0 (#19428)
Bumps [django-pgtrigger](https://github.com/AmbitionEng/django-pgtrigger) from 4.15.2 to 4.17.0.
- [Release notes](https://github.com/AmbitionEng/django-pgtrigger/releases)
- [Changelog](https://github.com/AmbitionEng/django-pgtrigger/blob/main/CHANGELOG.md)
- [Commits](https://github.com/AmbitionEng/django-pgtrigger/compare/4.15.2...4.17.0)

---
updated-dependencies:
- dependency-name: django-pgtrigger
  dependency-version: 4.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 20:23:53 +01:00
dependabot[bot]
b43a7de434 core: bump django-stubs[compatible-mypy] from 5.2.5 to 5.2.8 (#19424)
Bumps [django-stubs[compatible-mypy]](https://github.com/sponsors/typeddjango) from 5.2.5 to 5.2.8.
- [Commits](https://github.com/sponsors/typeddjango/commits)

---
updated-dependencies:
- dependency-name: django-stubs[compatible-mypy]
  dependency-version: 5.2.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 20:23:08 +01:00
dependabot[bot]
e8356cbc69 core: bump pyyaml from 6.0.2 to 6.0.3 (#19426)
Bumps [pyyaml](https://github.com/yaml/pyyaml) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/yaml/pyyaml/releases)
- [Changelog](https://github.com/yaml/pyyaml/blob/6.0.3/CHANGES)
- [Commits](https://github.com/yaml/pyyaml/compare/6.0.2...6.0.3)

---
updated-dependencies:
- dependency-name: pyyaml
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 20:22:33 +01:00
dependabot[bot]
6ff625cd4d core: bump bandit from 1.8.3 to 1.9.2 (#19422)
Bumps [bandit](https://github.com/PyCQA/bandit) from 1.8.3 to 1.9.2.
- [Release notes](https://github.com/PyCQA/bandit/releases)
- [Commits](https://github.com/PyCQA/bandit/compare/1.8.3...1.9.2)

---
updated-dependencies:
- dependency-name: bandit
  dependency-version: 1.9.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 20:22:23 +01:00
dependabot[bot]
2a625eed2d core: bump freezegun from 1.5.1 to 1.5.5 (#19423)
Bumps [freezegun](https://github.com/spulec/freezegun) from 1.5.1 to 1.5.5.
- [Release notes](https://github.com/spulec/freezegun/releases)
- [Changelog](https://github.com/spulec/freezegun/blob/master/CHANGELOG)
- [Commits](https://github.com/spulec/freezegun/compare/1.5.1...1.5.5)

---
updated-dependencies:
- dependency-name: freezegun
  dependency-version: 1.5.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 20:22:19 +01:00
Ken Sternberg
4a3555806c web/startup: deprecated theme names break theming (#19431)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* website: fix bad escaping of URLs in release notes

## What

Fixes bad escaping of URLs in the release notes that resulted in mangled output.

v2024.6.4 had entries that looked like this:

```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```

v2025.4.md had entries that looked like this:

```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```

A couple of straightforward search-and-replaces has fixed the issue.

## Notes

Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.

@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.

* web: fix early theme identification

# What

Upon initial load of the HTML, even before the Javascript VM has started loading the admin interface, check if the user has a theme name in localstorage and validate it before proceeding.

# Issue

[Leftover localStorage.theme breaks UI after update to 2025.12.0](https://github.com/goauthentik/authentik/issues/19387)

Reported: 2025-01-13 By: Github user @WIPocket

# Why

We’ve changed our theme names to the more customary “light” and “dark”; older installs may have our earlier keys, “light-theme” or “dark-theme”, and those can break the read, resulting in the theme not being loaded at all.
2026-01-14 20:20:43 +01:00
dependabot[bot]
5014dea495 core: bump importlib-metadata from 8.6.1 to 8.7.1 (#19430)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 15:59:45 +00:00
dependabot[bot]
79329feea6 core: bump geoip2 from 5.1.0 to 5.2.0 (#19429)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 15:58:10 +00:00
dependabot[bot]
8c217b5b6c core: bump debugpy from 1.8.14 to 1.8.19 (#19414)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 15:07:40 +00:00
Marc 'risson' Schmitt
c81f6c5b6f core: remove session migration (#14568) 2026-01-14 15:06:00 +00:00
Simonyi Gergő
68e982b536 website/docs: add 2026.2 release notes draft page (#19418)
Any PR should include a note here if it's relevant enough.
2026-01-14 16:04:36 +01:00
dependabot[bot]
7110a9027c core: bump wsproto from 1.2.0 to 1.3.2 (#19417)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 14:53:08 +00:00
dependabot[bot]
9dfb84ad9e core: bump bpython from 0.25 to 0.26 (#19408)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 14:49:42 +00:00
dependabot[bot]
531ee0347e core: bump pdoc from 15.0.3 to 16.0.0 (#19413)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 14:37:32 +00:00
dependabot[bot]
d66d0b7560 core: bump ruff from 0.11.9 to 0.14.11 (#19410)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2026-01-14 15:27:33 +01:00
dependabot[bot]
dee5da91ec core: bump python-kadmin-rs from 0.6.1 to 0.6.3 (#19416)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 14:22:27 +00:00
dependabot[bot]
0449d6f98d core: bump drf-orjson-renderer from 1.7.3 to 1.8.0 (#19415)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 14:15:54 +00:00
dependabot[bot]
87c53b748e core: bump black from 25.1.0 to 25.12.0 (#19412)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 14:14:12 +00:00
dependabot[bot]
06e667cfcc core: bump lxml from 6.0.0 to 6.0.2 (#19409)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 13:57:28 +00:00
dependabot[bot]
ed7d9fdf23 core: bump xmlsec from 1.3.16 to 1.3.17 (#19411)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 13:56:38 +00:00
dependabot[bot]
59f762bc0a core: bump library/nginx from 06eb0c8 to e3a22a7 in /website (#19394)
Bumps library/nginx from `06eb0c8` to `e3a22a7`.

---
updated-dependencies:
- dependency-name: library/nginx
  dependency-version: 1.29-trixie
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 14:44:12 +01:00
dependabot[bot]
f50796d7d2 core: bump library/node from 03729a7 to 6222695 in /website (#19393)
Bumps library/node from `03729a7` to `6222695`.

---
updated-dependencies:
- dependency-name: library/node
  dependency-version: 25.2.1-trixie
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 14:43:51 +01:00
Simonyi Gergő
a72b77e0a9 website/docs: remove "beta" tag from 2025.12 (#19404) 2026-01-14 08:21:52 -05:00
Dewi Roberts
41f1c24fe9 website/docs: add import to discord policy (#19397)
Add import line
2026-01-14 13:40:23 +01:00
dependabot[bot]
024ee90537 web: bump @types/node from 25.0.7 to 25.0.8 in /web (#19392)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.0.7 to 25.0.8.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 13:39:01 +01:00
Severin Schoepke
b8282dfd67 website/docs: mention dynamic overrides in redirect stage documentation (#19368)
Signed-off-by: Severin Schoepke <severin@users.noreply.github.com>
2026-01-14 11:59:57 +00:00
Dominic R
22e45025e6 web/admin: Pluralize Certificate-Key Pair deletion confirmation (#19389) 2026-01-14 11:55:08 +00:00
Dewi Roberts
6ba41daca0 website/docs: update gws provider docs (#18286)
* Update filenames, sidebar and redirect. Rework overview doc

* WIP

* Spelling

* Move info box

* WIP

* Update create-gws-provider.md

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

* Small tweaks

* Add note about key creation

* Update website/docs/add-secure-apps/providers/gws/configure-gws.md

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

* Add delegated user permissions

* Update configure-gws.md

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

* Fix link and section naming

* Apply suggestions from code review

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

* Update configure-gws.md

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

* Update website/docs/add-secure-apps/providers/gws/index.md

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

* Update website/docs/add-secure-apps/providers/gws/index.md

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

* Headers

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2026-01-14 11:17:52 +00:00
Marcelo Elizeche Landó
a72c04b885 core: Update supported versions in SECURITY.md (#19385)
* core: Update supported versions in SECURITY.md

Added support for version 2025.12.x in the security policy.

Signed-off-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>

* Apply suggestion from @BeryJu

Signed-off-by: Jens L. <jens@beryju.org>

---------

Signed-off-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Jens L. <jens@goauthentik.io>
2026-01-14 05:14:10 +00:00
dependabot[bot]
b368fdafca web: bump the eslint group across 1 directory with 3 updates (#19348)
Bumps the eslint group with 3 updates in the /web directory: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `@typescript-eslint/eslint-plugin` from 8.52.0 to 8.53.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.53.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.52.0 to 8.53.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.53.0/packages/parser)

Updates `typescript-eslint` from 8.52.0 to 8.53.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.53.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.53.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.53.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.53.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 21:35:05 +00:00
Dominic R
1641610273 website/integrations: Add DataDog. (#19320)
* website/integrations: Add DataDog.

* wip
2026-01-13 21:29:58 +00:00
Teffen Ellis
c2db63a60f web: UI Locale Fixes (#19235)
* Add fallback weights to accept language header.

* Fix context cache lifecycle, compatibility.

* Fix stale locale on API provided values.

* Update locale after changing user settings.

* Remove legacy XLF files.

* Apply suggestion from @BeryJu

Signed-off-by: Jens L. <jens@beryju.org>

---------

Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Jens L. <jens@goauthentik.io>
2026-01-13 18:56:28 +01:00
Marc 'risson' Schmitt
7c54b44b9f core: bump microsoft-kiota-http from 1.9.7 to v1.9.8 (#19362) 2026-01-13 17:08:57 +00:00
Jens L.
291b35c3db stages/authenticator_validate: decrease reputation on failed MFA attempt (#19378)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-13 18:05:47 +01:00
Marc 'risson' Schmitt
8f3c927ffb core: bump microsoft-kiota-authentication-azure from 1.9.7 to v1.9.8 (#19361) 2026-01-13 16:48:07 +00:00
Marc 'risson' Schmitt
31ce107332 core: bump httplib2 from 0.31.0 to v0.31.1 (#19360) 2026-01-13 16:45:53 +00:00
Marc 'risson' Schmitt
d0141065c8 core: bump websockets from 15.0.1 to v16.0 (#19366) 2026-01-13 16:44:18 +00:00
Ken Sternberg
c483356b91 web/elements: hidden secrets not propagating (#19029)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* website: fix bad escaping of URLs in release notes

## What

Fixes bad escaping of URLs in the release notes that resulted in mangled output.

v2024.6.4 had entries that looked like this:

```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```

v2025.4.md had entries that looked like this:

```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```

A couple of straightforward search-and-replaces has fixed the issue.

## Notes

Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.

@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.

* web/bug/hidden-secrets-not-propagating

# What

This commit updates ak-secret-text-input, adding the `name` attribute to all valid input fields and updating the value writer to match those of known-working components, to ensure that either variety of the display is fully and correctly updated with the content of the hidden secret.

# Why

The hidden input field is the one that HorizontalFormElement was expecting to read its value from, but that field never received a `name` because it wasn’t present when the field was first updated.

HorizontalFormElement writes the `name` field to the first `<input>` it finds. That was the “dummy” input field, which has no working value.

Form ignored the input element because the value it read came with an undefined name.

Object-oriented state management sometimes bites.

---------

Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2026-01-13 17:17:31 +01:00
Marc 'risson' Schmitt
f37121c37e core: bump boto3 from 1.42.24 to v1.42.26 (#19358) 2026-01-13 16:11:10 +00:00
Jens L.
7ee2036970 website/docs: update location for logs on windows (#19371)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-13 16:53:01 +01:00
Dominic R
3873f43ea3 outpost/proxyv2: fix stale session cookie causing 400 error in createState (#19026) 2026-01-13 10:52:42 -05:00
Dominic R
a479c79b34 internal/outpost: improve PostgreSQL connection options parsing (#19118)
* internal: Outpost's conn options should be base64 json

* correctly parse target_session_attrs + tests

* fix port handling to use env provided port

* add multiple port handling abilities to mirror the python config parser

---------

Co-authored-by: Duncan Tasker <tasatree@gmail.com>
2026-01-13 10:52:28 -05:00
Marc 'risson' Schmitt
aa5e273083 core: bump prometheus-client from 0.23.1 to v0.24.0 (#19364) 2026-01-13 15:30:41 +00:00
Marc 'risson' Schmitt
5bb5898762 core: bump protobuf from 6.33.2 to v6.33.4 (#19365) 2026-01-13 15:29:46 +00:00
Marc 'risson' Schmitt
ace7643d17 core: bump zope-interface from 8.1.1 to v8.2 (#19367) 2026-01-13 15:28:57 +00:00
Jens L.
9579fda164 revert: web: disable user settings fields when changes are not allowed (#19230)
Revert "web: disable user settings fields when changes are not allowed (#19132)"

This reverts commit c45110ed10.
2026-01-13 16:28:40 +01:00
Ken Sternberg
3a7d69b481 web/admin: always retrieve selected provider when editing the application (#19341)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* website: fix bad escaping of URLs in release notes

## What

Fixes bad escaping of URLs in the release notes that resulted in mangled output.

v2024.6.4 had entries that looked like this:

```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```

v2025.4.md had entries that looked like this:

```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```

A couple of straightforward search-and-replaces has fixed the issue.

## Notes

Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.

@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.

* web/admin: always retrieve selected provider when editing the application

# What

Re-writes the `fetch` function for ak-provider-search-input so that, if there’s an assigned value and it does not appear in the currently retrieved list of providers, prepend it to the list so that it is always present and always selectable.

# Why

Our pagination windows can restrict the list of objects retrieved from the server, and when we’re chasing composite objects we have to retrieve the displayable elements of that object from their respective tables. This combination means that a paginated retrieval may not have the object indicated by the parent object’s PK for that object collection. We have to retrieve it separately if it’s not in the current collection.

This problem is probably endemic to some of our design decisions.
2026-01-13 16:28:18 +01:00
Marc 'risson' Schmitt
88cb5555a8 core: bump azure-core from 1.37.0 to v1.38.0 (#19357) 2026-01-13 15:27:51 +00:00
Marc 'risson' Schmitt
c8f487f220 core: bump pathspec from 1.0.2 to v1.0.3 (#19363) 2026-01-13 15:06:37 +00:00
Marc 'risson' Schmitt
5b55b15170 core: bump google-api-core from 2.28.1 to v2.29.0 (#19359) 2026-01-13 15:03:34 +00:00
Marcelo Elizeche Landó
7034318a96 core: bump microsoft-kiota-serialization-text from 1.9.7 to v1.9.8 (#19274) 2026-01-13 14:56:50 +00:00
Marcelo Elizeche Landó
d1ac7e5815 core: bump proto-plus from 1.26.1 to v1.27.0 (#19279) 2026-01-13 14:14:29 +00:00
Jens L.
34547048a1 internal: rework liveness probe and proxy (#19312)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-13 15:11:07 +01:00
Marcelo Elizeche Landó
f0cbf3af72 core: bump azure-core from 1.36.0 to v1.37.0 (#19260) 2026-01-13 14:07:58 +00:00
Marcelo Elizeche Landó
43f2403a93 core: bump google-auth from 2.43.0 to v2.47.0 (#19265) 2026-01-13 14:07:28 +00:00
Marcelo Elizeche Landó
667aa22aef core: bump greenlet from 3.2.4 to v3.3.0 (#19267) 2026-01-13 14:02:08 +00:00
Marcelo Elizeche Landó
c8c6bd58f7 core: bump types-requests from 2.32.4.20250913 to v2.32.4.20260107 (#19285) 2026-01-13 14:00:24 +00:00
Marcelo Elizeche Landó
af9c3eafe5 core: bump pyparsing from 3.2.5 to v3.3.1 (#19282) 2026-01-13 13:51:37 +00:00
Marcelo Elizeche Landó
a54c0e45f5 core: bump autobahn from 25.11.1 to v25.12.2 (#19259) 2026-01-13 13:51:23 +00:00
Marcelo Elizeche Landó
a05a0d1f7c core: bump certifi from 2025.11.12 to v2026.1.4 (#19264) 2026-01-13 13:49:09 +00:00
Marcelo Elizeche Landó
9f97bb242d core: bump sqlparse from 0.5.4 to v0.5.5 (#19283) 2026-01-13 13:46:09 +00:00
Marcelo Elizeche Landó
27acfbf691 core: bump google-auth-httplib2 from 0.2.1 to v0.3.0 (#19266) 2026-01-13 13:41:42 +00:00
Marcelo Elizeche Landó
bdf90e226e core: bump aiohttp from 3.13.2 to v3.13.3 (#19257) 2026-01-13 13:39:06 +00:00
Marcelo Elizeche Landó
6bb378551b core: bump anyio from 4.12.0 to v4.12.1 (#19258) 2026-01-13 14:36:51 +01:00
Marcelo Elizeche Landó
4fbbdb46c8 core: bump txaio from 25.9.2 to v25.12.2 (#19284) 2026-01-13 13:35:15 +00:00
Marcelo Elizeche Landó
e251d454cc core: bump jsonschema from 4.25.1 to v4.26.0 (#19269) 2026-01-13 13:32:48 +00:00
Marcelo Elizeche Landó
c058f27d3e core: bump pathspec from 0.12.1 to v1.0.2 (#19277) 2026-01-13 13:32:23 +00:00
Marcelo Elizeche Landó
4aef76bebc core: bump opentelemetry-api from 1.39.0 to v1.39.1 (#19275) 2026-01-13 13:31:15 +00:00
Marcelo Elizeche Landó
9ee2b48ac6 core: bump pynacl from 1.6.1 to v1.6.2 (#19281) 2026-01-13 13:30:52 +00:00
Marcelo Elizeche Landó
3cf9883e3a core: bump boto3 from 1.42.1 to v1.42.24 (#19261) 2026-01-13 13:30:15 +00:00
Marcelo Elizeche Landó
2b18992db5 core: bump microsoft-kiota-serialization-form from 1.9.7 to v1.9.8 (#19271) 2026-01-13 13:29:58 +00:00
Marcelo Elizeche Landó
a736df4999 core: bump microsoft-kiota-serialization-multipart from 1.9.7 to v1.9.8 (#19273) 2026-01-13 13:29:37 +00:00
Marcelo Elizeche Landó
981394b25d core: bump cbor2 from 5.7.1 to v5.8.0 (#19263) 2026-01-13 13:28:31 +00:00
Marcelo Elizeche Landó
7f6d0ce909 core: bump ua-parser-builtins from 0.18.0.post1 to v202601 (#19286) 2026-01-13 14:04:11 +01:00
Marcelo Elizeche Landó
0790797628 core: bump protobuf from 6.33.1 to v6.33.2 (#19280) 2026-01-13 14:02:55 +01:00
Marcelo Elizeche Landó
897ed2fd8d core: bump platformdirs from 4.5.0 to v4.5.1 (#19278) 2026-01-13 14:02:33 +01:00
Marcelo Elizeche Landó
9203bc4edf core: bump orjson from 3.11.4 to v3.11.5 (#19276) 2026-01-13 14:02:15 +01:00
Marcelo Elizeche Landó
d8f261905d core: bump microsoft-kiota-serialization-json from 1.9.7 to v1.9.8 (#19272) 2026-01-13 14:01:22 +01:00
Marcelo Elizeche Landó
c2fe8c8235 core: bump microsoft-kiota-abstractions from 1.9.7 to v1.9.8 (#19270) 2026-01-13 14:01:04 +01:00
Marcelo Elizeche Landó
6334ff82f1 core: bump jsii from 1.120.0 to v1.125.0 (#19268) 2026-01-13 14:00:48 +01:00
Marc 'risson' Schmitt
f2f4d41678 packages/django-dramatiq-postgres: broker: empty message after task completed successfully (#19340) 2026-01-13 12:56:06 +00:00
dependabot[bot]
4a01940236 core: bump library/nginx from 7272239 to 06eb0c8 in /website (#19350)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 13:29:38 +01:00
dependabot[bot]
01efaab3ec web: bump @types/node from 25.0.6 to 25.0.7 in /web (#19353)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.0.6 to 25.0.7.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 12:59:49 +01:00
dependabot[bot]
ebd2b1c710 web: bump @sentry/browser from 10.32.1 to 10.33.0 in /web in the sentry group across 1 directory (#19347)
web: bump @sentry/browser in /web in the sentry group across 1 directory

Bumps the sentry group with 1 update in the /web directory: [@sentry/browser](https://github.com/getsentry/sentry-javascript).


Updates `@sentry/browser` from 10.32.1 to 10.33.0
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/10.32.1...10.33.0)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 10.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: sentry
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 12:48:30 +01:00
dependabot[bot]
5408b08f81 ci: bump actions/setup-go from 6.1.0 to 6.2.0 (#19351)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](4dc6199c7b...7a3fe6cf4c)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 12:48:19 +01:00
dependabot[bot]
22cb9117f4 web: bump the bundler group across 1 directory with 3 updates (#19349)
Bumps the bundler group with 1 update in the /web directory: [@vitest/browser](https://github.com/vitest-dev/vitest/tree/HEAD/packages/browser).


Updates `@vitest/browser` from 4.0.16 to 4.0.17
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.17/packages/browser)

Updates `@vitest/browser-playwright` from 4.0.16 to 4.0.17
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.17/packages/browser-playwright)

Updates `vitest` from 4.0.16 to 4.0.17
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.17/packages/vitest)

---
updated-dependencies:
- dependency-name: "@vitest/browser"
  dependency-version: 4.0.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
- dependency-name: "@vitest/browser-playwright"
  dependency-version: 4.0.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
- dependency-name: vitest
  dependency-version: 4.0.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 12:47:59 +01:00
dependabot[bot]
ee621b1b5d ci: bump actions/setup-go from 6.1.0 to 6.2.0 in /.github/actions/setup (#19352)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](4dc6199c7b...7a3fe6cf4c)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 12:47:39 +01:00
dependabot[bot]
b8347163bc core: bump goauthentik.io/api/v3 from 3.2026020.10 to 3.2026020.11 (#19300)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2026020.10 to 3.2026020.11.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2026020.10...v3.2026020.11)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2026020.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 12:47:25 +01:00
dependabot[bot]
b179ff251c web: bump type-fest from 5.3.1 to 5.4.0 in /web (#19354)
Bumps [type-fest](https://github.com/sindresorhus/type-fest) from 5.3.1 to 5.4.0.
- [Release notes](https://github.com/sindresorhus/type-fest/releases)
- [Commits](https://github.com/sindresorhus/type-fest/compare/v5.3.1...v5.4.0)

---
updated-dependencies:
- dependency-name: type-fest
  dependency-version: 5.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 12:45:33 +01:00
Teffen Ellis
4824515e03 web: Flow info, localization, back button. (#19234)
* Localize email sent message.

* Add back button to denied stage.

* Clean up flow user details.

* Fix linter warnings.
2026-01-13 05:21:04 +00:00
Dewi Roberts
f6a50a628b website/docs: update LDAP provider docs (#18272)
* Update docs, remove all images

* Move service account step

* Remove commas

* Minor improvements

* Table language improved

* Group table language improvements

* Fix stage capitalization

* Language

* Update file name, sidebar and redirect

* Add links

* Swap headers

* Update file to mdx

* Apply suggestions from code review

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

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2026-01-13 02:11:19 +00:00
Teffen Ellis
d949564cc6 web: Images styles, theming (#19233)
* Fix referencing of theme directly from element, rather than the root.

* Fix low-resolution icon scaling.
2026-01-12 14:33:07 -05:00
dependabot[bot]
31f6192311 web: bump @types/react from 19.2.7 to 19.2.8 in /web in the react group across 1 directory (#19330)
web: bump @types/react in /web in the react group across 1 directory

Bumps the react group with 1 update in the /web directory: [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react).


Updates `@types/react` from 19.2.7 to 19.2.8
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.2.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 17:52:07 +01:00
Dewi Roberts
c848a01e99 website/docs: update unique email policy (#19305)
* Update doc

* Update unique_email.md

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

* rewrite policy

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2026-01-12 14:18:43 +00:00
dependabot[bot]
a2f911deef core: bump library/nginx from ca871a8 to 7272239 in /website (#19334)
Bumps library/nginx from `ca871a8` to `7272239`.

---
updated-dependencies:
- dependency-name: library/nginx
  dependency-version: 1.29-trixie
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 15:10:18 +01:00
dependabot[bot]
f8f584d151 web: bump @types/node from 25.0.3 to 25.0.6 in /web (#19331)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.0.3 to 25.0.6.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 14:45:19 +01:00
dependabot[bot]
3421567a31 core: bump axllent/mailpit from v1.28.1 to v1.28.2 in /tests/e2e (#19329)
Bumps axllent/mailpit from v1.28.1 to v1.28.2.

---
updated-dependencies:
- dependency-name: axllent/mailpit
  dependency-version: v1.28.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 14:37:09 +01:00
dependabot[bot]
169e0e68d4 web: bump knip from 5.80.1 to 5.80.2 in /web (#19332)
Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 5.80.1 to 5.80.2.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/knip@5.80.2/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 5.80.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 14:24:25 +01:00
dependabot[bot]
0b4117cd3d web: bump pino from 10.1.0 to 10.1.1 in /web (#19333)
Bumps [pino](https://github.com/pinojs/pino) from 10.1.0 to 10.1.1.
- [Release notes](https://github.com/pinojs/pino/releases)
- [Commits](https://github.com/pinojs/pino/compare/v10.1.0...v10.1.1)

---
updated-dependencies:
- dependency-name: pino
  dependency-version: 10.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 14:24:15 +01:00
Dewi Roberts
a65c99d46b website/docs: add flow import warnings (#19307)
Add warnigns
2026-01-11 22:06:07 +00:00
Sebastian Wiesinger
2cc9192b31 website/docs: Fix documentation example for app_entitlements_attributes. (#19316)
Fix example for `app_entitlements_attributes`.

Fix example Python code for `app_entitlements_attributes`.

Signed-off-by: Sebastian Wiesinger <sebastian@karotte.org>
2026-01-11 22:00:35 +00:00
Dewi Roberts
646e604c05 website/docs: update m2m doc (#18963)
* Updates m2m doc, add mention to proxy provider about finding logs, updates filename/links/redirects

* Apply suggestions from code review

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Prettier

* wip

* Removed section and changed some wording

* Add section

* Update website/docs/add-secure-apps/providers/proxy/index.md

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

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2026-01-11 21:44:53 +00:00
Tom Crasset
81838734f7 website/docs: Fix typo in GitHub OAuth Source instructions (#18936)
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2026-01-11 21:40:00 +00:00
Dewi Roberts
44eede3a84 website/docs: deprecate GCDT auth stage (#19306)
Update stage doc
2026-01-11 15:51:17 -05:00
authentik-automation[bot]
310a5d980c core, web: update translations (#19237)
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>
2026-01-09 22:48:35 -05:00
Teffen Ellis
73ccead6cc web: Fix flow inspector advancement event. (#19309) 2026-01-09 16:59:56 +00:00
dependabot[bot]
caa4826120 web: bump knip from 5.80.0 to 5.80.1 in /web (#19301)
Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 5.80.0 to 5.80.1.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/knip@5.80.1/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 5.80.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-09 14:44:56 +01:00
Marcelo Elizeche Landó
4fd5c7a481 core: bump urllib3 from 2.5.0 to v2.6.3 (#19287) 2026-01-08 20:03:06 +01:00
Jens L.
3e9b59cc13 endpoints: show agent version (#19239)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-08 20:01:10 +01:00
Marcelo Elizeche Landó
e5c25b4d37 core: bump django from v5.2.9 to 5.2.10 (#19290)
bump django from v5.2.9 to 5.2.10
2026-01-08 18:34:01 +00:00
Jens L.
ec7bbd3e90 web/admin: add banner to flow import form (#19288)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-08 19:21:37 +01:00
dependabot[bot]
8792401010 web: bump chromedriver from 143.0.3 to 143.0.4 in /web (#19244)
Bumps [chromedriver](https://github.com/giggio/node-chromedriver) from 143.0.3 to 143.0.4.
- [Commits](https://github.com/giggio/node-chromedriver/compare/143.0.3...143.0.4)

---
updated-dependencies:
- dependency-name: chromedriver
  dependency-version: 143.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-08 19:02:16 +01:00
Jens L.
7ea0545d70 stages/password: replace session-based retries with reputation (#18643)
* stages/password: replace session-based retries with reputation

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* relative score

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-08 18:36:05 +01:00
Dewi Roberts
5a1430af72 website/integations: fix aws spelling (#19253)
Fix titles
2026-01-08 17:01:51 +00:00
Dewi Roberts
79ca35713a website/docs: update entra id provider docs (#18366)
* Updates doc filenames, sidebar, redirects and doc content

* Apply suggestions

* Apply suggestions

* Apply suggestions

* Update index.md

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

* Apply suggestions

* Apply suggestions

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
2026-01-08 16:52:50 +00:00
Marc 'risson' Schmitt
8649c5d373 stages/prompt: optimize API endpoints (#19251) 2026-01-08 16:06:02 +00:00
dependabot[bot]
150f7f4bac web: bump the rollup group across 1 directory with 4 updates (#19206)
Bumps the rollup group with 4 updates in the /web directory: [@rollup/rollup-darwin-arm64](https://github.com/rollup/rollup), [@rollup/rollup-linux-arm64-gnu](https://github.com/rollup/rollup), [@rollup/rollup-linux-x64-gnu](https://github.com/rollup/rollup) and [rollup](https://github.com/rollup/rollup).


Updates `@rollup/rollup-darwin-arm64` from 4.54.0 to 4.55.1
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.55.1)

Updates `@rollup/rollup-linux-arm64-gnu` from 4.54.0 to 4.55.1
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.55.1)

Updates `@rollup/rollup-linux-x64-gnu` from 4.54.0 to 4.55.1
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.55.1)

Updates `rollup` from 4.54.0 to 4.55.1
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.55.1)

---
updated-dependencies:
- dependency-name: "@rollup/rollup-darwin-arm64"
  dependency-version: 4.55.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-arm64-gnu"
  dependency-version: 4.55.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-version: 4.55.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rollup
- dependency-name: rollup
  dependency-version: 4.55.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rollup
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-08 15:13:23 +01:00
dependabot[bot]
fa61737c25 web: bump vite from 7.3.0 to 7.3.1 in /web (#19245)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.3.0 to 7.3.1.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.1/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.1/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-08 15:13:07 +01:00
rain capsule
e5784e40da website/docs: update github social login script example (#19246) 2026-01-08 13:45:22 +00:00
Dewi Roberts
49ab34e7e5 website/integrations: update AWS (#17861)
* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Spelling

* wip

---------

Co-authored-by: Dominic R <dominic@sdko.org>
2026-01-08 13:09:36 +00:00
dependabot[bot]
85355177a1 core: bump goauthentik.io/api/v3 from 3.2026020.8 to 3.2026020.10 (#19242)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-08 12:39:56 +00:00
Dominic R
1b4b50650c website: Fix typos. (#19243)
* website: Fix typos.

* wip
2026-01-08 08:27:37 +00:00
Dominic R
d7f9172539 core: fix read replica routing during transactions (#19086)
* core: fix transactional app creation failing with read replicas

When authentik is configured with pg read replicas, the application wizard fails with "Invalid pk - object does not exist" for the provider field.

The issue occurs in the blueprint validation flow:
1.  Provider is created on the primary database (e.g PK 159)
2. KeyOf.resolve() returns this PK for the application's provider field
3. ApplicationSerializer.is_valid() validates the provider FK
4. DRF's PrimaryKeyRelatedField queries to verify the PK exists
5. FailoverRouter routes this read to a replica
6. Replica hasn't replicated the new provider yet --> validation fails

Number 6 happens because the transaction has not been commited yet cause blueprint validation runs in transaction_rollback()

The fix introduces TransactionApplicationRequestSerializer which excludes provider-related fields (provider, provider_obj, backchannel_providers, backchannel_providers_obj) from validation.

This is safe because:
- The provider is created in the same blueprint transaction
- The KeyOf reference correctly links them during blueprint apply()
- The blueprint importer handles the actual FK assignment

* wip

* wip

* wip

* wip

* wip

* wip
2026-01-08 01:41:07 +00:00
Dominic R
b1c9a3c5ab website/glossary: improve (#18969)
* website/glossary: Fix eslint errors

* wip
2026-01-08 00:25:22 +00:00
Dominic R
39f6f72e96 stages/authenticator_static: set max token length to 100 chars (#19162)
* stages/authenticator_static: add max length validation for token_length field

* wip

* wip
2026-01-07 22:50:10 +00:00
dependabot[bot]
660a58757e core: bump goauthentik.io/api/v3 from 3.2026020.7 to 3.2026020.8 (#19218)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-07 17:01:44 +00:00
dependabot[bot]
c1c28313c5 lifecycle/aws: bump aws-cdk from 2.1100.2 to 2.1100.3 in /lifecycle/aws (#19219)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1100.2 to 2.1100.3.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1100.3/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1100.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-07 17:23:48 +01:00
dependabot[bot]
a5e3938737 web: bump @formatjs/intl-listformat from 8.1.1 to 8.1.2 in /web (#19220)
Bumps [@formatjs/intl-listformat](https://github.com/formatjs/formatjs) from 8.1.1 to 8.1.2.
- [Release notes](https://github.com/formatjs/formatjs/releases)
- [Commits](https://github.com/formatjs/formatjs/compare/@formatjs/intl-listformat@8.1.1...@formatjs/intl-listformat@8.1.2)

---
updated-dependencies:
- dependency-name: "@formatjs/intl-listformat"
  dependency-version: 8.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-07 17:23:37 +01:00
Jens L.
85759d5fd2 endpoints: include license status in agent config (#19227)
* web/admin: consistent OS display

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* include license status with agent config

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* slightly rework

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-07 17:23:13 +01:00
dependabot[bot]
9bb10fdc4c ci: bump astral-sh/setup-uv from 7.1.6 to 7.2.0 in /.github/actions/setup (#19221)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-07 15:27:46 +00:00
Jens L.
6e9972f148 website/docs: revisit endpoint docs the nth (#19116)
* website/docs: revisit endpoint docs the nth

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* more edits & examples

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* WIP

* Apply suggestions from code review

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update index.mdx

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

* Apply suggestions from code review

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

* Add edge browser extension

* Update website/docs/endpoint-devices/device-compliance/browser-extension.mdx

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: dewi-tik <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2026-01-07 10:51:17 +00:00
authentik-automation[bot]
d9065a0225 core, web: update translations (#19200)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2026-01-07 00:44:36 +00:00
Marc 'risson' Schmitt
1a4ae2f102 outpost/proxyv2: reduce max number of postgres connections (#19211) 2026-01-06 18:19:41 +00:00
Ken Sternberg
19667e116f web/maintenance: lint pass to add missing HTMLElementEventMap entries (#18953)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* website: fix bad escaping of URLs in release notes

## What

Fixes bad escaping of URLs in the release notes that resulted in mangled output.

v2024.6.4 had entries that looked like this:

```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```

v2025.4.md had entries that looked like this:

```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```

A couple of straightforward search-and-replaces has fixed the issue.

## Notes

Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.

@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.

* web/maintenance: lint pass to add missing HTMLElementEventMap entries

# What

For events where we had, through whatever mechanisms we used, abstracted event names enough that Typescript struggled with them, those names have been added to the respective elements’ JSDoc entry, so that Lit-Analyze could look a little harder.

In several places, outdated test harnesses were using old event names.

Finally, for RapiDoc and Openlayers, the event names provided did not have ElementEventMap entries. Since those events will always be listened for, from the contents within the shadowDOM, the Lit guidelines recommend listening for those on a customElement attached to `this`, and built with the constructor. This is no hardship; the listener always travels with the `:host`, so it does not need to be attached or detached, and the event handing logic is unchanged.

However, that change led to *Typescript* now complaining that there was no HTMLElementEventMap entry for those specific events. I have added `ts-expect-error` pragmas in those two places, with the appropriate comment. This seems like the better compromise, as Typescript is more robust.

* Update web/src/admin/events/EventMap.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>

* Update web/src/standalone/api-browser/index.entrypoint.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>

* Github's merge mangled this badly.  Had to fix.

---------

Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2026-01-06 10:19:34 -08:00
transifex-integration[bot]
87de3aa66b translate: Updates for project authentik and language pt_BR (#19082)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2026-01-06 18:52:23 +01:00
dependabot[bot]
0260e93e90 core: bump goauthentik.io/api/v3 from 3.2026020.6 to 3.2026020.7 (#19202)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-06 18:51:38 +01:00
dependabot[bot]
9e07c237e5 lifecycle/aws: bump aws-cdk from 2.1100.1 to 2.1100.2 in /lifecycle/aws (#19203)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-06 17:33:01 +00:00
dependabot[bot]
0a78fd21e1 core: bump axllent/mailpit from v1.28.0 to v1.28.1 in /tests/e2e (#19204)
Bumps axllent/mailpit from v1.28.0 to v1.28.1.

---
updated-dependencies:
- dependency-name: axllent/mailpit
  dependency-version: v1.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-06 16:07:45 +01:00
dependabot[bot]
3e930722ed web: bump knip from 5.79.0 to 5.80.0 in /web (#19207)
Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 5.79.0 to 5.80.0.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/knip@5.80.0/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 5.80.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-06 16:07:20 +01:00
Dewi Roberts
13e44cf3ca website/integrations: glpi: add step (#19208)
Add step
2026-01-06 13:29:34 +00:00
Dominic R
1a963d27c8 admin/files: support %(theme)s variable in media file paths (#19108)
* admin/files: support %(theme)s variable in media file paths

* wip

* Apply suggestion from @rissson

Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Dominic R <dominic@sdko.org>

---------

Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2026-01-06 13:21:11 +00:00
dependabot[bot]
e0dde82759 web: bump the eslint group across 1 directory with 3 updates (#19205)
Bumps the eslint group with 3 updates in the /web directory: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `@typescript-eslint/eslint-plugin` from 8.51.0 to 8.52.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.52.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.51.0 to 8.52.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.52.0/packages/parser)

Updates `typescript-eslint` from 8.51.0 to 8.52.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.52.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.52.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.52.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.52.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-06 13:57:37 +01:00
Dominic R
c3cf94550f core: add last_login filter to users API (#18993) 2026-01-06 04:02:02 +00:00
Tana M Berry
e273eb7483 website/docs: rewrite section about users and perms (#19195)
* rewrite

* bounce
2026-01-05 18:49:58 -06:00
Connor Peshek
4ac01724a5 rbac: Add show all to roles tab, add role tab to groups (#19097)
* improve sort order and inherit visual

* Update web/src/admin/groups/GroupViewPage.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Connor Peshek <connor@connorpeshek.me>

* Update web/src/admin/users/UserViewPage.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Connor Peshek <connor@connorpeshek.me>

* Update web/src/admin/roles/RelatedRoleList.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Connor Peshek <connor@connorpeshek.me>

* Update web/src/admin/roles/RelatedRoleList.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Connor Peshek <connor@connorpeshek.me>

* Update web/src/admin/roles/RelatedRoleList.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Connor Peshek <connor@connorpeshek.me>

* Update web/src/admin/roles/RelatedRoleList.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Connor Peshek <connor@connorpeshek.me>

* setup include inherited roles and fix returning nothing

* update api calls

* fix rendering error

* do not use set

* change from exception handling

* go off query param

* fix wording

* fix linting error for new group api structure

---------

Signed-off-by: Connor Peshek <connor@connorpeshek.me>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2026-01-05 23:14:44 +00:00
Teffen Ellis
24d99eae41 web: Defer table refresh, visibility checks. (#19194)
Fix types, args.
2026-01-05 18:02:41 -05:00
Connor Peshek
c6fd931663 Add docs for roles (#19196)
* Add docs for roles

* update users and roles
2026-01-05 21:56:12 +00:00
Teffen Ellis
2c813cbe03 web: Merge branch -- Stale notifications, synchronized context objects, rendering fixes (#19141)
* web: Fix stale notifications.

* Fix overlap of API and notifications drawers.

* Fix issues surrounding duplicate context controller values.

* Clean up drawer events, alignment.

* Export parts. Fix z-index, colors.

* Fix formatting, alignment. repeated renders.

* Fix indent.

* Fix progress bar fade out, positioning, labels.

* Fix clickable area.

* Ignore clickable icons.

* Clean up logging.

* Fix width.

* Move event listeners into decorator.

* Fix double counting of notifications.

* Fix ARIA lables.

* Fix empty state ARIA.

* Fix order of locale updating.

* Fix rebase.

* web: fix notification count update

* Update selector.

* web: Fix CAPTCHA locale.

* Clean up logging.

---------

Co-authored-by: macmoritz <tratarmoritz@gmail.com>
2026-01-05 15:54:50 -05:00
Teffen Ellis
957450b86f root: codespell: ignore Python virtual env, group patterns. (#19180)
core/codespell: Ignore Python virtual env, group patterns.
2026-01-05 19:24:51 +00:00
Ken Sternberg
47aa68fa93 web/maintenance: no missing element type definitions (#18950)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* website: fix bad escaping of URLs in release notes

## What

Fixes bad escaping of URLs in the release notes that resulted in mangled output.

v2024.6.4 had entries that looked like this:

```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```

v2025.4.md had entries that looked like this:

```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```

A couple of straightforward search-and-replaces has fixed the issue.

## Notes

Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.

@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.

* web/maintenance: lint pass to add missing HTMLElementTagNameMap entries

# What

This code mechanically adds HTMLElementTagNameMap entries to those files that were missing it.

Every entry in the report is in this format:

    ./src/elements/ak-table/stories/ak-select-table.stories.ts

        'ak-select-table-test-sort' has not been registered on HTMLElementTagNameMap
        84:  export class SimpleTableSortTest extends LitElem
        no-missing-element-type-definition

It was trivial to create a Perl script that extracted the file name, the tag name, and the class name, and turn that into a “Open this file and append the HTMLElementTagNameMap definition to the end,” then run `prettier` and `build` to validate that nothing broke.

I also had to hand-edit the JSDoc for `Form`. It is not, by itself, an element. It is an abstract class from which you can derive elements. The `@element` tag there confused lit-analyze, and lit-analyze was correct to call it out.

# Why

These entries help Typescript & Lit-Analyze lint our product, validating that each element is being used correctly and that the types being passed to it are correct.
2026-01-05 08:49:14 -08:00
Simonyi Gergő
ba9e7fe315 core: add prettier failure on duplicate group names (#18941)
* core: add prettier failure on duplicate group names

* add db_alias

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>

* lint

* migrate to system migration

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix error on empty database

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* returning a count of 0 still takes 1 row :P

---------

Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2026-01-05 17:44:07 +01:00
Jens L.
6b27b37540 website/integrations: make grafana terraform section expand (#19192)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-05 17:25:41 +01:00
Connor Peshek
fdb7fa6a10 lib: update error logging (#18628)
* lib: update error logging

---------

Co-authored-by: connor peshek <connorpeshek@connors-MacBook-Pro.local>
2026-01-05 09:44:04 -06:00
authentik-automation[bot]
880afb6f69 core, web: update translations (#19179)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2026-01-05 14:34:35 +00:00
dependabot[bot]
3142cfa050 web: bump @formatjs/intl-listformat from 8.1.0 to 8.1.1 in /web (#19182)
Bumps [@formatjs/intl-listformat](https://github.com/formatjs/formatjs) from 8.1.0 to 8.1.1.
- [Release notes](https://github.com/formatjs/formatjs/releases)
- [Commits](https://github.com/formatjs/formatjs/compare/@formatjs/intl-listformat@8.1.0...@formatjs/intl-listformat@8.1.1)

---
updated-dependencies:
- dependency-name: "@formatjs/intl-listformat"
  dependency-version: 8.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 13:23:45 +01:00
dependabot[bot]
cb2d509945 ci: bump getsentry/action-release from 3.4.0 to 3.5.0 (#19183)
Bumps [getsentry/action-release](https://github.com/getsentry/action-release) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/getsentry/action-release/releases)
- [Changelog](https://github.com/getsentry/action-release/blob/master/CHANGELOG.md)
- [Commits](128c5058bb...dab6548b3c)

---
updated-dependencies:
- dependency-name: getsentry/action-release
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 12:52:05 +01:00
dependabot[bot]
9a8c7bb23b web: bump knip from 5.78.0 to 5.79.0 in /web (#19181)
Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 5.78.0 to 5.79.0.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/knip@5.79.0/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 5.79.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 12:51:33 +01:00
Duncan Tasker
bc24815ae6 lifecycle: fix migration conn_options for psycopg connection (#19134)
fix migrations to add conn_options to the psycopg connection
2026-01-05 09:58:40 +01:00
Adithya S Narasinghe
c3eb401600 website/docs: remove duplicates in slo docs (#19170)
remove duplicated points in the iframe mode points in slo docs
2026-01-04 18:28:12 +00:00
Jens L.
1dd7269871 web/admin: adjust sync threshold, add tooltip (#19131)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-03 23:00:59 -05:00
Teffen Ellis
38381504c0 web: Fix user library colors, modal z-indexes, table progress bars (#19152)
* Fix progress bar fade out, positioning, labels.

* Export parts. Fix z-index, colors.

* Fix clickable area.

* Ignore clickable icons.
2026-01-03 22:43:31 -05:00
Dominic R
366ebc3a91 web: fix slug auto-updating when editing existing applications (#19169) 2026-01-04 03:36:13 +00:00
Dominic R
32f77f05f4 core: handle deserialization errors from FileField migration (#19067)
after migration 0054 changed icon fields from Django FileField to a TextField based custom FileField, old sessions which had serialized Source/Application model instances fail to deserialize.

The old FieldFile descriptors try to access field.storage which no longer exists.

We can't edit that migration since it has already been ran by many/

So, you  add AttributeError and TypeError to exception handling in SessionStore.decode() to return an empty session instead of crashing with 500.
2026-01-03 15:32:22 -05:00
authentik-automation[bot]
f077506c41 stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#19137)
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>
2026-01-03 21:30:16 +01:00
William Kray
9183e4967b website/integrations: vaultwarden: add custom email scope (#19160)
* update vaultwarden integration doc to include custom scope mapping needed

* wip

---------

Co-authored-by: Dominic R <dominic@sdko.org>
2026-01-03 02:31:54 +00:00
dependabot[bot]
af5bff725f ci: bump int128/docker-manifest-create-action from 2.10.0 to 2.12.0 (#19138)
Bumps [int128/docker-manifest-create-action](https://github.com/int128/docker-manifest-create-action) from 2.10.0 to 2.12.0.
- [Release notes](https://github.com/int128/docker-manifest-create-action/releases)
- [Commits](b60433fd43...6cdd53a833)

---
updated-dependencies:
- dependency-name: int128/docker-manifest-create-action
  dependency-version: 2.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-02 11:57:48 +01:00
authentik-automation[bot]
1c2cf4bb5c core, web: update translations (#19135)
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>
2026-01-02 11:33:11 +01:00
dependabot[bot]
c6a5062cd7 web: bump globals from 16.5.0 to 17.0.0 in /web (#19154)
Bumps [globals](https://github.com/sindresorhus/globals) from 16.5.0 to 17.0.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v16.5.0...v17.0.0)

---
updated-dependencies:
- dependency-name: globals
  dependency-version: 17.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-02 11:32:59 +01:00
Jens L.
e4127fdaf0 web/user: fix consent delete form missing details (#19147)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2026-01-02 11:31:11 +01:00
Teffen Ellis
7085743cac web: Token Form Fixes (#19121)
* Fix autofocus attribute.

* web: Fix label alignment, focus handlers, edit states.

* Tidy date functions.

* Use Dates over strings.
2026-01-01 19:03:57 -05:00
Jens L.
27bd6d6e92 website/docs: fix build (#19148)
* ensure we never throw errors in the browser

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* cleaner

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* rework

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix misleading variable

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* Tidy behavior.

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Teffen Ellis <teffen@goauthentik.io>
2026-01-01 18:30:27 +00:00
Jens L.
fecd852c2b website/docs: endpoint agent release notes (#19042)
* website/docs: endpoint agent release notes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* Apply suggestion from @dominic-r

Signed-off-by: Dominic R <dominic@sdko.org>

* rename, update

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Dominic R <dominic@sdko.org>
2026-01-01 13:53:54 +01:00
Dominic R
c45110ed10 web: disable user settings fields when changes are not allowed (#19132)
* web: disable user settings fields when changes are not allowed

Previously, when admins disabled the ability to change email, username, or name in System Settings, users would only see an error after attempting to submit the form.

Now, the field is marked as disabled.

* wip
2025-12-31 16:00:09 -05:00
SKAL
b1bfd457eb website/integrations: karakeep: don't hardcode wellknown's slug (#19127)
* Clarify OAUTH_WELLKNOWN_URL in documentation

Updated OAUTH_WELLKNOWN_URL placeholder for clarity.
I've updated it because this way it copies also the correct slug (which might be changed)

Signed-off-by: SKAL <pippo73@users.noreply.github.com>

* Update website/integrations/documentation/karakeep/index.md

Signed-off-by: Dominic R <dominic@sdko.org>

---------

Signed-off-by: SKAL <pippo73@users.noreply.github.com>
Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-12-31 16:06:14 +01:00
dependabot[bot]
8b579f064e core, web: bump qs from 6.14.0 to 6.14.1 in /packages/docusaurus-config (#19130)
Bumps [qs](https://github.com/ljharb/qs) from 6.14.0 to 6.14.1.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.0...v6.14.1)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-31 15:53:02 +01:00
dependabot[bot]
79b01f8c56 core: bump library/node from ccfd9da to 03729a7 in /website (#19125)
Bumps library/node from `ccfd9da` to `03729a7`.

---
updated-dependencies:
- dependency-name: library/node
  dependency-version: 25.2.1-trixie
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-31 15:08:32 +01:00
dependabot[bot]
d7e4b5c1ed core: bump github.com/jackc/pgx/v5 from 5.7.6 to 5.8.0 (#19088)
Bumps [github.com/jackc/pgx/v5](https://github.com/jackc/pgx) from 5.7.6 to 5.8.0.
- [Changelog](https://github.com/jackc/pgx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jackc/pgx/compare/v5.7.6...v5.8.0)

---
updated-dependencies:
- dependency-name: github.com/jackc/pgx/v5
  dependency-version: 5.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-31 15:08:21 +01:00
dependabot[bot]
8b2ccc9568 web: bump the swc group across 1 directory with 11 updates (#19124)
Bumps the swc group with 1 update in the /web directory: [@swc/core](https://github.com/swc-project/swc).


Updates `@swc/core` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-darwin-arm64` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-darwin-x64` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-linux-arm-gnueabihf` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-linux-arm64-gnu` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-linux-arm64-musl` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-linux-x64-gnu` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-linux-x64-musl` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-win32-arm64-msvc` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-win32-ia32-msvc` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

Updates `@swc/core-win32-x64-msvc` from 1.15.7 to 1.15.8
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.7...v1.15.8)

---
updated-dependencies:
- dependency-name: "@swc/core"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-darwin-x64"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm-gnueabihf"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm64-musl"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-x64-musl"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-arm64-msvc"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-ia32-msvc"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-x64-msvc"
  dependency-version: 1.15.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-31 14:57:41 +01:00
dependabot[bot]
84fa4f9dc8 core: bump library/nginx from ad85427 to ca871a8 in /website (#19126)
Bumps library/nginx from `ad85427` to `ca871a8`.

---
updated-dependencies:
- dependency-name: library/nginx
  dependency-version: 1.29-trixie
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-31 14:06:53 +01:00
Teffen Ellis
e5852b46cb web: Capitalize language display names, code owner fix (#19119)
* web: Capitalize locale display names.

* Fix broad code owner.
2025-12-30 18:04:36 -05:00
Teffen Ellis
c108877a85 web: Fix Impersonation, Lit Reactive Controller Contexts (#19114)
* web: Fix issue where impersonation does not trigger updates.

* web: Fix issues surrounding abort controller types, lifecycle.
2025-12-30 11:37:09 -05:00
dependabot[bot]
84f74ee306 web: bump the eslint group across 1 directory with 3 updates (#19110)
Bumps the eslint group with 3 updates in the /web directory: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `@typescript-eslint/eslint-plugin` from 8.50.1 to 8.51.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.51.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.50.1 to 8.51.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.51.0/packages/parser)

Updates `typescript-eslint` from 8.50.1 to 8.51.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.51.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.51.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.51.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.51.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-30 13:08:21 +01:00
dependabot[bot]
32cb16ec2f core: bump library/nginx from fb01117 to ad85427 in /website (#19112)
Bumps library/nginx from `fb01117` to `ad85427`.

---
updated-dependencies:
- dependency-name: library/nginx
  dependency-version: 1.29-trixie
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-30 13:08:08 +01:00
dependabot[bot]
d5a2f2dc14 web: bump the storybook group across 1 directory with 5 updates (#19111)
Bumps the storybook group with 4 updates in the /web directory: [@storybook/addon-docs](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs), [@storybook/addon-links](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/links), [@storybook/web-components](https://github.com/storybookjs/storybook/tree/HEAD/code/renderers/web-components) and [@storybook/web-components-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/web-components-vite).


Updates `@storybook/addon-docs` from 10.1.10 to 10.1.11
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.11/code/addons/docs)

Updates `@storybook/addon-links` from 10.1.10 to 10.1.11
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.11/code/addons/links)

Updates `@storybook/web-components` from 10.1.10 to 10.1.11
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.11/code/renderers/web-components)

Updates `@storybook/web-components-vite` from 10.1.10 to 10.1.11
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.11/code/frameworks/web-components-vite)

Updates `storybook` from 10.1.10 to 10.1.11
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.11/code/core)

---
updated-dependencies:
- dependency-name: "@storybook/addon-docs"
  dependency-version: 10.1.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/addon-links"
  dependency-version: 10.1.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/web-components"
  dependency-version: 10.1.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/web-components-vite"
  dependency-version: 10.1.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: storybook
  dependency-version: 10.1.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-30 13:07:56 +01:00
Dominic R
c22f043ad6 website/docs: release notes: Add more integrations (#19109) 2025-12-30 08:10:31 +00:00
Lukas
b2778702d0 website/integrations: Add Audiobookshelf (#19104)
* website/docs: Add Audiobookshelf Community Integration Documentation

* wip

---------

Co-authored-by: Dominic R <dominic@sdko.org>
2025-12-30 03:22:54 +00:00
Lukas
d43724deb8 website/integrations: Add Pulse (#19105)
* website/docs: Add Pulse Community Integration Documentation

* wip

---------

Co-authored-by: Dominic R <dominic@sdko.org>
2025-12-30 03:19:03 +00:00
Ken Sternberg
8b21392aa3 web/maintenance/no unknown attributes (part 1) (#18970)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* website: fix bad escaping of URLs in release notes

## What

Fixes bad escaping of URLs in the release notes that resulted in mangled output.

v2024.6.4 had entries that looked like this:

```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```

v2025.4.md had entries that looked like this:

```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```

A couple of straightforward search-and-replaces has fixed the issue.

## Notes

Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.

@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.

* web/maintenance/no-unknown-attributes-1

# What

This commit is a collection of fixes and adaptations discovered while running lit-analyzer in a stricter role than usual. These fixes are to 9 of the existing issues; there are 16 more that will be addressed in the next two pull requests.

The following issues were uncovered.

- `ak-slug-input` does not take `autocomplete`.
- `ak-wizard-page-type-create` does not take, or use, the `name` attribute. It also has no `value` of its own, so it is not processed as a form object.
- `ak-endpoints-device-access-groups-form` does not take a `pk` attribute. It takes an `.instancePk` property.
- `ak-provider-oauth2-redirect-uri` is only used in one place, and that place uses the term `input-id` for the key. The component was expected `inputId`. Since it is a string and therefore an attribute, kebab-case is the appropriate fix here.
- `input-mode` is not a valid attribute. The attribute is `inputmode`, and the property is `inputMode`. It may not be undefined. If it is defined, the default is `text`. I have fixed this in the attribute and in the two Forms that used it.
- `form-associated-element` had both `name` and `type` as readonly. Since they are native attributes, they can be attributes or they can be readonly. They can’t be both. I have made them read-write.
- `user-source-settings-page` is only used in one place, and that place uses the term `input-id` for the key. The component was expected `inputId`. Since it is a string and therefore an attribute, kebab-case is the appropriate fix here.

These guideposts will be placed on the PR.

* Update web/src/admin/providers/oauth2/OAuth2ProviderRedirectURI.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>

* Update web/src/components/ak-text-input.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>

* Fix duplicate lines in property declaration. Not sure how that snuck in there.

* Prettier has opinions.

---------

Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2025-12-29 10:50:16 -08:00
Austin Dudzik
7246681815 Update Vaultwarden documentation by removing warning (#19102)
Removed warning about SSO feature availability on testing images.

Signed-off-by: Austin Dudzik <65981261+austin-dudzik@users.noreply.github.com>
2025-12-29 18:01:49 +00:00
Dominic R
d5869674b7 web: Fix stale flow background (#19015) 2025-12-29 17:30:12 +00:00
Dominic R
2a97dd2912 web: fix promoted source button hover losing blue color (#19048) 2025-12-29 08:59:53 -08:00
dependabot[bot]
485d413548 web: bump knip from 5.77.1 to 5.78.0 in /web (#19090) 2025-12-29 17:55:01 +01:00
Dewi Roberts
cef54653ec website/docs: endpoint devices: add path to macos setup (#19093)
* Add path

* Update macos.md

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

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
2025-12-29 08:15:36 -05:00
Dewi Roberts
e16a0ab99d website/docs: endpoint devices: update features table (#19094)
* Update table

* Remove wording
2025-12-29 08:14:15 -05:00
Dominic R
722b425c3b website/docs: rel notes .12: add wallos (#19063) 2025-12-29 09:24:26 +00:00
Dominic R
ec227532c4 website/docs: endpoints: mention connector key required for stage to work (#19084)
keypair = CertificateKeyPair.objects.filter(pk=stage.connector.challenge_key_id).first()
  if not keypair:
      return self.executor.stage_ok()  # < --- skips the stage

took me a bit of time to find this and yea
2025-12-29 09:23:15 +00:00
Jens L.
7300737a12 web/admin: fix button alignment on user view page (#19079)
* web/admin: fix button alignment on user view page

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix width

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-28 16:15:18 +01:00
dependabot[bot]
9d70c5a3ed web: bump @formatjs/intl-listformat from 7.7.13 to 8.1.0 in /web (#19054)
* web: bump @formatjs/intl-listformat from 7.7.13 to 8.1.0 in /web

Bumps [@formatjs/intl-listformat](https://github.com/formatjs/formatjs) from 7.7.13 to 8.1.0.
- [Release notes](https://github.com/formatjs/formatjs/releases)
- [Commits](https://github.com/formatjs/formatjs/compare/@formatjs/intl-listformat@7.7.13...@formatjs/intl-listformat@8.1.0)

---
updated-dependencies:
- dependency-name: "@formatjs/intl-listformat"
  dependency-version: 8.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-12-28 15:19:53 +01:00
Jens L.
b5848765b2 internal: update TLS Suite (#19076)
* internal: update TLS Suite

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* disable chacha20 due to fips

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-28 14:46:27 +01:00
dependabot[bot]
1877a9d286 web: bump @lit/localize-tools from 0.8.0 to 0.8.1 in /web (#19040)
Bumps [@lit/localize-tools](https://github.com/lit/lit/tree/HEAD/packages/localize-tools) from 0.8.0 to 0.8.1.
- [Release notes](https://github.com/lit/lit/releases)
- [Changelog](https://github.com/lit/lit/blob/main/packages/localize-tools/CHANGELOG.md)
- [Commits](https://github.com/lit/lit/commits/HEAD/packages/localize-tools)

---
updated-dependencies:
- dependency-name: "@lit/localize-tools"
  dependency-version: 0.8.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-28 14:00:39 +01:00
dependabot[bot]
a5ed6b05e2 web: bump knip from 5.77.0 to 5.77.1 in /web (#19049)
Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 5.77.0 to 5.77.1.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/knip@5.77.1/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 5.77.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-28 14:00:20 +01:00
authentik-automation[bot]
5d66ba341d core, web: update translations (#18991)
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-12-28 14:00:00 +01:00
Jens L.
4f4e37f2b0 tests/e2e: add endpoint tests (#19072)
* tests/e2e: add endpoint tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* dont rely on hostname

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-28 12:53:00 +01:00
ocmateusz
a98d70ea7b website/integrations: owncloud: fix php (#19073) 2025-12-27 21:45:35 +00:00
Dominic R
aa8644ea27 web: fix file search input not resetting results properly (#19034) 2025-12-27 16:19:50 -05:00
Dominic R
fe0106886a blueprints: fix deadlock and task context error in MetaApplyBlueprint (#19033)
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-12-26 13:47:07 -05:00
authentik-automation[bot]
0a27684dbd *: Auto compress images (#19065)
*: compress images

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dominic-r <157558804+dominic-r@users.noreply.github.com>
2025-12-26 12:55:08 -05:00
Borut Mrak
25cae250cd website/docs: FreeIPA documentation updates (#15183)
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Borut Mrak <borut.mrak@acex.si>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-12-26 17:14:59 +00:00
Lukas
960d09300f website/integrations: Add Wallos (#19013)
Co-authored-by: dewi-tik <dewi@goauthentik.io>
2025-12-26 11:50:31 -05:00
Jens L.
46297698d6 blueprints: set enrollment token key (#19061)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-26 17:37:48 +01:00
Jens L.
448c8f8745 endpoints/devices: cleanup (#19047)
* endpoints: make device token internally managed

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix text and defaults for agent

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* re-org some code

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-26 14:20:20 +01:00
Amélie Lilith Krejčí
1685f8f9eb lib/sync: fix sync_dispatch (#19053)
* fix: add missing call to all on self.schedules

Fixes #19051

* fix: change the name of syncOutgoingTriggerMode ak-radio-input

Fixes #19052
2025-12-26 14:01:27 +01:00
Marcelo Elizeche Landó
61e45ca59a docs/release notes: update 2025.12 release notes (#19043)
* Add links and tags

* Update website/docs/releases/2025/v2025.12.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>

---------

Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-12-24 13:01:26 -03:00
dependabot[bot]
0a5e421c9c core: bump goauthentik.io/api/v3 from 3.2026020.5 to 3.2026020.6 (#19036)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2026020.5 to 3.2026020.6.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2026020.5...v3.2026020.6)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2026020.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-24 13:58:28 +01:00
dependabot[bot]
097b39d773 web: bump knip from 5.75.1 to 5.77.0 in /web (#19041)
Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 5.75.1 to 5.77.0.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/knip@5.77.0/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 5.77.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-24 13:56:04 +01:00
dependabot[bot]
a9c2613ba6 web: bump @lit/reactive-element from 2.1.1 to 2.1.2 in /web (#19037)
Bumps [@lit/reactive-element](https://github.com/lit/lit/tree/HEAD/packages/reactive-element) from 2.1.1 to 2.1.2.
- [Release notes](https://github.com/lit/lit/releases)
- [Changelog](https://github.com/lit/lit/blob/main/packages/reactive-element/CHANGELOG.md)
- [Commits](https://github.com/lit/lit/commits/lit@2.1.2/packages/reactive-element)

---
updated-dependencies:
- dependency-name: "@lit/reactive-element"
  dependency-version: 2.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-24 13:55:39 +01:00
dependabot[bot]
4684f8a4c4 web: bump lit from 3.3.1 to 3.3.2 in /web (#19038)
Bumps [lit](https://github.com/lit/lit/tree/HEAD/packages/lit) from 3.3.1 to 3.3.2.
- [Release notes](https://github.com/lit/lit/releases)
- [Changelog](https://github.com/lit/lit/blob/main/packages/lit/CHANGELOG.md)
- [Commits](https://github.com/lit/lit/commits/lit-element@3.3.2/packages/lit)

---
updated-dependencies:
- dependency-name: lit
  dependency-version: 3.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-24 13:54:36 +01:00
Dominic R
7845dcf687 web/admin: use consistent icon for inactive user status (#19032) 2025-12-24 03:23:16 +00:00
Jens L.
cc2dbf4db5 core: use chunked_queryset for expired message deletion (#19028)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-24 01:15:45 +01:00
Teffen Ellis
f520c90e16 web: Fix Storybook package resolution with npm link (#19016) 2025-12-23 18:40:47 +00:00
Teffen Ellis
342d9eb726 web: Locale selector UI fixes (#18972)
* Fix alignment, focus.

* Clean up.

* Tidy click area.

* Fix compatibility mode.

* Fix alignment.

* Fix issues surrounding labels, alignment, consistency.

* Update web/src/common/ui/locale/format.ts

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

* Tidy hover states.

* Tidy.

* Clean up parsing.

* Tidy comments, usage.

* Always use script naming over region.

* Remove unused.

* Spacing.

---------

Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2025-12-23 18:40:02 +00:00
Teffen Ellis
2f8dfff207 website/docs: Prioritize "Release Candidate" over "Current Release" (#18975)
Normalize labels.
2025-12-23 15:41:42 +01:00
dependabot[bot]
0ba071e1e5 core: bump goauthentik.io/api/v3 from 3.2026020.4 to 3.2026020.5 (#19017)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2026020.4 to 3.2026020.5.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2026020.4...v3.2026020.5)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2026020.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-23 14:50:54 +01:00
dependabot[bot]
6443d56d2b web: bump the eslint group across 1 directory with 3 updates (#19019)
Bumps the eslint group with 3 updates in the /web directory: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `@typescript-eslint/eslint-plugin` from 8.50.0 to 8.50.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.50.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.50.0 to 8.50.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.50.1/packages/parser)

Updates `typescript-eslint` from 8.50.0 to 8.50.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.50.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.50.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.50.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.50.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-23 13:43:43 +01:00
Jens L.
fcc0438961 web/admin: prevent file upload attempt when backend not managed (#18646)
* web/admin: prevent file upload attempt when backend not managed

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* wip

* fixup

* rework

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add check for reports

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix delete table for data exports missing details

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-12-23 13:41:27 +01:00
Jens L.
d9cd1096b9 api: rework schema generation (#18977)
* api: rework schema generation

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* better error message

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* actually fix tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* different test

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-23 12:20:24 +01:00
dependabot[bot]
fc4765d265 web: bump globby from 16.0.0 to 16.1.0 in /web (#18995)
Bumps [globby](https://github.com/sindresorhus/globby) from 16.0.0 to 16.1.0.
- [Release notes](https://github.com/sindresorhus/globby/releases)
- [Commits](https://github.com/sindresorhus/globby/compare/v16.0.0...v16.1.0)

---
updated-dependencies:
- dependency-name: globby
  dependency-version: 16.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-23 11:50:15 +01:00
dependabot[bot]
4b54684efa core: bump openapitools/openapi-generator-cli from v7.16.0 to v7.18.0 in /scripts/api (#19018)
core: bump openapitools/openapi-generator-cli in /scripts/api

Bumps openapitools/openapi-generator-cli from v7.16.0 to v7.18.0.

---
updated-dependencies:
- dependency-name: openapitools/openapi-generator-cli
  dependency-version: v7.18.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-23 11:49:39 +01:00
dependabot[bot]
519958fdbc web: bump the rollup group across 1 directory with 4 updates (#18994)
Bumps the rollup group with 4 updates in the /web directory: [@rollup/rollup-darwin-arm64](https://github.com/rollup/rollup), [@rollup/rollup-linux-arm64-gnu](https://github.com/rollup/rollup), [@rollup/rollup-linux-x64-gnu](https://github.com/rollup/rollup) and [rollup](https://github.com/rollup/rollup).


Updates `@rollup/rollup-darwin-arm64` from 4.53.5 to 4.54.0
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.5...v4.54.0)

Updates `@rollup/rollup-linux-arm64-gnu` from 4.53.5 to 4.54.0
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.5...v4.54.0)

Updates `@rollup/rollup-linux-x64-gnu` from 4.53.5 to 4.54.0
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.5...v4.54.0)

Updates `rollup` from 4.53.5 to 4.54.0
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.5...v4.54.0)

---
updated-dependencies:
- dependency-name: "@rollup/rollup-darwin-arm64"
  dependency-version: 4.54.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-arm64-gnu"
  dependency-version: 4.54.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-version: 4.54.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rollup
- dependency-name: rollup
  dependency-version: 4.54.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rollup
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 23:32:24 +01:00
Dewi Roberts
97ef6a5eb2 website/docs: improve endpoint devices docs (#19007)
* Remove sudo auth sections

* Add firefox extension link

* Add chrome extension

* Update release notes

* Remove link

* Fix link

* Fix release note wording
2025-12-22 20:32:20 +00:00
Jens L.
e23c28373c enterprise/search: add static autocomplete structure (#19008)
* enterprise/search: add static autocomplete structure

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add recursive structured for context

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-22 20:53:33 +01:00
Jens L.
7fa28c60c7 enterprise/reports: improve export list, confirmation (#18981)
* enterprise/reports: use verbose name for model label

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add confirmation for export

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update docs

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove duplicated api

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix duplicate

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix search query not updated

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* exclude page & page size

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* improve query display

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix user display

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* exclude unset params

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* Apply suggestions from code review

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Jens L. <jens@beryju.org>

* more code style

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix types

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2025-12-22 20:35:18 +01:00
Jens L.
3cd1a31365 providers/oauth2: Automated OpenID Conformance tests (#14785)
* some progress

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* somewhat working?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove some previous debugging things

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make it kinda work

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* revert more debugging stuff

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make tests mostly work

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* smaller screenshots?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove debugging

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* sleep a bit before checking again

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* cleanup, restart loop when we finished an operation

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* refactor conformance helper to requests (thanks chatgpt)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* properly install subtests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* maybe run in CI?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* dont hardcode IP

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix network and cookie deletion

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* upload cert exports

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* test

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* attempt to switch to generated

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make it work generated?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix teardown

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* re-add implicit and fix?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* Revert "re-add implicit and fix?"

This reverts commit 6a4d15fc22cf4b27ffa428be9ecc9a0e778961c6.

* Revert "fix teardown"

This reverts commit cb96b0cb988acedec1fe72ec437b68e2c38ed6b1.

* Revert "make it work generated?"

This reverts commit 4e29d2c5737ee9aaad6c0f4701caf7e0fb110e15.

* Revert "attempt to switch to generated"

This reverts commit 6f851e021d305a93be9cfbb4a9b6783231b6d7cf.

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* check authorize request param earlier

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix some

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix basic suite?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* another actual fix; don't return access_token when using response_type id_token

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add implicit test

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add custom profile scope that includes standard scopes to return number of warnings

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* use actual timestamp

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix missing offline_access, use scoped issuer

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* only run basic+implicit for now, fix other tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* split up

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix offline_access tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix waiting for compete on error

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix duplicate artifact

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix artifact

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* 👀

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix typing

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* typing

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix implicit

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* don't wait for conformance test

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* more disk space

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-22 20:21:22 +01:00
dependabot[bot]
b66e4074e2 ci: bump docker/setup-buildx-action from 3.11.1 to 3.12.0 (#18999)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.11.1 to 3.12.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](e468171a9d...8d2750c68a)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 3.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 16:34:46 +01:00
Jens L.
fa65d4730c blueprints: fix flaky tests (#19002)
* blueprints: attempt to fix tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix postgres debug logging

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-22 15:39:05 +01:00
Dominic R
e3d774b3ef web: fix Open button selecting row instead of navigating (#18992)
the `isEventTargetingListener()` function only checked the click target and the immediate parent for interactive elements (like links, buttons and more). when clicking the icon inside the Open button, the DOM structure is:

<a href=...>  <--- 2 levels up, never checked
<pf-tooltip>  <--- immediate parent, not interactive
<i> <---- click target, not interactive

Because <i> and <pf-tooltip> did not match the interactive elements query, the function returned false which caused the table rowClickListener to continue with row selection isntead of allowing the click.

The fix is to update the function to to traverse (up) the entire dom tree from the click target to the listener element (the table cell) and check for each ancestor for the interactive elements.
2025-12-22 15:02:59 +01:00
Jens L.
162e05ff9d events: notifications live update (#18980)
* this has been broken for a while but no one noticed...? cc @rissson

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* send WS broadcast for new notifications

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* better layout

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix e2e tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-21 23:02:56 +01:00
Henry Skrtich
238cefba45 web/admin: Fix haveibeenpwned link in PasswordPolicyForm (#18984)
web: Fix haveibeenpwned link in PasswordPolicyForm
2025-12-21 15:02:04 +01:00
Jens L.
bfa46ddc7e web/admin: fix dark theme on map (#18985)
web/admin: fix dark theme on map broken

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-21 15:01:26 +01:00
Jens L.
e24b60f806 blueprints: add InternallyManagedMixin instead of large list (#18983)
* blueprints: add InternallyManagedMixin instead of large list

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix recursion

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix e2e tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-21 03:31:41 +01:00
Stijn van Hees
0c792c8463 website/integrations: Fix path for Cloudflare Access (#18979)
Co-authored-by: Dominic R <dominic@sdko.org>
2025-12-20 16:57:57 +00:00
Ken Sternberg
1143de97d0 web/maintenance: no unknown tag names (#18944)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* website: fix bad escaping of URLs in release notes

## What

Fixes bad escaping of URLs in the release notes that resulted in mangled output.

v2024.6.4 had entries that looked like this:

```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```

v2025.4.md had entries that looked like this:

```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```

A couple of straightforward search-and-replaces has fixed the issue.

## Notes

Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.

@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.

* web/maintenance: lint pass to fix broken or unrecognized tag names

# What

This code removes two places in the code that referenced obsolete tag names.

In AkWizardFormPage, the case was a tag that was defined but never used. It, in turn, referenced a tag that did not exist.

In AkApplicationWizard’s ProviderChoices, we referenced eight custom components that did not exist and were never defined anywhere in the code. The references to `renderers` were obsolete; despite being defined they were never used. (This lack of use was covered up by lots of `export`s discarding Typescript’s check against unused field.)

- [x] The code has been formatted

# Why

- WizardFormPage references ‘ak-wizard-form’, which does not exist
- No other component imports, inherits, or extends WizardFormPage. It only exists by itself.

``` shell
$ rg 'WizardFormPage'
src/elements/wizard/WizardFormPage.ts
39:export class WizardFormPage extends WizardPage {
```

- The objects referenced here in these renderers do not exist.
- Without them, the priority ordering code becomes much simpler
- No LocalTypeCreate calls are needed; just use the default API TypeCreate types now

<!-- -->

    ./src/admin/applications/wizard/steps/ProviderChoices.ts

        Unknown tag <ak-application-wizard-authentication-by-oauth>. Did you mean <ak-application-wizard-application-step>?
        19:  html`<ak-application-wizard-authentication-by-oauth></ak-appl
        no-unknown-tag-name

        Unknown tag <ak-application-wizard-authentication-by-saml-configuration>. Did you mean <ak-application-wizard-application-step>?
        24:  html`<ak-application-wizard-authentication-by-saml-configuration></ak-appl
        no-unknown-tag-name

* A better way to prioritise, without losing the original script.

* further streamlining the priority order.

* Making it harder to add bad provider models to the application wizard.

* Prettier has opinions.

* Adding these to the tagname maps so lit-analyze can validate their uses.

* Made testing for valid returns from the server generic.  Suggestion from @GirlBossRush
2025-12-19 08:20:33 -08:00
Ken Sternberg
d6bc5871fa web/maintenance: fix missing custom web component imports (#18942)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* website: fix bad escaping of URLs in release notes

## What

Fixes bad escaping of URLs in the release notes that resulted in mangled output.

v2024.6.4 had entries that looked like this:

```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```

v2025.4.md had entries that looked like this:

```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```

A couple of straightforward search-and-replaces has fixed the issue.

## Notes

Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.

@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.

* web: lint pass to add all missing custom component imports

# What

The latest version of lit-analyze found 53(!) places in the codebase where we referenced a custom web component but not guarantee that it had been registered with the browser. Most of these are so commonplace that they had already been pulled in and registered elsewhere, but it’s still bad practice to leave these out.

* web/maintenance: lint pass to fix broken or unrecognized tag names

# What

This code removes two places in the code that referenced obsolete tag names.

In AkWizardFormPage, the case was a tag that was defined but never used. It, in turn, referenced a tag that did not exist.

In AkApplicationWizard’s ProviderChoices, we referenced eight custom components that did not exist and were never defined anywhere in the code. The references to `renderers` were obsolete; despite being defined they were never used. (This lack of use was covered up by lots of `export`s discarding Typescript’s check against unused field.)

- [x] The code has been formatted

# Why

- WizardFormPage references ‘ak-wizard-form’, which does not exist
- No other component imports, inherits, or extends WizardFormPage. It only exists by itself.

``` shell
$ rg 'WizardFormPage'
src/elements/wizard/WizardFormPage.ts
39:export class WizardFormPage extends WizardPage {
```

- The objects referenced here in these renderers do not exist.
- Without them, the priority ordering code becomes much simpler
- No LocalTypeCreate calls are needed; just use the default API TypeCreate types now

<!-- -->

    ./src/admin/applications/wizard/steps/ProviderChoices.ts

        Unknown tag <ak-application-wizard-authentication-by-oauth>. Did you mean <ak-application-wizard-application-step>?
        19:  html`<ak-application-wizard-authentication-by-oauth></ak-appl
        no-unknown-tag-name

        Unknown tag <ak-application-wizard-authentication-by-saml-configuration>. Did you mean <ak-application-wizard-application-step>?
        24:  html`<ak-application-wizard-authentication-by-saml-configuration></ak-appl
        no-unknown-tag-name

* Revert "web/maintenance: lint pass to fix broken or unrecognized tag names"

This reverts commit e9e073fbcc.
2025-12-19 08:19:25 -08:00
Dewi Roberts
0fec6fb81b website/docs: add note to active directory source doc (#18787)
Adds note

Co-authored-by: Dominic R <dominic@sdko.org>
2025-12-19 16:00:17 +01:00
dependabot[bot]
f8cf6b8530 ci: bump actions/attest-build-provenance from 3.0.0 to 3.1.0 (#18960)
Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](977bb373ed...00014ed6ed)

---
updated-dependencies:
- dependency-name: actions/attest-build-provenance
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-19 15:57:50 +01:00
dependabot[bot]
320ca655b4 web: bump @sentry/browser from 10.31.0 to 10.32.0 in /web in the sentry group across 1 directory (#18957)
web: bump @sentry/browser in /web in the sentry group across 1 directory

Bumps the sentry group with 1 update in the /web directory: [@sentry/browser](https://github.com/getsentry/sentry-javascript).


Updates `@sentry/browser` from 10.31.0 to 10.32.0
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/10.31.0...10.32.0)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 10.32.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: sentry
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-19 15:57:32 +01:00
dependabot[bot]
72dd63af31 web: bump the swc group across 1 directory with 11 updates (#18958)
Bumps the swc group with 1 update in the /web directory: [@swc/core](https://github.com/swc-project/swc).


Updates `@swc/core` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-darwin-arm64` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-darwin-x64` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-linux-arm-gnueabihf` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-linux-arm64-gnu` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-linux-arm64-musl` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-linux-x64-gnu` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-linux-x64-musl` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-win32-arm64-msvc` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-win32-ia32-msvc` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

Updates `@swc/core-win32-x64-msvc` from 1.15.6 to 1.15.7
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.6...v1.15.7)

---
updated-dependencies:
- dependency-name: "@swc/core"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-darwin-x64"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm-gnueabihf"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm64-musl"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-x64-musl"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-arm64-msvc"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-ia32-msvc"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-x64-msvc"
  dependency-version: 1.15.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-19 15:47:34 +01:00
dependabot[bot]
4cbffd5b27 web: bump chromedriver from 143.0.2 to 143.0.3 in /web (#18959)
Bumps [chromedriver](https://github.com/giggio/node-chromedriver) from 143.0.2 to 143.0.3.
- [Commits](https://github.com/giggio/node-chromedriver/compare/143.0.2...143.0.3)

---
updated-dependencies:
- dependency-name: chromedriver
  dependency-version: 143.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-19 15:29:13 +01:00
dependabot[bot]
4d9f4638fa core: bump goauthentik.io/api/v3 from 3.2026020.3 to 3.2026020.4 (#18956)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2026020.3 to 3.2026020.4.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2026020.3...v3.2026020.4)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2026020.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-19 11:36:45 +00:00
Connor Peshek
646a0d3692 root: move docker files to lifecycle/containers and change docker-compose to compose (#16624) 2025-12-18 18:23:54 -06:00
Dominic R
59460ac840 flows/executor: fix KeyError when session has no existing plan (#18951) 2025-12-19 00:21:32 +00:00
Jens L.
c67cd41c22 web/admin: fix endpoints user binding (#18935)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-19 00:07:52 +01:00
Teffen Ellis
5a840e8f6d website/docs: Fix version parsing. (#18948) 2025-12-18 21:59:48 +00:00
Dewi Roberts
81771ce609 website/docs: release notes: add endpoint device links to 2025.12 notes (#18940)
Add links to release notes
2025-12-18 20:16:59 +00:00
Teffen Ellis
5babdf64cb website/docs: Fix labels, Pre-Release detection (#18945)
* Fix import path.

* Show unlisted entries if release.

* Fix sidebar rendering.

* Fix positioning of pre-release note. Tidy phrasing.

* Clarify pre-release vs draft.
2025-12-18 21:01:47 +01:00
Dewi Roberts
de298d72de website/docs: endpoint devices (#18634)
* Initial

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Apply suggestions from code review

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

* Apply suggestions from code review

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

* Apply suggestions

* Apply suggestions

* Apply suggestions from code review

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

* Apply suggestions from code review

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

* WIP

* Apply suggestions from code review

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

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* fixes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* WIP

* Optimised images with calibre/image-actions

* Optimised images with calibre/image-actions

* Optimised images with calibre/image-actions

* Optimised images with calibre/image-actions

* Optimised images with calibre/image-actions

* Optimised images with calibre/image-actions

* Optimised images with calibre/image-actions

* Fix anchor

* Update website/docs/endpoint-devices/index.mdx

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

* WIP

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-12-18 19:09:11 +00:00
Jens L.
d7f3055cd8 stages/identification: replace sleep with make_password (#18883)
* stages/identification: replace sleep with make_password

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-12-18 19:09:10 +01:00
Jens L.
0beb8f9a12 web/elements: progress-bar and table loading header (#18934)
* add ak-progress-bar

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make intermediate smaller

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add table

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* hide table overflow

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-18 17:44:21 +01:00
Marc 'risson' Schmitt
6bfa07d761 crypto: fix extra cert data in db migration (#18937) 2025-12-18 16:34:31 +00:00
Weilu Jia
8d4c05c7e7 website/integrations: Add launch URL for Immich (#18921)
Signed-off-by: Weilu Jia <optix2000@users.noreply.github.com>
2025-12-18 16:24:51 +00:00
Victor Nawothnig
598b92d928 web/flow: Fix spurious double submit on ak-stage-autosubmit (#18727)
* Fix double submission on ak-stage-autosubmit

* use updated correctly

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Victor Nawothnig <Victor.Nawothnig+git@icloud.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-12-18 14:35:18 +00:00
Simonyi Gergő
90c8f23862 packages/ak-guardian: cast safely (#18929)
* packages/ak-guardian: cast safely

* use `regexp_like` instead of `pg_input_is_valid`

* alternative approach: RawSQL subquery

* remove extra fields we don't need

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

* prevent subquery collapse

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

* take into account foreignkeys

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

* shut up bandit

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

* clean up a bit

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-12-18 15:29:10 +01:00
Jens L.
62dc04a684 stages: remove more global state (#18641)
* add auth for active flow

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* migrate duo

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* migrate sms

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* migrate consent

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* migrate email and fix broken tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fallback

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* merge flow plan when restoring from token

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-18 13:12:35 +01:00
dependabot[bot]
68f3bf6ec1 web: bump the storybook group across 1 directory with 5 updates (#18817)
Bumps the storybook group with 4 updates in the /web directory: [@storybook/addon-docs](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs), [@storybook/addon-links](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/links), [@storybook/web-components](https://github.com/storybookjs/storybook/tree/HEAD/code/renderers/web-components) and [@storybook/web-components-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/web-components-vite).


Updates `@storybook/addon-docs` from 10.1.7 to 10.1.8
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.8/code/addons/docs)

Updates `@storybook/addon-links` from 10.1.7 to 10.1.8
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.8/code/addons/links)

Updates `@storybook/web-components` from 10.1.7 to 10.1.8
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.8/code/renderers/web-components)

Updates `@storybook/web-components-vite` from 10.1.7 to 10.1.8
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.8/code/frameworks/web-components-vite)

Updates `storybook` from 10.1.7 to 10.1.8
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v10.1.8/code/core)

---
updated-dependencies:
- dependency-name: "@storybook/addon-docs"
  dependency-version: 10.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/addon-links"
  dependency-version: 10.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/web-components"
  dependency-version: 10.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/web-components-vite"
  dependency-version: 10.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: storybook
  dependency-version: 10.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-18 13:02:01 +01:00
dependabot[bot]
8234613b76 web: bump the swc group across 1 directory with 11 updates (#18923)
Bumps the swc group with 1 update in the /web directory: [@swc/core](https://github.com/swc-project/swc).


Updates `@swc/core` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-darwin-arm64` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-darwin-x64` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-linux-arm-gnueabihf` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-linux-arm64-gnu` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-linux-arm64-musl` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-linux-x64-gnu` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-linux-x64-musl` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-win32-arm64-msvc` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-win32-ia32-msvc` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

Updates `@swc/core-win32-x64-msvc` from 1.15.5 to 1.15.6
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.5...v1.15.6)

---
updated-dependencies:
- dependency-name: "@swc/core"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-darwin-x64"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm-gnueabihf"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm64-musl"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-x64-musl"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-arm64-msvc"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-ia32-msvc"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-x64-msvc"
  dependency-version: 1.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-18 13:01:49 +01:00
dependabot[bot]
eec998cc8d lifecycle/aws: bump aws-cdk from 2.1100.0 to 2.1100.1 in /lifecycle/aws (#18922)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1100.0 to 2.1100.1.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1100.1/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1100.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-18 13:00:30 +01:00
authentik-automation[bot]
d01aa6bebf core, web: update translations (#18920)
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-12-18 12:57:02 +01:00
dependabot[bot]
cbbf315662 web: bump knip from 5.74.0 to 5.75.1 in /web (#18924)
Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 5.74.0 to 5.75.1.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/5.75.1/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 5.75.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-18 12:55:58 +01:00
dependabot[bot]
45ca767fd8 web: bump chromedriver from 143.0.1 to 143.0.2 in /web (#18926)
Bumps [chromedriver](https://github.com/giggio/node-chromedriver) from 143.0.1 to 143.0.2.
- [Commits](https://github.com/giggio/node-chromedriver/compare/143.0.1...143.0.2)

---
updated-dependencies:
- dependency-name: chromedriver
  dependency-version: 143.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-18 12:55:32 +01:00
dependabot[bot]
5d3e2e89e0 core: bump goauthentik/fips-debian from 189345a to 10dadf1 (#18927)
Bumps goauthentik/fips-debian from `189345a` to `10dadf1`.

---
updated-dependencies:
- dependency-name: goauthentik/fips-debian
  dependency-version: trixie-slim-fips
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-18 12:55:06 +01:00
Marcelo Elizeche Landó
5e2f261a0c tests/e2e: handle StaleElementReferenceException in parse_json_content (#18842)
Add retry logic and safer text recover
2025-12-17 20:27:03 -03:00
Tana M Berry
10a421e678 web/admin: add UI copy to RBAC modal (#18917)
add UI copy to RBAC modal
2025-12-17 20:23:20 +00:00
Marc 'risson' Schmitt
668ad3dadf root: fix docker-compose data mount (#18903) 2025-12-17 16:33:50 -03:00
João C. Fernandes
e7903d5391 core/groups: optimize prefetch queries to fetch only required fields (#18448)
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-12-17 17:15:31 +00:00
Jens L.
e38fffc44c web/admin: reword some things on the device view page (#18785)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-17 17:33:36 +01:00
Marc 'risson' Schmitt
4bc2bca448 website/docs: 2025.12: remove superfluous changes (#18910) 2025-12-17 16:24:12 +00:00
Jens L.
48916303d8 api: fix latest version for public schema (#18902) 2025-12-17 15:12:14 +00:00
Marc 'risson' Schmitt
d28109da6a ci/release-tag: checkout correct branch for make test-docker (#18880) 2025-12-17 15:08:05 +00:00
Marc 'risson' Schmitt
3bd299d52a api: fix page_size with invalid query param (#18879) 2025-12-17 15:06:22 +00:00
Tana M Berry
57418582c5 website/docs: added list of Int Guide contributors (also edited frontmatter) (#18888)
* alphabetize

* added frontmatter

* Apply suggestions from code review

Signed-off-by: Dominic R <dominic@sdko.org>

---------

Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-12-17 09:01:05 -06:00
Marc 'risson' Schmitt
f37958bcd0 tasks/middleware: close connections on worker status update database error (#18881) 2025-12-17 15:45:37 +01:00
dependabot[bot]
8931b621b4 core: bump goauthentik.io/api/v3 from 3.2026020.1 to 3.2026020.3 (#18892)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 13:24:57 +00:00
dependabot[bot]
9d3d96bab1 web: bump the eslint group across 1 directory with 5 updates (#18851)
Bumps the eslint group with 5 updates in the /web directory:

| Package | From | To |
| --- | --- | --- |
| [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) | `9.39.1` | `9.39.2` |
| [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.49.0` | `8.50.0` |
| [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.49.0` | `8.50.0` |
| [eslint](https://github.com/eslint/eslint) | `9.39.1` | `9.39.2` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.49.0` | `8.50.0` |



Updates `@eslint/js` from 9.39.1 to 9.39.2
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/commits/v9.39.2/packages/js)

Updates `@typescript-eslint/eslint-plugin` from 8.49.0 to 8.50.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.50.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.49.0 to 8.50.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.50.0/packages/parser)

Updates `eslint` from 9.39.1 to 9.39.2
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v9.39.1...v9.39.2)

Updates `typescript-eslint` from 8.49.0 to 8.50.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.50.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@eslint/js"
  dependency-version: 9.39.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.50.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.50.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: eslint
  dependency-version: 9.39.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.50.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 13:15:56 +01:00
dependabot[bot]
712f0ed95e web: bump the swc group across 1 directory with 11 updates (#18818)
Bumps the swc group with 1 update in the /web directory: [@swc/core](https://github.com/swc-project/swc).


Updates `@swc/core` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-darwin-arm64` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-darwin-x64` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-linux-arm-gnueabihf` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-linux-arm64-gnu` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-linux-arm64-musl` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-linux-x64-gnu` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-linux-x64-musl` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-win32-arm64-msvc` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-win32-ia32-msvc` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

Updates `@swc/core-win32-x64-msvc` from 1.15.3 to 1.15.4
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.15.3...v1.15.4)

---
updated-dependencies:
- dependency-name: "@swc/core"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-darwin-x64"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm-gnueabihf"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-arm64-musl"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-linux-x64-musl"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-arm64-msvc"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-ia32-msvc"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
- dependency-name: "@swc/core-win32-x64-msvc"
  dependency-version: 1.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: swc
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:32:37 +01:00
dependabot[bot]
1cd9c7bf9d web: bump the goauthentik group across 1 directory with 3 updates (#18819)
Bumps the goauthentik group with 3 updates in the /web directory: [@goauthentik/esbuild-plugin-live-reload](https://github.com/goauthentik/authentik/tree/HEAD/packages/esbuild-plugin-live-reload), [@goauthentik/eslint-config](https://github.com/goauthentik/authentik/tree/HEAD/packages/eslint-config) and [@goauthentik/prettier-config](https://github.com/goauthentik/authentik/tree/HEAD/packages/prettier-config).


Updates `@goauthentik/esbuild-plugin-live-reload` from 1.3.1 to 1.4.0
- [Release notes](https://github.com/goauthentik/authentik/releases)
- [Commits](https://github.com/goauthentik/authentik/commits/HEAD/packages/esbuild-plugin-live-reload)

Updates `@goauthentik/eslint-config` from 1.1.1 to 1.2.0
- [Release notes](https://github.com/goauthentik/authentik/releases)
- [Commits](https://github.com/goauthentik/authentik/commits/HEAD/packages/eslint-config)

Updates `@goauthentik/prettier-config` from 3.2.1 to 3.3.1
- [Release notes](https://github.com/goauthentik/authentik/releases)
- [Commits](https://github.com/goauthentik/authentik/commits/HEAD/packages/prettier-config)

---
updated-dependencies:
- dependency-name: "@goauthentik/esbuild-plugin-live-reload"
  dependency-version: 1.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: goauthentik
- dependency-name: "@goauthentik/eslint-config"
  dependency-version: 1.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: goauthentik
- dependency-name: "@goauthentik/prettier-config"
  dependency-version: 3.3.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: goauthentik
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:32:22 +01:00
dependabot[bot]
fb23751079 lifecycle/aws: bump aws-cdk from 2.1034.0 to 2.1100.0 in /lifecycle/aws (#18850)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1034.0 to 2.1100.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1100.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1100.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:32:01 +01:00
dependabot[bot]
e49aace000 web: bump @sentry/browser from 10.30.0 to 10.31.0 in /web in the sentry group across 1 directory (#18893)
web: bump @sentry/browser in /web in the sentry group across 1 directory

Bumps the sentry group with 1 update in the /web directory: [@sentry/browser](https://github.com/getsentry/sentry-javascript).


Updates `@sentry/browser` from 10.30.0 to 10.31.0
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/10.30.0...10.31.0)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 10.31.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: sentry
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:31:27 +01:00
dependabot[bot]
876b299f30 web: bump the bundler group across 1 directory with 7 updates (#18894)
Bumps the bundler group with 2 updates in the /web directory: [@vitest/browser](https://github.com/vitest-dev/vitest/tree/HEAD/packages/browser) and [esbuild](https://github.com/evanw/esbuild).


Updates `@vitest/browser` from 4.0.15 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/browser)

Updates `@vitest/browser-playwright` from 4.0.15 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/browser-playwright)

Updates `esbuild` from 0.27.1 to 0.27.2
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.27.1...v0.27.2)

Updates `vitest` from 4.0.15 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/vitest)

Updates `@esbuild/darwin-arm64` from 0.27.1 to 0.27.2
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.27.1...v0.27.2)

Updates `@esbuild/linux-arm64` from 0.27.1 to 0.27.2
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.27.1...v0.27.2)

Updates `@esbuild/linux-x64` from 0.27.1 to 0.27.2
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.27.1...v0.27.2)

---
updated-dependencies:
- dependency-name: "@vitest/browser"
  dependency-version: 4.0.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
- dependency-name: "@vitest/browser-playwright"
  dependency-version: 4.0.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
- dependency-name: esbuild
  dependency-version: 0.27.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
- dependency-name: vitest
  dependency-version: 4.0.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
- dependency-name: "@esbuild/darwin-arm64"
  dependency-version: 0.27.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
- dependency-name: "@esbuild/linux-arm64"
  dependency-version: 0.27.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
- dependency-name: "@esbuild/linux-x64"
  dependency-version: 0.27.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bundler
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:31:15 +01:00
dependabot[bot]
458439c396 web: bump the rollup group across 1 directory with 4 updates (#18852)
Bumps the rollup group with 4 updates in the /web directory: [@rollup/rollup-darwin-arm64](https://github.com/rollup/rollup), [@rollup/rollup-linux-arm64-gnu](https://github.com/rollup/rollup), [@rollup/rollup-linux-x64-gnu](https://github.com/rollup/rollup) and [rollup](https://github.com/rollup/rollup).


Updates `@rollup/rollup-darwin-arm64` from 4.53.3 to 4.53.4
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.3...v4.53.4)

Updates `@rollup/rollup-linux-arm64-gnu` from 4.53.3 to 4.53.4
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.3...v4.53.4)

Updates `@rollup/rollup-linux-x64-gnu` from 4.53.3 to 4.53.4
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.3...v4.53.4)

Updates `rollup` from 4.53.3 to 4.53.4
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.53.3...v4.53.4)

---
updated-dependencies:
- dependency-name: "@rollup/rollup-darwin-arm64"
  dependency-version: 4.53.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-arm64-gnu"
  dependency-version: 4.53.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-version: 4.53.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
- dependency-name: rollup
  dependency-version: 4.53.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:29:44 +01:00
dependabot[bot]
d3d0effe9d web: bump @types/node from 25.0.0 to 25.0.3 in /web (#18895)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.0.0 to 25.0.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:29:30 +01:00
dependabot[bot]
413b073191 web: bump knip from 5.73.3 to 5.74.0 in /web (#18896)
Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 5.73.3 to 5.74.0.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/5.74.0/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 5.74.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:28:48 +01:00
dependabot[bot]
46747ae3f2 core: bump goauthentik/fips-debian from 2f19fc1 to 189345a (#18897)
Bumps goauthentik/fips-debian from `2f19fc1` to `189345a`.

---
updated-dependencies:
- dependency-name: goauthentik/fips-debian
  dependency-version: trixie-slim-fips
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:28:39 +01:00
dependabot[bot]
d64a3aab39 core: bump astral-sh/uv from 0.9.17 to 0.9.18 (#18898)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.9.17 to 0.9.18.
- [Release notes](https://github.com/astral-sh/uv/releases)
- [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/uv/compare/0.9.17...0.9.18)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.9.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 12:28:28 +01:00
Dominic R
970cddae47 website/integrations: bookstack: fix redir url (#18891) 2025-12-17 08:42:50 +00:00
authentik-automation[bot]
24c4495ac2 core, web: update translations (#18807)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-12-17 00:42:03 +00:00
Dewi Roberts
ff38607fa3 web/admin: endpoint: change wording and add helper text (#18871)
* Change wording and add helper text

* Fix helper text

* Setup text change

* Update web/src/admin/endpoints/connectors/agent/AgentConnectorSetup.ts

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

* Update web/src/admin/endpoints/connectors/agent/AgentConnectorSetup.ts

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

* Update web/src/admin/endpoints/connectors/agent/EnrollmentTokenForm.ts

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

* Format.

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Co-authored-by: Teffen Ellis <teffen@sister.software>
2025-12-16 23:28:29 +00:00
Dominic R
eef8e57f6c web: fix file upload form (#18808)
* web: fix file upload form name mismatch and modal submit promise handling

Fixes the following error:

FileUploadForm.ts:74  POST http://authentik.localhost:9000/api/v3/admin/file/ 405 (Method Not Allowed)
(anonymous) @ fetch.ts:81
fetchApi @ runtime.ts:206
await in fetchApi
request @ runtime.ts:136
await in request
adminFileCreateRaw @ AdminApi.ts:191
adminFileCreate @ AdminApi.ts:206
send @ FileUploadForm.ts:74
submit @ Form.ts:363
(anonymous) @ ModalForm.ts:54
handleEvent @ lit-html.ts:2109
n @ helpers.ts:117Understand this error
Form.ts:403 authentik/forms: API rejected the form submission due to an invalid field that doesn't appear to be in the form. This is likely a bug in authentik. {detail: 'Response returned an error code'}
(anonymous) @ console.ts:39
(anonymous) @ Form.ts:403
Promise.catch
submit @ Form.ts:376
(anonymous) @ ModalForm.ts:54
handleEvent @ lit-html.ts:2109
n @ helpers.ts:117Understand this error
runtime.ts:140 Uncaught (in promise) ResponseError: Response returned an error code
    at mR.request (runtime.ts:140:15)
    at async mR.adminFileCreateRaw (AdminApi.ts:191:26)
    at async mR.adminFileCreate (AdminApi.ts:206:9)

- align file upload rename field with api name so validation errors map correctly
-improve custom filename extension logic to avoid double or incorrect  extensions
- prevent unhandled promise rejections from modal submit click handler and show  missing-form errors to users

* rev

* wip

* Update ModalForm.ts

Signed-off-by: Dominic R <dominic@sdko.org>

* scope better

* fix what it validates against

---------

Signed-off-by: Dominic R <dominic@sdko.org>
2025-12-16 18:37:22 +00:00
Jens L.
603820854b stages/authenticator_*: fix code input field not string (#18875)
* stages/authenticator_*: fix code input field not string

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* Update authentik/stages/authenticator_totp/stage.py

Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Jens L. <jens@beryju.org>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-12-16 19:10:48 +01:00
dependabot[bot]
4ad7f8be2a web: bump vite from 7.2.7 to 7.3.0 in /web (#18854)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.2.7 to 7.3.0.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.0/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.0/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-16 18:44:54 +01:00
Alexander Tereshkin
a605cd1e87 web: fix notification counter (#18781) 2025-12-16 18:41:11 +01:00
Alexander Tereshkin
936789f534 web: add custom message with links for empty data export list (#18830) 2025-12-16 17:36:12 +01:00
Jens L.
2f52d832ab website/docs: 2025.10.3 release notes (#18868)
* website/docs: 2025.10.3 release notes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-16 16:56:57 +01:00
Marcelo Elizeche Landó
036514730e website/docs: Add docs for passkey autofill (WebauthN Conditional UI) (#18805)
* Add docs for passkey autofill feature

* Apply suggestions from code review

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>

* improve configuration section

* remove blank lines

---------

Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-12-16 15:16:12 +00:00
Simonyi Gergő
d48129ba7b website/docs: adjust RBAC-related details in 2025.12 release notes (#18863)
* website/docs: adjust RBAC-related details in 2025.12 release notes

* adjust wording

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>

---------

Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-12-16 15:02:00 +00:00
Jens L.
d219f72ed6 outposts: fix permission errors for related certificates (#18861)
* outposts: fix permission errors for related certificates

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-16 15:01:25 +01:00
Simonyi Gergő
7b19045431 web/admin/rbac: misc object permission fixes (#18859)
* rbac: relabel "Assign role permissions" button

* fix object permissions in permissions table

This should have a backend-based fix in the future.
2025-12-16 14:33:25 +01:00
dependabot[bot]
0027813e4b core: bump library/golang from 5d35fb8 to 8e8f9c8 (#18855)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-16 13:09:10 +00:00
Simonyi Gergő
a6ebf1074f rbac: alter migrated direct permission roles (#18860)
These should not be marked as managed, because many of these permissions
were created by admins.
2025-12-16 13:40:49 +01:00
Marcelo Elizeche Landó
ea9689c493 core: add skip s3_test_server_available to TestResolveFileUrlS3Backend (#18858)
add skip s3_test_server_available to TestResolveFileUrlS3Backend
2025-12-16 12:59:13 +01:00
Jens L.
06e7335618 ci: replace codecov test-results action (#18862)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-12-16 12:50:54 +01:00
739 changed files with 19325 additions and 130568 deletions

View File

@@ -12,16 +12,17 @@ inputs:
runs:
using: "composite"
steps:
- name: Install apt deps
- name: Install apt deps & cleanup
if: ${{ contains(inputs.dependencies, 'system') || contains(inputs.dependencies, 'python') }}
shell: bash
run: |
sudo apt-get remove --purge man-db
sudo apt-get update
sudo apt-get install --no-install-recommends -y libpq-dev openssl libxmlsec1-dev pkg-config gettext libkrb5-dev krb5-kdc krb5-user krb5-admin-server
sudo rm -rf /usr/local/lib/android
- name: Install uv
if: ${{ contains(inputs.dependencies, 'python') }}
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v5
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v5
with:
enable-cache: true
- name: Setup python
@@ -43,20 +44,20 @@ runs:
registry-url: 'https://registry.npmjs.org'
- name: Setup go
if: ${{ contains(inputs.dependencies, 'go') }}
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v5
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v5
with:
go-version-file: "go.mod"
- name: Setup docker cache
if: ${{ contains(inputs.dependencies, 'runtime') }}
uses: AndreKurait/docker-cache@0fe76702a40db986d9663c24954fc14c6a6031b7
with:
key: docker-images-${{ runner.os }}-${{ hashFiles('.github/actions/setup/docker-compose.yml', 'Makefile') }}-${{ inputs.postgresql_version }}
key: docker-images-${{ runner.os }}-${{ hashFiles('.github/actions/setup/compose.yml', 'Makefile') }}-${{ inputs.postgresql_version }}
- name: Setup dependencies
if: ${{ contains(inputs.dependencies, 'runtime') }}
shell: bash
run: |
export PSQL_TAG=${{ inputs.postgresql_version }}
docker compose -f .github/actions/setup/docker-compose.yml up -d
docker compose -f .github/actions/setup/compose.yml up -d
cd web && npm i
- name: Generate config
if: ${{ contains(inputs.dependencies, 'python') }}

View File

@@ -11,11 +11,6 @@ services:
ports:
- 5432:5432
restart: always
redis:
image: docker.io/library/redis:7
ports:
- 6379:6379
restart: always
s3:
container_name: s3
image: docker.io/zenko/cloudserver

View File

@@ -12,15 +12,15 @@ runs:
with:
flags: ${{ inputs.flags }}
use_oidc: true
- uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1
- uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
with:
flags: ${{ inputs.flags }}
file: unittest.xml
use_oidc: true
report_type: test_results
- name: PostgreSQL Logs
shell: bash
run: |
if [[ $ACTIONS_RUNNER_DEBUG == 'true' || $ACTIONS_STEP_DEBUG == 'true' ]]; then
if [[ $RUNNER_DEBUG == '1' ]]; then
docker stop setup-postgresql-1
echo "::group::PostgreSQL Logs"
docker logs setup-postgresql-1

View File

@@ -44,7 +44,7 @@ jobs:
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -85,6 +85,7 @@ jobs:
id: push
with:
context: .
file: lifecycle/container/Dockerfile
push: ${{ steps.ev.outputs.shouldPush == 'true' }}
secrets: |
GEOIPUPDATE_ACCOUNT_ID=${{ secrets.GEOIPUPDATE_ACCOUNT_ID }}
@@ -95,7 +96,7 @@ jobs:
platforms: linux/${{ inputs.image_arch }}
cache-from: type=registry,ref=${{ steps.ev.outputs.attestImageNames }}:buildcache-${{ inputs.image_arch }}
cache-to: ${{ steps.ev.outputs.cacheTo }}
- uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:

View File

@@ -90,14 +90,14 @@ jobs:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: int128/docker-manifest-create-action@b60433fd4312d7a64a56d769b76ebe3f45cf36b4 # v2
- uses: int128/docker-manifest-create-action@6cdd53a8337cd50bc3ef8c7016579d8d460edd94 # v2
id: build
with:
tags: ${{ matrix.tag }}
sources: |
${{ steps.ev.outputs.attestImageNames }}@${{ needs.build-server-amd64.outputs.image-digest }}
${{ steps.ev.outputs.attestImageNames }}@${{ needs.build-server-arm64.outputs.image-digest }}
- uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
with:
subject-name: ${{ steps.ev.outputs.attestImageNames }}

View File

@@ -75,7 +75,7 @@ jobs:
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -101,7 +101,7 @@ jobs:
context: .
cache-from: type=registry,ref=ghcr.io/goauthentik/dev-docs:buildcache
cache-to: ${{ steps.ev.outputs.shouldPush == 'true' && 'type=registry,ref=ghcr.io/goauthentik/dev-docs:buildcache,mode=max' || '' }}
- uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:

View File

@@ -24,5 +24,5 @@ jobs:
dir="/tmp/authentik/${{ matrix.version }}"
mkdir -p $dir
cd $dir
wget https://${{ matrix.version }}.goauthentik.io/docker-compose.yml
wget https://${{ matrix.version }}.goauthentik.io/compose.yml
${current}/scripts/test_docker.sh

View File

@@ -84,7 +84,7 @@ jobs:
# Current version family based on
current_version_family=$(cat internal/constants/VERSION | grep -vE -- 'rc[0-9]+$' || true)
if [[ -n $current_version_family ]]; then
prev_stable=$current_version_family
prev_stable="version/${current_version_family}"
fi
echo "::notice::Checking out ${prev_stable} as stable version..."
git checkout ${prev_stable}
@@ -193,13 +193,15 @@ jobs:
glob: tests/e2e/test_source_scim*
- name: flows
glob: tests/e2e/test_flows*
- name: endpoints
glob: tests/e2e/test_endpoints_*
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Setup e2e env (chrome, etc)
run: |
docker compose -f tests/e2e/docker-compose.yml up -d --quiet-pull
docker compose -f tests/e2e/compose.yml up -d --quiet-pull
- id: cache-web
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v4
with:
@@ -221,6 +223,54 @@ jobs:
if: ${{ always() }}
with:
flags: e2e
test-openid-conformance:
name: test-openid-conformance (${{ matrix.job.name }})
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
job:
- name: basic
glob: tests/openid_conformance/test_basic.py
- name: implicit
glob: tests/openid_conformance/test_implicit.py
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Setup e2e env (chrome, etc)
run: |
docker compose -f tests/e2e/compose.yml up -d --quiet-pull
- name: Setup conformance suite
run: |
docker compose -f tests/openid_conformance/compose.yml up -d --quiet-pull
- id: cache-web
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v4
with:
path: web/dist
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
- name: prepare web ui
if: steps.cache-web.outputs.cache-hit != 'true'
working-directory: web
run: |
npm ci
make -C .. gen-client-ts
npm run build
npm run build:sfe
- name: run conformance
run: |
uv run coverage run manage.py test ${{ matrix.job.glob }}
uv run coverage xml
- uses: ./.github/actions/test-results
if: ${{ always() }}
with:
flags: conformance
- if: ${{ !cancelled() }}
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: conformance-certification-${{ matrix.job.name }}
path: tests/openid_conformance/exports/
ci-core-mark:
if: always()
needs:

View File

@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- name: Prepare and generate API
@@ -43,7 +43,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- name: Setup authentik env
@@ -92,7 +92,7 @@ jobs:
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -114,7 +114,7 @@ jobs:
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
tags: ${{ steps.ev.outputs.imageTags }}
file: ${{ matrix.type }}.Dockerfile
file: lifecycle/container/${{ matrix.type }}.Dockerfile
push: ${{ steps.ev.outputs.shouldPush == 'true' }}
build-args: |
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}
@@ -122,7 +122,7 @@ jobs:
context: .
cache-from: type=registry,ref=ghcr.io/goauthentik/dev-${{ matrix.type }}:buildcache
cache-to: ${{ steps.ev.outputs.shouldPush == 'true' && format('type=registry,ref=ghcr.io/goauthentik/dev-{0}:buildcache,mode=max', matrix.type) || '' }}
- uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:
@@ -148,7 +148,7 @@ jobs:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5

View File

@@ -35,7 +35,7 @@ jobs:
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -58,7 +58,7 @@ jobs:
push: true
platforms: linux/amd64,linux/arm64
context: .
- uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
if: true
with:
@@ -84,13 +84,13 @@ jobs:
- rac
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -121,10 +121,10 @@ jobs:
build-args: |
VERSION=${{ github.ref }}
tags: ${{ steps.ev.outputs.imageTags }}
file: ${{ matrix.type }}.Dockerfile
file: lifecycle/container/${{ matrix.type }}.Dockerfile
platforms: linux/amd64,linux/arm64
context: .
- uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
with:
subject-name: ${{ steps.ev.outputs.attestImageNames }}
@@ -147,7 +147,7 @@ jobs:
goarch: [amd64, arm64]
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
@@ -232,7 +232,7 @@ jobs:
container=$(docker container create ${{ steps.ev.outputs.imageMainName }})
docker cp ${container}:web/ .
- name: Create a Sentry.io release
uses: getsentry/action-release@128c5058bbbe93c8e02147fe0a9c713f166259a6 # v3
uses: getsentry/action-release@dab6548b3c03c4717878099e43782cf5be654289 # v3
continue-on-error: true
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

View File

@@ -49,8 +49,12 @@ jobs:
test:
name: Pre-release test
runs-on: ubuntu-latest
needs:
- check-inputs
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: "version-${{ needs.check-inputs.outputs.major_version }}"
- run: make test-docker
bump-authentik:
name: Bump authentik version

3
.gitignore vendored
View File

@@ -211,4 +211,5 @@ source_docs/
/vendor/
### Docker ###
docker-compose.override.yml
tests/openid_conformance/exports/*.zip
compose.override.yml

View File

@@ -16,10 +16,8 @@ go.sum @goauthentik/backend
# Infrastructure
.github/ @goauthentik/infrastructure
lifecycle/aws/ @goauthentik/infrastructure
Dockerfile @goauthentik/infrastructure
*Dockerfile @goauthentik/infrastructure
lifecycle/container/ @goauthentik/infrastructure
.dockerignore @goauthentik/infrastructure
docker-compose.yml @goauthentik/infrastructure
Makefile @goauthentik/infrastructure
.editorconfig @goauthentik/infrastructure
CODEOWNERS @goauthentik/infrastructure
@@ -40,7 +38,7 @@ packages/tsconfig @goauthentik/frontend
# Web
web/ @goauthentik/frontend
# Locale
locale/ @goauthentik/backend @goauthentik/frontend
/locale/ @goauthentik/backend @goauthentik/frontend
web/xliff/ @goauthentik/backend @goauthentik/frontend
# Docs
website/ @goauthentik/docs

112
Makefile
View File

@@ -20,24 +20,34 @@ GEN_API_TS = gen-ts-api
GEN_API_PY = gen-py-api
GEN_API_GO = gen-go-api
pg_user := $(shell uv run python -m authentik.lib.config postgresql.user 2>/dev/null)
pg_host := $(shell uv run python -m authentik.lib.config postgresql.host 2>/dev/null)
pg_name := $(shell uv run python -m authentik.lib.config postgresql.name 2>/dev/null)
BREW_LDFLAGS :=
BREW_CPPFLAGS :=
BREW_PKG_CONFIG_PATH :=
UV := uv
# For macOS users, add the libxml2 installed from brew libxmlsec1 to the build path
# to prevent SAML-related tests from failing and ensure correct pip dependency compilation
# These functions are only evaluated when called in specific targets
LIBXML2_EXISTS = $(shell brew list libxml2 2> /dev/null)
KRB5_EXISTS = $(shell brew list krb5 2> /dev/null)
LIBXML2_LDFLAGS = -L$(shell brew --prefix libxml2)/lib $(LDFLAGS)
LIBXML2_CPPFLAGS = -I$(shell brew --prefix libxml2)/include $(CPPFLAGS)
LIBXML2_PKG_CONFIG = $(shell brew --prefix libxml2)/lib/pkgconfig:$(PKG_CONFIG_PATH)
KRB_PATH =
ifneq ($(KRB5_EXISTS),)
KRB_PATH = PATH="$(shell brew --prefix krb5)/sbin:$(shell brew --prefix krb5)/bin:$$PATH"
ifeq ($(UNAME_S),Darwin)
# Only add for brew users who installed libxmlsec1
BREW_EXISTS := $(shell command -v brew 2> /dev/null)
ifdef BREW_EXISTS
LIBXML2_EXISTS := $(shell brew list libxml2 2> /dev/null)
ifdef LIBXML2_EXISTS
_xml_pref := $(shell brew --prefix libxml2)
BREW_LDFLAGS += -L${_xml_pref}/lib
BREW_CPPFLAGS += -I${_xml_pref}/include
BREW_PKG_CONFIG_PATH = ${_xml_pref}/lib/pkgconfig:$(PKG_CONFIG_PATH)
endif
KRB5_EXISTS := $(shell brew list krb5 2> /dev/null)
ifdef KRB5_EXISTS
_krb5_pref := $(shell brew --prefix krb5)
BREW_LDFLAGS += -L${_krb5_pref}/lib
BREW_CPPFLAGS += -I${_krb5_pref}/include
BREW_PKG_CONFIG_PATH = ${_krb5_pref}/lib/pkgconfig:$(PKG_CONFIG_PATH)
endif
UV := LDFLAGS="$(BREW_LDFLAGS)" CPPFLAGS="$(BREW_CPPFLAGS)" PKG_CONFIG_PATH="$(BREW_PKG_CONFIG_PATH)" uv
endif
endif
all: lint-fix lint gen web test ## Lint, build, and test everything
@@ -56,47 +66,47 @@ go-test:
go test -timeout 0 -v -race -cover ./...
test: ## Run the server tests and produce a coverage report (locally)
$(KRB_PATH) uv run coverage run manage.py test --keepdb $(or $(filter-out $@,$(MAKECMDGOALS)),authentik)
uv run coverage html
uv run coverage report
$(UV) run coverage run manage.py test --keepdb $(or $(filter-out $@,$(MAKECMDGOALS)),authentik)
$(UV) run coverage html
$(UV) run coverage report
lint-fix: lint-codespell ## Lint and automatically fix errors in the python source code. Reports spelling errors.
uv run black $(PY_SOURCES)
uv run ruff check --fix $(PY_SOURCES)
$(UV) run black $(PY_SOURCES)
$(UV) run ruff check --fix $(PY_SOURCES)
lint-codespell: ## Reports spelling errors.
uv run codespell -w
$(UV) run codespell -w
lint: ## Lint the python and golang sources
uv run bandit -c pyproject.toml -r $(PY_SOURCES)
$(UV) run bandit -c pyproject.toml -r $(PY_SOURCES)
golangci-lint run -v
core-install:
ifneq ($(LIBXML2_EXISTS),)
ifdef ($(BREW_EXISTS))
# Clear cache to ensure fresh compilation
uv cache clean
$(UV) cache clean
# Force compilation from source for lxml and xmlsec with correct environment
LDFLAGS="$(LIBXML2_LDFLAGS)" CPPFLAGS="$(LIBXML2_CPPFLAGS)" PKG_CONFIG_PATH="$(LIBXML2_PKG_CONFIG)" uv sync --frozen --reinstall-package lxml --reinstall-package xmlsec --no-binary-package lxml --no-binary-package xmlsec
$(UV) sync --frozen --reinstall-package lxml --reinstall-package xmlsec --no-binary-package lxml --no-binary-package xmlsec
else
uv sync --frozen
$(UV) sync --frozen
endif
migrate: ## Run the Authentik Django server's migrations
uv run python -m lifecycle.migrate
$(UV) run python -m lifecycle.migrate
i18n-extract: core-i18n-extract web-i18n-extract ## Extract strings that require translation into files to send to a translation service
aws-cfn:
cd lifecycle/aws && npm i && uv run npm run aws-cfn
cd lifecycle/aws && npm i && $(UV) run npm run aws-cfn
run-server: ## Run the main authentik server process
uv run ak server
$(UV) run ak server
run-worker: ## Run the main authentik worker process
uv run ak worker
$(UV) run ak worker
core-i18n-extract:
uv run ak makemessages \
$(UV) run ak makemessages \
--add-location file \
--no-obsolete \
--ignore web \
@@ -109,11 +119,17 @@ core-i18n-extract:
install: node-install docs-install core-install ## Install all requires dependencies for `node`, `docs` and `core`
dev-drop-db:
$(eval pg_user := $(shell $(UV) run python -m authentik.lib.config postgresql.user 2>/dev/null))
$(eval pg_host := $(shell $(UV) run python -m authentik.lib.config postgresql.host 2>/dev/null))
$(eval pg_name := $(shell $(UV) run python -m authentik.lib.config postgresql.name 2>/dev/null))
dropdb -U ${pg_user} -h ${pg_host} ${pg_name} || true
# Also remove the test-db if it exists
dropdb -U ${pg_user} -h ${pg_host} test_${pg_name} || true
dev-create-db:
$(eval pg_user := $(shell $(UV) run python -m authentik.lib.config postgresql.user 2>/dev/null))
$(eval pg_host := $(shell $(UV) run python -m authentik.lib.config postgresql.host 2>/dev/null))
$(eval pg_name := $(shell $(UV) run python -m authentik.lib.config postgresql.name 2>/dev/null))
createdb -U ${pg_user} -h ${pg_host} ${pg_name}
dev-reset: dev-drop-db dev-create-db migrate ## Drop and restore the Authentik PostgreSQL instance to a "fresh install" state.
@@ -141,14 +157,10 @@ gen-build: ## Extract the schema from the database
AUTHENTIK_DEBUG=true \
AUTHENTIK_TENANTS__ENABLED=true \
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
uv run ak make_blueprint_schema --file blueprints/schema.json
AUTHENTIK_DEBUG=true \
AUTHENTIK_TENANTS__ENABLED=true \
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
uv run ak spectacular --file schema.yml
$(UV) run ak build_schema
gen-compose:
uv run scripts/generate_docker_compose.py
$(UV) run scripts/generate_compose.py
gen-changelog: ## (Release) generate the changelog based from the commits since the last tag
git log --pretty=format:" - %s" $(shell git describe --tags $(shell git rev-list --tags --max-count=1))...$(shell git branch --show-current) | sort > changelog.md
@@ -156,7 +168,7 @@ gen-changelog: ## (Release) generate the changelog based from the commits since
gen-diff: ## (Release) generate the changelog diff between the current schema and the last tag
git show $(shell git describe --tags $(shell git rev-list --tags --max-count=1)):schema.yml > schema-old.yml
docker compose -f scripts/api/docker-compose.yml run --rm --user "${UID}:${GID}" diff \
docker compose -f scripts/api/compose.yml run --rm --user "${UID}:${GID}" diff \
--markdown \
/local/diff.md \
/local/schema-old.yml \
@@ -179,7 +191,7 @@ gen-clean-go: ## Remove generated API client for Go
gen-clean: gen-clean-ts gen-clean-go gen-clean-py ## Remove generated API clients
gen-client-ts: gen-clean-ts ## Build and install the authentik API for Typescript into the authentik UI Application
docker compose -f scripts/api/docker-compose.yml run --rm --user "${UID}:${GID}" gen \
docker compose -f scripts/api/compose.yml run --rm --user "${UID}:${GID}" gen \
generate \
-i /local/schema.yml \
-g typescript-fetch \
@@ -216,7 +228,7 @@ endif
go mod edit -replace goauthentik.io/api/v3=./${GEN_API_GO}
gen-dev-config: ## Generate a local development config file
uv run scripts/generate_config.py
$(UV) run scripts/generate_config.py
gen: gen-build gen-client-ts
@@ -300,7 +312,7 @@ docs-api-clean: ## Clean generated API documentation
docker: ## Build a docker image of the current source tree
mkdir -p ${GEN_API_TS}
DOCKER_BUILDKIT=1 docker build . --progress plain --tag ${DOCKER_IMAGE}
DOCKER_BUILDKIT=1 docker build . -f lifecycle/container/Dockerfile --progress plain --tag ${DOCKER_IMAGE}
test-docker:
BUILD=true ${PWD}/scripts/test_docker.sh
@@ -316,24 +328,24 @@ ci--meta-debug:
node --version
ci-mypy: ci--meta-debug
uv run mypy --strict $(PY_SOURCES)
$(UV) run mypy --strict $(PY_SOURCES)
ci-black: ci--meta-debug
uv run black --check $(PY_SOURCES)
$(UV) run black --check $(PY_SOURCES)
ci-ruff: ci--meta-debug
uv run ruff check $(PY_SOURCES)
$(UV) run ruff check $(PY_SOURCES)
ci-codespell: ci--meta-debug
uv run codespell -s
$(UV) run codespell -s
ci-bandit: ci--meta-debug
uv run bandit -r $(PY_SOURCES)
$(UV) run bandit -r $(PY_SOURCES)
ci-pending-migrations: ci--meta-debug
uv run ak makemigrations --check
$(UV) run ak makemigrations --check
ci-test: ci--meta-debug
uv run coverage run manage.py test --keepdb --randomly-seed ${CI_TEST_SEED} authentik
uv run coverage report
uv run coverage xml
$(UV) run coverage run manage.py test --keepdb authentik
$(UV) run coverage report
$(UV) run coverage xml

View File

@@ -20,8 +20,8 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni
| Version | Supported |
| ---------- | ---------- |
| 2025.8.x | ✅ |
| 2025.10.x | ✅ |
| 2025.12.x | ✅ |
## Reporting a Vulnerability

View File

@@ -37,7 +37,7 @@ class VersionSerializer(PassiveSerializer):
def get_version_latest(self, _) -> str:
"""Get latest version from cache"""
if get_current_tenant().schema_name == get_public_schema_name():
if get_current_tenant().schema_name != get_public_schema_name():
return authentik_version()
version_in_cache = cache.get(VERSION_CACHE_KEY)
if not version_in_cache: # pragma: no cover

View File

@@ -1,10 +1,16 @@
"""Test file service layer"""
from unittest import skipUnless
from django.http import HttpRequest
from django.test import TestCase
from authentik.admin.files.manager import FileManager
from authentik.admin.files.tests.utils import FileTestFileBackendMixin, FileTestS3BackendMixin
from authentik.admin.files.tests.utils import (
FileTestFileBackendMixin,
FileTestS3BackendMixin,
s3_test_server_available,
)
from authentik.admin.files.usage import FileUsage
from authentik.lib.config import CONFIG
@@ -81,6 +87,7 @@ class TestResolveFileUrlFileBackend(FileTestFileBackendMixin, TestCase):
self.assertEqual(result, "http://example.com/files/media/public/test.png")
@skipUnless(s3_test_server_available(), "S3 test server not available")
class TestResolveFileUrlS3Backend(FileTestS3BackendMixin, TestCase):
@CONFIG.patch("storage.media.s3.custom_domain", "s3.test:8080/test")
@CONFIG.patch("storage.media.s3.secure_urls", False)

View File

@@ -62,10 +62,10 @@ class TestSanitizeFilePath(TestCase):
"test@file.png", # @
"test#file.png", # #
"test$file.png", # $
"test%file.png", # %
"test%file.png", # % (but %(theme)s is allowed)
"test&file.png", # &
"test*file.png", # *
"test(file).png", # parentheses
"test(file).png", # parentheses (but %(theme)s is allowed)
"test[file].png", # brackets
"test{file}.png", # braces
]
@@ -108,3 +108,30 @@ class TestSanitizeFilePath(TestCase):
with self.assertRaises(ValidationError):
validate_file_name(path)
def test_sanitize_theme_variable_valid(self):
"""Test sanitizing filename with %(theme)s variable"""
# These should all be valid
validate_file_name("logo-%(theme)s.png")
validate_file_name("brand/logo-%(theme)s.svg")
validate_file_name("images/icon-%(theme)s.png")
validate_file_name("%(theme)s/logo.png")
validate_file_name("brand/%(theme)s/logo.png")
def test_sanitize_theme_variable_multiple(self):
"""Test sanitizing filename with multiple %(theme)s variables"""
validate_file_name("%(theme)s/logo-%(theme)s.png")
def test_sanitize_theme_variable_invalid_format(self):
"""Test that partial or malformed theme variables are rejected"""
invalid_paths = [
"test%(theme.png", # missing )s
"test%theme)s.png", # missing (
"test%(themes).png", # wrong variable name
"test%(THEME)s.png", # wrong case
"test%()s.png", # empty variable name
]
for path in invalid_paths:
with self.assertRaises(ValidationError):
validate_file_name(path)

View File

@@ -12,6 +12,10 @@ from authentik.admin.files.usage import FileUsage
MAX_FILE_NAME_LENGTH = 1024
MAX_PATH_COMPONENT_LENGTH = 255
# Theme variable placeholder that can be used in file paths
# This allows for theme-specific files like logo-%(theme)s.png
THEME_VARIABLE = "%(theme)s"
def validate_file_name(name: str) -> None:
if PassthroughBackend(FileUsage.MEDIA).supports_file(name) or StaticBackend(
@@ -39,12 +43,17 @@ def validate_upload_file_name(
if not name:
raise ValidationError(_("File name cannot be empty"))
# Same regex is used in the frontend as well
if not re.match(r"^[a-zA-Z0-9._/-]+$", name):
# Allow %(theme)s placeholder for theme-specific files
# We temporarily replace it for validation, then check the result
name_for_validation = name.replace(THEME_VARIABLE, "theme")
# Same regex is used in the frontend as well (without %(theme)s handling there)
if not re.match(r"^[a-zA-Z0-9._/-]+$", name_for_validation):
raise ValidationError(
_(
"File name can only contain letters (a-z, A-Z), numbers (0-9), "
"dots (.), hyphens (-), underscores (_), and forward slashes (/)"
"dots (.), hyphens (-), underscores (_), forward slashes (/), "
"and the special placeholder %(theme)s for theme-specific files"
)
)

View File

@@ -0,0 +1,45 @@
from json import dumps
from django.core.management.base import BaseCommand, no_translations
from drf_spectacular.drainage import GENERATOR_STATS
from drf_spectacular.generators import SchemaGenerator
from drf_spectacular.renderers import OpenApiYamlRenderer
from drf_spectacular.validation import validate_schema
from structlog.stdlib import get_logger
from authentik.blueprints.v1.schema import SchemaBuilder
class Command(BaseCommand):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.logger = get_logger()
def add_arguments(self, parser):
parser.add_argument("--blueprint-file", type=str, default="blueprints/schema.json")
parser.add_argument("--api-file", type=str, default="schema.yml")
@no_translations
def handle(self, *args, blueprint_file: str, api_file: str, **options):
self.build_blueprint(blueprint_file)
self.build_api(api_file)
def build_blueprint(self, file: str):
self.logger.debug("Building blueprint schema...", file=file)
blueprint_builder = SchemaBuilder()
blueprint_builder.build()
with open(file, "w") as _schema:
_schema.write(
dumps(blueprint_builder.schema, indent=4, default=SchemaBuilder.json_default)
)
def build_api(self, file: str):
self.logger.debug("Building API schema...", file=file)
generator = SchemaGenerator()
schema = generator.get_schema(request=None, public=True)
GENERATOR_STATS.emit_summary()
validate_schema(schema)
output = OpenApiYamlRenderer().render(schema, renderer_context={})
with open(file, "wb") as f:
f.write(output)

View File

@@ -15,7 +15,9 @@ class Pagination(pagination.PageNumberPagination):
def get_page_size(self, request):
if self.page_size_query_param in request.query_params:
return min(super().get_page_size(request), request.tenant.pagination_max_page_size)
page_size = super().get_page_size(request)
if page_size is not None:
return min(super().get_page_size(request), request.tenant.pagination_max_page_size)
return request.tenant.pagination_default_page_size
def get_paginated_response(self, data):

View File

@@ -1,9 +1,14 @@
"""Schema generation tests"""
from pathlib import Path
from django.core.management import call_command
from django.urls import reverse
from rest_framework.test import APITestCase
from yaml import safe_load
from authentik.lib.config import CONFIG
class TestSchemaGeneration(APITestCase):
"""Generic admin tests"""
@@ -21,3 +26,18 @@ class TestSchemaGeneration(APITestCase):
reverse("authentik_api:schema-browser"),
)
self.assertEqual(response.status_code, 200)
def test_build_schema(self):
"""Test schema build command"""
blueprint_file = Path("blueprints/schema.json")
api_file = Path("schema.yml")
blueprint_file.unlink()
api_file.unlink()
with (
CONFIG.patch("debug", True),
CONFIG.patch("tenants.enabled", True),
CONFIG.patch("outposts.disable_embedded_outpost", True),
):
call_command("build_schema")
self.assertTrue(blueprint_file.exists())
self.assertTrue(api_file.exists())

View File

@@ -31,6 +31,7 @@ class Capabilities(models.TextChoices):
"""Define capabilities which influence which APIs can/should be used"""
CAN_SAVE_MEDIA = "can_save_media"
CAN_SAVE_REPORTS = "can_save_reports"
CAN_GEO_IP = "can_geo_ip"
CAN_ASN = "can_asn"
CAN_IMPERSONATE = "can_impersonate"
@@ -70,6 +71,8 @@ class ConfigView(APIView):
caps = []
if get_file_manager(FileUsage.MEDIA).manageable:
caps.append(Capabilities.CAN_SAVE_MEDIA)
if get_file_manager(FileUsage.REPORTS).manageable:
caps.append(Capabilities.CAN_SAVE_REPORTS)
for processor in get_context_processors():
if cap := processor.capability():
caps.append(cap)

View File

@@ -8,45 +8,62 @@ metadata:
- Application (icon)
- Source (icon)
- Flow (background)
- Endpoint Enrollment token (key)
entries:
- model: authentik_core.token
identifiers:
identifier: "%(uid)s-token"
attrs:
key: "%(uid)s"
user: "%(user)s"
intent: api
- model: authentik_core.application
identifiers:
slug: "%(uid)s-app"
attrs:
name: "%(uid)s-app"
icon: https://goauthentik.io/img/icon.png
- model: authentik_sources_oauth.oauthsource
identifiers:
slug: "%(uid)s-source"
attrs:
name: "%(uid)s-source"
provider_type: azuread
consumer_key: "%(uid)s"
consumer_secret: "%(uid)s"
icon: https://goauthentik.io/img/icon.png
- model: authentik_flows.flow
identifiers:
slug: "%(uid)s-flow"
attrs:
name: "%(uid)s-flow"
title: "%(uid)s-flow"
designation: authentication
background: https://goauthentik.io/img/icon.png
- model: authentik_core.user
identifiers:
username: "%(uid)s"
attrs:
name: "%(uid)s"
password: "%(uid)s"
- model: authentik_core.user
identifiers:
username: "%(uid)s-no-password"
attrs:
name: "%(uid)s"
token:
- model: authentik_core.token
identifiers:
identifier: "%(uid)s-token"
attrs:
key: "%(uid)s"
user: "%(user)s"
intent: api
app:
- model: authentik_core.application
identifiers:
slug: "%(uid)s-app"
attrs:
name: "%(uid)s-app"
icon: https://goauthentik.io/img/icon.png
source:
- model: authentik_sources_oauth.oauthsource
identifiers:
slug: "%(uid)s-source"
attrs:
name: "%(uid)s-source"
provider_type: azuread
consumer_key: "%(uid)s"
consumer_secret: "%(uid)s"
icon: https://goauthentik.io/img/icon.png
flow:
- model: authentik_flows.flow
identifiers:
slug: "%(uid)s-flow"
attrs:
name: "%(uid)s-flow"
title: "%(uid)s-flow"
designation: authentication
background: https://goauthentik.io/img/icon.png
user:
- model: authentik_core.user
identifiers:
username: "%(uid)s"
attrs:
name: "%(uid)s"
password: "%(uid)s"
- model: authentik_core.user
identifiers:
username: "%(uid)s-no-password"
attrs:
name: "%(uid)s"
endpoint:
- model: authentik_endpoints_connectors_agent.agentconnector
id: connector
identifiers:
name: "%(uid)s"
- model: authentik_endpoints_connectors_agent.enrollmenttoken
identifiers:
name: "%(uid)s"
attrs:
key: "%(uid)s"
connector: !KeyOf connector

View File

@@ -5,6 +5,7 @@ from django.test import TransactionTestCase
from authentik.blueprints.v1.importer import Importer
from authentik.core.models import Token, User
from authentik.core.tests.utils import create_test_admin_user
from authentik.endpoints.connectors.agent.models import EnrollmentToken
from authentik.lib.generators import generate_id
from authentik.lib.tests.utils import load_fixture
@@ -29,12 +30,18 @@ class TestBlueprintsV1ConditionalFields(TransactionTestCase):
def test_user(self):
"""Test user"""
user: User = User.objects.filter(username=self.uid).first()
user = User.objects.filter(username=self.uid).first()
self.assertIsNotNone(user)
self.assertTrue(user.check_password(self.uid))
def test_user_null(self):
"""Test user"""
user: User = User.objects.filter(username=f"{self.uid}-no-password").first()
user = User.objects.filter(username=f"{self.uid}-no-password").first()
self.assertIsNotNone(user)
self.assertFalse(user.has_usable_password())
def test_enrollment_token(self):
"""Test endpoint enrollment token"""
token = EnrollmentToken.objects.filter(name=self.uid).first()
self.assertIsNotNone(token)
self.assertEqual(token.key, self.uid)

View File

@@ -149,7 +149,7 @@ class TestBlueprintsV1Tasks(TransactionTestCase):
instance.status,
BlueprintInstanceStatus.UNKNOWN,
)
apply_blueprint(instance.pk)
apply_blueprint.send(instance.pk).get_result(block=True)
instance.refresh_from_db()
self.assertEqual(instance.last_applied_hash, "")
self.assertEqual(

View File

@@ -9,7 +9,7 @@ from functools import reduce
from json import JSONDecodeError, loads
from operator import ixor
from os import getenv
from typing import Any, Literal, Union
from typing import Any, Literal
from uuid import UUID
from deepmerge import always_merger
@@ -70,19 +70,17 @@ class BlueprintEntryDesiredState(Enum):
class BlueprintEntryPermission:
"""Describe object-level permissions"""
permission: Union[str, "YAMLTag"]
user: Union[int, "YAMLTag", None] = field(default=None)
role: Union[str, "YAMLTag", None] = field(default=None)
permission: str | YAMLTag
user: int | YAMLTag | None = field(default=None)
role: str | YAMLTag | None = field(default=None)
@dataclass
class BlueprintEntry:
"""Single entry of a blueprint"""
model: Union[str, "YAMLTag"]
state: Union[BlueprintEntryDesiredState, "YAMLTag"] = field(
default=BlueprintEntryDesiredState.PRESENT
)
model: str | YAMLTag
state: BlueprintEntryDesiredState | YAMLTag = field(default=BlueprintEntryDesiredState.PRESENT)
conditions: list[Any] = field(default_factory=list)
identifiers: dict[str, Any] = field(default_factory=dict)
attrs: dict[str, Any] | None = field(default_factory=dict)
@@ -96,7 +94,7 @@ class BlueprintEntry:
self.__tag_contexts: list[YAMLTagContext] = []
@staticmethod
def from_model(model: SerializerModel, *extra_identifier_names: str) -> "BlueprintEntry":
def from_model(model: SerializerModel, *extra_identifier_names: str) -> BlueprintEntry:
"""Convert a SerializerModel instance to a blueprint Entry"""
identifiers = {
"pk": model.pk,
@@ -114,8 +112,8 @@ class BlueprintEntry:
def get_tag_context(
self,
depth: int = 0,
context_tag_type: type["YAMLTagContext"] | tuple["YAMLTagContext", ...] | None = None,
) -> "YAMLTagContext":
context_tag_type: type[YAMLTagContext] | tuple[YAMLTagContext, ...] | None = None,
) -> YAMLTagContext:
"""Get a YAMLTagContext object located at a certain depth in the tag tree"""
if depth < 0:
raise ValueError("depth must be a positive number or zero")
@@ -130,7 +128,7 @@ class BlueprintEntry:
except IndexError as exc:
raise ValueError(f"invalid depth: {depth}. Max depth: {len(contexts) - 1}") from exc
def tag_resolver(self, value: Any, blueprint: "Blueprint") -> Any:
def tag_resolver(self, value: Any, blueprint: Blueprint) -> Any:
"""Check if we have any special tags that need handling"""
val = copy(value)
@@ -152,23 +150,23 @@ class BlueprintEntry:
return val
def get_attrs(self, blueprint: "Blueprint") -> dict[str, Any]:
def get_attrs(self, blueprint: Blueprint) -> dict[str, Any]:
"""Get attributes of this entry, with all yaml tags resolved"""
return self.tag_resolver(self.attrs, blueprint)
def get_identifiers(self, blueprint: "Blueprint") -> dict[str, Any]:
def get_identifiers(self, blueprint: Blueprint) -> dict[str, Any]:
"""Get attributes of this entry, with all yaml tags resolved"""
return self.tag_resolver(self.identifiers, blueprint)
def get_state(self, blueprint: "Blueprint") -> BlueprintEntryDesiredState:
def get_state(self, blueprint: Blueprint) -> BlueprintEntryDesiredState:
"""Get the blueprint state, with yaml tags resolved if present"""
return BlueprintEntryDesiredState(self.tag_resolver(self.state, blueprint))
def get_model(self, blueprint: "Blueprint") -> str:
def get_model(self, blueprint: Blueprint) -> str:
"""Get the blueprint model, with yaml tags resolved if present"""
return str(self.tag_resolver(self.model, blueprint))
def get_permissions(self, blueprint: "Blueprint") -> Generator[BlueprintEntryPermission]:
def get_permissions(self, blueprint: Blueprint) -> Generator[BlueprintEntryPermission]:
"""Get permissions of this entry, with all yaml tags resolved"""
for perm in self.permissions:
yield BlueprintEntryPermission(
@@ -177,7 +175,7 @@ class BlueprintEntry:
role=self.tag_resolver(perm.role, blueprint),
)
def check_all_conditions_match(self, blueprint: "Blueprint") -> bool:
def check_all_conditions_match(self, blueprint: Blueprint) -> bool:
"""Check all conditions of this entry match (evaluate to True)"""
return all(self.tag_resolver(self.conditions, blueprint))
@@ -232,7 +230,7 @@ class KeyOf(YAMLTag):
id_from: str
def __init__(self, loader: "BlueprintLoader", node: ScalarNode) -> None:
def __init__(self, loader: BlueprintLoader, node: ScalarNode) -> None:
super().__init__()
self.id_from = node.value
@@ -258,7 +256,7 @@ class Env(YAMLTag):
key: str
default: Any | None
def __init__(self, loader: "BlueprintLoader", node: ScalarNode | SequenceNode) -> None:
def __init__(self, loader: BlueprintLoader, node: ScalarNode | SequenceNode) -> None:
super().__init__()
self.default = None
if isinstance(node, ScalarNode):
@@ -277,7 +275,7 @@ class File(YAMLTag):
path: str
default: Any | None
def __init__(self, loader: "BlueprintLoader", node: ScalarNode | SequenceNode) -> None:
def __init__(self, loader: BlueprintLoader, node: ScalarNode | SequenceNode) -> None:
super().__init__()
self.default = None
if isinstance(node, ScalarNode):
@@ -305,7 +303,7 @@ class Context(YAMLTag):
key: str
default: Any | None
def __init__(self, loader: "BlueprintLoader", node: ScalarNode | SequenceNode) -> None:
def __init__(self, loader: BlueprintLoader, node: ScalarNode | SequenceNode) -> None:
super().__init__()
self.default = None
if isinstance(node, ScalarNode):
@@ -328,7 +326,7 @@ class ParseJSON(YAMLTag):
raw: str
def __init__(self, loader: "BlueprintLoader", node: ScalarNode) -> None:
def __init__(self, loader: BlueprintLoader, node: ScalarNode) -> None:
super().__init__()
self.raw = node.value
@@ -345,7 +343,7 @@ class Format(YAMLTag):
format_string: str
args: list[Any]
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
super().__init__()
self.format_string = loader.construct_object(node.value[0])
self.args = []
@@ -372,7 +370,7 @@ class Find(YAMLTag):
model_name: str | YAMLTag
conditions: list[list]
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
super().__init__()
self.model_name = loader.construct_object(node.value[0])
self.conditions = []
@@ -444,7 +442,7 @@ class Condition(YAMLTag):
"XNOR": lambda args: not (reduce(ixor, args) if len(args) > 1 else args[0]),
}
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
super().__init__()
self.mode = loader.construct_object(node.value[0])
self.args = []
@@ -478,7 +476,7 @@ class If(YAMLTag):
when_true: Any
when_false: Any
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
super().__init__()
self.condition = loader.construct_object(node.value[0])
if len(node.value) == 1:
@@ -518,7 +516,7 @@ class Enumerate(YAMLTag, YAMLTagContext):
),
}
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
super().__init__()
self.iterable = loader.construct_object(node.value[0])
self.output_body = loader.construct_object(node.value[1])
@@ -584,7 +582,7 @@ class EnumeratedItem(YAMLTag):
_SUPPORTED_CONTEXT_TAGS = (Enumerate,)
def __init__(self, _loader: "BlueprintLoader", node: ScalarNode) -> None:
def __init__(self, _loader: BlueprintLoader, node: ScalarNode) -> None:
super().__init__()
self.depth = int(node.value)
@@ -640,7 +638,7 @@ class AtIndex(YAMLTag):
attribute: int | str | YAMLTag
default: Any | UNSET
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
super().__init__()
self.obj = loader.construct_object(node.value[0])
self.attribute = loader.construct_object(node.value[1])
@@ -757,7 +755,7 @@ class EntryInvalidError(SentryIgnoredException):
@staticmethod
def from_entry(
msg_or_exc: str | Exception, entry: BlueprintEntry, *args, **kwargs
) -> "EntryInvalidError":
) -> EntryInvalidError:
"""Create EntryInvalidError with the context of an entry"""
error = EntryInvalidError(msg_or_exc, *args, **kwargs)
if isinstance(msg_or_exc, ValidationError):

View File

@@ -15,7 +15,6 @@ from django.db.models import Model
from django.db.models.query_utils import Q
from django.db.transaction import atomic
from django.db.utils import IntegrityError
from django_channels_postgres.models import GroupChannel, Message
from guardian.models import RoleObjectPermission, UserObjectPermission
from rest_framework.exceptions import ValidationError
from rest_framework.serializers import BaseSerializer, Serializer
@@ -41,55 +40,17 @@ from authentik.core.models import (
User,
UserSourceConnection,
)
from authentik.endpoints.connectors.agent.models import (
AgentDeviceConnection,
AppleNonce,
DeviceAuthenticationToken,
)
from authentik.endpoints.connectors.agent.models import (
DeviceToken as EndpointDeviceToken,
)
from authentik.endpoints.models import Connector, Device, DeviceConnection, DeviceFactSnapshot
from authentik.endpoints.models import Connector
from authentik.enterprise.license import LicenseKey
from authentik.enterprise.models import LicenseUsage
from authentik.enterprise.providers.google_workspace.models import (
GoogleWorkspaceProviderGroup,
GoogleWorkspaceProviderUser,
)
from authentik.enterprise.providers.microsoft_entra.models import (
MicrosoftEntraProviderGroup,
MicrosoftEntraProviderUser,
)
from authentik.enterprise.providers.ssf.models import StreamEvent
from authentik.enterprise.stages.authenticator_endpoint_gdtc.models import (
EndpointDevice,
EndpointDeviceConnection,
)
from authentik.events.logs import LogEvent, capture_logs
from authentik.events.utils import cleanse_dict
from authentik.flows.models import FlowToken, Stage
from authentik.lib.models import SerializerModel
from authentik.flows.models import Stage
from authentik.lib.models import InternallyManagedMixin, SerializerModel
from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.reflection import get_apps
from authentik.outposts.models import OutpostServiceConnection
from authentik.policies.models import Policy, PolicyBindingModel
from authentik.policies.reputation.models import Reputation
from authentik.providers.oauth2.models import (
AccessToken,
AuthorizationCode,
DeviceToken,
RefreshToken,
)
from authentik.providers.proxy.models import ProxySession
from authentik.providers.rac.models import ConnectionToken
from authentik.providers.saml.models import SAMLSession
from authentik.providers.scim.models import SCIMProviderGroup, SCIMProviderUser
from authentik.rbac.models import Role
from authentik.sources.scim.models import SCIMSourceGroup, SCIMSourceUser
from authentik.stages.authenticator_webauthn.models import WebAuthnDeviceType
from authentik.stages.consent.models import UserConsent
from authentik.tasks.models import Task, TaskLog
from authentik.tenants.models import Tenant
# Context set when the serializer is created in a blueprint context
# Update website/docs/customize/blueprints/v1/models.md when used
@@ -125,49 +86,16 @@ def excluded_models() -> list[type[Model]]:
# 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
FlowToken,
LicenseUsage,
SCIMProviderGroup,
SCIMProviderUser,
Tenant,
Task,
TaskLog,
ConnectionToken,
AuthorizationCode,
AccessToken,
RefreshToken,
ProxySession,
Reputation,
WebAuthnDeviceType,
SCIMSourceUser,
SCIMSourceGroup,
GoogleWorkspaceProviderUser,
GoogleWorkspaceProviderGroup,
MicrosoftEntraProviderUser,
MicrosoftEntraProviderGroup,
EndpointDevice,
EndpointDeviceConnection,
EndpointDeviceToken,
Device,
DeviceConnection,
DeviceAuthenticationToken,
AppleNonce,
AgentDeviceConnection,
DeviceFactSnapshot,
DeviceToken,
StreamEvent,
UserConsent,
SAMLSession,
Message,
GroupChannel,
)
def is_model_allowed(model: type[Model]) -> bool:
"""Check if model is allowed"""
return model not in excluded_models() and issubclass(model, SerializerModel | BaseMetaModel)
return (
model not in excluded_models()
and issubclass(model, SerializerModel | BaseMetaModel)
and not issubclass(model, InternallyManagedMixin)
)
class DoRollback(SentryIgnoredException):
@@ -219,7 +147,7 @@ class Importer:
}
@staticmethod
def from_string(yaml_input: str, context: dict | None = None) -> "Importer":
def from_string(yaml_input: str, context: dict | None = None) -> Importer:
"""Parse YAML string and create blueprint importer from it"""
import_dict = load(yaml_input, BlueprintLoader)
try:

View File

@@ -23,7 +23,7 @@ class ApplyBlueprintMetaSerializer(PassiveSerializer):
# We cannot override `instance` as that will confuse rest_framework
# and make it attempt to update the instance
blueprint_instance: "BlueprintInstance"
blueprint_instance: BlueprintInstance
def validate(self, attrs):
from authentik.blueprints.models import BlueprintInstance
@@ -37,14 +37,21 @@ class ApplyBlueprintMetaSerializer(PassiveSerializer):
return super().validate(attrs)
def create(self, validated_data: dict) -> MetaResult:
from authentik.blueprints.v1.tasks import apply_blueprint
from authentik.blueprints.v1.importer import Importer
if not self.blueprint_instance:
LOGGER.info("Blueprint does not exist, but not required")
return MetaResult()
LOGGER.debug("Applying blueprint from meta model", blueprint=self.blueprint_instance)
apply_blueprint(self.blueprint_instance.pk)
# Apply blueprint directly using Importer to avoid task context requirements
# and prevent deadlocks when called from within another blueprint task
blueprint_content = self.blueprint_instance.retrieve()
importer = Importer.from_string(blueprint_content, self.blueprint_instance.context)
valid, logs = importer.validate()
[log.log() for log in logs]
if valid:
importer.apply()
return MetaResult()

View File

@@ -1,9 +1,7 @@
"""Generate JSON Schema for blueprints"""
from json import dumps
from typing import Any
from django.core.management.base import BaseCommand, no_translations
from django.db.models import Model, fields
from django.db.models.fields.related import OneToOneField
from drf_jsonschema_serializer.convert import converter, field_to_converter
@@ -40,13 +38,12 @@ class PrimaryKeyRelatedFieldConverter:
return {"type": "integer"}
class Command(BaseCommand):
class SchemaBuilder:
"""Generate JSON Schema for blueprints"""
schema: dict
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def __init__(self):
self.schema = {
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://goauthentik.io/blueprints/schema.json",
@@ -93,16 +90,6 @@ class Command(BaseCommand):
"$defs": {"blueprint_entry": {"oneOf": []}},
}
def add_arguments(self, parser):
parser.add_argument("--file", type=str)
@no_translations
def handle(self, *args, file: str, **options):
"""Generate JSON Schema for blueprints"""
self.build()
with open(file, "w") as _schema:
_schema.write(dumps(self.schema, indent=4, default=Command.json_default))
@staticmethod
def json_default(value: Any) -> Any:
"""Helper that handles gettext_lazy strings that JSON doesn't handle"""
@@ -124,7 +111,7 @@ class Command(BaseCommand):
try:
serializer_class = model_instance.serializer
except NotImplementedError as exc:
raise NotImplementedError(model_instance) from exc
raise ValueError(f"SerializerModel not implemented by {model}") from exc
serializer = serializer_class(
context={
SERIALIZER_CONTEXT_BLUEPRINT: False,

View File

@@ -12,7 +12,6 @@ from django.db import DatabaseError, InternalError, ProgrammingError
from django.utils.text import slugify
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django_dramatiq_postgres.middleware import CurrentTaskNotFound
from dramatiq.actor import actor
from dramatiq.middleware import Middleware
from structlog.stdlib import get_logger
@@ -40,7 +39,6 @@ from authentik.events.utils import sanitize_dict
from authentik.lib.config import CONFIG
from authentik.tasks.apps import PRIORITY_HIGH
from authentik.tasks.middleware import CurrentTask
from authentik.tasks.models import Task
from authentik.tasks.schedules.models import Schedule
from authentik.tenants.models import Tenant
@@ -191,10 +189,7 @@ def check_blueprint_v1_file(blueprint: BlueprintFile):
@actor(description=_("Apply single blueprint."))
def apply_blueprint(instance_pk: UUID):
try:
self = CurrentTask.get_task()
except CurrentTaskNotFound:
self = Task()
self = CurrentTask.get_task()
self.set_uid(str(instance_pk))
instance: BlueprintInstance | None = None
try:

View File

@@ -33,6 +33,16 @@ from authentik.endpoints.connectors.agent.auth import AgentAuth
from authentik.rbac.api.roles import RoleSerializer
from authentik.rbac.decorators import permission_required
PARTIAL_USER_SERIALIZER_MODEL_FIELDS = [
"pk",
"username",
"name",
"is_active",
"last_login",
"email",
"attributes",
]
class PartialUserSerializer(ModelSerializer):
"""Partial User Serializer, does not include child relations."""
@@ -42,16 +52,7 @@ class PartialUserSerializer(ModelSerializer):
class Meta:
model = User
fields = [
"pk",
"username",
"name",
"is_active",
"last_login",
"email",
"attributes",
"uid",
]
fields = PARTIAL_USER_SERIALIZER_MODEL_FIELDS + ["uid"]
class RelatedGroupSerializer(ModelSerializer):
@@ -84,6 +85,7 @@ class GroupSerializer(ModelSerializer):
source="roles",
required=False,
)
inherited_roles_obj = SerializerMethodField(allow_null=True)
num_pk = IntegerField(read_only=True)
@property
@@ -107,6 +109,13 @@ class GroupSerializer(ModelSerializer):
return True
return str(request.query_params.get("include_parents", "false")).lower() == "true"
@property
def _should_include_inherited_roles(self) -> bool:
request: Request = self.context.get("request", None)
if not request:
return True
return str(request.query_params.get("include_inherited_roles", "false")).lower() == "true"
@extend_schema_field(PartialUserSerializer(many=True))
def get_users_obj(self, instance: Group) -> list[PartialUserSerializer] | None:
if not self._should_include_users:
@@ -125,6 +134,15 @@ class GroupSerializer(ModelSerializer):
return None
return RelatedGroupSerializer(instance.parents, many=True).data
@extend_schema_field(RoleSerializer(many=True))
def get_inherited_roles_obj(self, instance: Group) -> list | None:
"""Return only inherited roles from ancestor groups (excludes direct roles)"""
if not self._should_include_inherited_roles:
return None
direct_role_pks = instance.roles.values_list("pk", flat=True)
inherited_roles = instance.all_roles().exclude(pk__in=direct_role_pks)
return RoleSerializer(inherited_roles, many=True).data
def validate_is_superuser(self, superuser: bool):
"""Ensure that the user creating this group has permissions to set the superuser flag"""
request: Request = self.context.get("request", None)
@@ -166,6 +184,7 @@ class GroupSerializer(ModelSerializer):
"attributes",
"roles",
"roles_obj",
"inherited_roles_obj",
"children",
"children_obj",
]
@@ -246,19 +265,30 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
]
def get_ql_fields(self):
from akql.schema import BoolField, JSONSearchField, StrField
from djangoql.schema import BoolField, StrField
from authentik.enterprise.search.fields import (
JSONSearchField,
)
return [
StrField(Group, "name"),
BoolField(Group, "is_superuser", nullable=True),
JSONSearchField(Group, "attributes", suggest_nested=False),
JSONSearchField(Group, "attributes"),
]
def get_queryset(self):
base_qs = Group.objects.all().prefetch_related("roles")
if self.serializer_class(context={"request": self.request})._should_include_users:
base_qs = base_qs.prefetch_related("users")
# Only fetch fields needed by PartialUserSerializer to reduce DB load and instantiation
# time
base_qs = base_qs.prefetch_related(
Prefetch(
"users",
queryset=User.objects.all().only(*PARTIAL_USER_SERIALIZER_MODEL_FIELDS),
)
)
else:
base_qs = base_qs.prefetch_related(
Prefetch("users", queryset=User.objects.all().only("id"))
@@ -277,6 +307,7 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
OpenApiParameter("include_users", bool, default=True),
OpenApiParameter("include_children", bool, default=False),
OpenApiParameter("include_parents", bool, default=False),
OpenApiParameter("include_inherited_roles", bool, default=False),
]
)
def list(self, request, *args, **kwargs):
@@ -287,6 +318,7 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
OpenApiParameter("include_users", bool, default=True),
OpenApiParameter("include_children", bool, default=False),
OpenApiParameter("include_parents", bool, default=False),
OpenApiParameter("include_inherited_roles", bool, default=False),
]
)
def retrieve(self, request, *args, **kwargs):

View File

@@ -416,6 +416,11 @@ class UsersFilter(FilterSet):
last_updated = IsoDateTimeFilter(field_name="last_updated")
last_updated__gt = IsoDateTimeFilter(field_name="last_updated", lookup_expr="gt")
last_login__lt = IsoDateTimeFilter(field_name="last_login", lookup_expr="lt")
last_login = IsoDateTimeFilter(field_name="last_login")
last_login__gt = IsoDateTimeFilter(field_name="last_login", lookup_expr="gt")
last_login__isnull = BooleanFilter(field_name="last_login", lookup_expr="isnull")
is_superuser = BooleanFilter(field_name="ak_groups", method="filter_is_superuser")
uuid = UUIDFilter(field_name="uuid")
@@ -473,6 +478,7 @@ class UsersFilter(FilterSet):
"email",
"date_joined",
"last_updated",
"last_login",
"name",
"is_active",
"is_superuser",
@@ -493,7 +499,7 @@ class UserViewSet(
"""User Viewset"""
queryset = User.objects.none()
ordering = ["username", "date_joined", "last_updated"]
ordering = ["username", "date_joined", "last_updated", "last_login"]
serializer_class = UserSerializer
filterset_class = UsersFilter
search_fields = ["email", "name", "uuid", "username"]
@@ -504,7 +510,12 @@ class UserViewSet(
]
def get_ql_fields(self):
from akql.schema import BoolField, ChoiceSearchField, JSONSearchField, StrField
from djangoql.schema import BoolField, StrField
from authentik.enterprise.search.fields import (
ChoiceSearchField,
JSONSearchField,
)
return [
StrField(User, "username"),
@@ -513,7 +524,7 @@ class UserViewSet(
StrField(User, "path"),
BoolField(User, "is_active", nullable=True),
ChoiceSearchField(User, "type"),
JSONSearchField(User, "attributes", suggest_nested=False),
JSONSearchField(User, "attributes"),
]
def get_queryset(self):

View File

@@ -1,101 +1,9 @@
# 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 authentik.lib.migrations import progress_bar
from authentik.root.middleware import ClientIPMiddleware
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"""
try:
return pickle.loads(data) # nosec
except Exception:
return {}
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,
uuid=old_auth_session.uuid,
)
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):
@@ -205,8 +113,4 @@ class Migration(migrations.Migration):
"verbose_name_plural": "Authenticated Sessions",
},
),
migrations.RunPython(
code=migrate_database_sessions,
reverse_code=migrations.RunPython.noop,
),
]

View File

@@ -18,10 +18,9 @@ def migrate_object_permissions(apps: Apps, schema_editor: BaseDatabaseSchemaEdit
RoleModelPermission = apps.get_model("guardian", "RoleModelPermission")
def get_role_for_user_id(user_id: int) -> Role:
name = f"ak-managed-role--user-{user_id}"
name = f"ak-migrated-role--user-{user_id}"
role, created = Role.objects.using(db_alias).get_or_create(
name=name,
managed=name,
)
if created:
role.users.add(user_id)
@@ -32,11 +31,10 @@ def migrate_object_permissions(apps: Apps, schema_editor: BaseDatabaseSchemaEdit
if not role:
# Every django group should already have a role, so this should never happen.
# But let's be nice.
name = f"ak-managed-role--group-{group_id}"
name = f"ak-migrated-role--group-{group_id}"
role, created = Role.objects.using(db_alias).get_or_create(
group_id=group_id,
name=name,
managed=name,
)
if created:
role.group_id = group_id

View File

@@ -3,7 +3,7 @@
from datetime import datetime
from enum import StrEnum
from hashlib import sha256
from typing import Any, Optional, Self
from typing import Any, Self
from uuid import uuid4
import pgtrigger
@@ -225,7 +225,7 @@ class Group(SerializerModel, AttributesMixin):
# in the LDAP Outpost we use the last 5 chars so match here
return int(str(self.pk.int)[:5])
def is_member(self, user: "User") -> bool:
def is_member(self, user: User) -> bool:
"""Recursively check if `user` is member of us, or any parent."""
return user.all_groups().filter(group_uuid=self.group_uuid).exists()
@@ -466,7 +466,7 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
always_merger.merge(final_attributes, self.attributes)
return final_attributes
def app_entitlements(self, app: "Application | None") -> QuerySet["ApplicationEntitlement"]:
def app_entitlements(self, app: Application | None) -> QuerySet[ApplicationEntitlement]:
"""Get all entitlements this user has for `app`."""
if not app:
return []
@@ -485,7 +485,7 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
).order_by("name")
return qs
def app_entitlements_attributes(self, app: "Application | None") -> dict:
def app_entitlements_attributes(self, app: Application | None) -> dict:
"""Get a dictionary containing all merged attributes from app entitlements for `app`."""
final_attributes = {}
for attrs in self.app_entitlements(app).values_list("attributes", flat=True):
@@ -654,7 +654,7 @@ class BackchannelProvider(Provider):
class ApplicationQuerySet(QuerySet):
def with_provider(self) -> "QuerySet[Application]":
def with_provider(self) -> QuerySet[Application]:
qs = self.select_related("provider")
for subclass in Provider.objects.get_queryset()._get_subclasses_recurse(Provider):
qs = qs.select_related(f"provider__{subclass}")
@@ -713,9 +713,7 @@ class Application(SerializerModel, PolicyBindingModel):
return get_file_manager(FileUsage.MEDIA).file_url(self.meta_icon)
def get_launch_url(
self, user: Optional["User"] = None, user_data: dict | None = None
) -> str | None:
def get_launch_url(self, user: User | None = None, user_data: dict | None = None) -> str | None:
"""Get launch URL if set, otherwise attempt to get launch URL based on provider.
Args:
@@ -948,7 +946,7 @@ class Source(ManagedModel, SerializerModel, PolicyBindingModel):
raise NotImplementedError
@property
def property_mapping_type(self) -> "type[PropertyMapping]":
def property_mapping_type(self) -> type[PropertyMapping]:
"""Return property mapping type used by this object"""
if self.managed == self.MANAGED_INBUILT:
from authentik.core.models import PropertyMapping
@@ -1069,7 +1067,7 @@ class ExpiringModel(models.Model):
return self.delete(*args, **kwargs)
@classmethod
def filter_not_expired(cls, **kwargs) -> QuerySet["Self"]:
def filter_not_expired(cls, **kwargs) -> QuerySet[Self]:
"""Filer for tokens which are not expired yet or are not expiring,
and match filters in `kwargs`"""
for obj in cls.objects.filter(**kwargs).filter(Q(expires__lt=now(), expiring=True)):
@@ -1265,7 +1263,7 @@ class AuthenticatedSession(SerializerModel):
return f"Authenticated Session {str(self.pk)[:10]}"
@staticmethod
def from_request(request: HttpRequest, user: User) -> Optional["AuthenticatedSession"]:
def from_request(request: HttpRequest, user: User) -> AuthenticatedSession | None:
"""Create a new session from a http request"""
if not hasattr(request, "session") or not request.session.exists(
request.session.session_key

View File

@@ -66,9 +66,12 @@ class SessionStore(SessionBase):
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)
except (pickle.PickleError, AttributeError, TypeError):
# PickleError, ValueError - unpickling exceptions
# AttributeError - can happen when Django model fields (e.g., FileField) are unpickled
# and their descriptors fail to initialize (e.g., missing storage)
# TypeError - can happen with incompatible pickled objects
# If any of these happen, just return an empty dictionary (an empty session)
pass
return {}

View File

@@ -63,7 +63,7 @@ def user_logged_in_session(sender, request: HttpRequest, user: User, **_):
@receiver(post_delete, sender=AuthenticatedSession)
def authenticated_session_delete(sender: type[Model], instance: "AuthenticatedSession", **_):
def authenticated_session_delete(sender: type[Model], instance: AuthenticatedSession, **_):
"""Delete session when authenticated session is deleted"""
Session.objects.filter(session_key=instance.pk).delete()

View File

@@ -49,7 +49,7 @@ class SourceMapper:
def build_object_properties(
self,
object_type: type[User | Group],
manager: "PropertyMappingManager | None" = None,
manager: PropertyMappingManager | None = None,
user: User | None = None,
request: HttpRequest | None = None,
**kwargs,

View File

@@ -35,8 +35,13 @@ def clean_expired_models():
LOGGER.debug("Expired models", model=cls, amount=amount)
self.info(f"Expired {amount} {cls._meta.verbose_name_plural}")
clear_expired_cache()
Message.delete_expired()
GroupChannel.delete_expired()
for cls in [Message, GroupChannel]:
objects = cls.objects.all().filter(expires__lt=now())
amount = objects.count()
for obj in chunked_queryset(objects):
obj.delete()
LOGGER.debug("Expired models", model=cls, amount=amount)
self.info(f"Expired {amount} {cls._meta.verbose_name_plural}")
@actor(description=_("Remove temporary users created by SAML Sources."))

View File

@@ -10,15 +10,23 @@
{% elif ui_theme == "light" %}
<meta name="color-scheme" content="light" />
<meta name="theme-color" content="#ffffff">
{% else %}
{% else %}
<script data-id="theme-script">
"use strict";
(function () {
try {
/* Ignore older theme names */
let locallyStoredTheme = window.localStorage?.getItem("theme") || null;
if (typeof locallyStoredTheme === "string") {
locallyStoredTheme = locallyStoredTheme.trim();
}
if (!(["auto", "light", "dark"].includes(locallyStoredTheme))) {
locallyStoredTheme = null;
}
const initialThemeChoice =
new URLSearchParams(window.location.search).get("theme") ||
window.localStorage?.getItem("theme");
new URLSearchParams(window.location.search).get("theme") || locallyStoredTheme;
const themeChoice =
initialThemeChoice || document.documentElement.dataset.themeChoice || "auto";

View File

@@ -5,9 +5,10 @@ from django.test import TestCase
from authentik.core.models import Group, PropertyMapping, Source, User
from authentik.core.sources.mapper import SourceMapper
from authentik.lib.generators import generate_id
from authentik.lib.models import InternallyManagedMixin
class ProxySource(Source):
class ProxySource(InternallyManagedMixin, Source):
@property
def property_mapping_type(self):
return PropertyMapping

View File

@@ -740,3 +740,90 @@ class TestUsersAPI(APITestCase):
response.content,
{"name": ["This field must be unique."]},
)
def test_filter_last_login(self):
"""Test API filtering by last_login"""
from datetime import timedelta
from django.utils import timezone
User.objects.all().delete()
admin = create_test_admin_user()
self.client.force_login(admin)
# Create users with different last_login values
user_recent = create_test_user()
user_recent.last_login = timezone.now()
user_recent.save()
user_old = create_test_user()
user_old.last_login = timezone.now() - timedelta(days=400) # Over 1 year ago
user_old.save()
user_never = create_test_user()
user_never.last_login = None # Never logged in
user_never.save()
# Filter users who logged in before 1 year ago
one_year_ago = (timezone.now() - timedelta(days=365)).isoformat()
response = self.client.get(
reverse("authentik_api:user-list"),
data={"last_login__lt": one_year_ago},
)
self.assertEqual(response.status_code, 200)
body = loads(response.content)
self.assertEqual(len(body["results"]), 1)
self.assertEqual(body["results"][0]["pk"], user_old.pk)
# Filter users who have never logged in
response = self.client.get(
reverse("authentik_api:user-list"),
data={"last_login__isnull": True},
)
self.assertEqual(response.status_code, 200)
body = loads(response.content)
# Should include user_never and admin (who hasn't logged in via the app)
pks = [r["pk"] for r in body["results"]]
self.assertIn(user_never.pk, pks)
def test_sort_by_last_login(self):
"""Test API sorting by last_login"""
from datetime import timedelta
from django.utils import timezone
User.objects.all().delete()
admin = create_test_admin_user()
self.client.force_login(admin)
user1 = create_test_user()
user1.last_login = timezone.now() - timedelta(days=10)
user1.save()
user2 = create_test_user()
user2.last_login = timezone.now() - timedelta(days=5)
user2.save()
# Ascending order (oldest first)
response = self.client.get(
reverse("authentik_api:user-list"),
data={"ordering": "last_login"},
)
self.assertEqual(response.status_code, 200)
body = loads(response.content)
# Users with null last_login come first, then user1 (older), then user2 (newer)
self.assertEqual(len(body["results"]), 3)
# Descending order (newest first)
response = self.client.get(
reverse("authentik_api:user-list"),
data={"ordering": "-last_login"},
)
self.assertEqual(response.status_code, 200)
body = loads(response.content)
# user2 should come before user1 (more recent login)
pks = [r["pk"] for r in body["results"]]
self.assertIn(user1.pk, pks)
self.assertIn(user2.pk, pks)
# Verify user2 comes before user1 in descending order
self.assertLess(pks.index(user2.pk), pks.index(user1.pk))

View File

@@ -7,14 +7,17 @@ from cryptography.x509 import load_pem_x509_certificate
from django.db import migrations, models
from authentik.crypto.signals import extract_certificate_metadata
from authentik.lib.migrations import progress_bar
def backfill_certificate_metadata(apps, schema_editor): # noqa: ARG001
"""Backfill certificate metadata and kid for existing records."""
db_alias = schema_editor.connection.alias
CertificateKeyPair = apps.get_model("authentik_crypto", "CertificateKeyPair")
for cert in CertificateKeyPair.objects.all():
print("\nStoring extra data about certificates, this might take a couple of minutes...")
for cert in progress_bar(CertificateKeyPair.objects.using(db_alias).all()):
updated_fields = []
if cert.certificate_data:
@@ -47,7 +50,7 @@ def backfill_certificate_metadata(apps, schema_editor): # noqa: ARG001
updated_fields.append("kid")
if updated_fields:
cert.save(update_fields=updated_fields)
cert.save(update_fields=updated_fields, using=db_alias)
class Migration(migrations.Migration):

View File

@@ -3,7 +3,7 @@ from rest_framework.fields import SerializerMethodField
from authentik.core.api.utils import ModelSerializer
from authentik.endpoints.api.connectors import ConnectorSerializer
from authentik.endpoints.api.device_fact_snapshots import DeviceFactSnapshotSerializer
from authentik.endpoints.models import DeviceConnection
from authentik.endpoints.models import Connector, DeviceConnection, DeviceFactSnapshot
class DeviceConnectionSerializer(ModelSerializer):
@@ -12,10 +12,19 @@ class DeviceConnectionSerializer(ModelSerializer):
latest_snapshot = SerializerMethodField(allow_null=True)
def get_latest_snapshot(self, instance: DeviceConnection) -> DeviceFactSnapshotSerializer:
snapshot = instance.devicefactsnapshot_set.order_by("-created").first()
snapshot: DeviceFactSnapshot | None = instance.devicefactsnapshot_set.order_by(
"-created"
).first()
if not snapshot:
return None
return DeviceFactSnapshotSerializer(snapshot).data
connector: Connector = Connector.objects.get_subclass(pk=snapshot.connection.connector_id)
vendor = connector.controller.vendor_identifier()
return DeviceFactSnapshotSerializer(
snapshot,
context={
"vendor": vendor,
},
).data
class Meta:
model = DeviceConnection

View File

@@ -1,11 +1,32 @@
from enum import StrEnum
from rest_framework.fields import SerializerMethodField
from authentik.core.api.utils import ModelSerializer
from authentik.endpoints.controller import MERGED_VENDOR
from authentik.endpoints.facts import DeviceFacts
from authentik.endpoints.models import DeviceFactSnapshot
from authentik.endpoints.models import Connector, DeviceFactSnapshot
from authentik.lib.utils.reflection import all_subclasses
def get_vendor_choices():
choices = [(MERGED_VENDOR, MERGED_VENDOR)]
for connector_type in all_subclasses(Connector):
ident = connector_type().controller.vendor_identifier()
choices.append((ident, ident))
return choices
vendors = StrEnum("DeviceConnectorVendors", get_vendor_choices())
class DeviceFactSnapshotSerializer(ModelSerializer):
data = DeviceFacts()
vendor = SerializerMethodField()
def get_vendor(self, instance: DeviceFactSnapshot) -> vendors:
return self.context.get("vendor", MERGED_VENDOR)
class Meta:
model = DeviceFactSnapshot
@@ -14,6 +35,7 @@ class DeviceFactSnapshotSerializer(ModelSerializer):
"connection",
"created",
"expires",
"vendor",
]
extra_kwargs = {
"created": {"read_only": True},

View File

@@ -1,3 +1,4 @@
from django.db import models
from rest_framework.fields import (
BooleanField,
CharField,
@@ -14,6 +15,12 @@ from authentik.endpoints.models import Device
from authentik.lib.utils.time import timedelta_from_string
from authentik.providers.oauth2.views.jwks import JWKSView
try:
from authentik.enterprise.models import LicenseUsageStatus
except ImportError:
class LicenseUsageStatus(models.TextChoices): ...
class AgentConfigSerializer(PassiveSerializer):
@@ -29,6 +36,7 @@ class AgentConfigSerializer(PassiveSerializer):
auth_terminate_session_on_expiry = BooleanField()
system_config = SerializerMethodField()
license_status = SerializerMethodField(required=False, allow_null=True)
def get_device_id(self, instance: AgentConnector) -> str:
device: Device = self.context["device"]
@@ -54,6 +62,14 @@ class AgentConfigSerializer(PassiveSerializer):
def get_system_config(self, instance: AgentConnector) -> ConfigSerializer:
return ConfigView.get_config(self.context["request"]).data
def get_license_status(self, instance: AgentConnector) -> LicenseUsageStatus:
try:
from authentik.enterprise.license import LicenseKey
return LicenseKey.cached_summary().status
except ModuleNotFoundError:
return None
class EnrollSerializer(PassiveSerializer):

View File

@@ -1,11 +1,13 @@
from typing import cast
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiResponse, extend_schema
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.fields import ChoiceField
from rest_framework.permissions import IsAuthenticated
from rest_framework.relations import PrimaryKeyRelatedField
from rest_framework.request import Request
from rest_framework.response import Response
@@ -22,6 +24,9 @@ from authentik.endpoints.connectors.agent.api.agent import (
from authentik.endpoints.connectors.agent.auth import (
AgentAuth,
AgentEnrollmentAuth,
DeviceAuthFedAuthentication,
agent_auth_issue_token,
check_device_policies,
)
from authentik.endpoints.connectors.agent.controller import MDMConfigResponseSerializer
from authentik.endpoints.connectors.agent.models import (
@@ -32,7 +37,10 @@ from authentik.endpoints.connectors.agent.models import (
)
from authentik.endpoints.facts import DeviceFacts, OSFamily
from authentik.endpoints.models import Device
from authentik.events.models import Event, EventAction
from authentik.flows.planner import PLAN_CONTEXT_DEVICE
from authentik.lib.utils.reflection import ConditionalInheritance
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
class AgentConnectorSerializer(ConnectorSerializer):
@@ -163,3 +171,43 @@ class AgentConnectorViewSet(
connection: AgentDeviceConnection = token.device
connection.create_snapshot(data.validated_data)
return Response(status=204)
@extend_schema(
request=OpenApiTypes.NONE,
parameters=[OpenApiParameter("device", OpenApiTypes.STR, location="query", required=True)],
responses={
200: AgentTokenResponseSerializer(),
404: OpenApiResponse(description="Device not found"),
},
)
@action(
methods=["POST"],
detail=False,
pagination_class=None,
filter_backends=[],
permission_classes=[IsAuthenticated],
authentication_classes=[DeviceAuthFedAuthentication],
)
def auth_fed(self, request: Request) -> Response:
federated_token, device, connector = request.auth
policy_result = check_device_policies(device, federated_token.user, request._request)
if not policy_result.passing:
raise ValidationError(
{"policy_result": "Policy denied access", "policy_messages": policy_result.messages}
)
token, exp = agent_auth_issue_token(device, connector, federated_token.user)
rel_exp = int((exp - now()).total_seconds())
Event.new(
EventAction.LOGIN,
**{
PLAN_CONTEXT_METHOD: "jwt",
PLAN_CONTEXT_METHOD_ARGS: {
"jwt": federated_token,
"provider": federated_token.provider,
},
PLAN_CONTEXT_DEVICE: device,
},
).from_http(request, user=federated_token.user)
return Response({"token": token, "expires_in": rel_exp})

View File

@@ -1,9 +1,11 @@
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import CharField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
from authentik.core.api.tokens import TokenViewSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer
@@ -19,6 +21,11 @@ class EnrollmentTokenSerializer(ModelSerializer):
source="device_group", read_only=True, required=False
)
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
if SERIALIZER_CONTEXT_BLUEPRINT in self.context:
self.fields["key"] = CharField(required=False)
class Meta:
model = EnrollmentToken
fields = [

View File

@@ -1,13 +1,28 @@
from typing import Any
from django.http import HttpRequest
from django.utils.timezone import now
from drf_spectacular.extensions import OpenApiAuthenticationExtension
from jwt import PyJWTError, decode, encode
from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework.exceptions import PermissionDenied
from rest_framework.request import Request
from structlog.stdlib import get_logger
from authentik.api.authentication import IPCUser, validate_auth
from authentik.core.middleware import CTX_AUTH_VIA
from authentik.core.models import User
from authentik.endpoints.connectors.agent.models import DeviceToken, EnrollmentToken
from authentik.crypto.apps import MANAGED_KEY
from authentik.crypto.models import CertificateKeyPair
from authentik.endpoints.connectors.agent.models import AgentConnector, DeviceToken, EnrollmentToken
from authentik.endpoints.models import Device
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.engine import PolicyEngine
from authentik.policies.models import PolicyBindingModel
from authentik.providers.oauth2.models import AccessToken, JWTAlgorithms, OAuth2Provider
LOGGER = get_logger()
PLATFORM_ISSUER = "goauthentik.io/platform"
class DeviceUser(IPCUser):
@@ -40,3 +55,96 @@ class AgentAuth(BaseAuthentication):
raise PermissionDenied()
CTX_AUTH_VIA.set("endpoint_token")
return (DeviceUser(), device_token)
def agent_auth_issue_token(device: Device, connector: AgentConnector, user: User, **kwargs):
kp = CertificateKeyPair.objects.filter(managed=MANAGED_KEY).first()
if not kp:
return None, None
exp = now() + timedelta_from_string(connector.auth_session_duration)
token = encode(
{
"iss": PLATFORM_ISSUER,
"aud": str(device.pk),
"iat": int(now().timestamp()),
"exp": int(exp.timestamp()),
"preferred_username": user.username,
**kwargs,
},
kp.private_key,
headers={
"kid": kp.kid,
},
algorithm=JWTAlgorithms.from_private_key(kp.private_key),
)
return token, exp
class DeviceAuthFedAuthentication(BaseAuthentication):
def authenticate(self, request):
raw_token = validate_auth(get_authorization_header(request))
if not raw_token:
LOGGER.warning("Missing token")
return None
device = Device.filter_not_expired(name=request.query_params.get("device")).first()
if not device:
LOGGER.warning("Couldn't find device")
return None
connectors_for_device = AgentConnector.objects.filter(device__in=[device])
connector = connectors_for_device.first()
providers = OAuth2Provider.objects.filter(agentconnector__in=connectors_for_device)
federated_token = AccessToken.objects.filter(
token=raw_token, provider__in=providers
).first()
if not federated_token:
LOGGER.warning("Couldn't lookup provider")
return None
_key, _alg = federated_token.provider.jwt_key
try:
decode(
raw_token,
_key.public_key(),
algorithms=[_alg],
options={
"verify_aud": False,
},
)
LOGGER.info(
"successfully verified JWT with provider", provider=federated_token.provider.name
)
return (federated_token.user, (federated_token, device, connector))
except (PyJWTError, ValueError, TypeError, AttributeError) as exc:
LOGGER.warning("failed to verify JWT", exc=exc, provider=federated_token.provider.name)
return None
class DeviceFederationAuthSchema(OpenApiAuthenticationExtension):
"""Auth schema"""
target_class = DeviceAuthFedAuthentication
name = "device_federation"
def get_security_definition(self, auto_schema):
"""Auth schema"""
return {"type": "http", "scheme": "bearer"}
def check_device_policies(device: Device, user: User, request: HttpRequest):
"""Check policies bound to device group and device"""
if device.access_group:
result = check_pbm_policies(device.access_group, user, request)
if result.passing:
return result
return check_pbm_policies(device, user, request)
def check_pbm_policies(pbm: PolicyBindingModel, user: User, request: HttpRequest):
policy_engine = PolicyEngine(pbm, user, request)
policy_engine.use_cache = False
policy_engine.empty_result = False
policy_engine.mode = pbm.policy_engine_mode
policy_engine.build()
result = policy_engine.result
LOGGER.debug("PolicyAccessView user_has_access", user=user.username, result=result, pbm=pbm.pk)
return result

View File

@@ -44,6 +44,10 @@ class MDMConfigResponseSerializer(PassiveSerializer):
class AgentConnectorController(BaseController[AgentConnector]):
@staticmethod
def vendor_identifier() -> str:
return "goauthentik.io/platform"
def supported_enrollment_methods(self):
return []

View File

@@ -16,7 +16,7 @@ from authentik.endpoints.models import (
)
from authentik.flows.stage import StageView
from authentik.lib.generators import generate_key
from authentik.lib.models import SerializerModel
from authentik.lib.models import InternallyManagedMixin, SerializerModel
from authentik.lib.utils.time import timedelta_string_validator
if TYPE_CHECKING:
@@ -68,7 +68,7 @@ class AgentConnector(Connector):
return AuthenticatorEndpointStageView
@property
def controller(self) -> type["AgentConnectorController"]:
def controller(self) -> type[AgentConnectorController]:
from authentik.endpoints.connectors.agent.controller import AgentConnectorController
return AgentConnectorController
@@ -97,7 +97,7 @@ class AgentDeviceUserBinding(DeviceUserBinding):
apple_enclave_key_id = models.TextField()
class DeviceToken(ExpiringModel):
class DeviceToken(InternallyManagedMixin, ExpiringModel):
"""Per-device token used for authentication."""
token_uuid = models.UUIDField(primary_key=True, default=uuid4)
@@ -143,7 +143,7 @@ class EnrollmentToken(ExpiringModel, SerializerModel):
]
class DeviceAuthenticationToken(ExpiringModel):
class DeviceAuthenticationToken(InternallyManagedMixin, ExpiringModel):
identifier = models.UUIDField(default=uuid4, primary_key=True)
device = models.ForeignKey(Device, on_delete=models.CASCADE)
@@ -160,7 +160,7 @@ class DeviceAuthenticationToken(ExpiringModel):
verbose_name_plural = _("Device authentication tokens")
class AppleNonce(ExpiringModel):
class AppleNonce(InternallyManagedMixin, ExpiringModel):
nonce = models.TextField()
device_token = models.ForeignKey(DeviceToken, on_delete=models.CASCADE)

View File

@@ -1,4 +1,5 @@
from datetime import timedelta
from hashlib import sha256
from hmac import compare_digest
from django.http import HttpResponse
@@ -8,7 +9,7 @@ from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, IntegerField
from authentik.crypto.models import CertificateKeyPair
from authentik.endpoints.connectors.agent.models import DeviceToken
from authentik.endpoints.connectors.agent.models import DeviceAuthenticationToken, DeviceToken
from authentik.endpoints.models import Device, EndpointStage, StageMode
from authentik.flows.challenge import (
Challenge,
@@ -20,6 +21,7 @@ from authentik.lib.generators import generate_id
from authentik.lib.utils.time import timedelta_from_string
from authentik.providers.oauth2.models import JWTAlgorithms
PLAN_CONTEXT_DEVICE_AUTH_TOKEN = "goauthentik.io/endpoints/device_auth_token" # nosec
PLAN_CONTEXT_AGENT_ENDPOINT_CHALLENGE = "goauthentik.io/endpoints/connectors/agent/challenge"
QS_CHALLENGE = "challenge"
QS_CHALLENGE_RESPONSE = "response"
@@ -85,12 +87,36 @@ class AuthenticatorEndpointStageView(ChallengeStageView):
response_class = EndpointAgentChallengeResponse
def get(self, request, *args, **kwargs):
# Check if we're in a device interactive auth flow, in which case we use that
# to prove which device is being used
if response := self.check_device_ia():
return response
stage: EndpointStage = self.executor.current_stage
keypair = CertificateKeyPair.objects.filter(pk=stage.connector.challenge_key_id).first()
if not keypair:
return self.executor.stage_ok()
return super().get(request, *args, **kwargs)
def check_device_ia(self):
"""Check if we're in a device interactive authentication flow, and if so,
there won't be a browser extension to talk to. However we can authenticate
on the DTH header"""
if PLAN_CONTEXT_DEVICE_AUTH_TOKEN not in self.executor.plan.context:
return None
auth_token: DeviceAuthenticationToken = self.executor.plan.context.get(
PLAN_CONTEXT_DEVICE_AUTH_TOKEN
)
device_token_hash = self.request.headers.get("X-Authentik-Platform-Auth-DTH")
if not device_token_hash:
return None
if not compare_digest(
device_token_hash, sha256(auth_token.device_token.key.encode()).hexdigest()
):
return self.executor.stage_invalid("Invalid device token")
self.logger.debug("Setting device based on DTH header")
self.executor.plan.context[PLAN_CONTEXT_DEVICE] = auth_token.device
return self.executor.stage_ok()
def get_challenge(self, *args, **kwargs) -> Challenge:
stage: EndpointStage = self.executor.current_stage
keypair = CertificateKeyPair.objects.get(pk=stage.connector.challenge_key_id)

View File

@@ -1,3 +1,4 @@
from hashlib import sha256
from json import loads
from django.urls import reverse
@@ -7,10 +8,14 @@ from authentik.core.tests.utils import create_test_cert, create_test_flow
from authentik.endpoints.connectors.agent.models import (
AgentConnector,
AgentDeviceConnection,
DeviceAuthenticationToken,
DeviceToken,
EnrollmentToken,
)
from authentik.endpoints.connectors.agent.stage import PLAN_CONTEXT_AGENT_ENDPOINT_CHALLENGE
from authentik.endpoints.connectors.agent.stage import (
PLAN_CONTEXT_AGENT_ENDPOINT_CHALLENGE,
PLAN_CONTEXT_DEVICE_AUTH_TOKEN,
)
from authentik.endpoints.models import Device, EndpointStage, StageMode
from authentik.flows.models import FlowStageBinding
from authentik.flows.planner import PLAN_CONTEXT_DEVICE
@@ -35,6 +40,11 @@ class TestEndpointStage(FlowTestCase):
device=self.connection,
key=generate_id(),
)
self.device_auth_token = DeviceAuthenticationToken.objects.create(
device=self.device,
device_token=self.device_token,
connector=self.connector,
)
def test_endpoint_stage(self):
flow = create_test_flow()
@@ -194,3 +204,31 @@ class TestEndpointStage(FlowTestCase):
"response": [{"string": "Invalid challenge response", "code": "invalid"}]
},
)
def test_endpoint_stage_ia_dth(self):
"""Test with DTH"""
flow = create_test_flow()
stage = EndpointStage.objects.create(connector=self.connector)
FlowStageBinding.objects.create(stage=stage, target=flow, order=0)
# Send an "invalid" request first, to populate the flow plan
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
plan = self.get_flow_plan()
plan.context[PLAN_CONTEXT_DEVICE_AUTH_TOKEN] = DeviceAuthenticationToken.objects.get(
pk=self.device_auth_token.pk
)
self.set_flow_plan(plan)
with self.assertFlowFinishes() as plan:
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
HTTP_X_AUTHENTIK_PLATFORM_AUTH_DTH=sha256(
self.device_token.key.encode()
).hexdigest(),
)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
plan = plan()
self.assertNotIn(PLAN_CONTEXT_AGENT_ENDPOINT_CHALLENGE, plan.context)
self.assertEqual(plan.context[PLAN_CONTEXT_DEVICE], self.device)

View File

@@ -5,6 +5,8 @@ from authentik.endpoints.models import Connector
from authentik.flows.stage import StageView
from authentik.lib.sentry import SentryIgnoredException
MERGED_VENDOR = "goauthentik.io/@merged"
class EnrollmentMethods(models.TextChoices):
# Automatically enrolled through user action
@@ -28,6 +30,10 @@ class BaseController[T: "Connector"]:
self.connector = connector
self.logger = get_logger().bind(connector=connector.name)
@staticmethod
def vendor_identifier() -> str:
raise NotImplementedError
def supported_enrollment_methods(self) -> list[EnrollmentMethods]:
return []

View File

@@ -15,7 +15,7 @@ from authentik.core.models import AttributesMixin, ExpiringModel
from authentik.flows.models import Stage
from authentik.flows.stage import StageView
from authentik.lib.merge import MERGE_LIST_UNIQUE
from authentik.lib.models import InheritanceForeignKey, SerializerModel
from authentik.lib.models import InheritanceForeignKey, InternallyManagedMixin, SerializerModel
from authentik.lib.utils.time import timedelta_from_string, timedelta_string_validator
from authentik.policies.models import PolicyBinding, PolicyBindingModel
from authentik.tasks.schedules.common import ScheduleSpec
@@ -28,7 +28,7 @@ LOGGER = get_logger()
DEVICE_FACTS_CACHE_TIMEOUT = 3600
class Device(ExpiringModel, AttributesMixin, PolicyBindingModel):
class Device(InternallyManagedMixin, ExpiringModel, AttributesMixin, PolicyBindingModel):
device_uuid = models.UUIDField(default=uuid4, primary_key=True)
name = models.TextField(unique=True)
@@ -43,7 +43,7 @@ class Device(ExpiringModel, AttributesMixin, PolicyBindingModel):
return f"goauthentik.io/endpoints/devices/{self.device_uuid}/facts"
@property
def cached_facts(self) -> "DeviceFactSnapshot":
def cached_facts(self) -> DeviceFactSnapshot:
if cached := cache.get(self.cache_key_facts):
return cached
facts = self.facts
@@ -51,7 +51,7 @@ class Device(ExpiringModel, AttributesMixin, PolicyBindingModel):
return facts
@property
def facts(self) -> "DeviceFactSnapshot":
def facts(self) -> DeviceFactSnapshot:
data = {}
last_updated = datetime.fromtimestamp(0, UTC)
for snapshot_data, snapshort_created in DeviceFactSnapshot.filter_not_expired(
@@ -86,7 +86,7 @@ class DeviceUserBinding(PolicyBinding):
verbose_name_plural = _("Device User bindings")
class DeviceConnection(SerializerModel):
class DeviceConnection(InternallyManagedMixin, SerializerModel):
device_connection_uuid = models.UUIDField(default=uuid4, primary_key=True)
device = models.ForeignKey("Device", on_delete=models.CASCADE)
connector = models.ForeignKey("Connector", on_delete=models.CASCADE)
@@ -115,7 +115,7 @@ class DeviceConnection(SerializerModel):
verbose_name_plural = _("Device connections")
class DeviceFactSnapshot(ExpiringModel, SerializerModel):
class DeviceFactSnapshot(InternallyManagedMixin, ExpiringModel, SerializerModel):
snapshot_id = models.UUIDField(primary_key=True, default=uuid4)
connection = models.ForeignKey(DeviceConnection, on_delete=models.CASCADE)
data = models.JSONField(default=dict)
@@ -157,7 +157,7 @@ class Connector(ScheduledModel, SerializerModel):
raise NotImplementedError
@property
def controller(self) -> type["BaseController[Connector]"]:
def controller(self) -> type[BaseController[Connector]]:
raise NotImplementedError
@property
@@ -205,7 +205,7 @@ class EndpointStage(Stage):
mode = models.TextField(choices=StageMode.choices, default=StageMode.OPTIONAL)
@property
def view(self) -> type["StageView"]:
def view(self) -> type[StageView]:
from authentik.endpoints.stage import EndpointStageView
return EndpointStageView

View File

@@ -1,6 +1,8 @@
"""Enterprise API Views"""
from collections.abc import Callable
from datetime import timedelta
from functools import wraps
from django.utils.timezone import now
from django.utils.translation import gettext as _
@@ -35,6 +37,18 @@ class EnterpriseRequiredMixin:
return super().validate(attrs)
def enterprise_action(func: Callable):
"""Check permissions for a single custom action"""
@wraps(func)
def wrapper(*args, **kwargs) -> Response:
if not LicenseKey.cached_summary().status.is_valid:
raise ValidationError(_("Enterprise is required to use this endpoint."))
return func(*args, **kwargs)
return wrapper
class LicenseSerializer(ModelSerializer):
"""License Serializer"""

View File

@@ -1,31 +1,20 @@
from django.urls import reverse
from django.utils.timezone import now
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from drf_spectacular.utils import extend_schema
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from structlog.stdlib import get_logger
from authentik.endpoints.connectors.agent.api.agent import (
AgentAuthenticationResponse,
AgentTokenResponseSerializer,
)
from authentik.endpoints.connectors.agent.auth import AgentAuth
from authentik.endpoints.connectors.agent.models import (
DeviceAuthenticationToken,
DeviceToken,
)
from authentik.enterprise.endpoints.connectors.agent.auth import (
DeviceAuthFedAuthentication,
agent_auth_issue_token,
check_device_policies,
)
from authentik.events.models import Event, EventAction
from authentik.flows.planner import PLAN_CONTEXT_DEVICE
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
from authentik.enterprise.api import enterprise_action
LOGGER = get_logger()
@@ -37,6 +26,7 @@ class AgentConnectorViewSetMixin:
responses=AgentAuthenticationResponse(),
)
@action(methods=["POST"], detail=False, authentication_classes=[AgentAuth])
@enterprise_action
def auth_ia(self, request: Request) -> Response:
token: DeviceToken = request.auth
auth_token = DeviceAuthenticationToken.objects.create(
@@ -54,43 +44,3 @@ class AgentConnectorViewSetMixin:
),
}
)
@extend_schema(
request=OpenApiTypes.NONE,
parameters=[OpenApiParameter("device", OpenApiTypes.STR, location="query", required=True)],
responses={
200: AgentTokenResponseSerializer(),
404: OpenApiResponse(description="Device not found"),
},
)
@action(
methods=["POST"],
detail=False,
pagination_class=None,
filter_backends=[],
permission_classes=[IsAuthenticated],
authentication_classes=[DeviceAuthFedAuthentication],
)
def auth_fed(self, request: Request) -> Response:
federated_token, device, connector = request.auth
policy_result = check_device_policies(device, federated_token.user, request._request)
if not policy_result.passing:
raise ValidationError(
{"policy_result": "Policy denied access", "policy_messages": policy_result.messages}
)
token, exp = agent_auth_issue_token(device, connector, federated_token.user)
rel_exp = int((exp - now()).total_seconds())
Event.new(
EventAction.LOGIN,
**{
PLAN_CONTEXT_METHOD: "jwt",
PLAN_CONTEXT_METHOD_ARGS: {
"jwt": federated_token,
"provider": federated_token.provider,
},
PLAN_CONTEXT_DEVICE: device,
},
).from_http(request, user=federated_token.user)
return Response({"token": token, "expires_in": rel_exp})

View File

@@ -1,113 +0,0 @@
from django.http import HttpRequest
from django.utils.timezone import now
from drf_spectacular.extensions import OpenApiAuthenticationExtension
from jwt import PyJWTError, decode, encode
from rest_framework.authentication import BaseAuthentication
from structlog.stdlib import get_logger
from authentik.api.authentication import get_authorization_header, validate_auth
from authentik.core.models import User
from authentik.crypto.apps import MANAGED_KEY
from authentik.crypto.models import CertificateKeyPair
from authentik.endpoints.connectors.agent.models import AgentConnector
from authentik.endpoints.models import Device
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.engine import PolicyEngine
from authentik.policies.models import PolicyBindingModel
from authentik.providers.oauth2.models import AccessToken, JWTAlgorithms, OAuth2Provider
LOGGER = get_logger()
PLATFORM_ISSUER = "goauthentik.io/platform"
def agent_auth_issue_token(device: Device, connector: AgentConnector, user: User, **kwargs):
kp = CertificateKeyPair.objects.filter(managed=MANAGED_KEY).first()
if not kp:
return None, None
exp = now() + timedelta_from_string(connector.auth_session_duration)
token = encode(
{
"iss": PLATFORM_ISSUER,
"aud": str(device.pk),
"iat": int(now().timestamp()),
"exp": int(exp.timestamp()),
"preferred_username": user.username,
**kwargs,
},
kp.private_key,
headers={
"kid": kp.kid,
},
algorithm=JWTAlgorithms.from_private_key(kp.private_key),
)
return token, exp
class DeviceAuthFedAuthentication(BaseAuthentication):
def authenticate(self, request):
raw_token = validate_auth(get_authorization_header(request))
if not raw_token:
LOGGER.warning("Missing token")
return None
device = Device.filter_not_expired(name=request.query_params.get("device")).first()
if not device:
LOGGER.warning("Couldn't find device")
return None
connectors_for_device = AgentConnector.objects.filter(device__in=[device])
connector = connectors_for_device.first()
providers = OAuth2Provider.objects.filter(agentconnector__in=connectors_for_device)
federated_token = AccessToken.objects.filter(
token=raw_token, provider__in=providers
).first()
if not federated_token:
LOGGER.warning("Couldn't lookup provider")
return None
_key, _alg = federated_token.provider.jwt_key
try:
decode(
raw_token,
_key.public_key(),
algorithms=[_alg],
options={
"verify_aud": False,
},
)
LOGGER.info(
"successfully verified JWT with provider", provider=federated_token.provider.name
)
return (federated_token.user, (federated_token, device, connector))
except (PyJWTError, ValueError, TypeError, AttributeError) as exc:
LOGGER.warning("failed to verify JWT", exc=exc, provider=federated_token.provider.name)
return None
class DeviceFederationAuthSchema(OpenApiAuthenticationExtension):
"""Auth schema"""
target_class = DeviceAuthFedAuthentication
name = "device_federation"
def get_security_definition(self, auto_schema):
"""Auth schema"""
return {"type": "http", "scheme": "bearer"}
def check_device_policies(device: Device, user: User, request: HttpRequest):
"""Check policies bound to device group and device"""
if device.access_group:
result = check_pbm_policies(device.access_group, user, request)
if result.passing:
return result
return check_pbm_policies(device, user, request)
def check_pbm_policies(pbm: PolicyBindingModel, user: User, request: HttpRequest):
policy_engine = PolicyEngine(pbm, user, request)
policy_engine.use_cache = False
policy_engine.empty_result = False
policy_engine.mode = pbm.policy_engine_mode
policy_engine.build()
result = policy_engine.result
LOGGER.debug("PolicyAccessView user_has_access", user=user.username, result=result, pbm=pbm.pk)
return result

View File

@@ -63,8 +63,21 @@ class TestConnectorAuthIA(FlowTestCase):
)
self.assertEqual(response.status_code, 200)
@patch(
"authentik.enterprise.license.LicenseKey.validate",
MagicMock(
return_value=LicenseKey(
aud="",
exp=expiry_valid,
name=generate_id(),
internal_users=100,
external_users=100,
)
),
)
@reconcile_app("authentik_crypto")
def test_auth_ia_fulfill(self):
License.objects.create(key=generate_id())
self.client.force_login(self.user)
response = self.client.post(
reverse("authentik_api:agentconnector-auth-ia"),

View File

@@ -3,12 +3,13 @@ from hmac import compare_digest
from django.http import Http404, HttpRequest, HttpResponse, HttpResponseBadRequest, QueryDict
from authentik.endpoints.connectors.agent.models import AgentConnector, DeviceAuthenticationToken
from authentik.endpoints.models import Device
from authentik.enterprise.endpoints.connectors.agent.auth import (
from authentik.endpoints.connectors.agent.auth import (
agent_auth_issue_token,
check_device_policies,
)
from authentik.endpoints.connectors.agent.models import AgentConnector, DeviceAuthenticationToken
from authentik.endpoints.connectors.agent.stage import PLAN_CONTEXT_DEVICE_AUTH_TOKEN
from authentik.endpoints.models import Device
from authentik.enterprise.policy import EnterprisePolicyAccessView
from authentik.flows.exceptions import FlowNonApplicableException
from authentik.flows.models import in_memory_stage
@@ -16,8 +17,6 @@ from authentik.flows.planner import PLAN_CONTEXT_DEVICE, FlowPlanner
from authentik.flows.stage import StageView
from authentik.providers.oauth2.utils import HttpResponseRedirectScheme
PLAN_CONTEXT_DEVICE_AUTH_TOKEN = "goauthentik.io/endpoints/device_auth_token" # nosec
QS_AGENT_IA_TOKEN = "ak-auth-ia-token" # nosec

View File

@@ -93,7 +93,7 @@ class LicenseKey:
license_flags: list[LicenseFlags] = field(default_factory=list)
@staticmethod
def validate(jwt: str, check_expiry=True) -> "LicenseKey":
def validate(jwt: str, check_expiry=True) -> LicenseKey:
"""Validate the license from a given JWT"""
try:
headers = get_unverified_header(jwt)
@@ -128,7 +128,7 @@ class LicenseKey:
return body
@staticmethod
def get_total() -> "LicenseKey":
def get_total() -> LicenseKey:
"""Get a summarized version of all (not expired) licenses"""
total = LicenseKey(get_license_aud(), 0, "Summarized license", 0, 0)
for lic in License.objects.all():

View File

@@ -11,7 +11,7 @@ from django.utils.translation import gettext as _
from rest_framework.serializers import BaseSerializer
from authentik.core.models import ExpiringModel
from authentik.lib.models import SerializerModel
from authentik.lib.models import InternallyManagedMixin, SerializerModel
if TYPE_CHECKING:
from authentik.enterprise.license import LicenseKey
@@ -50,7 +50,7 @@ class License(SerializerModel):
return LicenseSerializer
@property
def status(self) -> "LicenseKey":
def status(self) -> LicenseKey:
"""Get parsed license status"""
from authentik.enterprise.license import LicenseKey
@@ -81,7 +81,7 @@ class LicenseUsageStatus(models.TextChoices):
return self in [LicenseUsageStatus.VALID, LicenseUsageStatus.EXPIRY_SOON]
class LicenseUsage(ExpiringModel):
class LicenseUsage(InternallyManagedMixin, ExpiringModel):
"""a single license usage record"""
expires = models.DateTimeField(default=usage_expiry)

View File

@@ -18,7 +18,7 @@ from authentik.core.models import (
User,
UserTypes,
)
from authentik.lib.models import SerializerModel
from authentik.lib.models import InternallyManagedMixin, SerializerModel
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient
from authentik.lib.sync.outgoing.models import OutgoingSyncDeleteAction, OutgoingSyncProvider
@@ -32,7 +32,7 @@ def default_scopes() -> list[str]:
]
class GoogleWorkspaceProviderUser(SerializerModel):
class GoogleWorkspaceProviderUser(InternallyManagedMixin, SerializerModel):
"""Mapping of a user and provider to a Google user ID"""
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
@@ -58,7 +58,7 @@ class GoogleWorkspaceProviderUser(SerializerModel):
return f"Google Workspace Provider User {self.user_id} to {self.provider_id}"
class GoogleWorkspaceProviderGroup(SerializerModel):
class GoogleWorkspaceProviderGroup(InternallyManagedMixin, SerializerModel):
"""Mapping of a group and provider to a Google group ID"""
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)

View File

@@ -18,12 +18,12 @@ from authentik.core.models import (
User,
UserTypes,
)
from authentik.lib.models import SerializerModel
from authentik.lib.models import InternallyManagedMixin, SerializerModel
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient
from authentik.lib.sync.outgoing.models import OutgoingSyncDeleteAction, OutgoingSyncProvider
class MicrosoftEntraProviderUser(SerializerModel):
class MicrosoftEntraProviderUser(InternallyManagedMixin, SerializerModel):
"""Mapping of a user and provider to a Microsoft user ID"""
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
@@ -49,7 +49,7 @@ class MicrosoftEntraProviderUser(SerializerModel):
return f"Microsoft Entra Provider User {self.user_id} to {self.provider_id}"
class MicrosoftEntraProviderGroup(SerializerModel):
class MicrosoftEntraProviderGroup(InternallyManagedMixin, SerializerModel):
"""Mapping of a group and provider to a Microsoft group ID"""
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)

View File

@@ -19,7 +19,7 @@ class SCIMOAuthException(SCIMRequestException):
class SCIMOAuthAuth:
def __init__(self, provider: "SCIMProvider"):
def __init__(self, provider: SCIMProvider):
self.provider = provider
self.user = provider.auth_oauth_user
self.logger = get_logger().bind()

View File

@@ -14,7 +14,7 @@ from jwt import encode
from authentik.core.models import BackchannelProvider, ExpiringModel, Token
from authentik.crypto.models import CertificateKeyPair
from authentik.lib.models import CreatedUpdatedModel
from authentik.lib.models import CreatedUpdatedModel, InternallyManagedMixin
from authentik.lib.utils.time import timedelta_from_string, timedelta_string_validator
from authentik.providers.oauth2.models import JWTAlgorithms, OAuth2Provider
from authentik.tasks.models import TasksModel
@@ -153,7 +153,7 @@ class Stream(models.Model):
return encode(data, key, algorithm=alg, headers=headers)
class StreamEvent(CreatedUpdatedModel, ExpiringModel):
class StreamEvent(InternallyManagedMixin, CreatedUpdatedModel, ExpiringModel):
"""Single stream event to be sent"""
uuid = models.UUIDField(default=uuid4, primary_key=True, editable=False)

View File

@@ -17,9 +17,9 @@ if TYPE_CHECKING:
class SSFTokenAuth(BaseAuthentication):
"""SSF Token auth"""
view: "SSFView"
view: SSFView
def __init__(self, view: "SSFView") -> None:
def __init__(self, view: SSFView) -> None:
super().__init__()
self.view = view

View File

@@ -4,37 +4,35 @@ from django.urls import reverse
from drf_spectacular.utils import extend_schema
from rest_framework import mixins
from rest_framework.decorators import action
from rest_framework.fields import CharField
from rest_framework.fields import CharField, SerializerMethodField
from rest_framework.permissions import BasePermission
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from authentik.core.api.groups import PartialUserSerializer
from authentik.core.api.utils import ModelSerializer
from authentik.core.models import User
from authentik.enterprise.api import EnterpriseRequiredMixin
from authentik.enterprise.reports.models import DataExport
from authentik.enterprise.reports.tasks import generate_export
from authentik.rbac.permissions import HasPermission
class RequestedBySerializer(ModelSerializer):
class Meta:
model = User
fields = ("pk", "username")
class ContentTypeSerializer(ModelSerializer):
app_label = CharField(read_only=True)
model = CharField(read_only=True)
verbose_name_plural = SerializerMethodField()
def get_verbose_name_plural(self, ct: ContentType) -> str:
return ct.model_class()._meta.verbose_name_plural
class Meta:
model = ContentType
fields = ("id", "app_label", "model")
fields = ("id", "app_label", "model", "verbose_name_plural")
class DataExportSerializer(EnterpriseRequiredMixin, ModelSerializer):
requested_by = RequestedBySerializer(read_only=True)
requested_by = PartialUserSerializer(read_only=True)
content_type = ContentTypeSerializer(read_only=True)
class Meta:

View File

@@ -0,0 +1,149 @@
"""DjangoQL search"""
from collections import OrderedDict, defaultdict
from collections.abc import Generator
from django.db import connection
from django.db.models import Model, Q
from djangoql.compat import text_type
from djangoql.schema import StrField
from djangoql.serializers import DjangoQLSchemaSerializer
class JSONSearchField(StrField):
"""JSON field for DjangoQL"""
model: Model
def __init__(
self,
model=None,
name=None,
nullable=None,
suggest_nested=False,
fixed_structure: OrderedDict | None = None,
):
# Set this in the constructor to not clobber the type variable
self.type = "relation"
self.suggest_nested = suggest_nested
self.fixed_structure = fixed_structure
super().__init__(model, name, nullable)
def get_lookup(self, path, operator, value):
search = "__".join(path)
op, invert = self.get_operator(operator)
q = Q(**{f"{search}{op}": self.get_lookup_value(value)})
return ~q if invert else q
def json_field_keys(self) -> Generator[tuple[str]]:
with connection.cursor() as cursor:
cursor.execute(
f"""
WITH RECURSIVE "{self.name}_keys" AS (
SELECT
ARRAY[jsonb_object_keys("{self.name}")] AS key_path_array,
"{self.name}" -> jsonb_object_keys("{self.name}") AS value
FROM {self.model._meta.db_table}
WHERE "{self.name}" IS NOT NULL
AND jsonb_typeof("{self.name}") = 'object'
UNION ALL
SELECT
ck.key_path_array || jsonb_object_keys(ck.value),
ck.value -> jsonb_object_keys(ck.value) AS value
FROM "{self.name}_keys" ck
WHERE jsonb_typeof(ck.value) = 'object'
),
unique_paths AS (
SELECT DISTINCT key_path_array
FROM "{self.name}_keys"
)
SELECT key_path_array FROM unique_paths;
""" # nosec
)
return (x[0] for x in cursor.fetchall())
def get_fixed_structure(self, serializer: DjangoQLSchemaSerializer) -> OrderedDict:
new_dict = OrderedDict()
if not self.fixed_structure:
return new_dict
new_dict.setdefault(self.relation(), {})
for key, value in self.fixed_structure.items():
new_dict[self.relation()][key] = serializer.serialize_field(value)
if isinstance(value, JSONSearchField):
new_dict.update(value.get_nested_options(serializer))
return new_dict
def get_nested_options(self, serializer: DjangoQLSchemaSerializer) -> OrderedDict:
"""Get keys of all nested objects to show autocomplete"""
if not self.suggest_nested:
if self.fixed_structure:
return self.get_fixed_structure(serializer)
return OrderedDict()
def recursive_function(parts: list[str], parent_parts: list[str] | None = None):
if not parent_parts:
parent_parts = []
path = parts.pop(0)
parent_parts.append(path)
relation_key = "_".join(parent_parts)
if len(parts) > 1:
out_dict = {
relation_key: {
parts[0]: {
"type": "relation",
"relation": f"{relation_key}_{parts[0]}",
}
}
}
child_paths = recursive_function(parts.copy(), parent_parts.copy())
child_paths.update(out_dict)
return child_paths
else:
return {relation_key: {parts[0]: {}}}
relation_structure = defaultdict(dict)
for relations in self.json_field_keys():
result = recursive_function([self.relation()] + relations)
for relation_key, value in result.items():
for sub_relation_key, sub_value in value.items():
if not relation_structure[relation_key].get(sub_relation_key, None):
relation_structure[relation_key][sub_relation_key] = sub_value
else:
relation_structure[relation_key][sub_relation_key].update(sub_value)
final_dict = defaultdict(dict)
for key, value in relation_structure.items():
for sub_key, sub_value in value.items():
if not sub_value:
final_dict[key][sub_key] = {
"type": "str",
"nullable": True,
}
else:
final_dict[key][sub_key] = sub_value
return OrderedDict(final_dict)
def relation(self) -> str:
return f"{self.model._meta.app_label}.{self.model._meta.model_name}_{self.name}"
class ChoiceSearchField(StrField):
def __init__(self, model=None, name=None, nullable=None):
super().__init__(model, name, nullable, suggest_options=True)
def get_options(self, search):
result = []
choices = self._field_choices()
if choices:
search = search.lower()
for c in choices:
choice = text_type(c[0])
if search in choice.lower():
result.append(choice)
return result

View File

@@ -1,15 +1,18 @@
"""QL search"""
"""DjangoQL search"""
from akql.exceptions import AKQLError
from akql.queryset import apply_search
from akql.schema import AKQLSchema
from django.apps import apps
from django.db.models import QuerySet
from djangoql.ast import Name
from djangoql.exceptions import DjangoQLError
from djangoql.queryset import apply_search
from djangoql.schema import DjangoQLSchema
from drf_spectacular.plumbing import ResolvedComponent, build_object_type
from rest_framework.filters import SearchFilter
from rest_framework.request import Request
from structlog.stdlib import get_logger
from authentik.enterprise.search.fields import JSONSearchField
LOGGER = get_logger()
AUTOCOMPLETE_SCHEMA = ResolvedComponent(
name="Autocomplete",
@@ -19,8 +22,27 @@ AUTOCOMPLETE_SCHEMA = ResolvedComponent(
)
class BaseSchema(DjangoQLSchema):
"""Base Schema which deals with JSON Fields"""
def resolve_name(self, name: Name):
model = self.model_label(self.current_model)
root_field = name.parts[0]
field = self.models[model].get(root_field)
# If the query goes into a JSON field, return the root
# field as the JSON field will do the rest
if isinstance(field, JSONSearchField):
# This is a workaround; build_filter will remove the right-most
# entry in the path as that is intended to be the same as the field
# however for JSON that is not the case
if name.parts[-1] != root_field:
name.parts.append(root_field)
return field
return super().resolve_name(name)
class QLSearch(SearchFilter):
"""rest_framework search filter which uses AKQL"""
"""rest_framework search filter which uses DjangoQL"""
def __init__(self):
super().__init__()
@@ -37,30 +59,24 @@ class QLSearch(SearchFilter):
params = params.replace("\x00", "") # strip null characters
return params
def get_schema(self, request: Request, view) -> AKQLSchema:
def get_schema(self, request: Request, view) -> BaseSchema:
ql_fields = []
if hasattr(view, "get_ql_fields"):
ql_fields = view.get_ql_fields()
class InlineSchema(AKQLSchema):
class InlineSchema(BaseSchema):
def get_fields(self, model):
return ql_fields or []
return InlineSchema
def get_search_context(self, request: Request):
return {
"$ak_user": request.user.pk,
}
def filter_queryset(self, request: Request, queryset: QuerySet, view) -> QuerySet:
search_query = self.get_search_terms(request)
schema = self.get_schema(request, view)
if len(search_query) == 0 or not self.enabled:
return self._fallback.filter_queryset(request, queryset, view)
context = self.get_search_context(request)
try:
return apply_search(queryset, search_query, context=context, schema=schema)
except AKQLError as exc:
return apply_search(queryset, search_query, schema=schema)
except DjangoQLError as exc:
LOGGER.debug("Failed to parse search expression", exc=exc)
return self._fallback.filter_queryset(request, queryset, view)

View File

@@ -1,20 +1,26 @@
from akql.schema import JSONSearchField
from akql.serializers import AKQLSchemaSerializer
from djangoql.serializers import DjangoQLSchemaSerializer
from drf_spectacular.generators import SchemaGenerator
from authentik.enterprise.search.fields import JSONSearchField
from authentik.enterprise.search.ql import AUTOCOMPLETE_SCHEMA
class AKQLSchemaSerializer(AKQLSchemaSerializer):
class AKQLSchemaSerializer(DjangoQLSchemaSerializer):
def serialize(self, schema):
serialization = super().serialize(schema)
for _, fields in schema.models.items():
for _, field in fields.items():
if not isinstance(field, JSONSearchField):
continue
serialization["models"].update(field.get_nested_options())
serialization["models"].update(field.get_nested_options(self))
return serialization
def serialize_field(self, field):
result = super().serialize_field(field)
if isinstance(field, JSONSearchField):
result["relation"] = field.relation()
return result
def postprocess_schema_search_autocomplete(result, generator: SchemaGenerator, **kwargs):
generator.registry.register_on_missing(AUTOCOMPLETE_SCHEMA)

View File

@@ -11,7 +11,7 @@ from rest_framework.serializers import BaseSerializer, Serializer
from authentik.core.types import UserSettingSerializer
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
from authentik.flows.stage import StageView
from authentik.lib.models import DeprecatedMixin, SerializerModel
from authentik.lib.models import DeprecatedMixin, InternallyManagedMixin, SerializerModel
from authentik.stages.authenticator.models import Device
@@ -63,7 +63,7 @@ class AuthenticatorEndpointGDTCStage(DeprecatedMixin, ConfigurableStage, Friendl
verbose_name_plural = _("Endpoint Authenticator Google Device Trust Connector Stages")
class EndpointDevice(SerializerModel, Device):
class EndpointDevice(InternallyManagedMixin, SerializerModel, Device):
"""Endpoint Device for a single user"""
uuid = models.UUIDField(primary_key=True, default=uuid4)
@@ -91,7 +91,7 @@ class EndpointDevice(SerializerModel, Device):
verbose_name_plural = _("Endpoint Devices")
class EndpointDeviceConnection(models.Model):
class EndpointDeviceConnection(InternallyManagedMixin, models.Model):
device = models.ForeignKey(EndpointDevice, on_delete=models.CASCADE)
stage = models.ForeignKey(AuthenticatorEndpointGDTCStage, on_delete=models.CASCADE)

View File

@@ -1,5 +1,6 @@
"""Events API Views"""
from collections import OrderedDict
from datetime import timedelta
import django_filters
@@ -136,16 +137,51 @@ class EventViewSet(
filterset_class = EventsFilter
def get_ql_fields(self):
from akql.schema import ChoiceSearchField, DateTimeField, JSONSearchField, StrField
from djangoql.schema import DateTimeField, IntField, StrField
from authentik.enterprise.search.fields import ChoiceSearchField, JSONSearchField
return [
ChoiceSearchField(Event, "action"),
StrField(Event, "event_uuid"),
StrField(Event, "app", suggest_options=True),
StrField(Event, "client_ip"),
JSONSearchField(Event, "user", suggest_nested=False),
JSONSearchField(Event, "brand", suggest_nested=False),
JSONSearchField(Event, "context", suggest_nested=False),
JSONSearchField(
Event,
"user",
fixed_structure=OrderedDict(
pk=IntField(),
username=StrField(),
email=StrField(),
),
),
JSONSearchField(
Event,
"brand",
fixed_structure=OrderedDict(
pk=StrField(),
app=StrField(),
name=StrField(),
model_name=StrField(),
),
),
JSONSearchField(
Event,
"context",
fixed_structure=OrderedDict(
http_request=JSONSearchField(
Event,
"context_http_request",
fixed_structure=OrderedDict(
args=JSONSearchField(Event, "context_http_request_args"),
path=StrField(),
method=StrField(),
request_id=StrField(),
user_agent=StrField(),
),
),
),
),
DateTimeField(Event, "created", suggest_options=True),
]

View File

@@ -1,6 +1,6 @@
"""ASN Enricher"""
from typing import TYPE_CHECKING, Optional, TypedDict
from typing import TYPE_CHECKING, TypedDict
from django.http import HttpRequest
from geoip2.errors import GeoIP2Error
@@ -27,7 +27,7 @@ class ASNDict(TypedDict):
class ASNContextProcessor(MMDBContextProcessor):
"""ASN Database reader wrapper"""
def capability(self) -> Optional["Capabilities"]:
def capability(self) -> Capabilities | None:
from authentik.api.v3.config import Capabilities
return Capabilities.CAN_ASN
@@ -35,7 +35,7 @@ class ASNContextProcessor(MMDBContextProcessor):
def path(self) -> str | None:
return CONFIG.get("events.context_processors.asn")
def enrich_event(self, event: "Event"):
def enrich_event(self, event: Event):
asn = self.asn_dict(event.client_ip)
if not asn:
return

View File

@@ -1,7 +1,7 @@
"""Base event enricher"""
from functools import cache
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING
from django.http import HttpRequest
@@ -13,7 +13,7 @@ if TYPE_CHECKING:
class EventContextProcessor:
"""Base event enricher"""
def capability(self) -> Optional["Capabilities"]:
def capability(self) -> Capabilities | None:
"""Return the capability this context processor provides"""
return None
@@ -21,7 +21,7 @@ class EventContextProcessor:
"""Return true if this context processor is configured"""
return False
def enrich_event(self, event: "Event"):
def enrich_event(self, event: Event):
"""Modify event"""
raise NotImplementedError

View File

@@ -1,6 +1,6 @@
"""events GeoIP Reader"""
from typing import TYPE_CHECKING, Optional, TypedDict
from typing import TYPE_CHECKING, TypedDict
from django.http import HttpRequest
from geoip2.errors import GeoIP2Error
@@ -29,7 +29,7 @@ class GeoIPDict(TypedDict):
class GeoIPContextProcessor(MMDBContextProcessor):
"""Slim wrapper around GeoIP API"""
def capability(self) -> Optional["Capabilities"]:
def capability(self) -> Capabilities | None:
from authentik.api.v3.config import Capabilities
return Capabilities.CAN_GEO_IP
@@ -37,7 +37,7 @@ class GeoIPContextProcessor(MMDBContextProcessor):
def path(self) -> str | None:
return CONFIG.get("events.context_processors.geoip")
def enrich_event(self, event: "Event"):
def enrich_event(self, event: Event):
city = self.city_dict(event.client_ip)
if not city:
return

View File

@@ -7,7 +7,7 @@ from typing import Any
from django.utils.timezone import now
from rest_framework.fields import CharField, ChoiceField, DateTimeField, DictField
from structlog import configure, get_config
from structlog.stdlib import NAME_TO_LEVEL, ProcessorFormatter
from structlog.stdlib import NAME_TO_LEVEL, ProcessorFormatter, get_logger
from structlog.testing import LogCapture
from structlog.types import EventDict
@@ -25,7 +25,7 @@ class LogEvent:
attributes: dict[str, Any] = field(default_factory=dict)
@staticmethod
def from_event_dict(item: EventDict) -> "LogEvent":
def from_event_dict(item: EventDict) -> LogEvent:
event = item.pop("event")
log_level = item.pop("level").lower()
timestamp = datetime.fromisoformat(item.pop("timestamp")).replace(tzinfo=UTC)
@@ -36,6 +36,9 @@ class LogEvent:
event, log_level, item.pop("logger"), timestamp, attributes=sanitize_dict(item)
)
def log(self):
get_logger(self.logger).log(NAME_TO_LEVEL[self.log_level], self.event, **self.attributes)
class LogEventSerializer(PassiveSerializer):
"""Single log message with all context logged."""

View File

@@ -19,6 +19,7 @@ from authentik.blueprints.v1.importer import excluded_models
from authentik.core.models import Group, User
from authentik.events.models import Event, EventAction, Notification
from authentik.events.utils import model_to_dict
from authentik.lib.models import InternallyManagedMixin
from authentik.lib.sentry import should_ignore_exception
from authentik.lib.utils.errors import exception_to_dict
from authentik.stages.authenticator_static.models import StaticToken
@@ -40,7 +41,7 @@ _CTX_REQUEST = ContextVar[HttpRequest | None]("authentik_events_log_request", de
def should_log_model(model: Model) -> bool:
"""Return true if operation on `model` should be logged"""
return model.__class__ not in IGNORED_MODELS
return model.__class__ not in IGNORED_MODELS and not isinstance(model, InternallyManagedMixin)
def should_log_m2m(model: Model) -> bool:

View File

@@ -8,6 +8,8 @@ from inspect import currentframe
from typing import Any
from uuid import uuid4
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.apps import apps
from django.db import models
from django.http import HttpRequest
@@ -41,6 +43,7 @@ from authentik.lib.utils.http import get_http_session
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.models import PolicyBindingModel
from authentik.root.middleware import ClientIPMiddleware
from authentik.root.ws.consumer import build_user_group
from authentik.stages.email.models import EmailTemplates
from authentik.stages.email.utils import TemplateEmailMessage
from authentik.tasks.models import TasksModel
@@ -148,7 +151,7 @@ class Event(SerializerModel, ExpiringModel):
action: str | EventAction,
app: str | None = None,
**kwargs,
) -> "Event":
) -> Event:
"""Create new Event instance from arguments. Instance is NOT saved."""
if not isinstance(action, EventAction):
action = EventAction.CUSTOM_PREFIX + action
@@ -166,19 +169,19 @@ class Event(SerializerModel, ExpiringModel):
event = Event(action=action, app=app, context=cleaned_kwargs)
return event
def with_exception(self, exc: Exception) -> "Event":
def with_exception(self, exc: Exception) -> Event:
"""Add data from 'exc' to the event in a database-saveable format"""
self.context.setdefault("message", str(exc))
self.context["exception"] = exception_to_dict(exc)
return self
def set_user(self, user: User) -> "Event":
def set_user(self, user: User) -> Event:
"""Set `.user` based on user, ensuring the correct attributes are copied.
This should only be used when self.from_http is *not* used."""
self.user = get_user(user)
return self
def from_http(self, request: HttpRequest, user: User | None = None) -> "Event":
def from_http(self, request: HttpRequest, user: User | None = None) -> Event:
"""Add data from a Django-HttpRequest, allowing the creation of
Events independently from requests.
`user` arguments optionally overrides user from requests."""
@@ -340,7 +343,7 @@ class NotificationTransport(TasksModel, SerializerModel):
),
)
def send(self, notification: "Notification") -> list[str]:
def send(self, notification: Notification) -> list[str]:
"""Send notification to user, called from async task"""
if self.mode == TransportMode.LOCAL:
return self.send_local(notification)
@@ -352,7 +355,7 @@ class NotificationTransport(TasksModel, SerializerModel):
return self.send_email(notification)
raise ValueError(f"Invalid mode {self.mode} set")
def send_local(self, notification: "Notification") -> list[str]:
def send_local(self, notification: Notification) -> list[str]:
"""Local notification delivery"""
if self.webhook_mapping_body:
self.webhook_mapping_body.evaluate(
@@ -361,9 +364,18 @@ class NotificationTransport(TasksModel, SerializerModel):
notification=notification,
)
notification.save()
layer = get_channel_layer()
async_to_sync(layer.group_send)(
build_user_group(notification.user),
{
"type": "event.notification",
"id": str(notification.pk),
"data": notification.serializer(notification).data,
},
)
return []
def send_webhook(self, notification: "Notification") -> list[str]:
def send_webhook(self, notification: Notification) -> list[str]:
"""Send notification to generic webhook"""
default_body = {
"body": notification.body,
@@ -407,7 +419,7 @@ class NotificationTransport(TasksModel, SerializerModel):
response.text,
]
def send_webhook_slack(self, notification: "Notification") -> list[str]:
def send_webhook_slack(self, notification: Notification) -> list[str]:
"""Send notification to slack or slack-compatible endpoints"""
fields = [
{
@@ -465,7 +477,7 @@ class NotificationTransport(TasksModel, SerializerModel):
response.text,
]
def send_email(self, notification: "Notification") -> list[str]:
def send_email(self, notification: Notification) -> list[str]:
"""Send notification via global email configuration"""
from authentik.stages.email.tasks import send_mail

View File

@@ -18,7 +18,7 @@ class DiagramElement:
identifier: str
description: str
action: str | None = None
source: list["DiagramElement"] | None = None
source: list[DiagramElement] | None = None
style: list[str] = field(default_factory=lambda: ["[", "]"])

18
authentik/flows/auth.py Normal file
View File

@@ -0,0 +1,18 @@
from typing import cast
from django.contrib.auth.models import AnonymousUser
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
from authentik.flows.views.executor import SESSION_KEY_PLAN
class FlowActive(BaseAuthentication):
"""Authenticate requests when a flow is currently active"""
def authenticate(self, request: Request):
plan = cast(FlowPlan | None, request.session.get(SESSION_KEY_PLAN))
if not plan:
return None
return (plan.context.get(PLAN_CONTEXT_PENDING_USER, AnonymousUser()), plan)

View File

@@ -2,7 +2,7 @@
from dataclasses import asdict, is_dataclass
from enum import Enum
from typing import TYPE_CHECKING, Optional, TypedDict
from typing import TYPE_CHECKING, TypedDict
from uuid import UUID
from django.core.serializers.json import DjangoJSONEncoder
@@ -137,7 +137,7 @@ class PermissionDict(TypedDict):
class ChallengeResponse(PassiveSerializer):
"""Base class for all challenge responses"""
stage: Optional["StageView"]
stage: StageView | None
component = CharField(default="xak-flow-response-default")
def __init__(self, instance=None, data=None, **kwargs):

View File

@@ -23,7 +23,7 @@ class StageMarker:
def process(
self,
plan: "FlowPlan",
plan: FlowPlan,
binding: FlowStageBinding,
http_request: HttpRequest,
) -> FlowStageBinding | None:
@@ -40,7 +40,7 @@ class ReevaluateMarker(StageMarker):
def process(
self,
plan: "FlowPlan",
plan: FlowPlan,
binding: FlowStageBinding,
http_request: HttpRequest,
) -> FlowStageBinding | None:

View File

@@ -20,7 +20,7 @@ from authentik.core.models import Token
from authentik.core.types import UserSettingSerializer
from authentik.flows.challenge import FlowLayout
from authentik.lib.config import CONFIG
from authentik.lib.models import InheritanceForeignKey, SerializerModel
from authentik.lib.models import InheritanceForeignKey, InternallyManagedMixin, SerializerModel
from authentik.lib.utils.reflection import class_to_path
from authentik.policies.models import PolicyBindingModel
@@ -90,7 +90,7 @@ class Stage(SerializerModel):
objects = InheritanceManager()
@property
def view(self) -> type["StageView"]:
def view(self) -> type[StageView]:
"""Return StageView class that implements logic for this stage"""
# This is a bit of a workaround, since we can't set class methods with setattr
if hasattr(self, "__in_memory_type"):
@@ -117,7 +117,7 @@ class Stage(SerializerModel):
return f"Stage {self.name}"
def in_memory_stage(view: type["StageView"], **kwargs) -> Stage:
def in_memory_stage(view: type[StageView], **kwargs) -> Stage:
"""Creates an in-memory stage instance, based on a `view` as view.
Any key-word arguments are set as attributes on the stage object,
accessible via `self.executor.current_stage`."""
@@ -301,7 +301,7 @@ class FriendlyNamedStage(models.Model):
abstract = True
class FlowToken(Token):
class FlowToken(InternallyManagedMixin, Token):
"""Subclass of a standard Token, stores the currently active flow plan upon creation.
Can be used to later resume a flow."""
@@ -310,13 +310,13 @@ class FlowToken(Token):
revoke_on_execution = models.BooleanField(default=True)
@staticmethod
def pickle(plan: "FlowPlan") -> str:
def pickle(plan: FlowPlan) -> str:
"""Pickle into string"""
data = dumps(plan)
return b64encode(data).decode()
@property
def plan(self) -> "FlowPlan":
def plan(self) -> FlowPlan:
"""Load Flow plan from pickled version"""
return loads(b64decode(self._plan.encode())) # nosec

View File

@@ -123,7 +123,7 @@ class FlowPlan:
def requires_flow_executor(
self,
allowed_silent_types: list["StageView"] | None = None,
allowed_silent_types: list[StageView] | None = None,
):
# Check if we actually need to show the Flow executor, or if we can jump straight to the end
found_unskippable = True
@@ -145,7 +145,7 @@ class FlowPlan:
request: HttpRequest,
flow: Flow,
next: str | None = None,
allowed_silent_types: list["StageView"] | None = None,
allowed_silent_types: list[StageView] | None = None,
) -> HttpResponse:
"""Redirect to the flow executor for this flow plan"""
from authentik.flows.views.executor import (

View File

@@ -46,13 +46,13 @@ HIST_FLOWS_STAGE_TIME = Histogram(
class StageView(View):
"""Abstract Stage"""
executor: "FlowExecutorView"
executor: FlowExecutorView
request: HttpRequest = None
logger: BoundLogger
def __init__(self, executor: "FlowExecutorView", **kwargs):
def __init__(self, executor: FlowExecutorView, **kwargs):
self.executor = executor
current_stage = getattr(self.executor, "current_stage", None)
self.logger = get_logger().bind(
@@ -257,7 +257,7 @@ class AccessDeniedStage(ChallengeStageView):
error_message: str | None
def __init__(self, executor: "FlowExecutorView", error_message: str | None = None, **kwargs):
def __init__(self, executor: FlowExecutorView, error_message: str | None = None, **kwargs):
super().__init__(executor, **kwargs)
self.error_message = error_message

View File

@@ -48,6 +48,14 @@ class FlowTestCase(APITestCase):
self.assertEqual(raw_response[key], expected)
return raw_response
def get_flow_plan(self) -> FlowPlan | None:
return self.client.session.get(SESSION_KEY_PLAN)
def set_flow_plan(self, plan: FlowPlan):
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
def assertStageRedirects(self, response: HttpResponse, to: str) -> dict[str, Any]:
"""Wrapper around assertStageResponse that checks for a redirect"""
return self.assertStageResponse(response, component="xak-flow-redirect", to=to)

View File

@@ -147,6 +147,8 @@ class FlowExecutorView(APIView):
token.delete()
if not isinstance(plan, FlowPlan):
return None
if existing_plan := self.request.session.get(SESSION_KEY_PLAN):
plan.context.update(existing_plan.context)
plan.context[PLAN_CONTEXT_IS_RESTORED] = token
self._logger.debug("f(exec): restored flow plan from token", plan=plan)
return plan

View File

@@ -37,18 +37,18 @@ SVG_FONTS = [
]
def avatar_mode_none(user: "User", mode: str) -> str | None:
def avatar_mode_none(user: User, mode: str) -> str | None:
"""No avatar"""
return DEFAULT_AVATAR
def avatar_mode_attribute(user: "User", mode: str) -> str | None:
def avatar_mode_attribute(user: User, mode: str) -> str | None:
"""Avatars based on a user attribute"""
avatar = get_path_from_dict(user.attributes, mode[11:], default=None)
return avatar
def avatar_mode_gravatar(user: "User", mode: str) -> str | None:
def avatar_mode_gravatar(user: User, mode: str) -> str | None:
"""Gravatar avatars"""
mail_hash = sha256(user.email.lower().encode("utf-8")).hexdigest() # nosec
@@ -141,7 +141,7 @@ def generate_avatar_from_name(
return etree.tostring(root_element).decode()
def avatar_mode_generated(user: "User", mode: str) -> str | None:
def avatar_mode_generated(user: User, mode: str) -> str | None:
"""Wrapper that converts generated avatar to base64 svg"""
# By default generate based off of user's display name
name = user.name.strip()
@@ -155,7 +155,7 @@ def avatar_mode_generated(user: "User", mode: str) -> str | None:
return f"data:image/svg+xml;base64,{b64encode(svg.encode('utf-8')).decode('utf-8')}"
def avatar_mode_url(user: "User", mode: str) -> str | None:
def avatar_mode_url(user: User, mode: str) -> str | None:
"""Format url"""
mail_hash = md5(user.email.lower().encode("utf-8"), usedforsecurity=False).hexdigest() # nosec
@@ -197,7 +197,7 @@ def avatar_mode_url(user: "User", mode: str) -> str | None:
return formatted_url
def get_avatar(user: "User", request: HttpRequest | None = None) -> str:
def get_avatar(user: User, request: HttpRequest | None = None) -> str:
"""Get avatar with configured mode"""
mode_map = {
"none": avatar_mode_none,

View File

@@ -238,7 +238,7 @@ class BaseEvaluator:
address: str | list[str],
subject: str,
body: str | None = None,
stage: "EmailStage | None" = None,
stage: EmailStage | None = None,
template: str | None = None,
context: dict | None = None,
) -> bool:

View File

@@ -111,6 +111,7 @@ def get_logger_config():
"hpack": "WARNING",
"httpx": "WARNING",
"azure": "WARNING",
"httpcore": "WARNING",
}
for handler_name, level in handler_level_map.items():
base_config["loggers"][handler_name] = {

View File

@@ -64,6 +64,10 @@ class DeprecatedMixin:
"""Mixin for classes that are deprecated"""
class InternallyManagedMixin:
"""Mixin for models that should _not_ be manageable via blueprint."""
class DomainlessURLValidator(URLValidator):
"""Subclass of URLValidator which doesn't check the domain
(to allow hostnames without domain)"""

View File

@@ -1,25 +1,61 @@
from json import JSONDecodeError
from authentik.lib.sentry import SentryIgnoredException
class BaseSyncException(SentryIgnoredException):
"""Base class for all sync exceptions"""
error_prefix = "Sync error"
error_default = "Error communicating with remote system"
def __init__(self, response=None):
super().__init__()
self.response = response
def __str__(self):
if self.response is not None:
if hasattr(self.response, "json"):
try:
return f"{self.error_prefix}: {self.response.json()}"
except JSONDecodeError:
pass
if hasattr(self.response, "text"):
return f"{self.error_prefix}: {self.response.text}"
return f"{self.error_prefix}: {self.response}"
return self.error_default
def __repr__(self):
return self.__str__()
class TransientSyncException(BaseSyncException):
"""Transient sync exception which may be caused by network blips, etc"""
error_prefix = "Network error"
error_default = "Network error communicating with remote system"
class NotFoundSyncException(BaseSyncException):
"""Exception when an object was not found in the remote system"""
error_prefix = "Object not found"
error_default = "Object not found in remote system"
class ObjectExistsSyncException(BaseSyncException):
"""Exception when an object already exists in the remote system"""
error_prefix = "Object exists"
error_default = "Object exists in remote system"
class BadRequestSyncException(BaseSyncException):
"""Exception when invalid data was sent to the remote system"""
error_prefix = "Bad request"
error_default = "Bad request to remote system"
class DryRunRejected(BaseSyncException):
"""When dry_run is enabled and a provider dropped a mutating request"""

View File

@@ -84,7 +84,7 @@ class OutgoingSyncProvider(ScheduledModel, Model):
raise NotImplementedError
def sync_dispatch(self) -> None:
for schedule in self.schedules:
for schedule in self.schedules.all():
schedule.send()
@property

View File

@@ -1,16 +1,17 @@
"""authentik database utilities"""
import gc
from collections.abc import Generator
from django.db import reset_queries
from django.db.models import QuerySet
from django.db.models import Model, QuerySet
def chunked_queryset(queryset: QuerySet, chunk_size: int = 1_000):
def chunked_queryset[T: Model](queryset: QuerySet[T], chunk_size: int = 1_000) -> Generator[T]:
if not queryset.exists():
return []
def get_chunks(qs: QuerySet):
def get_chunks(qs: QuerySet) -> Generator[QuerySet[T]]:
qs = qs.order_by("pk")
pks = qs.values_list("pk", flat=True)
start_pk = pks[0]

View File

@@ -3,7 +3,7 @@
import re
from dataclasses import asdict
from json import dumps
from typing import TYPE_CHECKING, Generic, TypeVar
from typing import TYPE_CHECKING, TypeVar
from dacite.core import from_dict
from django.http import HttpResponseNotFound
@@ -33,12 +33,12 @@ def get_version() -> str:
return authentik_version()
class KubernetesObjectReconciler(Generic[T]):
class KubernetesObjectReconciler[T]:
"""Base Kubernetes Reconciler, handles the basic logic."""
controller: "KubernetesController"
controller: KubernetesController
def __init__(self, controller: "KubernetesController"):
def __init__(self, controller: KubernetesController):
self.controller = controller
self.namespace = controller.outpost.config.kubernetes_namespace
self.logger = get_logger().bind(type=self.__class__.__name__)

View File

@@ -39,7 +39,7 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
outpost: Outpost
def __init__(self, controller: "KubernetesController") -> None:
def __init__(self, controller: KubernetesController) -> None:
super().__init__(controller)
self.api = AppsV1Api(controller.client)
self.outpost = self.controller.outpost

Some files were not shown because too many files have changed in this diff Show More