Compare commits

..

195 Commits

Author SHA1 Message Date
Teffen Ellis
c11f407470 web: Demo. 2025-08-25 22:40:00 +02:00
Teffen Ellis
b7c6b961a1 web: Flesh out wave boi. 2025-08-25 18:25:20 +02:00
Teffen Ellis
e6adb72695 web: Flesh out reload behavior. 2025-08-25 18:25:18 +02:00
Teffen Ellis
9cbdcd2cad web: Automatic reload during server start up. 2025-08-25 18:25:12 +02:00
Marc 'risson' Schmitt
197f4c5585 providers/oauth2: avoid deadlock during session migration (#16361) 2025-08-25 17:48:20 +02:00
dependabot[bot]
80e9865c6a lifecycle/aws: bump aws-cdk from 2.1025.0 to 2.1026.0 in /lifecycle/aws (#16352)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 12:25:57 +00:00
dependabot[bot]
c08df26c65 core: bump github.com/stretchr/testify from 1.10.0 to 1.11.0 (#16357)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 14:07:09 +02:00
dependabot[bot]
332a53ceff core: bump axllent/mailpit from v1.27.5 to v1.27.6 in /tests/e2e (#16358)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 14:06:01 +02:00
Mo
4919772d68 website/docs: fix missing trailing slash in vaultwarden documentation (#16348)
Missing trailing slash in documentation

Won't work without the missing forward slash.
Source: https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect#authentik

Signed-off-by: Mo <65728018+Moe1369@users.noreply.github.com>
2025-08-24 22:16:54 +01:00
Dominic R
a978b4b60e root: fix security.md (#16345)
Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-24 22:13:45 +01:00
Dewi Roberts
17bd1f1574 root: update security.md with github reporting link (#16332)
* Adds github reporting link

* Applied suggestions

* Improved wording

* Improved wording
2025-08-22 16:46:16 +01:00
Marc 'risson' Schmitt
0b4be1fdda website/docs: 2025.8.1 release notes (#16343) 2025-08-22 14:51:40 +00:00
Marc 'risson' Schmitt
e305c98eb8 packages/django-dramatiq-postgres: broker: fix various timing issues (#16340) 2025-08-22 14:04:54 +00:00
Dewi Roberts
35bd1d9907 website/docs: adds details to certificates doc (#16335)
* Clarifies certs directory mounting and adds instruction for manually re-triggering discovery.

* Fixed mounting info

* Update website/docs/sys-mgmt/certificates.md

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

* Update website/docs/sys-mgmt/certificates.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: Dominic R <dominic@sdko.org>
2025-08-22 14:53:44 +01:00
Marc 'risson' Schmitt
3150885889 outposts: allow ingress path type configuration (#16339) 2025-08-22 15:36:18 +02:00
authentik-automation[bot]
5fd96518d3 core, web: update translations (#16321)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-08-22 12:47:49 +00:00
Marc 'risson' Schmitt
287647beea outposts: fix service connection update task arguments (#16312) 2025-08-22 14:31:49 +02:00
Marcelo Elizeche Landó
2c1a0ca0fc core: use email backend for test_email management command (#16311) 2025-08-22 14:17:02 +02:00
dependabot[bot]
da47095ebc core: bump astral-sh/uv from 0.8.12 to 0.8.13 (#16325)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-22 14:15:57 +02:00
Dominic R
2ea95ba189 website: Move docs netlify.toml (#16320)
* website: Move docs netlify.toml

* Update publish path in Netlify configuration

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

---------

Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-22 13:36:16 +02:00
Tana M Berry
b277828b21 website/docs: add link in 2025.8 rel notes to back-channel logout docs (#16306)
Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-08-21 19:12:54 +00:00
Marc 'risson' Schmitt
8765c92fc4 packages/django-dramatiq-postgres: middleware: fix listening on hosts where ipv6 is not supported (#16308) 2025-08-21 19:11:21 +00:00
Teffen Ellis
536688f23b website: Fix version origin detection, build-time URLs (#15774)
* website: Update route base path.

* website: Add copy step for migration.

* website: Use build redirects.

* website: Ensure that netlify config is picked up.

* website: Add shared Netlify plugin cache.

* website: Use relative path.

* website: Fix routing when moving across versioned URLs.

* website: Fix issues surrounding origin detection.

* website: Allow integrations to omit plugin data, fix types.
2025-08-21 18:31:54 +00:00
Teffen Ellis
7861f5a40e web/a11y: Associating labels with inputs (#16119)
web: Flesh out use of label component.

web: Add correct ID to stage inputs.
2025-08-21 18:28:38 +00:00
Teffen Ellis
e7b43b72ab web: Username truncation, field alignment. (#16283) 2025-08-21 18:03:51 +02:00
Dewi Roberts
2bf9a9d4fe website/docs: adds a webhook header mapping example (#16301)
* Adds webhook header example

* Small changes

* Update website/docs/sys-mgmt/events/transports.md

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

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-08-21 16:59:03 +01:00
Teffen Ellis
f6af8f3b9d web: Fix issue where form group uses unknown slot. (#16276) 2025-08-21 17:56:26 +02:00
Marc 'risson' Schmitt
c9a4eff3a8 lifecycle: set PROMETHEUS_MULTIPROC_DIR as early as possible (#16298) 2025-08-21 11:09:36 -03:00
Marc 'risson' Schmitt
b893305e5f providers/oauth2: fix logout token missing sid, fix wrong sub mode used (#16295) 2025-08-21 10:43:10 -03:00
dependabot[bot]
b3a5cc8320 web: bump core-js from 3.45.0 to 3.45.1 in /web (#16290)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.45.0 to 3.45.1.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.45.1/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-version: 3.45.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-08-21 08:29:05 -04:00
Dominic R
94d7a989a1 root: Remove CODEOWNERS entries from docs/ directory (#16287) 2025-08-21 14:19:09 +02:00
Dominic R
359fa5d5df *: Fix dead doc link (#16288) 2025-08-21 14:09:20 +02:00
Dominic R
11c9015a49 web: saml provider view: fix state refresh issues (#14474)
* web: saml provider view: fix state refresh issues

Fixes the following issues:
1. Fixed incorrect certificate download when changing a signing certificate - previously, clicking "Download Signing Certificate" after updating a certificate would still download the old certificate until the page was refreshed.
2. Fixed missing UI updates when adding a signing certificate - previously, when a signing certificate was added to a provider, the download button wouldn't appear until the page was refreshed.
3. Fixed persistent download button when removing a certificate - previously, when a signing certificate was removed from a provider, the download button would still be visible until the page was refreshed.

* prob has more uses than for certs only

* teffen's suggestions

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

* fix

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

* this should fix it?

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

---------

Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-21 03:39:16 +02:00
Max
f135990c6b web: fix "Explore integrations" link in Quick actions (#16274)
fix "Explore integrations" link in Quick actions
2025-08-20 19:21:46 -04:00
Max
6f63a3eb15 website/integrations: fix dead links to external docs (#16273) 2025-08-20 18:46:27 +00:00
Marc 'risson' Schmitt
2209fcea2a tasks: add rel_obj to system task exception event (#16270) 2025-08-20 17:29:05 +00:00
Marc 'risson' Schmitt
e5efb50a37 website/docs: update 2025.8 release notes (#16269) 2025-08-20 19:15:20 +02:00
dependabot[bot]
bbc02dc065 web: bump @patternfly/elements from 4.1.0 to 4.2.0 in /web (#16265)
Bumps [@patternfly/elements](https://github.com/patternfly/patternfly-elements/tree/HEAD/elements) from 4.1.0 to 4.2.0.
- [Release notes](https://github.com/patternfly/patternfly-elements/releases)
- [Changelog](https://github.com/patternfly/patternfly-elements/blob/main/elements/CHANGELOG.md)
- [Commits](https://github.com/patternfly/patternfly-elements/commits/@patternfly/elements@4.2.0/elements)

---
updated-dependencies:
- dependency-name: "@patternfly/elements"
  dependency-version: 4.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>
2025-08-20 13:05:02 +01:00
dependabot[bot]
f3f81951c6 web: bump mermaid from 11.9.0 to 11.10.0 in /web (#16263)
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 11.9.0 to 11.10.0.
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Commits](https://github.com/mermaid-js/mermaid/compare/mermaid@11.9.0...mermaid@11.10.0)

---
updated-dependencies:
- dependency-name: mermaid
  dependency-version: 11.10.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-08-20 13:04:50 +01:00
dependabot[bot]
739eff66e0 web: bump @types/guacamole-common-js from 1.5.3 to 1.5.4 in /web (#16262)
Bumps [@types/guacamole-common-js](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/guacamole-common-js) from 1.5.3 to 1.5.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/guacamole-common-js)

---
updated-dependencies:
- dependency-name: "@types/guacamole-common-js"
  dependency-version: 1.5.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-08-20 13:04:24 +01:00
Dominic R
48de61a926 security: Bump supported versions (#16261)
Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-20 12:41:45 +01:00
Marcelo Elizeche Landó
032031f2cf core: bump channels from 4.3.0 to v4.3.1 (#16260) 2025-08-20 13:25:44 +02:00
transifex-integration[bot]
4e44209af1 translate: Updates for file web/xliff/en.xlf in cs_CZ (#16264)
* Translate web/xliff/en.xlf in cs_CZ

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

* Translate web/xliff/en.xlf in cs_CZ

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

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-20 11:12:41 +00:00
dependabot[bot]
289555abcd website: bump the eslint group in /website with 3 updates (#16248) 2025-08-19 21:38:10 +01:00
Marcelo Elizeche Landó
943c456555 stages/authenticator_duo: Add test to fix codecov error (#16257)
* Add test to fix codecov error

* use self.assertJSONEqual instead of assertEqual
2025-08-19 22:12:39 +02:00
dependabot[bot]
a79b914d39 core: bump selenium/standalone-chrome from 138.0 to 139.0 in /tests/e2e (#16256) 2025-08-19 21:06:20 +01:00
dependabot[bot]
7a8816abd1 web: bump the eslint group across 2 directories with 3 updates (#16255) 2025-08-19 21:06:00 +01:00
Dominic R
93e448c3fd website/docs: sys-mgmt/s3: Clean up and improve (#16242)
* website/docs: sys-mgmt/s3: Clean up and improve

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

Co-authored-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/docs/sys-mgmt/ops/storage-s3.md

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

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-08-19 15:01:32 -05:00
Tana M Berry
109c869f97 website/docs: Advanced queries, remove reference to QL and add more examples (#16191)
* remove reference to QL

* add Jens' examples

* tweak

* Update website/docs/users-sources/user/user_basic_operations.md

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/docs/users-sources/user/user_basic_operations.md

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* add note about UX ticks

* tweak

* argh

* clarify there are more values

* add link to Event actions list

* tweaks, typo

* Update website/docs/users-sources/user/user_basic_operations.md

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

* Update website/docs/sys-mgmt/events/logging-events.md

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* jens edits

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tana@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-08-19 14:27:00 -05:00
Dominic R
8029fdad7b website/integrations: emby (#15921)
Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana Berry <tana@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Ivan Schaller <ivan@schaller.sh>
2025-08-19 14:12:45 -05:00
Marcelo Elizeche Landó
d2aac457ef stages/authenticator_duo: return generic error message (#16194)
* return generic error message

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

* fix linting

* Trigger Build

---------

Signed-off-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
2025-08-19 18:27:48 +02:00
dependabot[bot]
70ce5ccceb core: bump axllent/mailpit from v1.27.4 to v1.27.5 in /tests/e2e (#16252)
Bumps axllent/mailpit from v1.27.4 to v1.27.5.

---
updated-dependencies:
- dependency-name: axllent/mailpit
  dependency-version: v1.27.5
  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-08-19 17:05:56 +01:00
dependabot[bot]
173c334478 core: bump astral-sh/uv from 0.8.11 to 0.8.12 (#16250)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.8.11 to 0.8.12.
- [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.8.11...0.8.12)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.8.12
  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-08-19 17:05:33 +01:00
dependabot[bot]
6e321097a1 web: bump the rollup group across 1 directory with 4 updates (#16251)
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.46.2 to 4.46.3
- [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.46.2...v4.46.3)

Updates `@rollup/rollup-linux-arm64-gnu` from 4.46.2 to 4.46.3
- [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.46.2...v4.46.3)

Updates `@rollup/rollup-linux-x64-gnu` from 4.46.2 to 4.46.3
- [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.46.2...v4.46.3)

Updates `rollup` from 4.46.2 to 4.46.3
- [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.46.2...v4.46.3)

---
updated-dependencies:
- dependency-name: "@rollup/rollup-darwin-arm64"
  dependency-version: 4.46.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-arm64-gnu"
  dependency-version: 4.46.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-version: 4.46.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
- dependency-name: rollup
  dependency-version: 4.46.3
  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-08-19 17:05:29 +01:00
dependabot[bot]
f3bf8097b8 core: bump goauthentik/fips-python from 3.13.6-slim-bookworm-fips to 3.13.7-slim-bookworm-fips (#16253)
core: bump goauthentik/fips-python

Bumps goauthentik/fips-python from 3.13.6-slim-bookworm-fips to 3.13.7-slim-bookworm-fips.

---
updated-dependencies:
- dependency-name: goauthentik/fips-python
  dependency-version: 3.13.7-slim-bookworm-fips
  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-08-19 17:05:16 +01:00
authentik-automation[bot]
b869433e4d core, web: update translations (#16244)
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-08-19 13:51:45 +01:00
Dominic R
5aef86c3d1 core: Block usage of Django's createsuperuser (#16215)
wip
2025-08-19 13:43:06 +01:00
Dominic R
970ac44ff8 web: Do not mark Attributes as a mandatory field (#16004)
* web: Do not mark Attributes as a mandatory field

* fix lint

* Teffen's suggestion
2025-08-19 14:16:49 +02:00
dependabot[bot]
9145d55e6c web: bump @types/react from 19.1.8 to 19.1.10 in /packages/docusaurus-config (#16131)
web: bump @types/react in /packages/docusaurus-config

Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 19.1.8 to 19.1.10.
- [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.1.10
  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-08-18 20:39:35 +01:00
Dominic R
1c36b361b2 router: fix missing response headers on compressed 404 for static files (#16216)
* router: only serve dist assets if present; fallback to backend 404

* fix

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-08-18 20:18:28 +01:00
Teffen Ellis
d55e23cdb8 web: Fix ak-flow-card footer alignment. (#16236) 2025-08-18 18:10:51 +00:00
Teffen Ellis
52673e4223 web: Fix reported error precedence (#16231)
* web: Fix issue where controlled element is not assigned.

* web: Fix preferred error to display when API response include fields.

* web: Clarify error message alert.

* web: Fix issue where impersonation form can be submitted with empty
fields. Clarify message behavior.
2025-08-18 17:39:44 +00:00
Marc 'risson' Schmitt
5cbcbf8d2c brands: revert sort matched brand by match length (revert #15413) (#16233) 2025-08-18 17:22:00 +00:00
Dominic R
f29a4c1876 website/integrations: vaultwarden (#16057)
Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-08-18 11:36:41 -05:00
Brian Begun
38fb5cd712 website/integrations: update tautulli (#16059)
* Update index.md

Revised tutorial using new template.  Sorry for the delay on this.  

Signed-off-by: Brian Begun <begunfx@usa.net>

* Update website/integrations/media/tautulli/index.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Brian Begun <begunfx@usa.net>

* fix linting

* remove placeholder section

* Update website/integrations/media/tautulli/index.md

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

* Update website/integrations/media/tautulli/index.md

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

* Update website/integrations/media/tautulli/index.md

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

* Update website/integrations/media/tautulli/index.md

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

* Update website/integrations/media/tautulli/index.md

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

* Update website/integrations/media/tautulli/index.md

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

* Update website/integrations/media/tautulli/index.md

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

* Update website/integrations/media/tautulli/index.md

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

---------

Signed-off-by: Brian Begun <begunfx@usa.net>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-08-18 11:30:35 -05:00
authentik-automation[bot]
5b2aad586f core, web: update translations (#16210)
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-08-18 17:12:15 +01:00
Simonyi Gergő
2dd1c7b1ab rbac: assign InitialPermissions in a middleware (#16138)
assign `InitialPermission`s in a middleware

This will catch more creation events, hopefully fixing things like
https://github.com/goauthentik/authentik/issues/14313
2025-08-18 18:02:48 +02:00
dependabot[bot]
57c24e5c1c website: bump @types/node from 24.2.1 to 24.3.0 in /website (#16218)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.2.1 to 24.3.0.
- [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: 24.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-08-18 16:50:46 +01:00
dependabot[bot]
76d9b3479e web: bump the goauthentik group across 1 directory with 2 updates (#16219)
Bumps the goauthentik group with 2 updates in the /web directory: @goauthentik/prettier-config and [@goauthentik/api](https://github.com/goauthentik/authentik).


Updates `@goauthentik/prettier-config` from 1.0.5 to 3.1.0

Updates `@goauthentik/api` from 2024.6.0-1720200294 to 2025.10.0-rc1-1755254677
- [Release notes](https://github.com/goauthentik/authentik/releases)
- [Commits](https://github.com/goauthentik/authentik/commits)

---
updated-dependencies:
- dependency-name: "@goauthentik/prettier-config"
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: goauthentik
- dependency-name: "@goauthentik/api"
  dependency-version: 2025.10.0-rc1-1755254677
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: goauthentik
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 16:50:38 +01:00
dependabot[bot]
e9f946cdf2 web: bump @types/node from 24.2.1 to 24.3.0 in /packages/prettier-config (#16220)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.2.1 to 24.3.0.
- [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: 24.3.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-08-18 16:50:22 +01:00
dependabot[bot]
167452f1ed web: bump @types/node from 24.2.1 to 24.3.0 in /packages/esbuild-plugin-live-reload (#16221)
web: bump @types/node in /packages/esbuild-plugin-live-reload

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.2.1 to 24.3.0.
- [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: 24.3.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-08-18 16:50:14 +01:00
dependabot[bot]
dbfdb37e83 web: bump @types/node from 22.15.19 to 24.3.0 in /web (#16222)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.15.19 to 24.3.0.
- [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: 24.3.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>
2025-08-18 16:48:49 +01:00
dependabot[bot]
efdbf7aeed core: bump goauthentik.io/api/v3 from 3.2025100.1 to 3.2025100.2 (#16217)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 15:43:36 +02:00
Dominic R
8e9e4de80f website: prettierignore: Add docsmg Rust target (#16067) 2025-08-18 15:31:21 +02:00
Teffen Ellis
a63c5b1846 web: Improvements to ReCaptcha resizing (#16171)
* web: Remove comments from serialized HTML.

* web: Apply color theme to iframe.

* web: Fix issues surrounding reCaptcha resize events not propagating.
2025-08-18 13:24:14 +00:00
Teffen Ellis
80b84fa8a8 web/a11y: QL Search Input (#16198)
web: Fix issues surrounding form submission, keyboard focus, alignment.
2025-08-18 15:01:47 +02:00
Dominic R
4ce9795491 website/integrations: headscale: Remove href in product description (#16214)
Not included in any other integration and frankly unneeded with the link right below

Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-18 01:41:27 -05:00
dependabot[bot]
e50cf1c150 web: bump @sentry/browser from 10.3.0 to 10.4.0 in /web in the sentry group across 1 directory (#16122)
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.3.0 to 10.4.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.3.0...10.4.0)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 10.4.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-08-15 17:37:25 +01:00
authentik-automation[bot]
4178717386 core, web: update translations (#16195)
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-08-15 17:36:59 +01:00
M-Slanec
20d068f767 policies/password: Fix amount_uppercase in password policy check (#16197)
Fix amount_uppercase in password policy check

Co-authored-by: Matthew Slanec <matthewslanec@Matthews-MacBook-Pro.local>
2025-08-15 13:51:43 +01:00
authentik-automation[bot]
5b7a42e6d6 web: bump API Client version (#16203)
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-08-15 13:04:59 +01:00
dependabot[bot]
1398561142 core: bump astral-sh/uv from 0.8.10 to 0.8.11 (#16201) 2025-08-15 12:27:42 +01:00
dependabot[bot]
55657e149b web: bump chromedriver from 139.0.0 to 139.0.1 in /web (#16200)
Bumps [chromedriver](https://github.com/giggio/node-chromedriver) from 139.0.0 to 139.0.1.
- [Commits](https://github.com/giggio/node-chromedriver/compare/139.0.0...139.0.1)

---
updated-dependencies:
- dependency-name: chromedriver
  dependency-version: 139.0.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-08-15 11:47:52 +01:00
authentik-automation[bot]
d5d7140631 stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#16196)
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-08-15 11:46:40 +01:00
Marcelo Elizeche Landó
17ff12f68f core: Add email template selector (#16170)
* Unify all email templates under stages.email.models.EmailTemplates

* Add template selector to Email Authenticator Stage

* fix tests

* Add email_template field to events.notificationtransport

* update schemas

* Make email_template default as None, add UI to notif transports

* Add showEmail and fix default selection in TransportForm

* fix required field for emailtemplate and webhookurl in TransportForm

* use switch because typescript is whinning

* Add email_subject_prefix to NotificationTransport

* Add tests, update migration

* remove duplicate API

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

* rename template name

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

* move send_once up

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

* better defaults

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

* no null

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

* update test for email templates endpoint

* fix test url

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-08-15 11:44:18 +01:00
Tana M Berry
9c9a6e3d66 website/docs: add content about new Advanced Query searches (#16019)
Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-08-14 17:31:36 +02:00
dependabot[bot]
2cd81b2e78 web: bump the eslint group across 2 directories with 3 updates (#16133)
Bumps the eslint group with 1 update in the /packages/eslint-config directory: [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).
Bumps the eslint group with 1 update in the /web directory: [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `typescript-eslint` from 8.39.0 to 8.39.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.39.1/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.39.0 to 8.39.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.39.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.39.0 to 8.39.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.39.1/packages/parser)

Updates `typescript-eslint` from 8.39.0 to 8.39.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.39.1/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.39.0 to 8.39.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.39.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.39.0 to 8.39.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.39.1/packages/parser)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.39.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.39.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.39.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.39.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-08-14 14:31:52 +01:00
dependabot[bot]
bad426f694 web: bump @types/react from 19.1.8 to 19.1.10 in /web (#16125)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 19.1.8 to 19.1.10.
- [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.1.10
  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-08-14 14:31:44 +01:00
dependabot[bot]
6404fba2e4 web: bump core-js from 3.44.0 to 3.45.0 in /web (#16123)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.44.0 to 3.45.0.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.45.0/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-version: 3.45.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-08-14 14:31:28 +01:00
Marc 'risson' Schmitt
c33b9f2d3f web/admin: fix settings saving (#16184)
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-08-14 12:33:33 +00:00
dependabot[bot]
bac6e965f4 website: bump the eslint group in /website with 3 updates (#16124)
Bumps the eslint group in /website with 3 updates: [@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.39.0 to 8.39.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.39.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.39.0 to 8.39.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.39.1/packages/parser)

Updates `typescript-eslint` from 8.39.0 to 8.39.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.39.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.39.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-08-14 12:01:48 +01:00
dependabot[bot]
36cb4dc750 web: bump typedoc-plugin-markdown from 4.8.0 to 4.8.1 in /packages/esbuild-plugin-live-reload (#16126)
web: bump typedoc-plugin-markdown

Bumps [typedoc-plugin-markdown](https://github.com/typedoc2md/typedoc-plugin-markdown/tree/HEAD/packages/typedoc-plugin-markdown) from 4.8.0 to 4.8.1.
- [Release notes](https://github.com/typedoc2md/typedoc-plugin-markdown/releases)
- [Changelog](https://github.com/typedoc2md/typedoc-plugin-markdown/blob/main/packages/typedoc-plugin-markdown/CHANGELOG.md)
- [Commits](https://github.com/typedoc2md/typedoc-plugin-markdown/commits/typedoc-plugin-markdown@4.8.1/packages/typedoc-plugin-markdown)

---
updated-dependencies:
- dependency-name: typedoc-plugin-markdown
  dependency-version: 4.8.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-08-14 12:01:34 +01:00
dependabot[bot]
45d9945a3a web: bump the storybook group across 1 directory with 5 updates (#16134)
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 9.1.1 to 9.1.2
- [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/v9.1.2/code/addons/docs)

Updates `@storybook/addon-links` from 9.1.1 to 9.1.2
- [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/v9.1.2/code/addons/links)

Updates `@storybook/web-components` from 9.1.1 to 9.1.2
- [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/v9.1.2/code/renderers/web-components)

Updates `@storybook/web-components-vite` from 9.1.1 to 9.1.2
- [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/v9.1.2/code/frameworks/web-components-vite)

Updates `storybook` from 9.1.1 to 9.1.2
- [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/v9.1.2/code/core)

---
updated-dependencies:
- dependency-name: "@storybook/addon-docs"
  dependency-version: 9.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/addon-links"
  dependency-version: 9.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/web-components"
  dependency-version: 9.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/web-components-vite"
  dependency-version: 9.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: storybook
  dependency-version: 9.1.2
  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-08-14 11:59:51 +01:00
dependabot[bot]
23285ad664 core: bump goauthentik.io/api/v3 from 3.2025064.8 to 3.2025100.1 (#16161)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2025064.8 to 3.2025100.1.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Changelog](https://github.com/goauthentik/client-go/blob/main/model_version_history.go)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2025064.8...v3.2025100.1)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2025100.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-08-14 11:59:24 +01:00
dependabot[bot]
91ab9503fd web: bump the esbuild group across 2 directories with 4 updates (#16162)
Bumps the esbuild group with 1 update in the /packages/esbuild-plugin-live-reload directory: [esbuild](https://github.com/evanw/esbuild).
Bumps the esbuild group with 1 update in the /web directory: [esbuild](https://github.com/evanw/esbuild).


Updates `esbuild` from 0.25.8 to 0.25.9
- [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.25.8...v0.25.9)

Updates `@esbuild/darwin-arm64` from 0.25.8 to 0.25.9
- [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.25.8...v0.25.9)

Updates `@esbuild/linux-arm64` from 0.25.8 to 0.25.9
- [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.25.8...v0.25.9)

Updates `@esbuild/linux-x64` from 0.25.8 to 0.25.9
- [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.25.8...v0.25.9)

Updates `esbuild` from 0.25.8 to 0.25.9
- [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.25.8...v0.25.9)

Updates `@esbuild/darwin-arm64` from 0.25.8 to 0.25.9
- [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.25.8...v0.25.9)

Updates `@esbuild/linux-arm64` from 0.25.8 to 0.25.9
- [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.25.8...v0.25.9)

Updates `@esbuild/linux-x64` from 0.25.8 to 0.25.9
- [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.25.8...v0.25.9)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.25.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/darwin-arm64"
  dependency-version: 0.25.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/linux-arm64"
  dependency-version: 0.25.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/linux-x64"
  dependency-version: 0.25.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: esbuild
  dependency-version: 0.25.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/darwin-arm64"
  dependency-version: 0.25.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/linux-arm64"
  dependency-version: 0.25.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/linux-x64"
  dependency-version: 0.25.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: esbuild
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:58:58 +01:00
dependabot[bot]
fb7802e6af web: bump the wdio group across 1 directory with 3 updates (#16163)
Bumps the wdio group with 3 updates in the /web directory: [@wdio/browser-runner](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-browser-runner), [@wdio/cli](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-cli) and [@wdio/spec-reporter](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-spec-reporter).


Updates `@wdio/browser-runner` from 9.19.0 to 9.19.1
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v9.19.1/packages/wdio-browser-runner)

Updates `@wdio/cli` from 9.19.0 to 9.19.1
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v9.19.1/packages/wdio-cli)

Updates `@wdio/spec-reporter` from 9.19.0 to 9.19.1
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v9.19.1/packages/wdio-spec-reporter)

---
updated-dependencies:
- dependency-name: "@wdio/browser-runner"
  dependency-version: 9.19.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: wdio
- dependency-name: "@wdio/cli"
  dependency-version: 9.19.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: wdio
- dependency-name: "@wdio/spec-reporter"
  dependency-version: 9.19.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: wdio
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:58:46 +01:00
authentik-automation[bot]
0f13a63528 core, web: update translations (#16175)
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-08-14 11:57:52 +01:00
dependabot[bot]
36daf4b519 core: bump github.com/getsentry/sentry-go from 0.35.0 to 0.35.1 (#16176)
Bumps [github.com/getsentry/sentry-go](https://github.com/getsentry/sentry-go) from 0.35.0 to 0.35.1.
- [Release notes](https://github.com/getsentry/sentry-go/releases)
- [Changelog](https://github.com/getsentry/sentry-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-go/compare/v0.35.0...v0.35.1)

---
updated-dependencies:
- dependency-name: github.com/getsentry/sentry-go
  dependency-version: 0.35.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-08-14 11:57:44 +01:00
dependabot[bot]
5cc4793b84 lifecycle/aws: bump aws-cdk from 2.1024.0 to 2.1025.0 in /lifecycle/aws (#16177)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1024.0 to 2.1025.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1025.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1025.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-08-14 11:57:36 +01:00
dependabot[bot]
a6063d4af4 core: bump library/golang from 1.24-bookworm to 1.25-bookworm (#16178)
Bumps library/golang from 1.24-bookworm to 1.25-bookworm.

---
updated-dependencies:
- dependency-name: library/golang
  dependency-version: 1.25-bookworm
  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-08-14 11:57:24 +01:00
dependabot[bot]
8f450e6e14 core: bump astral-sh/uv from 0.8.9 to 0.8.10 (#16179)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.8.9 to 0.8.10.
- [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.8.9...0.8.10)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.8.10
  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-08-14 11:57:15 +01:00
Dominic R
a1fc0605e2 website/integrations: nextcloud: Cleanup SAML service config (#16066)
* wip

* wip

* wip
2025-08-14 10:44:34 +01:00
Teffen Ellis
c886e4ff6b web: Fix issue where clicking a list item scrolls container. (#16174) 2025-08-13 21:30:58 +00:00
Marc 'risson' Schmitt
f91ebc2ad5 ci: release tag: fix missing env variables (#16172) 2025-08-13 21:09:41 +01:00
Jens L.
dbe7bfe58b tasks: add sentry dramatiq integration (#16167) 2025-08-13 18:53:12 +01:00
Teffen Ellis
05d4d207d7 web: Fix hidden textarea required attribute. (#16168)
* web: Fix hidden textarea `required` attribute.

* web: Fix missing flag property.

* web: Clarify field error reporting.
2025-08-13 12:31:00 -04:00
Marc 'risson' Schmitt
11efc75451 ci: release: consolidation bump version and on tag (#16164)
Co-authored-by: Dominic R <dominic@sdko.org>
2025-08-13 18:21:12 +02:00
authentik-automation[bot]
4d2d020be1 web: bump API Client version (#16152)
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-08-13 14:48:57 +01:00
Marc 'risson' Schmitt
9c0905d76d ci: fix docker hub credentials (#16165) 2025-08-13 15:18:39 +02:00
Marc 'risson' Schmitt
3ca94b2198 root: fix custom packages installation in docker (#16157) 2025-08-13 12:24:21 +00:00
Marc 'risson' Schmitt
dbf51fb11f ci: release publish: fix missing permissions (#16155) 2025-08-13 13:22:35 +01:00
Marc 'risson' Schmitt
ad69eb955f ci: docker push: fix version missing dash (#16153) 2025-08-13 13:22:14 +01:00
transifex-integration[bot]
c867ebc014 translate: Updates for file web/xliff/en.xlf in fr (#16160)
Translate web/xliff/en.xlf in fr

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-13 12:06:38 +00:00
authentik-automation[bot]
adea1e460c core, web: update translations (#16159)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-08-13 00:38:30 +00:00
Marc 'risson' Schmitt
846c58e617 root: fix custom packages installation in docker (#16150) 2025-08-12 21:29:56 +00:00
Marcelo Elizeche Landó
352079fc3c core: bump redis from 6.2.0 to v6.3.0 (#15983) 2025-08-12 23:20:40 +02:00
dependabot[bot]
6786391732 core: bump github.com/redis/go-redis/v9 from 9.11.0 to 9.12.1 (#16121)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 23:19:52 +02:00
dependabot[bot]
4b3d08154d core: bump astral-sh/uv from 0.8.8 to 0.8.9 (#16120)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 23:19:33 +02:00
authentik-automation[bot]
130fe4cac7 root: bump version to 2025.10.0-rc1 (#16149)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-08-12 21:17:14 +00:00
Marc 'risson' Schmitt
c7679434e1 ci: release bump version: run migrations (#16148) 2025-08-12 20:22:29 +00:00
Marc 'risson' Schmitt
8bc58e24e9 website/docs: 2025.8 release notes: add changelog and API diff (#16147) 2025-08-12 22:12:30 +02:00
Marc 'risson' Schmitt
2aa256d532 root: fix missing uv run in makefile (#16146) 2025-08-12 19:58:09 +00:00
authentik-automation[bot]
2f2bdd032d web: bump API Client version (#16132)
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-08-12 19:46:45 +00:00
Dametto Luca
e36529614f website/docs: Fixed documentation issue for core_users_recovery_email_create (#16140)
Co-authored-by: Luca Dametto <>
2025-08-12 21:20:14 +02:00
Marc 'risson' Schmitt
883367263a ci: release branch off: fix missing migrations (#16145) 2025-08-12 19:00:58 +00:00
Marc 'risson' Schmitt
96a47c69e0 ci: setup action: uninstall man-db (#16144) 2025-08-12 20:45:29 +02:00
Marc 'risson' Schmitt
3ae9721698 ci: release: add missing env variables (#16143) 2025-08-12 18:28:52 +00:00
Marc 'risson' Schmitt
30a3ad402b ci: release branch off: use github app for branch creation (#16141) 2025-08-12 19:48:53 +02:00
Marc 'risson' Schmitt
4e500030d1 ci: release branch off: various fixes (#16137) 2025-08-12 16:49:02 +00:00
Marc 'risson' Schmitt
885f1cc018 ci: add release bump version workflow (#16136)
Co-authored-by: Dominic R <dominic@sdko.org>
2025-08-12 16:48:12 +00:00
Marc 'risson' Schmitt
a4c7e7ba2e root: bump version to 2025.8.0-rc1 (#16135) 2025-08-12 15:24:23 +00:00
Marc 'risson' Schmitt
a4dbd1dc93 ci: add release branch-off workflow (#16130) 2025-08-12 14:39:51 +00:00
Teffen Ellis
1bc2daae98 web: Form validation regressions, consistency fixes (#15894)
* web: Clean up naming of inputs.

* web: Flesh out label components, slots.

* web: Expand clickable area of labels.

* web: Fix issue where launch URL is required.

* web: Surface string errors verbatim.

* web: Fix issues surrounding client-side error reporting, form validation,
server-side error reporting.

* web: Clarify property visibility.

* web: Fix issue where provider errors are not surfaced.

* web: Fix issue where wizard steps do not consistently use form validation.

* web: Fix issue where render root is not preferred.

* web: Fix import path.

* web: Fix selectors.

* keep labels aligned

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

* web: Fix field nesting.

* web: Fix issue where required secret text inputs fail validation when editing existing entities.

- We need to make the component have a better understanding of this concept.

* web: Fix slot alignment on legacy elements.

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-08-12 14:34:08 +00:00
Jens L.
a38239509b root: Better version bump (#14905)
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-08-12 13:50:12 +00:00
Marcelo Elizeche Landó
34bab28985 website/docs: remove slash from API reference (#16117) 2025-08-12 15:02:19 +02:00
Marc 'risson' Schmitt
b68adec303 packages/django-dramatiq-postgres: broker: remember previously fetched notifies (#16128) 2025-08-12 12:57:45 +00:00
dependabot[bot]
cf4dd24b6f ci: bump actions/checkout from 4 to 5 (#16127)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  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>
2025-08-12 13:47:23 +01:00
Dominic R
ffe767fe13 outpost: proxy: handle nil HTTP response in attemptBasicAuth function (#13781)
* outpost: proxy: handle nil HTTP response in attemptBasicAuth function

Fixes a nil pointer dereference that occurs when an HTTP request fails in the attemptBasicAuth function. Added additional checks to safely handle cases where the HTTP response or its body is nil.

* add defer res.Body.Close() to prevent resource leaks in basic auth

* oops

* this

* Revert "this"

This reverts commit 7f7d110291.

* wip

* better?
2025-08-12 11:40:18 +01:00
authentik-automation[bot]
c0732ec687 core, web: update translations (#16118)
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-08-12 11:16:03 +01:00
authentik-automation[bot]
cf72074820 core, web: update translations (#16116)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-08-11 16:50:00 +00:00
Jens L.
e154fee28a lib/sync: drop sync task when triggered by users' last_login change (#15553)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-08-11 17:20:17 +01:00
transifex-integration[bot]
85ccd7acbc translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN [Manual Sync] (#16109)
Translate django.po in zh_CN [Manual Sync]

90% of minimum 60% translated source file: 'django.po'
on 'zh_CN'.

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:51:34 +00:00
transifex-integration[bot]
3f52706e3f translate: Updates for file locale/en/LC_MESSAGES/django.po in fi [Manual Sync] (#16093)
Translate django.po in fi [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:39:16 +00:00
transifex-integration[bot]
662ac47332 translate: Updates for file locale/en/LC_MESSAGES/django.po in pt [Manual Sync] (#16098)
Translate django.po in pt [Manual Sync]

88% of minimum 60% translated source file: 'django.po'
on 'pt'.

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:34:38 +00:00
transifex-integration[bot]
b3e69c1665 translate: Updates for file web/xliff/en.xlf in zh_TW [Manual Sync] (#16113)
Translate web/xliff/en.xlf in zh_TW [Manual Sync]

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

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

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

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

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

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

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:33:20 +00:00
transifex-integration[bot]
9ac320a5d9 translate: Updates for file locale/en/LC_MESSAGES/django.po in tr [Manual Sync] (#16096)
Translate django.po in tr [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:32:00 +00:00
transifex-integration[bot]
7ce1ac08d4 translate: Updates for file locale/en/LC_MESSAGES/django.po in de [Manual Sync] (#16091)
Translate django.po in de [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:31:45 +00:00
transifex-integration[bot]
fc68221495 translate: Updates for file locale/en/LC_MESSAGES/django.po in ru [Manual Sync] (#16090)
Translate django.po in ru [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:31:09 +00:00
transifex-integration[bot]
37066eef6c translate: Updates for file web/xliff/en.xlf in it [Manual Sync] (#16095)
Translate web/xliff/en.xlf in it [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:30:51 +00:00
transifex-integration[bot]
63e116f109 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans [Manual Sync] (#16112)
Translate django.po in zh-Hans [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:30:14 +00:00
transifex-integration[bot]
eb0611950c translate: Updates for file locale/en/LC_MESSAGES/django.po in pl [Manual Sync] (#16092)
Translate django.po in pl [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:29:37 +00:00
transifex-integration[bot]
c03fe12406 translate: Updates for file web/xliff/en.xlf in de [Manual Sync] (#16110)
Translate web/xliff/en.xlf in de [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:28:38 +00:00
transifex-integration[bot]
72ac793065 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_TW [Manual Sync] (#16107)
Translate django.po in zh_TW [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:25:55 +00:00
transifex-integration[bot]
43ed08c636 translate: Updates for file web/xliff/en.xlf in es [Manual Sync] (#16106)
Translate web/xliff/en.xlf in es [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:23:34 +00:00
transifex-integration[bot]
2534261954 translate: Updates for file web/xliff/en.xlf in cs_CZ [Manual Sync] (#16104)
Translate web/xliff/en.xlf in cs_CZ [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:18:10 +00:00
transifex-integration[bot]
41cd3305f9 translate: Updates for file web/xliff/en.xlf in ru [Manual Sync] (#16114)
Translate web/xliff/en.xlf in ru [Manual Sync]

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

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

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

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:05:36 +00:00
transifex-integration[bot]
13bdad33cb translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR [Manual Sync] (#16105)
Translate django.po in pt_BR [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 15:03:55 +00:00
transifex-integration[bot]
0fd53bb8cf translate: Updates for file web/xliff/en.xlf in zh_CN [Manual Sync] (#16103)
Translate web/xliff/en.xlf in zh_CN [Manual Sync]

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

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

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

90% of minimum 60% translated source file: 'django.po'
on 'it'.

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 14:58:43 +00:00
transifex-integration[bot]
6d1d15d6e8 translate: Updates for file web/xliff/en.xlf in nl [Manual Sync] (#16100)
Translate web/xliff/en.xlf in nl [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 14:55:42 +00:00
transifex-integration[bot]
638dfb4d3c translate: Updates for file web/xliff/en.xlf in ko [Manual Sync] (#16101)
Translate web/xliff/en.xlf in ko [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 14:55:08 +00:00
transifex-integration[bot]
080588bb41 translate: Updates for file web/xliff/en.xlf in zh-Hans [Manual Sync] (#16099)
Translate en.xlf in zh-Hans [Manual Sync]

96% of minimum 60% translated source file: 'en.xlf'
on 'zh-Hans'.

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 14:54:52 +00:00
transifex-integration[bot]
6700ed8b9d translate: Updates for file web/xliff/en.xlf in pl [Manual Sync] (#16094)
Translate web/xliff/en.xlf in pl [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 14:54:32 +00:00
Marc 'risson' Schmitt
d2da2fb966 website/docs: 2025.8 release notes (#15975)
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-08-11 14:48:32 +00:00
Jens L.
08ddd3e8d7 providers/rac: fix property mapping expression not executing (#15819)
* providers/rac: fix property mapping expression not executing

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>
2025-08-11 15:17:00 +01:00
Marc 'risson' Schmitt
67d9534181 packages/django-dramatiq-postgres: broker: fix infinite loop (#16088) 2025-08-11 13:55:46 +00:00
transifex-integration[bot]
575cf63f5b translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#16086)
Translate locale/en/LC_MESSAGES/django.po in fr

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'fr'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 13:29:06 +00:00
transifex-integration[bot]
1731d1e68d translate: Updates for file web/xliff/en.xlf in fr (#16087)
Translate web/xliff/en.xlf in fr

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-11 13:06:53 +00:00
authentik-automation[bot]
ad29786512 core, web: update translations (#16063)
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-08-11 12:00:02 +01:00
dependabot[bot]
0e5d1c2983 web: bump @types/node from 22.15.19 to 24.2.1 in /web (#16084)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.15.19 to 24.2.1.
- [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: 24.2.1
  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>
2025-08-11 11:43:57 +01:00
dependabot[bot]
a1174192ce website: bump @types/node from 24.2.0 to 24.2.1 in /website (#16068)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.2.0 to 24.2.1.
- [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: 24.2.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-08-11 11:43:43 +01:00
dependabot[bot]
01b299c970 website: bump the eslint group in /website with 2 updates (#16069)
Bumps the eslint group in /website with 2 updates: [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) and [eslint](https://github.com/eslint/eslint).


Updates `@eslint/js` from 9.32.0 to 9.33.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.33.0/packages/js)

Updates `eslint` from 9.32.0 to 9.33.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.32.0...v9.33.0)

---
updated-dependencies:
- dependency-name: "@eslint/js"
  dependency-version: 9.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: eslint
  dependency-version: 9.33.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-08-11 11:43:39 +01:00
dependabot[bot]
16e9061468 core: bump goauthentik/fips-python from 3.13.5-slim-bookworm-fips to 3.13.6-slim-bookworm-fips (#16070)
core: bump goauthentik/fips-python

Bumps goauthentik/fips-python from 3.13.5-slim-bookworm-fips to 3.13.6-slim-bookworm-fips.

---
updated-dependencies:
- dependency-name: goauthentik/fips-python
  dependency-version: 3.13.6-slim-bookworm-fips
  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-08-11 11:43:36 +01:00
dependabot[bot]
0c66fe1a2c core: bump astral-sh/uv from 0.8.6 to 0.8.8 (#16071)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.8.6 to 0.8.8.
- [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.8.6...0.8.8)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.8.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>
2025-08-11 11:43:33 +01:00
dependabot[bot]
dff2b871e1 core: bump goauthentik.io/api/v3 from 3.2025064.7 to 3.2025064.8 (#16072)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2025064.7 to 3.2025064.8.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Changelog](https://github.com/goauthentik/client-go/blob/main/model_version_history.go)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2025064.7...v3.2025064.8)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2025064.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>
2025-08-11 11:43:29 +01:00
dependabot[bot]
510816983b core: bump axllent/mailpit from v1.27.3 to v1.27.4 in /tests/e2e (#16073)
Bumps axllent/mailpit from v1.27.3 to v1.27.4.

---
updated-dependencies:
- dependency-name: axllent/mailpit
  dependency-version: v1.27.4
  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-08-11 11:43:26 +01:00
dependabot[bot]
a936e16b68 web: bump the wdio group across 1 directory with 3 updates (#16074)
Bumps the wdio group with 3 updates in the /web directory: [@wdio/browser-runner](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-browser-runner), [@wdio/cli](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-cli) and [@wdio/spec-reporter](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-spec-reporter).


Updates `@wdio/browser-runner` from 9.18.4 to 9.19.0
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v9.19.0/packages/wdio-browser-runner)

Updates `@wdio/cli` from 9.18.4 to 9.19.0
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v9.19.0/packages/wdio-cli)

Updates `@wdio/spec-reporter` from 9.18.0 to 9.19.0
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v9.19.0/packages/wdio-spec-reporter)

---
updated-dependencies:
- dependency-name: "@wdio/browser-runner"
  dependency-version: 9.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: wdio
- dependency-name: "@wdio/cli"
  dependency-version: 9.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: wdio
- dependency-name: "@wdio/spec-reporter"
  dependency-version: 9.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: wdio
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-11 11:43:22 +01:00
dependabot[bot]
6c8c9804ce web: bump @goauthentik/prettier-config from 1.0.5 to 3.1.0 in /web in the goauthentik group across 1 directory (#16075)
web: bump @goauthentik/prettier-config

Bumps the goauthentik group with 1 update in the /web directory: @goauthentik/prettier-config.


Updates `@goauthentik/prettier-config` from 1.0.5 to 3.1.0

---
updated-dependencies:
- dependency-name: "@goauthentik/prettier-config"
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: goauthentik
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-11 11:43:18 +01:00
dependabot[bot]
988c339576 web: bump the eslint group across 3 directories with 2 updates (#16076)
Bumps the eslint group with 1 update in the /packages/eslint-config directory: [eslint](https://github.com/eslint/eslint).
Bumps the eslint group with 1 update in the /packages/prettier-config directory: [eslint](https://github.com/eslint/eslint).
Bumps the eslint group with 1 update in the /web directory: [eslint](https://github.com/eslint/eslint).


Updates `eslint` from 9.32.0 to 9.33.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.32.0...v9.33.0)

Updates `eslint` from 9.32.0 to 9.33.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.32.0...v9.33.0)

Updates `@eslint/js` from 9.32.0 to 9.33.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.33.0/packages/js)

Updates `eslint` from 9.32.0 to 9.33.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.32.0...v9.33.0)

Updates `@eslint/js` from 9.32.0 to 9.33.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.33.0/packages/js)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 9.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: eslint
  dependency-version: 9.33.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@eslint/js"
  dependency-version: 9.33.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: eslint
  dependency-version: 9.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@eslint/js"
  dependency-version: 9.33.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-08-11 11:43:15 +01:00
dependabot[bot]
1380d04480 web: bump yaml from 2.8.0 to 2.8.1 in /web (#16077)
Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.0 to 2.8.1.
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](https://github.com/eemeli/yaml/compare/v2.8.0...v2.8.1)

---
updated-dependencies:
- dependency-name: yaml
  dependency-version: 2.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-08-11 11:43:12 +01:00
dependabot[bot]
f06ebd7dc3 web: bump @types/node from 24.2.0 to 24.2.1 in /packages/esbuild-plugin-live-reload (#16078)
web: bump @types/node in /packages/esbuild-plugin-live-reload

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.2.0 to 24.2.1.
- [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: 24.2.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-08-11 11:43:09 +01:00
dependabot[bot]
c35dff77fb web: bump @types/node from 24.2.0 to 24.2.1 in /packages/prettier-config (#16080)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.2.0 to 24.2.1.
- [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: 24.2.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-08-11 11:43:06 +01:00
dependabot[bot]
28b0c9c87b web: bump @sentry/browser from 10.2.0 to 10.3.0 in /web in the sentry group across 1 directory (#16081)
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.2.0 to 10.3.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.2.0...10.3.0)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 10.3.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-08-11 11:43:02 +01:00
dependabot[bot]
589ee66fa1 web: bump typescript from 5.8.3 to 5.9.2 in /packages/esbuild-plugin-live-reload (#16082)
web: bump typescript in /packages/esbuild-plugin-live-reload

Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.8.3 to 5.9.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release-publish.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.8.3...v5.9.2)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 5.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>
2025-08-11 11:42:59 +01:00
dependabot[bot]
b234a17e96 web: bump typedoc from 0.28.9 to 0.28.10 in /packages/esbuild-plugin-live-reload (#16083)
web: bump typedoc in /packages/esbuild-plugin-live-reload

Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.28.9 to 0.28.10.
- [Release notes](https://github.com/TypeStrong/TypeDoc/releases)
- [Changelog](https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/TypeDoc/compare/v0.28.9...v0.28.10)

---
updated-dependencies:
- dependency-name: typedoc
  dependency-version: 0.28.10
  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-08-11 11:42:56 +01:00
Jens L.
7d4ce2abfc packages/django-dramatiq-postgres: run worker in the same base process, use structlog (#16061)
* run worker inline, not as subprocess

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

* fix logging mismatch between std library and structlog

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

* switch to structlog for dramatiq

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

* check if we need to log error

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

* don't hardcode

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

* close db connections before starting worker

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

* fix healthcheck endpoint logging

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-08-10 21:32:11 +00:00
Dominic R
aeb5c9a24f core: Prevent application creation with reserved slugs (#15930)
* wip

* wip

* Update applications.py

Co-authored-by: Jens L. <jens@beryju.org>
Signed-off-by: Dominic R <dominic@sdko.org>

* Update authentik/core/tests/test_applications_reserved_slugs.py

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

* wip

* aa

* cleanup

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

---------

Signed-off-by: Dominic R <dominic@sdko.org>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@beryju.org>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-08-10 18:55:39 +01:00
dependabot[bot]
38e0a5794d web: bump tmp from 0.2.3 to 0.2.5 in /packages/prettier-config (#16062)
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.3 to 0.2.5.
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.2.3...v0.2.5)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-10 18:54:11 +01:00
authentik-automation[bot]
fdf0416ea9 web: bump API Client version (#16060)
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-08-10 17:29:26 +01:00
Jens L.
e771bb74ee policies: buffered policy access view for concurrent authorization attempts when unauthenticated (#15034)
Co-authored-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-08-10 16:22:05 +00:00
Jens L.
50a22e685e web/flows: update default flow background (#16056)
* web/flows: update default flow background

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

* Optimised images with calibre/image-actions

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-08-10 15:17:25 +01:00
Jens L.
e789818526 web/elements: fix QL autocomplete not working (#16054)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-08-09 20:48:21 +01:00
343 changed files with 22678 additions and 4803 deletions

View File

@@ -1,36 +0,0 @@
[bumpversion]
current_version = 2025.6.4
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
serialize =
{major}.{minor}.{patch}-{rc_t}{rc_n}
{major}.{minor}.{patch}
message = release: {new_version}
tag_name = version/{new_version}
[bumpversion:part:rc_t]
values =
rc
final
optional_value = final
[bumpversion:file:pyproject.toml]
[bumpversion:file:uv.lock]
[bumpversion:file:package.json]
[bumpversion:file:package-lock.json]
[bumpversion:file:docker-compose.yml]
[bumpversion:file:schema.yml]
[bumpversion:file:blueprints/schema.json]
[bumpversion:file:authentik/__init__.py]
[bumpversion:file:internal/constants/constants.go]
[bumpversion:file:lifecycle/aws/template.yaml]

View File

@@ -1,5 +1,6 @@
htmlcov
*.env.yml
node_modules
**/node_modules
dist/**
build/**

View File

@@ -54,6 +54,10 @@ outputs:
runs:
using: "composite"
steps:
- name: Setup authentik env
uses: ./.github/actions/setup
with:
dependencies: "python"
- name: Generate config
id: ev
shell: bash
@@ -64,4 +68,4 @@ runs:
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
REF: ${{ github.ref }}
run: |
python3 ${{ github.action_path }}/push_vars.py
uv run python3 ${{ github.action_path }}/push_vars.py

View File

@@ -1,12 +1,10 @@
"""Helper script to get the actual branch name, docker safe"""
import configparser
import os
from json import dumps
from time import time
parser = configparser.ConfigParser()
parser.read(".bumpversion.cfg")
from authentik import authentik_version
# Decide if we should push the image or not
should_push = True
@@ -31,7 +29,7 @@ is_release = "dev" not in image_names[0]
sha = os.environ["GITHUB_SHA"] if not is_pull_request else os.getenv("PR_HEAD_SHA")
# 2042.1.0 or 2042.1.0-rc1
version = parser.get("bumpversion", "current_version")
version = authentik_version()
# 2042.1
version_family = ".".join(version.split("-", 1)[0].split(".")[:-1])
prerelease = "-" in version

View File

@@ -2,6 +2,9 @@ name: "Setup authentik testing environment"
description: "Setup authentik testing environment"
inputs:
dependencies:
description: "List of dependencies to setup"
default: "system,python,node,go,runtime"
postgresql_version:
description: "Optional postgresql image tag"
default: "16"
@@ -10,42 +13,52 @@ runs:
using: "composite"
steps:
- name: Install apt deps
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
- name: Install uv
if: ${{ contains(inputs.dependencies, 'python') }}
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Setup python
if: ${{ contains(inputs.dependencies, 'python') }}
uses: actions/setup-python@v5
with:
python-version-file: "pyproject.toml"
- name: Install Python deps
if: ${{ contains(inputs.dependencies, 'python') }}
shell: bash
run: uv sync --all-extras --dev --frozen
- name: Setup node
if: ${{ contains(inputs.dependencies, 'node') }}
uses: actions/setup-node@v4
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- name: Setup go
if: ${{ contains(inputs.dependencies, 'go') }}
uses: actions/setup-go@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 }}
- 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
cd web && npm ci
- name: Generate config
if: ${{ contains(inputs.dependencies, 'python') }}
shell: uv run python {0}
run: |
from authentik.lib.generators import generate_id

View File

@@ -42,14 +42,14 @@ jobs:
# Needed for checkout
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: docker/setup-qemu-action@v3.6.0
- uses: docker/setup-buildx-action@v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_USERNAME: ${{ secrets.DOCKER_CORP_USERNAME }}
with:
image-name: ${{ inputs.image_name }}
image-arch: ${{ inputs.image_arch }}
@@ -58,8 +58,8 @@ jobs:
if: ${{ inputs.registry_dockerhub }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
username: ${{ secrets.DOCKER_CORP_USERNAME }}
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
- name: Login to GitHub Container Registry
if: ${{ inputs.registry_ghcr }}
uses: docker/login-action@v3

View File

@@ -49,12 +49,12 @@ jobs:
tags: ${{ steps.ev.outputs.imageTagsJSON }}
shouldPush: ${{ steps.ev.outputs.shouldPush }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_USERNAME: ${{ secrets.DOCKER_CORP_USERNAME }}
with:
image-name: ${{ inputs.image_name }}
merge-server:
@@ -69,20 +69,20 @@ jobs:
matrix:
tag: ${{ fromJson(needs.get-tags.outputs.tags) }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_USERNAME: ${{ secrets.DOCKER_CORP_USERNAME }}
with:
image-name: ${{ inputs.image_name }}
- name: Login to Docker Hub
if: ${{ inputs.registry_dockerhub }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
username: ${{ secrets.DOCKER_CORP_USERNAME }}
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
- name: Login to GitHub Container Registry
if: ${{ inputs.registry_ghcr }}
uses: docker/login-action@v3

View File

@@ -20,7 +20,7 @@ jobs:
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
token: ${{ steps.generate_token.outputs.token }}
- name: Install poetry & deps

View File

@@ -18,7 +18,7 @@ jobs:
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
token: ${{ steps.generate_token.outputs.token }}
- uses: actions/setup-node@v4

View File

@@ -21,7 +21,7 @@ jobs:
command:
- prettier-check
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Install Dependencies
working-directory: website/
run: npm ci
@@ -32,7 +32,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version-file: website/package.json
@@ -66,7 +66,7 @@ jobs:
- lint
- build
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/download-artifact@v5
with:
name: api-docs

View File

@@ -21,7 +21,7 @@ jobs:
check-changes-applied:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup authentik env
uses: ./.github/actions/setup
- uses: actions/setup-node@v4

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: generate docs

View File

@@ -21,7 +21,7 @@ jobs:
command:
- prettier-check
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Install dependencies
working-directory: website/
run: npm ci
@@ -32,7 +32,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version-file: website/package.json
@@ -48,7 +48,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version-file: website/package.json
@@ -70,7 +70,7 @@ jobs:
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU
@@ -81,7 +81,7 @@ jobs:
uses: ./.github/actions/docker-push-variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_USERNAME: ${{ secrets.DOCKER_CORP_USERNAME }}
with:
image-name: ghcr.io/goauthentik/dev-docs
- name: Login to Container Registry

View File

@@ -19,7 +19,7 @@ jobs:
- version-2025-4
- version-2025-2
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- run: |
current="$(pwd)"
dir="/tmp/authentik/${{ matrix.version }}"

View File

@@ -36,7 +36,7 @@ jobs:
- ruff
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: run job
@@ -44,7 +44,7 @@ jobs:
test-migrations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: run migrations
@@ -71,7 +71,7 @@ jobs:
- 17-alpine
run_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: checkout stable
@@ -126,7 +126,7 @@ jobs:
- 17-alpine
run_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup authentik env
uses: ./.github/actions/setup
with:
@@ -153,7 +153,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Create k8s Kind Cluster
@@ -198,7 +198,7 @@ jobs:
- name: flows
glob: tests/e2e/test_flows*
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Setup e2e env (chrome, etc)
@@ -271,14 +271,14 @@ jobs:
pull-requests: write
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_USERNAME: ${{ secrets.DOCKER_CORP_USERNAME }}
with:
image-name: ghcr.io/goauthentik/dev-server
- name: Comment on PR

View File

@@ -16,7 +16,7 @@ jobs:
lint-golint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
@@ -37,7 +37,7 @@ jobs:
test-unittest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
@@ -79,7 +79,7 @@ jobs:
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU
@@ -90,7 +90,7 @@ jobs:
uses: ./.github/actions/docker-push-variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_USERNAME: ${{ secrets.DOCKER_CORP_USERNAME }}
with:
image-name: ghcr.io/goauthentik/dev-${{ matrix.type }}
- name: Login to Container Registry
@@ -138,7 +138,7 @@ jobs:
goos: [linux]
goarch: [amd64, arm64]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-go@v5

View File

@@ -31,7 +31,7 @@ jobs:
- command: lit-analyse
project: web
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version-file: ${{ matrix.project }}/package.json
@@ -48,7 +48,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version-file: web/package.json
@@ -76,7 +76,7 @@ jobs:
- ci-web-mark
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version-file: web/package.json

View File

@@ -33,7 +33,7 @@ jobs:
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
token: ${{ steps.generate_token.outputs.token }}
- name: Compress images

View File

@@ -21,7 +21,7 @@ jobs:
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
token: ${{ steps.generate_token.outputs.token }}
- name: Setup authentik env

View File

@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Cleanup
run: |

View File

@@ -26,7 +26,7 @@ jobs:
- packages/tsconfig
- packages/esbuild-plugin-live-reload
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 2
- uses: actions/setup-node@v4

View File

@@ -24,7 +24,7 @@ jobs:
language: ["go", "javascript", "python"]
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Initialize CodeQL

View File

@@ -26,5 +26,5 @@ jobs:
image: semgrep/semgrep
if: (github.actor != 'dependabot[bot]')
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- run: semgrep ci

View File

@@ -0,0 +1,83 @@
---
name: Release - Branch-off
on:
workflow_dispatch:
inputs:
next_version:
description: Next major version (for example, if releasing 2042.2, this is 2042.4)
required: true
type: string
env:
POSTGRES_DB: authentik
POSTGRES_USER: authentik
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
jobs:
check-inputs:
name: Check inputs validity
runs-on: ubuntu-latest
steps:
- run: |
echo "${{ inputs.next_version }}" | grep -E "^[0-9]{4}\.[0-9]{1,2}$"
branch-off:
name: Branch-off
needs:
- check-inputs
runs-on: ubuntu-latest
steps:
- id: app-token
name: Generate app token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Checkout main
uses: actions/checkout@v5
with:
ref: main
token: "${{ steps.app-token.outputs.token }}"
- name: Setup authentik env
uses: ./.github/actions/setup
with:
dependencies: python
- name: Create version branch
run: |
current_major_version="$(uv version --short | grep -oE "^[0-9]{4}\.[0-9]{1,2}")"
git checkout -b "version-${current_major_version}"
git push origin "version-${current_major_version}"
bump-version-pr:
name: Open version bump PR
needs:
- branch-off
runs-on: ubuntu-latest
steps:
- id: generate_token
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Checkout main
uses: actions/checkout@v5
with:
ref: main
token: ${{ steps.generate_token.outputs.token }}
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Run migrations
run: make migrate
- name: Bump version
run: "make bump version=${{ inputs.next_version }}.0-rc1"
- name: Create pull request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ steps.generate_token.outputs.token }}
branch: release-bump-${{ inputs.next_version }}
commit-message: "root: bump version to ${{ inputs.next_version }}.0-rc1"
title: "root: bump version to ${{ inputs.next_version }}.0-rc1"
body: "root: bump version to ${{ inputs.next_version }}.0-rc1"
delete-branch: true
signoff: true
# ID from https://api.github.com/users/authentik-automation[bot]
author: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>

View File

@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
environment: internal-production
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
ref: main
- run: |

View File

@@ -10,6 +10,7 @@ jobs:
uses: ./.github/workflows/_reusable-docker-build.yaml
secrets: inherit
permissions:
contents: read
# Needed to upload container images to ghcr.io
packages: write
# Needed for attestation
@@ -23,13 +24,14 @@ jobs:
build-docs:
runs-on: ubuntu-latest
permissions:
contents: read
# Needed to upload container images to ghcr.io
packages: write
# Needed for attestation
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.6.0
- name: Set up Docker Buildx
@@ -66,6 +68,7 @@ jobs:
build-outpost:
runs-on: ubuntu-latest
permissions:
contents: read
# Needed to upload container images to ghcr.io
packages: write
# Needed for attestation
@@ -80,7 +83,7 @@ jobs:
- radius
- rac
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
@@ -143,7 +146,7 @@ jobs:
goos: [linux, darwin]
goarch: [amd64, arm64]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
@@ -183,7 +186,7 @@ jobs:
AWS_REGION: eu-central-1
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: "arn:aws:iam::016170277896:role/github_goauthentik_authentik"
@@ -199,7 +202,7 @@ jobs:
- build-outpost-binary
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Run test suite in final docker images
run: |
echo "PG_PASS=$(openssl rand 32 | base64 -w 0)" >> .env
@@ -215,7 +218,7 @@ jobs:
- build-outpost-binary
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev

View File

@@ -1,39 +1,195 @@
---
name: Release - On tag
name: Release - Tag new version
on:
push:
tags:
- "version/*"
workflow_dispatch:
inputs:
version:
description: Version
required: true
type: string
release_reason:
description: Release reason
required: true
type: choice
options:
- bugfix
- feature
- security
- other
- prerelease
env:
POSTGRES_DB: authentik
POSTGRES_USER: authentik
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
jobs:
build:
name: Create Release from Tag
check-inputs:
name: Check inputs validity
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Pre-release test
- id: check
run: |
make test-docker
- id: generate_token
uses: tibdex/github-app-token@v2
echo "${{ inputs.version }}" | grep -E '^[0-9]{4}\.(0?[1-9]|1[0-2])\.[0-9]+(-rc[0-9]+)?$'
echo "major_version=${{ inputs.version }}" | grep -oE "^major_version=[0-9]{4}\.[0-9]{1,2}" >> "$GITHUB_OUTPUT"
- id: changelog-url
run: |
if [ "${{ inputs.release_reason }}" = "feature" ] || [ "${{ inputs.release_reason }}" = "prerelease" ]; then
changelog_url="https://docs.goauthentik.io/docs/releases/${{ steps.check.outputs.major_version }}"
else
changelog_url="https://docs.goauthentik.io/docs/releases/${{ steps.check.outputs.major_version }}#fixed-in-$(echo -n ${{ inputs.version }} | sed 's/\.//g')"
fi
echo "changelog_url=${changelog_url}" >> "$GITHUB_OUTPUT"
outputs:
major_version: "${{ steps.check.outputs.major_version }}"
changelog_url: "${{ steps.changelog-url.outputs.changelog_url }}"
test:
name: Pre-release test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- run: make test-docker
bump-authentik:
name: Bump authentik version
needs:
- check-inputs
- test
runs-on: ubuntu-latest
steps:
- id: app-token
name: Generate app token
uses: actions/create-github-app-token@v2
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- id: get-user-id
name: Get GitHub app user ID
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
GH_TOKEN: "${{ steps.app-token.outputs.token }}"
- uses: actions/checkout@v5
with:
image-name: ghcr.io/goauthentik/server
ref: "version-${{ needs.check-inputs.outputs.major_version }}"
token: "${{ steps.app-token.outputs.token }}"
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Run migrations
run: make migrate
- name: Bump version
run: "make bump version=${{ inputs.version }}"
- name: Commit and push
run: |
# ID from https://api.github.com/users/authentik-automation[bot]
git config --global user.name '${{ steps.app-token.outputs.app-slug }}[bot]'
git config --global user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com'
git commit -a -m "release: ${{ inputs.version }}" --allow-empty
git tag "version/${{ inputs.version }}" HEAD -m "version/${{ inputs.version }}"
git push --follow-tags
- name: Create Release
id: create_release
uses: actions/create-release@v1.1.4
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ steps.ev.outputs.version }}
token: "${{ steps.app-token.outputs.token }}"
tag_name: "version/${{ inputs.version }}"
name: Release ${{ inputs.version }}
draft: true
prerelease: ${{ steps.ev.outputs.prerelease == 'true' }}
prerelease: ${{ inputs.release_reason == 'prerelease' }}
generate_release_notes: true
body: |
See ${{ needs.check-inputs.outputs.changelog_url }}
bump-helm:
name: Bump Helm version
if: ${{ inputs.release_reason != 'prerelease' }}
needs:
- bump-authentik
runs-on: ubuntu-latest
steps:
- id: app-token
name: Generate app token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
repositories: helm
- id: get-user-id
name: Get GitHub app user ID
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: "${{ steps.app-token.outputs.token }}"
- uses: actions/checkout@v5
with:
repository: "${{ github.repository_owner }}/helm"
token: "${{ steps.app-token.outputs.token }}"
- name: Bump version
run: |
sed -i 's/^version: .*/version: ${{ inputs.version }}/' charts/authentik/Chart.yaml
sed -i 's/^appVersion: .*/appVersion: ${{ inputs.version }}/' charts/authentik/Chart.yaml
sed -i 's/upgrade to authentik .*/upgrade to authentik ${{ inputs.version }}/' charts/authentik/Chart.yaml
sed -E -i 's/[0-9]{4}\.[0-9]{1,2}\.[0-9]+$/${{ inputs.version }}/' charts/authentik/Chart.yaml
./scripts/helm-docs.sh
- name: Create pull request
uses: peter-evans/create-pull-request@v7
with:
token: "${{ steps.app-token.outputs.token }}"
branch: bump-${{ inputs.version }}
commit-message: "charts/authentik: bump to ${{ inputs.version }}"
title: "charts/authentik: bump to ${{ inputs.version }}"
body: "charts/authentik: bump to ${{ inputs.version }}"
delete-branch: true
signoff: true
author: "${{ steps.app-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>"
bump-version:
name: Bump version repository
if: ${{ inputs.release_reason != 'prerelease' }}
needs:
- check-inputs
- bump-authentik
runs-on: ubuntu-latest
steps:
- id: app-token
name: Generate app token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
repositories: version
- id: get-user-id
name: Get GitHub app user ID
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: "${{ steps.app-token.outputs.token }}"
- uses: actions/checkout@v5
with:
repository: "${{ github.repository_owner }}/version"
token: "${{ steps.app-token.outputs.token }}"
- name: Bump version
if: "${{ inputs.release_reason == 'feature' }}"
run: |
changelog_url="https://docs.goauthentik.io/docs/releases/${{ needs.check-inputs.outputs.major_version }}"
jq \
--arg version "${{ inputs.version }}" \
--arg changelog "See ${changelog_url}" \
--arg changelog_url "${changelog_url}" \
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url' version.json > version.new.json
mv version.new.json version.json
- name: Bump version
if: "${{ inputs.release_reason != 'feature' }}"
run: |
changelog_url="https://docs.goauthentik.io/docs/releases/${{ needs.check-inputs.outputs.major_version }}#fixed-in-$(echo -n ${{ inputs.version}} | sed 's/\.//g')"
jq \
--arg version "${{ inputs.version }}" \
--arg changelog "See ${changelog_url}" \
--arg changelog_url "${changelog_url}" \
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url' version.json > version.new.json
mv version.new.json version.json
- name: Create pull request
uses: peter-evans/create-pull-request@v7
with:
token: "${{ steps.app-token.outputs.token }}"
branch: bump-${{ inputs.version }}
commit-message: "version: bump to ${{ inputs.version }}"
title: "version: bump to ${{ inputs.version }}"
body: "version: bump to ${{ inputs.version }}"
delete-branch: true
signoff: true
author: "${{ steps.app-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>"

View File

@@ -9,7 +9,7 @@ jobs:
if: ${{ github.repository != 'goauthentik/authentik-internal' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- if: ${{ env.MIRROR_KEY != '' }}

View File

@@ -8,7 +8,7 @@ jobs:
if: ${{ github.repository != 'goauthentik/authentik-internal' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- if: ${{ env.MIRROR_KEY != '' }}

View File

@@ -26,11 +26,11 @@ jobs:
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: actions/checkout@v5
if: ${{ github.event_name != 'pull_request' }}
with:
token: ${{ steps.generate_token.outputs.token }}
- uses: actions/checkout@v4
- uses: actions/checkout@v5
if: ${{ github.event_name == 'pull_request' }}
- name: Setup authentik env
uses: ./.github/actions/setup

View File

@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.event.pull_request.user.login == 'transifex-integration[bot]'}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- id: generate_token
uses: tibdex/github-app-token@v2
with:

View File

@@ -33,17 +33,12 @@ packages/prettier-config @goauthentik/frontend
packages/tsconfig @goauthentik/frontend
# Web
web/ @goauthentik/frontend
tests/wdio/ @goauthentik/frontend
# Locale
locale/ @goauthentik/backend @goauthentik/frontend
web/xliff/ @goauthentik/backend @goauthentik/frontend
# Docs & Website
docs/ @goauthentik/docs
# TODO Remove after moving website to docs
# Docs
website/ @goauthentik/docs
CODE_OF_CONDUCT.md @goauthentik/docs
# Security
SECURITY.md @goauthentik/security @goauthentik/docs
# TODO Remove after moving website to docs
website/security/ @goauthentik/security @goauthentik/docs
docs/security/ @goauthentik/security @goauthentik/docs

View File

@@ -26,7 +26,7 @@ RUN npm run build && \
npm run build:sfe
# Stage 2: Build go proxy
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.25-bookworm AS go-builder
ARG TARGETOS
ARG TARGETARCH
@@ -76,9 +76,9 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
/bin/sh -c "GEOIPUPDATE_LICENSE_KEY_FILE=/run/secrets/GEOIPUPDATE_LICENSE_KEY /usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
# Stage 4: Download uv
FROM ghcr.io/astral-sh/uv:0.8.6 AS uv
FROM ghcr.io/astral-sh/uv:0.8.13 AS uv
# Stage 5: Base python image
FROM ghcr.io/goauthentik/fips-python:3.13.5-slim-bookworm-fips AS python-base
FROM ghcr.io/goauthentik/fips-python:3.13.7-slim-bookworm-fips AS python-base
ENV VENV_PATH="/ak-root/.venv" \
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
@@ -175,6 +175,7 @@ COPY ./lifecycle/ /lifecycle
COPY ./authentik/sources/kerberos/krb5.conf /etc/krb5.conf
COPY --from=go-builder /go/authentik /bin/authentik
COPY ./packages/ /ak-root/packages
RUN ln -s /ak-root/packages /packages
COPY --from=python-deps /ak-root/.venv /ak-root/.venv
COPY --from=node-builder /work/web/dist/ /web/dist/
COPY --from=node-builder /work/web/authentik/ /web/authentik/

View File

@@ -16,6 +16,7 @@ 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)
redis_db := $(shell uv run python -m authentik.lib.config redis.db 2>/dev/null)
all: lint-fix lint test gen web ## Lint, build, and test everything
@@ -57,7 +58,7 @@ migrate: ## Run the Authentik Django server's migrations
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 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
@@ -79,10 +80,10 @@ core-i18n-extract:
install: node-install docs-install core-install ## Install all requires dependencies for `node`, `docs` and `core`
dev-drop-db:
dropdb -U ${pg_user} -h ${pg_host} ${pg_name}
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
redis-cli -n 0 flushall
redis-cli -n ${redis_db} flushall
dev-create-db:
createdb -U ${pg_user} -h ${pg_host} ${pg_name}
@@ -93,6 +94,17 @@ update-test-mmdb: ## Update test GeoIP and ASN Databases
curl -L https://raw.githubusercontent.com/maxmind/MaxMind-DB/refs/heads/main/test-data/GeoLite2-ASN-Test.mmdb -o ${PWD}/tests/GeoLite2-ASN-Test.mmdb
curl -L https://raw.githubusercontent.com/maxmind/MaxMind-DB/refs/heads/main/test-data/GeoLite2-City-Test.mmdb -o ${PWD}/tests/GeoLite2-City-Test.mmdb
bump: ## Bump authentik version. Usage: make bump version=20xx.xx.xx
ifndef version
$(error Usage: make bump version=20xx.xx.xx )
endif
sed -i 's/^version = ".*"/version = "$(version)"/' pyproject.toml
sed -i 's/^VERSION = ".*"/VERSION = "$(version)"/' authentik/__init__.py
$(MAKE) gen-build gen-compose aws-cfn
npm version --no-git-tag-version --allow-same-version $(version)
cd ${PWD}/web && npm version --no-git-tag-version --allow-same-version $(version)
echo -n $(version) > ${PWD}/internal/constants/VERSION
#########################
## API Schema
#########################
@@ -107,6 +119,9 @@ gen-build: ## Extract the schema from the database
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
uv run ak spectacular --file schema.yml
gen-compose:
uv run scripts/generate_docker_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
npx prettier --write changelog.md

View File

@@ -20,12 +20,33 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni
| Version | Supported |
| --------- | --------- |
| 2025.4.x | ✅ |
| 2025.6.x | ✅ |
| 2025.8.x | ✅ |
## Reporting a Vulnerability
To report a vulnerability, send an email to [security@goauthentik.io](mailto:security@goauthentik.io). Be sure to include relevant information like which version you've found the issue in, instructions on how to reproduce the issue, and anything else that might make it easier for us to find the issue.
If you discover a potential vulnerability, please report it responsibly through one of the following channels:
- **Email**: [security@goauthentik.io](mailto:security@goauthentik.io)
- **GitHub**: Submit a private security advisory via our [repositorys advisory portal](https://github.com/goauthentik/authentik/security/advisories/new)
When submitting a report, please include as much detail as possible, such as:
- **Affected version(s)**: The version of authentik where the issue was identified.
- **Steps to reproduce**: A clear description or proof of concept to help us verify the issue.
- **Impact assessment**: How the vulnerability could be exploited and its potential effect.
- **Additional information**: Logs, configuration details (if relevant), or any suggested mitigations.
We kindly ask that you do not disclose the vulnerability publicly until we have confirmed and addressed the issue.
Our team will:
- Acknowledge receipt of your report as quickly as possible.
- Keep you updated on the investigation and resolution progress.
## Researcher Recognition
We value contributions from the security community. For each valid report, we will publish a dedicated entry on our Security Advisory page that optionally includes the reporters name (or preferred alias). Please note that while we do not currently offer monetary bounties, we are committed to giving researchers appropriate credit for their efforts in keeping authentik secure.
## Severity levels

View File

@@ -1,20 +1,28 @@
"""authentik root module"""
from functools import lru_cache
from os import environ
__version__ = "2025.6.4"
VERSION = "2025.10.0-rc1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
def get_build_hash(fallback: str | None = None) -> str:
@lru_cache
def authentik_version() -> str:
return VERSION
@lru_cache
def authentik_build_hash(fallback: str | None = None) -> str:
"""Get build hash"""
build_hash = environ.get(ENV_GIT_HASH_KEY, fallback if fallback else "")
return fallback if build_hash == "" and fallback else build_hash
def get_full_version() -> str:
@lru_cache
def authentik_full_version() -> str:
"""Get full version, with build hash appended"""
version = __version__
if (build_hash := get_build_hash()) != "":
version = authentik_version()
if (build_hash := authentik_build_hash()) != "":
return f"{version}+{build_hash}"
return version

View File

@@ -16,7 +16,7 @@ from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from authentik import get_full_version
from authentik import authentik_full_version
from authentik.core.api.utils import PassiveSerializer
from authentik.enterprise.license import LicenseKey
from authentik.lib.config import CONFIG
@@ -78,7 +78,7 @@ class SystemInfoSerializer(PassiveSerializer):
"""Get versions"""
return {
"architecture": platform.machine(),
"authentik_version": get_full_version(),
"authentik_version": authentik_full_version(),
"environment": get_env(),
"openssl_fips_enabled": (
backend._fips_enabled if LicenseKey.get_total().status().is_valid else None

View File

@@ -10,7 +10,7 @@ from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from authentik import __version__, get_build_hash
from authentik import authentik_build_hash, authentik_version
from authentik.admin.tasks import VERSION_CACHE_KEY, VERSION_NULL, update_latest_version
from authentik.core.api.utils import PassiveSerializer
from authentik.outposts.models import Outpost
@@ -29,20 +29,20 @@ class VersionSerializer(PassiveSerializer):
def get_build_hash(self, _) -> str:
"""Get build hash, if version is not latest or released"""
return get_build_hash()
return authentik_build_hash()
def get_version_current(self, _) -> str:
"""Get current version"""
return __version__
return authentik_version()
def get_version_latest(self, _) -> str:
"""Get latest version from cache"""
if get_current_tenant().schema_name == get_public_schema_name():
return __version__
return authentik_version()
version_in_cache = cache.get(VERSION_CACHE_KEY)
if not version_in_cache: # pragma: no cover
update_latest_version.send()
return __version__
return authentik_version()
return version_in_cache
def get_version_latest_valid(self, _) -> bool:

View File

@@ -8,7 +8,7 @@ from packaging.version import parse
from requests import RequestException
from structlog.stdlib import get_logger
from authentik import __version__, get_build_hash
from authentik import authentik_build_hash, authentik_version
from authentik.admin.apps import PROM_INFO
from authentik.events.models import Event, EventAction
from authentik.lib.config import CONFIG
@@ -19,16 +19,16 @@ LOGGER = get_logger()
VERSION_NULL = "0.0.0"
VERSION_CACHE_KEY = "authentik_latest_version"
VERSION_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
LOCAL_VERSION = parse(__version__)
LOCAL_VERSION = parse(authentik_version())
def _set_prom_info():
"""Set prometheus info for version"""
PROM_INFO.info(
{
"version": __version__,
"version": authentik_version(),
"latest": cache.get(VERSION_CACHE_KEY, ""),
"build_hash": get_build_hash(),
"build_hash": authentik_build_hash(),
}
)

View File

@@ -5,7 +5,7 @@ from json import loads
from django.test import TestCase
from django.urls import reverse
from authentik import __version__
from authentik import authentik_version
from authentik.blueprints.tests import reconcile_app
from authentik.core.models import Group, User
from authentik.lib.generators import generate_id
@@ -27,7 +27,7 @@ class TestAdminAPI(TestCase):
response = self.client.get(reverse("authentik_api:admin_version"))
self.assertEqual(response.status_code, 200)
body = loads(response.content)
self.assertEqual(body["version_current"], __version__)
self.assertEqual(body["version_current"], authentik_version())
def test_apps(self):
"""Test apps API"""

View File

@@ -11,7 +11,7 @@ from rest_framework.relations import PrimaryKeyRelatedField
from rest_framework.serializers import Serializer
from structlog.stdlib import get_logger
from authentik import __version__
from authentik import authentik_version
from authentik.blueprints.v1.common import BlueprintEntryDesiredState
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT, is_model_allowed
from authentik.blueprints.v1.meta.registry import BaseMetaModel, registry
@@ -48,7 +48,7 @@ class Command(BaseCommand):
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://goauthentik.io/blueprints/schema.json",
"type": "object",
"title": f"authentik {__version__} Blueprint schema",
"title": f"authentik {authentik_version()} Blueprint schema",
"required": ["version", "entries"],
"properties": {
"version": {

View File

@@ -3,10 +3,10 @@
from typing import Any
from django.db import models
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import extend_schema, extend_schema_field
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, ChoiceField, ListField
from rest_framework.fields import CharField, ChoiceField, ListField, SerializerMethodField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import AllowAny
from rest_framework.request import Request
@@ -18,6 +18,8 @@ from authentik.brands.models import Brand
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer, PassiveSerializer
from authentik.rbac.filters import SecretKeyFilter
from authentik.tenants.api.settings import FlagJSONField
from authentik.tenants.flags import Flag
from authentik.tenants.utils import get_current_tenant
@@ -110,6 +112,16 @@ class CurrentBrandSerializer(PassiveSerializer):
flow_device_code = CharField(source="flow_device_code.slug", required=False)
default_locale = CharField(read_only=True)
flags = SerializerMethodField()
@extend_schema_field(field=FlagJSONField)
def get_flags(self, _):
values = {}
for flag in Flag.available():
_flag = flag()
if _flag.visibility == "public":
values[_flag.key] = _flag.get()
return values
class BrandViewSet(UsedByMixin, ModelViewSet):

View File

@@ -10,11 +10,20 @@ from authentik.core.tests.utils import create_test_admin_user, create_test_brand
from authentik.lib.generators import generate_id
from authentik.providers.oauth2.models import OAuth2Provider
from authentik.providers.saml.models import SAMLProvider
from authentik.tenants.flags import Flag
class TestBrands(APITestCase):
"""Test brands"""
def setUp(self):
super().setUp()
self.default_flags = {}
for flag in Flag.available():
_flag = flag()
if _flag.visibility == "public":
self.default_flags[_flag.key] = _flag.get()
def test_current_brand(self):
"""Test Current brand API"""
brand = create_test_brand()
@@ -29,6 +38,7 @@ class TestBrands(APITestCase):
"ui_footer_links": [],
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
)
@@ -49,27 +59,7 @@ class TestBrands(APITestCase):
"ui_footer_links": [],
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
},
)
def test_brand_subdomain_same_suffix(self):
"""Test Current brand API"""
Brand.objects.all().delete()
Brand.objects.create(domain="bar.baz", branding_title="custom")
Brand.objects.create(domain="foo.bar.baz", branding_title="custom")
self.assertJSONEqual(
self.client.get(
reverse("authentik_api:brand-current"), HTTP_HOST="foo.bar.baz"
).content.decode(),
{
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
"branding_favicon": "/static/dist/assets/icons/icon.png",
"branding_title": "custom",
"branding_custom_css": "",
"matched_domain": "foo.bar.baz",
"ui_footer_links": [],
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
)
@@ -87,6 +77,7 @@ class TestBrands(APITestCase):
"ui_footer_links": [],
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
)
@@ -167,6 +158,7 @@ class TestBrands(APITestCase):
"ui_footer_links": [],
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
)

View File

@@ -4,12 +4,11 @@ from typing import Any
from django.db.models import F, Q
from django.db.models import Value as V
from django.db.models.functions import Length
from django.http.request import HttpRequest
from django.utils.html import _json_script_escapes
from django.utils.safestring import mark_safe
from authentik import get_full_version
from authentik import authentik_full_version
from authentik.brands.models import Brand
from authentik.lib.sentry import get_http_meta
from authentik.tenants.models import Tenant
@@ -21,9 +20,9 @@ DEFAULT_BRAND = Brand(domain="fallback")
def get_brand_for_request(request: HttpRequest) -> Brand:
"""Get brand object for current request"""
db_brands = (
Brand.objects.annotate(host_domain=V(request.get_host()), match_length=Length("domain"))
Brand.objects.annotate(host_domain=V(request.get_host()))
.filter(Q(host_domain__iendswith=F("domain")) | _q_default)
.order_by("-match_length", "default")
.order_by("default")
)
brands = list(db_brands.all())
if len(brands) < 1:
@@ -44,5 +43,5 @@ def context_processor(request: HttpRequest) -> dict[str, Any]:
"brand_css": brand_css,
"footer_links": tenant.footer_links,
"html_meta": {**get_http_meta()},
"version": get_full_version(),
"version": authentik_full_version(),
}

View File

@@ -6,6 +6,7 @@ from copy import copy
from django.core.cache import cache
from django.db.models import QuerySet
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from guardian.shortcuts import get_objects_for_user
@@ -66,6 +67,15 @@ class ApplicationSerializer(ModelSerializer):
user = self.context["request"].user
return app.get_launch_url(user)
def validate_slug(self, slug: str) -> str:
if slug in Application.reserved_slugs:
raise ValidationError(
_("The slug '{slug}' is reserved and cannot be used for applications.").format(
slug=slug
)
)
return slug
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
if SERIALIZER_CONTEXT_BLUEPRINT in self.context:

View File

@@ -620,7 +620,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
)
@action(detail=True, pagination_class=None, filter_backends=[], methods=["POST"])
def recovery(self, request: Request, pk: int) -> Response:
"""Create a temporary link that a user can use to recover their accounts"""
"""Create a temporary link that a user can use to recover their account"""
link, _ = self._create_recovery_link()
return Response({"link": link})
@@ -641,7 +641,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
)
@action(detail=True, pagination_class=None, filter_backends=[], methods=["POST"])
def recovery_email(self, request: Request, pk: int) -> Response:
"""Create a temporary link that a user can use to recover their accounts"""
"""Send an email with a temporary link that a user can use to recover their account"""
for_user: User = self.get_object()
if for_user.email == "":
LOGGER.debug("User doesn't have an email address")

View File

@@ -21,8 +21,6 @@ from rest_framework.serializers import (
raise_errors_on_nested_writes,
)
from authentik.rbac.permissions import assign_initial_permissions
def is_dict(value: Any):
"""Ensure a value is a dictionary, useful for JSONFields"""
@@ -52,15 +50,6 @@ class ModelSerializer(BaseModelSerializer):
serializer_field_mapping = BaseModelSerializer.serializer_field_mapping.copy()
serializer_field_mapping[models.JSONField] = JSONDictField
def create(self, validated_data):
instance = super().create(validated_data)
request = self.context.get("request")
if request and hasattr(request, "user") and not request.user.is_anonymous:
assign_initial_permissions(request.user, instance)
return instance
def update(self, instance: Model, validated_data):
raise_errors_on_nested_writes("update", self, validated_data)
info = model_meta.get_field_info(instance)

View File

@@ -11,7 +11,7 @@ from django.core.management.base import BaseCommand
from django.db.models import Model
from django.db.models.signals import post_save, pre_delete
from authentik import get_full_version
from authentik import authentik_full_version
from authentik.core.models import User
from authentik.events.middleware import should_log_model
from authentik.events.models import Event, EventAction
@@ -19,7 +19,7 @@ from authentik.events.utils import model_to_dict
def get_banner_text(shell_type="shell") -> str:
return f"""### authentik {shell_type} ({get_full_version()})
return f"""### authentik {shell_type} ({authentik_full_version()})
### Node {platform.node()} | Arch {platform.machine()} | Python {platform.python_version()} """

View File

@@ -548,6 +548,9 @@ class Application(SerializerModel, PolicyBindingModel):
objects = ApplicationQuerySet.as_manager()
# Reserved slugs that would clash with OAuth2 provider endpoints
reserved_slugs = ["authorize", "token", "device", "userinfo", "introspect", "revoke"]
@property
def serializer(self) -> Serializer:
from authentik.core.api.applications import ApplicationSerializer

View File

@@ -3,7 +3,7 @@
from django import template
from django.templatetags.static import static as static_loader
from authentik import get_full_version
from authentik import authentik_full_version
register = template.Library()
@@ -11,4 +11,4 @@ register = template.Library()
@register.simple_tag()
def versioned_script(path: str) -> str:
"""Wrapper around {% static %} tag that supports setting the version"""
return static_loader(path.replace("%v", get_full_version()))
return static_loader(path.replace("%v", authentik_full_version()))

View File

@@ -257,3 +257,35 @@ class TestApplicationsAPI(APITestCase):
self.assertEqual(
Application.objects.with_provider().get(slug=slug).get_provider(), provider
)
def test_create_application_with_reserved_slug(self):
"""Test creating an application with a reserved slug"""
self.client.force_login(self.user)
response = self.client.post(
reverse("authentik_api:application-list"),
{
"name": "Test Application",
"slug": Application.reserved_slugs[0],
},
)
self.assertEqual(response.status_code, 400)
self.assertIn("slug", response.data)
self.assertIn("reserved", response.data["slug"][0])
def test_update_application_with_reserved_slug(self):
"""Test updating an application to use a reserved slug"""
self.client.force_login(self.user)
app = Application.objects.create(
name="Test Application",
slug="valid-slug",
)
response = self.client.patch(
reverse("authentik_api:application-detail", kwargs={"slug": app.slug}),
{
"slug": Application.reserved_slugs[0],
},
)
self.assertEqual(response.status_code, 400)
self.assertIn("slug", response.data)
self.assertIn("reserved", response.data["slug"][0])

View File

@@ -10,7 +10,7 @@ from django.utils.translation import gettext as _
from django.views.generic.base import RedirectView, TemplateView
from rest_framework.request import Request
from authentik import get_build_hash
from authentik import authentik_build_hash
from authentik.admin.tasks import LOCAL_VERSION
from authentik.api.v3.config import ConfigView
from authentik.brands.api import CurrentBrandSerializer
@@ -52,7 +52,7 @@ class InterfaceView(TemplateView):
kwargs["brand_json"] = dumps(brand.data)
kwargs["version_family"] = f"{LOCAL_VERSION.major}.{LOCAL_VERSION.minor}"
kwargs["version_subdomain"] = f"version-{LOCAL_VERSION.major}-{LOCAL_VERSION.minor}"
kwargs["build"] = get_build_hash()
kwargs["build"] = authentik_build_hash()
kwargs["url_kwargs"] = self.kwargs
kwargs["base_url"] = self.request.build_absolute_uri(CONFIG.get("web.path", "/"))
kwargs["base_url_rel"] = CONFIG.get("web.path", "/")

View File

@@ -12,7 +12,7 @@ from cryptography.x509.oid import NameOID
from django.db import models
from django.utils.translation import gettext_lazy as _
from authentik import __version__
from authentik import authentik_version
from authentik.crypto.models import CertificateKeyPair
@@ -85,7 +85,7 @@ class CertificateBuilder:
.issuer_name(
x509.Name(
[
x509.NameAttribute(NameOID.COMMON_NAME, f"authentik {__version__}"),
x509.NameAttribute(NameOID.COMMON_NAME, f"authentik {authentik_version()}"),
]
)
)

View File

@@ -23,6 +23,7 @@ from authentik.events.models import (
)
from authentik.events.utils import get_user
from authentik.rbac.decorators import permission_required
from authentik.stages.email.models import get_template_choices
class NotificationTransportSerializer(ModelSerializer):
@@ -30,6 +31,18 @@ class NotificationTransportSerializer(ModelSerializer):
mode_verbose = SerializerMethodField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["email_template"].choices = get_template_choices()
def validate_email_template(self, value: str) -> str:
"""Check validity of email template"""
choices = get_template_choices()
for path, _ in choices:
if path == value:
return value
raise ValidationError(f"Invalid template '{value}' specified.")
def get_mode_verbose(self, instance: NotificationTransport) -> str:
"""Return selected mode with a UI Label"""
return TransportMode(instance.mode).label
@@ -52,6 +65,8 @@ class NotificationTransportSerializer(ModelSerializer):
"webhook_url",
"webhook_mapping_body",
"webhook_mapping_headers",
"email_subject_prefix",
"email_template",
"send_once",
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.1.11 on 2025-08-14 13:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_events", "0011_alter_systemtask_options"),
]
operations = [
migrations.AddField(
model_name="notificationtransport",
name="email_subject_prefix",
field=models.TextField(blank=True, default="authentik Notification: "),
),
migrations.AddField(
model_name="notificationtransport",
name="email_template",
field=models.TextField(default="email/event_notification.html"),
),
]

View File

@@ -18,7 +18,7 @@ from requests import RequestException
from rest_framework.serializers import Serializer
from structlog.stdlib import get_logger
from authentik import get_full_version
from authentik import authentik_full_version
from authentik.brands.models import Brand
from authentik.brands.utils import DEFAULT_BRAND
from authentik.core.middleware import (
@@ -41,6 +41,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.stages.email.models import EmailTemplates
from authentik.stages.email.utils import TemplateEmailMessage
from authentik.tasks.models import TasksModel
from authentik.tenants.models import Tenant
@@ -295,6 +296,15 @@ class NotificationTransport(TasksModel, SerializerModel):
name = models.TextField(unique=True)
mode = models.TextField(choices=TransportMode.choices, default=TransportMode.LOCAL)
send_once = models.BooleanField(
default=False,
help_text=_(
"Only send notification once, for example when sending a webhook into a chat channel."
),
)
email_subject_prefix = models.TextField(default="authentik Notification: ", blank=True)
email_template = models.TextField(default=EmailTemplates.EVENT_NOTIFICATION)
webhook_url = models.TextField(blank=True, validators=[DomainlessURLValidator()])
webhook_mapping_body = models.ForeignKey(
@@ -319,12 +329,6 @@ class NotificationTransport(TasksModel, SerializerModel):
"Mapping should return a dictionary of key-value pairs"
),
)
send_once = models.BooleanField(
default=False,
help_text=_(
"Only send notification once, for example when sending a webhook into a chat channel."
),
)
def send(self, notification: "Notification") -> list[str]:
"""Send notification to user, called from async task"""
@@ -434,7 +438,7 @@ class NotificationTransport(TasksModel, SerializerModel):
"title": notification.body,
"color": "#fd4b2d",
"fields": fields,
"footer": f"authentik {get_full_version()}",
"footer": f"authentik {authentik_full_version()}",
}
],
}
@@ -462,7 +466,6 @@ class NotificationTransport(TasksModel, SerializerModel):
notification=notification,
)
return None
subject_prefix = "authentik Notification: "
context = {
"key_value": {
"user_email": notification.user.email,
@@ -490,10 +493,10 @@ class NotificationTransport(TasksModel, SerializerModel):
"from": self.name,
}
mail = TemplateEmailMessage(
subject=subject_prefix + context["title"],
subject=self.email_subject_prefix + context["title"],
to=[(notification.user.name, notification.user.email)],
language=notification.user.locale(),
template_name="email/event_notification.html",
template_name=self.email_template,
template_context=context,
)
send_mail.send_with_options(args=(mail.__dict__,), rel_obj=self)

View File

@@ -5,10 +5,12 @@ from unittest.mock import PropertyMock, patch
from django.core import mail
from django.core.mail.backends.locmem import EmailBackend
from django.test import TestCase
from django.urls import reverse
from requests_mock import Mocker
from authentik import get_full_version
from authentik import authentik_full_version
from authentik.core.tests.utils import create_test_admin_user
from authentik.events.api.notification_transports import NotificationTransportSerializer
from authentik.events.models import (
Event,
Notification,
@@ -18,6 +20,7 @@ from authentik.events.models import (
TransportMode,
)
from authentik.lib.generators import generate_id
from authentik.stages.email.models import get_template_choices
class TestEventTransports(TestCase):
@@ -118,7 +121,7 @@ class TestEventTransports(TestCase):
{"short": True, "title": "Event user", "value": self.user.username},
{"title": "foo", "value": "bar,"},
],
"footer": f"authentik {get_full_version()}",
"footer": f"authentik {authentik_full_version()}",
}
],
},
@@ -138,3 +141,76 @@ class TestEventTransports(TestCase):
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "authentik Notification: custom_foo")
self.assertIn(self.notification.body, mail.outbox[0].alternatives[0][0])
def test_transport_email_custom_template(self):
"""Test email transport with custom template"""
transport: NotificationTransport = NotificationTransport.objects.create(
name=generate_id(),
mode=TransportMode.EMAIL,
email_template="email/event_notification.html",
)
with patch(
"authentik.stages.email.models.EmailStage.backend_class",
PropertyMock(return_value=EmailBackend),
):
transport.send(self.notification)
self.assertEqual(len(mail.outbox), 1)
self.assertIn(self.notification.body, mail.outbox[0].alternatives[0][0])
def test_transport_email_custom_subject_prefix(self):
"""Test email transport with custom subject prefix"""
transport: NotificationTransport = NotificationTransport.objects.create(
name=generate_id(),
mode=TransportMode.EMAIL,
email_subject_prefix="[CUSTOM] ",
)
with patch(
"authentik.stages.email.models.EmailStage.backend_class",
PropertyMock(return_value=EmailBackend),
):
transport.send(self.notification)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "[CUSTOM] custom_foo")
def test_transport_email_validation(self):
"""Test email transport template validation"""
# Test valid template
serializer = NotificationTransportSerializer(
data={
"name": generate_id(),
"mode": TransportMode.EMAIL,
"email_template": "email/event_notification.html",
}
)
self.assertTrue(serializer.is_valid())
# Test invalid template - should fail due to choices validation
serializer = NotificationTransportSerializer(
data={
"name": generate_id(),
"mode": TransportMode.EMAIL,
"email_template": "invalid/template.html",
}
)
self.assertFalse(serializer.is_valid())
self.assertIn("email_template", serializer.errors)
def test_templates_api_endpoint(self):
"""Test templates API endpoint returns valid templates"""
self.client.force_login(self.user)
response = self.client.get(reverse("authentik_api:emailstage-templates"))
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertIsInstance(data, list)
# Check that we have at least the default templates
template_names = [item["name"] for item in data]
self.assertIn("email/event_notification.html", template_names)
# Verify all templates are valid choices
valid_choices = dict(get_template_choices())
for template in data:
self.assertIn(template["name"], valid_choices)
self.assertEqual(template["description"], valid_choices[template["name"]])

View File

@@ -10,7 +10,7 @@ from django.core.management.base import BaseCommand
from django.test import RequestFactory
from structlog.stdlib import get_logger
from authentik import __version__
from authentik import authentik_version
from authentik.core.tests.utils import create_test_admin_user
from authentik.flows.models import Flow
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner
@@ -99,7 +99,7 @@ class Command(BaseCommand):
total_min: int = min(min(inner) for inner in values)
total_avg = sum(sum(inner) for inner in values) / sum(len(inner) for inner in values)
print(f"Version: {__version__}")
print(f"Version: {authentik_version()}")
print(f"Processes: {len(values)}")
print(f"\tMax: {total_max * 100}ms")
print(f"\tMin: {total_min * 100}ms")

View File

@@ -154,6 +154,7 @@ worker:
consumer_listen_timeout: "seconds=30"
task_max_retries: 20
task_default_time_limit: "minutes=10"
lock_purge_interval: "minutes=1"
task_purge_interval: "days=1"
task_expiration: "days=30"
scheduler_interval: "seconds=60"

View File

@@ -14,7 +14,7 @@ LOG_PRE_CHAIN = [
# is not from structlog.
structlog.stdlib.add_log_level,
structlog.stdlib.add_logger_name,
structlog.processors.TimeStamper(),
structlog.processors.TimeStamper(fmt="iso", utc=False),
structlog.processors.StackInfoRenderer(),
]

View File

@@ -10,6 +10,7 @@ from django.db import DatabaseError, InternalError, OperationalError, Programmin
from django.http.response import Http404
from django_redis.exceptions import ConnectionInterrupted
from docker.errors import DockerException
from dramatiq.errors import Retry
from h11 import LocalProtocolError
from ldap3.core.exceptions import LDAPException
from psycopg.errors import Error
@@ -21,6 +22,7 @@ from sentry_sdk import init as sentry_sdk_init
from sentry_sdk.api import set_tag
from sentry_sdk.integrations.argv import ArgvIntegration
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.dramatiq import DramatiqIntegration
from sentry_sdk.integrations.redis import RedisIntegration
from sentry_sdk.integrations.socket import SocketIntegration
from sentry_sdk.integrations.stdlib import StdlibIntegration
@@ -29,7 +31,7 @@ from sentry_sdk.tracing import BAGGAGE_HEADER_NAME, SENTRY_TRACE_HEADER_NAME
from structlog.stdlib import get_logger
from websockets.exceptions import WebSocketException
from authentik import __version__, get_build_hash
from authentik import authentik_build_hash, authentik_version
from authentik.lib.config import CONFIG
from authentik.lib.utils.http import authentik_user_agent
from authentik.lib.utils.reflection import get_env
@@ -68,6 +70,8 @@ ignored_classes = (
LocalProtocolError,
# rest_framework error
APIException,
# dramatiq errors
Retry,
# custom baseclass
SentryIgnoredException,
# ldap errors
@@ -106,19 +110,20 @@ def sentry_init(**sentry_init_kwargs):
dsn=CONFIG.get("error_reporting.sentry_dsn"),
integrations=[
ArgvIntegration(),
StdlibIntegration(),
DjangoIntegration(transaction_style="function_name", cache_spans=True),
DramatiqIntegration(),
RedisIntegration(),
ThreadingIntegration(propagate_hub=True),
SocketIntegration(),
StdlibIntegration(),
ThreadingIntegration(propagate_hub=True),
],
before_send=before_send,
traces_sampler=traces_sampler,
release=f"authentik@{__version__}",
release=f"authentik@{authentik_version()}",
transport=SentryTransport,
**kwargs,
)
set_tag("authentik.build_hash", get_build_hash("tagged"))
set_tag("authentik.build_hash", authentik_build_hash("tagged"))
set_tag("authentik.env", get_env())
set_tag("authentik.component", "backend")

View File

@@ -16,8 +16,18 @@ def register_signals(
"""Register sync signals"""
uid = class_to_path(provider_type)
def model_post_save(sender: type[Model], instance: User | Group, created: bool, **_):
def model_post_save(
sender: type[Model],
instance: User | Group,
created: bool,
update_fields: list[str] | None = None,
**_,
):
"""Post save handler"""
# Special case for user object; don't start sync task when we've only updated `last_login`
# This primarily happens during user login
if sender == User and update_fields == {"last_login"}:
return
task_sync_direct_dispatch.send(
class_to_path(instance.__class__),
instance.pk,

View File

@@ -5,7 +5,7 @@ from uuid import uuid4
from requests.sessions import PreparedRequest, Session
from structlog.stdlib import get_logger
from authentik import get_full_version
from authentik import authentik_full_version
from authentik.lib.config import CONFIG
LOGGER = get_logger()
@@ -13,7 +13,7 @@ LOGGER = get_logger()
def authentik_user_agent() -> str:
"""Get a common user agent"""
return f"authentik@{get_full_version()}"
return f"authentik@{authentik_full_version()}"
class TimeoutSession(Session):

View File

@@ -13,7 +13,7 @@ from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from authentik import get_build_hash
from authentik import authentik_build_hash
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import JSONDictField, ModelSerializer, PassiveSerializer
@@ -194,7 +194,7 @@ class OutpostViewSet(UsedByMixin, ModelViewSet):
"openssl_version": state.openssl_version,
"fips_enabled": state.fips_enabled,
"hostname": state.hostname,
"build_hash_should": get_build_hash(),
"build_hash_should": authentik_build_hash(),
}
)
return Response(OutpostHealthSerializer(states, many=True).data)

View File

@@ -4,7 +4,7 @@ from dataclasses import dataclass
from structlog.stdlib import get_logger
from authentik import __version__, get_build_hash
from authentik import authentik_build_hash, authentik_version
from authentik.events.logs import LogEvent, capture_logs
from authentik.lib.config import CONFIG
from authentik.lib.sentry import SentryIgnoredException
@@ -99,6 +99,6 @@ class BaseController:
image_name_template: str = CONFIG.get("outposts.container_image_base")
return image_name_template % {
"type": self.outpost.type,
"version": __version__,
"build_hash": get_build_hash(),
"version": authentik_version(),
"build_hash": authentik_build_hash(),
}

View File

@@ -13,7 +13,7 @@ from paramiko.ssh_exception import SSHException
from structlog.stdlib import get_logger
from yaml import safe_dump
from authentik import __version__
from authentik import authentik_version
from authentik.outposts.apps import MANAGED_OUTPOST
from authentik.outposts.controllers.base import BaseClient, BaseController, ControllerException
from authentik.outposts.docker_ssh import DockerInlineSSH, SSHManagedExternallyException
@@ -185,7 +185,7 @@ class DockerController(BaseController):
try:
self.client.images.pull(image)
except DockerException: # pragma: no cover
image = f"ghcr.io/goauthentik/{self.outpost.type}:{__version__}"
image = f"ghcr.io/goauthentik/{self.outpost.type}:{authentik_version()}"
self.client.images.pull(image)
return image

View File

@@ -17,7 +17,7 @@ from requests import Response
from structlog.stdlib import get_logger
from urllib3.exceptions import HTTPError
from authentik import __version__
from authentik import authentik_version
from authentik.outposts.apps import MANAGED_OUTPOST
from authentik.outposts.controllers.base import ControllerException
from authentik.outposts.controllers.k8s.triggers import NeedsRecreate, NeedsUpdate
@@ -29,8 +29,8 @@ T = TypeVar("T", V1Pod, V1Deployment)
def get_version() -> str:
"""Wrapper for __version__ to make testing easier"""
return __version__
"""Wrapper for authentik_version() to make testing easier"""
return authentik_version()
class KubernetesObjectReconciler(Generic[T]):

View File

@@ -23,7 +23,7 @@ from kubernetes.client import (
V1SecurityContext,
)
from authentik import get_full_version
from authentik import authentik_full_version
from authentik.outposts.controllers.base import FIELD_MANAGER
from authentik.outposts.controllers.k8s.base import KubernetesObjectReconciler
from authentik.outposts.controllers.k8s.triggers import NeedsUpdate
@@ -94,7 +94,7 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
meta = self.get_object_meta(name=self.name)
image_name = self.controller.get_container_image()
image_pull_secrets = self.outpost.config.kubernetes_image_pull_secrets
version = get_full_version().replace("+", "-")
version = authentik_full_version().replace("+", "-")
return V1Deployment(
metadata=meta,
spec=V1DeploymentSpec(

View File

@@ -19,7 +19,7 @@ from packaging.version import Version, parse
from rest_framework.serializers import Serializer
from structlog.stdlib import get_logger
from authentik import __version__, get_build_hash
from authentik import authentik_build_hash, authentik_version
from authentik.blueprints.models import ManagedModel
from authentik.brands.models import Brand
from authentik.core.models import (
@@ -40,7 +40,7 @@ from authentik.outposts.controllers.k8s.utils import get_namespace
from authentik.tasks.schedules.common import ScheduleSpec
from authentik.tasks.schedules.models import ScheduledModel
OUR_VERSION = parse(__version__)
OUR_VERSION = parse(authentik_version())
OUTPOST_HELLO_INTERVAL = 10
LOGGER = get_logger()
@@ -76,6 +76,7 @@ class OutpostConfig:
kubernetes_ingress_annotations: dict[str, str] = field(default_factory=dict)
kubernetes_ingress_secret_name: str = field(default="authentik-outpost-tls")
kubernetes_ingress_class_name: str | None = field(default=None)
kubernetes_ingress_path_type: str | None = field(default=None)
kubernetes_httproute_annotations: dict[str, str] = field(default_factory=dict)
kubernetes_httproute_parent_refs: list[dict[str, str]] = field(default_factory=list)
kubernetes_service_type: str = field(default="ClusterIP")
@@ -151,7 +152,7 @@ class OutpostServiceConnection(ScheduledModel, models.Model):
state = cache.get(self.state_key, None)
if not state:
outpost_service_connection_monitor.send_with_options(args=(self.pk), rel_obj=self)
outpost_service_connection_monitor.send_with_options(args=(self.pk,), rel_obj=self)
return OutpostServiceConnectionState("", False)
return state
@@ -481,7 +482,7 @@ class OutpostState:
"""Check if outpost version matches our version"""
if not self.version:
return False
if self.build_hash != get_build_hash():
if self.build_hash != authentik_build_hash():
return False
return parse(self.version) != OUR_VERSION

View File

@@ -6,7 +6,7 @@ from channels.routing import URLRouter
from channels.testing import WebsocketCommunicator
from django.test import TransactionTestCase
from authentik import __version__
from authentik import authentik_version
from authentik.core.tests.utils import create_test_flow
from authentik.outposts.consumer import WebsocketMessage, WebsocketMessageInstruction
from authentik.outposts.models import Outpost, OutpostType
@@ -65,7 +65,7 @@ class TestOutpostWS(TransactionTestCase):
WebsocketMessage(
instruction=WebsocketMessageInstruction.HELLO,
args={
"version": __version__,
"version": authentik_version(),
"buildHash": "foo",
"uuid": "123",
},

View File

@@ -7,6 +7,7 @@ For example: The 'dummy' policy is available at `authentik.policies.dummy`.
from prometheus_client import Gauge, Histogram
from authentik.blueprints.apps import ManagedAppConfig
from authentik.tenants.flags import Flag
GAUGE_POLICIES_CACHED = Gauge(
"authentik_policies_cached",
@@ -32,6 +33,12 @@ HIST_POLICIES_EXECUTION_TIME = Histogram(
)
class BufferedPolicyAccessViewFlag(Flag[bool], key="policies_buffered_access_view"):
default = False
visibility = "public"
class AuthentikPoliciesConfig(ManagedAppConfig):
"""authentik policies app config"""
@@ -39,3 +46,4 @@ class AuthentikPoliciesConfig(ManagedAppConfig):
label = "authentik_policies"
verbose_name = "authentik Policies"
default = True
mountpoint = "policy/"

View File

@@ -103,7 +103,7 @@ class PasswordPolicy(Policy):
if self.amount_lowercase > 0 and len(RE_LOWER.findall(password)) < self.amount_lowercase:
LOGGER.debug("password failed", check="static", reason="amount_lowercase")
return PolicyResult(False, self.error_message)
if self.amount_uppercase > 0 and len(RE_UPPER.findall(password)) < self.amount_lowercase:
if self.amount_uppercase > 0 and len(RE_UPPER.findall(password)) < self.amount_uppercase:
LOGGER.debug("password failed", check="static", reason="amount_uppercase")
return PolicyResult(False, self.error_message)
if self.amount_symbols > 0:

View File

@@ -0,0 +1,121 @@
{% extends 'login/base_full.html' %}
{% load static %}
{% load i18n %}
{% block head %}
{{ block.super }}
<script>
"use strict";
let redirecting = false;
async function checkAuth() {
if (redirecting) {
console.debug(
"authentik/policies/buffer: Already authenticating in another tab. This page will refresh once authentication is completed.",
);
return true;
}
const url = "{{ check_auth_url }}";
console.debug("authentik/policies/buffer: Checking authentication...");
return fetch(url, {
method: "HEAD",
})
.then((response) => {
if (response.status >= 400) {
return false;
}
console.debug("authentik/policies/buffer: Continuing");
if ("{{ auth_req_method }}" === "post") {
document.querySelector("form")?.submit();
return true;
}
window.location.assign("{{ continue_url|escapejs }}");
return true;
})
.catch((error) => {
console.warn("authentik/policies/buffer: Error checking authentication.", error);
return false;
})
}
const offset = 20;
let timeoutID = -1;
let timeout = 100;
let attempts = 0;
async function main() {
window.clearTimeout(timeoutID);
attempts += 1;
redirecting = await checkAuth();
console.debug(`authentik/policies/buffer: Waiting ${timeout}ms...`);
timeoutID = window.setTimeout(main, timeout);
timeout += offset * attempts;
if (timeout >= 2000) {
timeout = 2000;
}
}
document.addEventListener("visibilitychange", async () => {
if (document.hidden) return;
console.debug("authentik/policies/buffer: Checking authentication on tab activate...");
redirecting = await checkAuth();
});
main();
</script>
{% endblock %}
{% block title %}
{% trans 'Waiting for authentication...' %} - {{ brand.branding_title }}
{% endblock %}
{% block card_title %}
{% trans 'Waiting for authentication...' %}
{% endblock %}
{% block card %}
<form class="pf-c-form" method="{{ auth_req_method }}" action="{{ continue_url }}">
{% if auth_req_method == "post" %}
{% for key, value in auth_req_body.items %}
<input type="hidden" name="{{ key }}" value="{{ value }}" />
{% endfor %}
{% endif %}
<div class="pf-c-empty-state">
<div class="pf-c-empty-state__content">
<div class="pf-c-empty-state__icon">
<span class="pf-c-spinner pf-m-xl" role="progressbar">
<span class="pf-c-spinner__clipper"></span>
<span class="pf-c-spinner__lead-ball"></span>
<span class="pf-c-spinner__tail-ball"></span>
</span>
</div>
<h1 class="pf-c-title pf-m-lg">
{% trans "You're already authenticating in another tab. This page will refresh once authentication is completed." %}
</h1>
</div>
</div>
<div class="pf-c-form__group pf-m-action">
<a href="{{ auth_req_url }}" class="pf-c-button pf-m-primary pf-m-block">
{% trans "Authenticate in this tab" %}
</a>
</div>
</form>
{% endblock %}

View File

@@ -0,0 +1,125 @@
from django.contrib.auth.models import AnonymousUser
from django.contrib.sessions.middleware import SessionMiddleware
from django.http import HttpResponse
from django.test import RequestFactory, TestCase
from django.urls import reverse
from authentik.core.models import Application, Provider
from authentik.core.tests.utils import create_test_flow, create_test_user
from authentik.flows.models import FlowDesignation
from authentik.flows.planner import FlowPlan
from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.lib.generators import generate_id
from authentik.lib.tests.utils import dummy_get_response
from authentik.policies.apps import BufferedPolicyAccessViewFlag
from authentik.policies.views import (
QS_BUFFER_ID,
SESSION_KEY_BUFFER,
BufferedPolicyAccessView,
BufferView,
PolicyAccessView,
)
from authentik.tenants.flags import patch_flag
class TestPolicyViews(TestCase):
"""Test PolicyAccessView"""
def setUp(self):
super().setUp()
self.factory = RequestFactory()
self.user = create_test_user()
def test_pav(self):
"""Test simple policy access view"""
provider = Provider.objects.create(
name=generate_id(),
)
app = Application.objects.create(name=generate_id(), slug=generate_id(), provider=provider)
class TestView(PolicyAccessView):
def resolve_provider_application(self):
self.provider = provider
self.application = app
def get(self, *args, **kwargs):
return HttpResponse("foo")
req = self.factory.get("/")
req.user = self.user
res = TestView.as_view()(req)
self.assertEqual(res.status_code, 200)
self.assertEqual(res.content, b"foo")
@patch_flag(BufferedPolicyAccessViewFlag, True)
def test_pav_buffer(self):
"""Test simple policy access view"""
provider = Provider.objects.create(
name=generate_id(),
)
app = Application.objects.create(name=generate_id(), slug=generate_id(), provider=provider)
flow = create_test_flow(FlowDesignation.AUTHENTICATION)
class TestView(BufferedPolicyAccessView):
def resolve_provider_application(self):
self.provider = provider
self.application = app
def get(self, *args, **kwargs):
return HttpResponse("foo")
req = self.factory.get("/")
req.user = AnonymousUser()
middleware = SessionMiddleware(dummy_get_response)
middleware.process_request(req)
req.session[SESSION_KEY_PLAN] = FlowPlan(flow.pk)
req.session.save()
res = TestView.as_view()(req)
self.assertEqual(res.status_code, 302)
self.assertTrue(res.url.startswith(reverse("authentik_policies:buffer")))
@patch_flag(BufferedPolicyAccessViewFlag, True)
def test_pav_buffer_skip(self):
"""Test simple policy access view (skip buffer)"""
provider = Provider.objects.create(
name=generate_id(),
)
app = Application.objects.create(name=generate_id(), slug=generate_id(), provider=provider)
flow = create_test_flow(FlowDesignation.AUTHENTICATION)
class TestView(BufferedPolicyAccessView):
def resolve_provider_application(self):
self.provider = provider
self.application = app
def get(self, *args, **kwargs):
return HttpResponse("foo")
req = self.factory.get("/?skip_buffer=true")
req.user = AnonymousUser()
middleware = SessionMiddleware(dummy_get_response)
middleware.process_request(req)
req.session[SESSION_KEY_PLAN] = FlowPlan(flow.pk)
req.session.save()
res = TestView.as_view()(req)
self.assertEqual(res.status_code, 302)
self.assertTrue(res.url.startswith(reverse("authentik_flows:default-authentication")))
def test_buffer(self):
"""Test buffer view"""
uid = generate_id()
req = self.factory.get(f"/?{QS_BUFFER_ID}={uid}")
req.user = AnonymousUser()
middleware = SessionMiddleware(dummy_get_response)
middleware.process_request(req)
ts = generate_id()
req.session[SESSION_KEY_BUFFER % uid] = {
"method": "get",
"body": {},
"url": f"/{ts}",
}
req.session.save()
res = BufferView.as_view()(req)
self.assertEqual(res.status_code, 200)
self.assertIn(ts, res.render().content.decode())

View File

@@ -1,7 +1,14 @@
"""API URLs"""
from django.urls import path
from authentik.policies.api.bindings import PolicyBindingViewSet
from authentik.policies.api.policies import PolicyViewSet
from authentik.policies.views import BufferView
urlpatterns = [
path("buffer", BufferView.as_view(), name="buffer"),
]
api_urlpatterns = [
("policies/all", PolicyViewSet),

View File

@@ -1,23 +1,37 @@
"""authentik access helper classes"""
from typing import Any
from uuid import uuid4
from django.contrib import messages
from django.contrib.auth.mixins import AccessMixin
from django.contrib.auth.views import redirect_to_login
from django.http import HttpRequest, HttpResponse
from django.http import HttpRequest, HttpResponse, QueryDict
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.http import urlencode
from django.utils.translation import gettext as _
from django.views.generic.base import View
from django.views.generic.base import TemplateView, View
from structlog.stdlib import get_logger
from authentik.core.models import Application, Provider, User
from authentik.flows.views.executor import SESSION_KEY_APPLICATION_PRE, SESSION_KEY_POST
from authentik.flows.models import Flow, FlowDesignation
from authentik.flows.planner import FlowPlan
from authentik.flows.views.executor import (
SESSION_KEY_APPLICATION_PRE,
SESSION_KEY_PLAN,
SESSION_KEY_POST,
)
from authentik.lib.sentry import SentryIgnoredException
from authentik.policies.apps import BufferedPolicyAccessViewFlag
from authentik.policies.denied import AccessDeniedResponse
from authentik.policies.engine import PolicyEngine
from authentik.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger()
QS_BUFFER_ID = "af_bf_id"
QS_SKIP_BUFFER = "skip_buffer"
SESSION_KEY_BUFFER = "authentik/policies/pav_buffer/%s"
class RequestValidationError(SentryIgnoredException):
@@ -125,3 +139,66 @@ class PolicyAccessView(AccessMixin, View):
for message in result.messages:
messages.error(self.request, _(message))
return result
def url_with_qs(url: str, **kwargs):
"""Update/set querystring of `url` with the parameters in `kwargs`. Original query string
parameters are retained"""
if "?" not in url:
return url + f"?{urlencode(kwargs)}"
url, _, qs = url.partition("?")
qs = QueryDict(qs, mutable=True)
qs.update(kwargs)
return url + f"?{urlencode(qs.items())}"
class BufferView(TemplateView):
"""Buffer view"""
template_name = "policies/buffer.html"
def get_context_data(self, **kwargs):
buf_id = self.request.GET.get(QS_BUFFER_ID)
buffer: dict = self.request.session.get(SESSION_KEY_BUFFER % buf_id)
kwargs["auth_req_method"] = buffer["method"]
kwargs["auth_req_body"] = buffer["body"]
kwargs["auth_req_url"] = url_with_qs(buffer["url"], **{QS_SKIP_BUFFER: True})
kwargs["check_auth_url"] = reverse("authentik_api:user-me")
kwargs["continue_url"] = url_with_qs(buffer["url"], **{QS_BUFFER_ID: buf_id})
return super().get_context_data(**kwargs)
class BufferedPolicyAccessView(PolicyAccessView):
"""PolicyAccessView which buffers access requests in case the user is not logged in"""
def handle_no_permission(self):
plan: FlowPlan | None = self.request.session.get(SESSION_KEY_PLAN)
if plan:
flow = Flow.objects.filter(pk=plan.flow_pk).first()
if not flow or flow.designation != FlowDesignation.AUTHENTICATION:
LOGGER.debug("Not buffering request, no flow or flow not for authentication")
return super().handle_no_permission()
if not plan:
LOGGER.debug("Not buffering request, no flow plan active")
return super().handle_no_permission()
if not BufferedPolicyAccessViewFlag().get():
return super().handle_no_permission()
if self.request.GET.get(QS_SKIP_BUFFER):
LOGGER.debug("Not buffering request, explicit skip")
return super().handle_no_permission()
buffer_id = str(uuid4())
LOGGER.debug("Buffering access request", bf_id=buffer_id)
self.request.session[SESSION_KEY_BUFFER % buffer_id] = {
"body": self.request.POST,
"url": self.request.build_absolute_uri(self.request.get_full_path()),
"method": self.request.method.lower(),
}
return redirect(
url_with_qs(reverse("authentik_policies:buffer"), **{QS_BUFFER_ID: buffer_id})
)
def dispatch(self, request, *args, **kwargs):
response = super().dispatch(request, *args, **kwargs)
if QS_BUFFER_ID in self.request.GET:
self.request.session.pop(SESSION_KEY_BUFFER % self.request.GET[QS_BUFFER_ID], None)
return response

View File

@@ -11,7 +11,8 @@ def migrate_sessions(apps, schema_editor, model):
AuthenticatedSession = apps.get_model("authentik_core", "AuthenticatedSession")
db_alias = schema_editor.connection.alias
for obj in Model.objects.using(db_alias).all():
objs = list(Model.objects.using(db_alias).select_related("old_session").all())
for obj in objs:
if not obj.old_session:
continue
obj.session = (

View File

@@ -23,7 +23,12 @@ def user_session_deleted_oauth_backchannel_logout_and_tokens_removal(
backchannel_logout_notification_dispatch.send(
revocations=[
(token.provider_id, token.id_token.iss, token.session.user.uid)
(
token.provider_id,
token.id_token.iss,
token.id_token.sub,
instance.session.session_key,
)
for token in access_tokens
],
)

View File

@@ -14,13 +14,19 @@ LOGGER = get_logger()
@actor(description=_("Send a back-channel logout request to the registered client"))
def send_backchannel_logout_request(provider_pk: int, iss: str, sub: str = None) -> bool:
def send_backchannel_logout_request(
provider_pk: int,
iss: str,
sub: str | None = None,
session_key: str | None = None,
) -> bool:
"""Send a back-channel logout request to the registered client
Args:
provider_pk: The OAuth2 provider's primary key
iss: The issuer URL for the logout token
sub: The subject identifier to include in the logout token
session_key: The authentik session key to hash and include in the logout token
Returns:
bool: True if the request was sent successfully, False otherwise
@@ -33,11 +39,10 @@ def send_backchannel_logout_request(provider_pk: int, iss: str, sub: str = None)
return
# Generate the logout token
logout_token = create_logout_token(iss, provider, None, sub)
logout_token = create_logout_token(provider, iss, sub, session_key)
# Get the back-channel logout URI from the provider's dedicated backchannel_logout_uri field
# Back-channel logout requires explicit configuration - no fallback to redirect URIs
backchannel_logout_uri = provider.backchannel_logout_uri
if not backchannel_logout_uri:
self.info("No back-channel logout URI found for provider")
@@ -60,9 +65,9 @@ def send_backchannel_logout_request(provider_pk: int, iss: str, sub: str = None)
def backchannel_logout_notification_dispatch(revocations: list, **kwargs):
"""Handle backchannel logout notifications dispatched via signal"""
for revocation in revocations:
provider_pk, iss, sub = revocation
provider_pk, iss, sub, session_key = revocation
provider = OAuth2Provider.objects.filter(pk=provider_pk).first()
send_backchannel_logout_request.send_with_options(
args=(provider_pk, iss, sub),
args=(provider_pk, iss, sub, session_key),
rel_obj=provider,
)

View File

@@ -217,17 +217,17 @@ class HttpResponseRedirectScheme(HttpResponseRedirect):
def create_logout_token(
iss: str,
provider: OAuth2Provider,
session_key: str | None = None,
iss: str,
sub: str | None = None,
session_key: str | None = None,
) -> str:
"""Create a logout token for Back-Channel Logout
As per https://openid.net/specs/openid-connect-backchannel-1_0.html
"""
LOGGER.debug("Creating logout token", provider=provider, session_key=session_key, sub=sub)
LOGGER.debug("Creating logout token", provider=provider, sub=sub)
# Create the logout token payload
payload = {

View File

@@ -30,7 +30,7 @@ from authentik.flows.stage import StageView
from authentik.lib.utils.time import timedelta_from_string
from authentik.lib.views import bad_request_message
from authentik.policies.types import PolicyRequest
from authentik.policies.views import PolicyAccessView, RequestValidationError
from authentik.policies.views import BufferedPolicyAccessView, RequestValidationError
from authentik.providers.oauth2.constants import (
PKCE_METHOD_PLAIN,
PKCE_METHOD_S256,
@@ -334,7 +334,7 @@ class OAuthAuthorizationParams:
return code
class AuthorizationFlowInitView(PolicyAccessView):
class AuthorizationFlowInitView(BufferedPolicyAccessView):
"""OAuth2 Flow initializer, checks access to application and starts flow"""
params: OAuthAuthorizationParams

View File

@@ -127,6 +127,9 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
and self.controller.outpost.config.kubernetes_ingress_secret_name
):
tls_hosts.append(external_host_name.hostname)
path_type = "Prefix"
if self.controller.outpost.config.kubernetes_ingress_path_type:
path_type = self.controller.outpost.config.kubernetes_ingress_path_type
if proxy_provider.mode in [
ProxyMode.FORWARD_SINGLE,
ProxyMode.FORWARD_DOMAIN,
@@ -143,7 +146,7 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
),
),
path="/outpost.goauthentik.io",
path_type="Prefix",
path_type=path_type,
)
]
),
@@ -161,7 +164,7 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
),
),
path="/",
path_type="Prefix",
path_type=path_type,
)
]
),

View File

@@ -120,9 +120,13 @@ class RACPropertyMapping(PropertyMapping):
def evaluate(self, user: User | None, request: HttpRequest | None, **kwargs) -> Any:
"""Evaluate `self.expression` using `**kwargs` as Context."""
if len(self.static_settings) > 0:
return self.static_settings
return super().evaluate(user, request, **kwargs)
settings = {}
for key, value in self.static_settings.items():
if value and value != "":
settings[key] = value
if self.expression != "":
always_merger.merge(settings, super().evaluate(user, request, **kwargs))
return settings
@property
def component(self) -> str:

View File

@@ -18,14 +18,14 @@ from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, FlowPlanner
from authentik.flows.stage import RedirectStage
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.engine import PolicyEngine
from authentik.policies.views import PolicyAccessView
from authentik.policies.views import BufferedPolicyAccessView
from authentik.providers.rac.models import ConnectionToken, Endpoint, RACProvider
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
PLAN_CONNECTION_SETTINGS = "connection_settings"
class RACStartView(PolicyAccessView):
class RACStartView(BufferedPolicyAccessView):
"""Start a RAC connection by checking access and creating a connection token"""
endpoint: Endpoint

View File

@@ -35,8 +35,8 @@ REQUEST_KEY_SAML_SIG_ALG = "SigAlg"
REQUEST_KEY_SAML_RESPONSE = "SAMLResponse"
REQUEST_KEY_RELAY_STATE = "RelayState"
SESSION_KEY_AUTH_N_REQUEST = "authentik/providers/saml/authn_request"
SESSION_KEY_LOGOUT_REQUEST = "authentik/providers/saml/logout_request"
PLAN_CONTEXT_SAML_AUTH_N_REQUEST = "authentik/providers/saml/authn_request"
PLAN_CONTEXT_SAML_LOGOUT_REQUEST = "authentik/providers/saml/logout_request"
# This View doesn't have a URL on purpose, as its called by the FlowExecutor
@@ -50,10 +50,11 @@ class SAMLFlowFinalView(ChallengeStageView):
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
application: Application = self.executor.plan.context[PLAN_CONTEXT_APPLICATION]
provider: SAMLProvider = get_object_or_404(SAMLProvider, pk=application.provider_id)
if SESSION_KEY_AUTH_N_REQUEST not in self.request.session:
if PLAN_CONTEXT_SAML_AUTH_N_REQUEST not in self.executor.plan.context:
self.logger.warning("No AuthNRequest in context")
return self.executor.stage_invalid()
auth_n_request: AuthNRequest = self.request.session.pop(SESSION_KEY_AUTH_N_REQUEST)
auth_n_request: AuthNRequest = self.executor.plan.context[PLAN_CONTEXT_SAML_AUTH_N_REQUEST]
try:
response = AssertionProcessor(provider, request, auth_n_request).build_response()
except SAMLException as exc:
@@ -106,6 +107,3 @@ class SAMLFlowFinalView(ChallengeStageView):
def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
# We'll never get here since the challenge redirects to the SP
return HttpResponseBadRequest()
def cleanup(self):
self.request.session.pop(SESSION_KEY_AUTH_N_REQUEST, None)

View File

@@ -19,9 +19,9 @@ from authentik.providers.saml.exceptions import CannotHandleAssertion
from authentik.providers.saml.models import SAMLProvider
from authentik.providers.saml.processors.logout_request_parser import LogoutRequestParser
from authentik.providers.saml.views.flows import (
PLAN_CONTEXT_SAML_LOGOUT_REQUEST,
REQUEST_KEY_RELAY_STATE,
REQUEST_KEY_SAML_REQUEST,
SESSION_KEY_LOGOUT_REQUEST,
)
LOGGER = get_logger()
@@ -33,6 +33,10 @@ class SAMLSLOView(PolicyAccessView):
flow: Flow
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.plan_context = {}
def resolve_provider_application(self):
self.application = get_object_or_404(Application, slug=self.kwargs["application_slug"])
self.provider: SAMLProvider = get_object_or_404(
@@ -59,6 +63,7 @@ class SAMLSLOView(PolicyAccessView):
request,
{
PLAN_CONTEXT_APPLICATION: self.application,
**self.plan_context,
},
)
plan.append_stage(in_memory_stage(SessionEndStage))
@@ -83,7 +88,7 @@ class SAMLSLOBindingRedirectView(SAMLSLOView):
self.request.GET[REQUEST_KEY_SAML_REQUEST],
relay_state=self.request.GET.get(REQUEST_KEY_RELAY_STATE, None),
)
self.request.session[SESSION_KEY_LOGOUT_REQUEST] = logout_request
self.plan_context[PLAN_CONTEXT_SAML_LOGOUT_REQUEST] = logout_request
except CannotHandleAssertion as exc:
Event.new(
EventAction.CONFIGURATION_ERROR,
@@ -111,7 +116,7 @@ class SAMLSLOBindingPOSTView(SAMLSLOView):
payload[REQUEST_KEY_SAML_REQUEST],
relay_state=payload.get(REQUEST_KEY_RELAY_STATE, None),
)
self.request.session[SESSION_KEY_LOGOUT_REQUEST] = logout_request
self.plan_context[PLAN_CONTEXT_SAML_LOGOUT_REQUEST] = logout_request
except CannotHandleAssertion as exc:
LOGGER.info(str(exc))
return bad_request_message(self.request, str(exc))

View File

@@ -15,16 +15,16 @@ from authentik.flows.models import in_memory_stage
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_SSO, FlowPlanner
from authentik.flows.views.executor import SESSION_KEY_POST
from authentik.lib.views import bad_request_message
from authentik.policies.views import PolicyAccessView
from authentik.policies.views import BufferedPolicyAccessView
from authentik.providers.saml.exceptions import CannotHandleAssertion
from authentik.providers.saml.models import SAMLBindings, SAMLProvider
from authentik.providers.saml.processors.authn_request_parser import AuthNRequestParser
from authentik.providers.saml.views.flows import (
PLAN_CONTEXT_SAML_AUTH_N_REQUEST,
REQUEST_KEY_RELAY_STATE,
REQUEST_KEY_SAML_REQUEST,
REQUEST_KEY_SAML_SIG_ALG,
REQUEST_KEY_SAML_SIGNATURE,
SESSION_KEY_AUTH_N_REQUEST,
SAMLFlowFinalView,
)
from authentik.stages.consent.stage import (
@@ -35,10 +35,14 @@ from authentik.stages.consent.stage import (
LOGGER = get_logger()
class SAMLSSOView(PolicyAccessView):
class SAMLSSOView(BufferedPolicyAccessView):
"""SAML SSO Base View, which plans a flow and injects our final stage.
Calls get/post handler."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.plan_context = {}
def resolve_provider_application(self):
self.application = get_object_or_404(Application, slug=self.kwargs["application_slug"])
self.provider: SAMLProvider = get_object_or_404(
@@ -68,6 +72,7 @@ class SAMLSSOView(PolicyAccessView):
PLAN_CONTEXT_CONSENT_HEADER: _("You're about to sign into %(application)s.")
% {"application": self.application.name},
PLAN_CONTEXT_CONSENT_PERMISSIONS: [],
**self.plan_context,
},
)
except FlowNonApplicableException:
@@ -83,7 +88,7 @@ class SAMLSSOView(PolicyAccessView):
def post(self, request: HttpRequest, application_slug: str) -> HttpResponse:
"""GET and POST use the same handler, but we can't
override .dispatch easily because PolicyAccessView's dispatch"""
override .dispatch easily because BufferedPolicyAccessView's dispatch"""
return self.get(request, application_slug)
@@ -103,7 +108,7 @@ class SAMLSSOBindingRedirectView(SAMLSSOView):
self.request.GET.get(REQUEST_KEY_SAML_SIGNATURE),
self.request.GET.get(REQUEST_KEY_SAML_SIG_ALG),
)
self.request.session[SESSION_KEY_AUTH_N_REQUEST] = auth_n_request
self.plan_context[PLAN_CONTEXT_SAML_AUTH_N_REQUEST] = auth_n_request
except CannotHandleAssertion as exc:
Event.new(
EventAction.CONFIGURATION_ERROR,
@@ -137,7 +142,7 @@ class SAMLSSOBindingPOSTView(SAMLSSOView):
payload[REQUEST_KEY_SAML_REQUEST],
payload.get(REQUEST_KEY_RELAY_STATE),
)
self.request.session[SESSION_KEY_AUTH_N_REQUEST] = auth_n_request
self.plan_context[PLAN_CONTEXT_SAML_AUTH_N_REQUEST] = auth_n_request
except CannotHandleAssertion as exc:
LOGGER.info(str(exc))
return bad_request_message(self.request, str(exc))
@@ -151,4 +156,4 @@ class SAMLSSOBindingInitView(SAMLSSOView):
"""Create SAML Response from scratch"""
LOGGER.debug("No SAML Request, using IdP-initiated flow.")
auth_n_request = AuthNRequestParser(self.provider).idp_initiated()
self.request.session[SESSION_KEY_AUTH_N_REQUEST] = auth_n_request
self.plan_context[PLAN_CONTEXT_SAML_AUTH_N_REQUEST] = auth_n_request

View File

@@ -0,0 +1,69 @@
"""InitialPermissions middleware"""
from collections.abc import Callable
from contextvars import ContextVar
from functools import partial
from django.db.models import Model
from django.db.models.signals import post_save
from django.http import HttpRequest, HttpResponse
from authentik.core.models import User
from authentik.rbac.permissions import assign_initial_permissions
_CTX_REQUEST = ContextVar[HttpRequest | None]("authentik_initial_permissions_request", default=None)
class InitialPermissionsMiddleware:
"""Register a handler for duration of request-response that assigns InitialPermissions"""
get_response: Callable[[HttpRequest], HttpResponse]
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
self.get_response = get_response
def get_uid(self, request_id: str) -> str:
return f"InitialPermissionMiddleware-{request_id}"
def connect(self, request: HttpRequest):
if not hasattr(request, "request_id"):
return
post_save.connect(
partial(self.post_save_handler, request=request),
dispatch_uid=self.get_uid(request.request_id),
weak=False,
)
def disconnect(self, request: HttpRequest):
if not hasattr(request, "request_id"):
return
post_save.disconnect(dispatch_uid=self.get_uid(request.request_id))
def __call__(self, request: HttpRequest) -> HttpResponse:
_CTX_REQUEST.set(request)
self.connect(request)
response = self.get_response(request)
self.disconnect(request)
_CTX_REQUEST.set(None)
return response
def process_exception(self, request: HttpRequest, exception: Exception):
self.disconnect(request)
def post_save_handler(
self,
request: HttpRequest,
instance: Model,
created: bool,
**_,
):
if not created:
return
if request.request_id != _CTX_REQUEST.get().request_id:
return
user: User = request.user
if not user or user.is_anonymous:
return
assign_initial_permissions(user, instance)

View File

@@ -5,9 +5,12 @@ from django.db.models import Model
from guardian.shortcuts import assign_perm
from rest_framework.permissions import BasePermission, DjangoObjectPermissions
from rest_framework.request import Request
from structlog.stdlib import get_logger
from authentik.rbac.models import InitialPermissions, InitialPermissionsMode
LOGGER = get_logger()
class ObjectPermissions(DjangoObjectPermissions):
"""RBAC Permissions"""
@@ -71,4 +74,10 @@ def assign_initial_permissions(user, instance: Model):
if initial_permissions.mode == InitialPermissionsMode.USER
else initial_permissions.role.group
)
LOGGER.debug(
"Adding initial permission",
initial_permission=permission,
subject=assign_to,
object=instance,
)
assign_perm(permission, assign_to, instance)

View File

@@ -4,13 +4,12 @@ import importlib
from collections import OrderedDict
from hashlib import sha512
from pathlib import Path
from tempfile import gettempdir
import orjson
from sentry_sdk import set_tag
from xmlsec import enable_debug_trace
from authentik import __version__
from authentik import authentik_version
from authentik.lib.config import CONFIG, django_db_config, redis_url
from authentik.lib.logging import get_logger_config, structlog_configure
from authentik.lib.sentry import sentry_init
@@ -144,13 +143,13 @@ GUARDIAN_MONKEY_PATCH_USER = False
SPECTACULAR_SETTINGS = {
"TITLE": "authentik",
"DESCRIPTION": "Making authentication simple.",
"VERSION": __version__,
"VERSION": authentik_version(),
"COMPONENT_SPLIT_REQUEST": True,
"SCHEMA_PATH_PREFIX": "/api/v([0-9]+(beta)?)",
"SCHEMA_PATH_PREFIX_TRIM": True,
"SERVERS": [
{
"url": "/api/v3/",
"url": "/api/v3",
},
],
"CONTACT": {
@@ -266,6 +265,7 @@ MIDDLEWARE = [
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"authentik.core.middleware.ImpersonateMiddleware",
"authentik.rbac.middleware.InitialPermissionsMiddleware",
]
MIDDLEWARE_LAST = [
"django_prometheus.middleware.PrometheusAfterMiddleware",
@@ -368,6 +368,9 @@ DRAMATIQ = {
"broker_class": "authentik.tasks.broker.Broker",
"channel_prefix": "authentik",
"task_model": "authentik.tasks.models.Task",
"lock_purge_interval": timedelta_from_string(
CONFIG.get("worker.lock_purge_interval")
).total_seconds(),
"task_purge_interval": timedelta_from_string(
CONFIG.get("worker.task_purge_interval")
).total_seconds(),
@@ -424,7 +427,6 @@ DRAMATIQ = {
(
"authentik.tasks.middleware.MetricsMiddleware",
{
"multiproc_dir": str(Path(gettempdir()) / "authentik_prometheus_tmp"),
"prefix": "authentik",
},
),
@@ -567,7 +569,7 @@ if DEBUG:
enable_debug_trace(True)
CONFIG.log("info", "Booting authentik", version=__version__)
CONFIG.log("info", "Booting authentik", version=authentik_version())
# Load subapps's settings
_filter_and_update(SHARED_APPS + TENANT_APPS)

View File

@@ -5,7 +5,7 @@ from ssl import OPENSSL_VERSION
import pytest
from cryptography.hazmat.backends.openssl.backend import backend
from authentik import get_full_version
from authentik import authentik_full_version
IS_CI = "CI" in environ
@@ -22,7 +22,7 @@ def pytest_sessionstart(*_, **__):
def pytest_report_header(*_, **__):
"""Add authentik version to pytest output"""
return [
f"authentik version: {get_full_version()}",
f"authentik version: {authentik_full_version()}",
f"OpenSSL version: {OPENSSL_VERSION}, FIPS: {backend._fips_enabled}",
]

View File

@@ -6,7 +6,7 @@ from django.http.response import Http404
from requests.exceptions import RequestException
from structlog.stdlib import get_logger
from authentik import __version__
from authentik import authentik_version
from authentik.core.sources.flow_manager import SourceFlowManager
from authentik.lib.utils.http import get_http_session
from authentik.sources.plex.models import (
@@ -38,7 +38,7 @@ class PlexAuth:
"""Get common headers"""
return {
"X-Plex-Product": "authentik",
"X-Plex-Version": __version__,
"X-Plex-Version": authentik_version(),
"X-Plex-Device-Vendor": "goauthentik.io",
}

View File

@@ -198,7 +198,10 @@ class AuthenticatorDuoStageViewSet(UsedByMixin, ModelViewSet):
return {"error": "", "count": created}
except RuntimeError as exc:
LOGGER.warning("failed to get users from duo", exc=exc)
return {"error": str(exc), "count": created}
return {
"error": "An internal error occurred while importing devices.",
"count": created,
}
class DuoDeviceSerializer(ModelSerializer):

View File

@@ -168,6 +168,8 @@ class AuthenticatorDuoStageTests(FlowTestCase):
client_secret=generate_id(),
api_hostname=generate_id(),
)
# Test missing admin credentials
response = self.client.post(
reverse(
"authentik_api:authenticatorduostage-import-devices-automatic",
@@ -178,6 +180,31 @@ class AuthenticatorDuoStageTests(FlowTestCase):
)
self.assertEqual(response.status_code, 400)
# Test internal error handling
stage.admin_integration_key = generate_id()
stage.admin_secret_key = generate_id()
stage.save()
with patch(
"duo_client.admin.Admin.get_users_iterator",
MagicMock(side_effect=RuntimeError("Duo API error")),
):
response = self.client.post(
reverse(
"authentik_api:authenticatorduostage-import-devices-automatic",
kwargs={
"pk": str(stage.pk),
},
),
)
self.assertEqual(response.status_code, 400)
self.assertJSONEqual(
response.content,
{
"error": "An internal error occurred while importing devices.",
"count": 0,
},
)
def test_api_import_automatic(self):
"""test `import_devices_automatic`"""
self.client.force_login(self.user)

View File

@@ -15,18 +15,10 @@ from authentik.lib.config import CONFIG
from authentik.lib.models import SerializerModel
from authentik.lib.utils.time import timedelta_string_validator
from authentik.stages.authenticator.models import SideChannelDevice
from authentik.stages.email.models import EmailTemplates
from authentik.stages.email.utils import TemplateEmailMessage
class EmailTemplates(models.TextChoices):
"""Templates used for rendering the Email"""
EMAIL_OTP = (
"email/email_otp.html",
_("Email OTP"),
) # nosec
class AuthenticatorEmailStage(ConfigurableStage, FriendlyNamedStage, Stage):
"""Use Email-based authentication instead of authenticator-based."""

File diff suppressed because one or more lines are too long

View File

@@ -35,7 +35,12 @@ class Command(TenantCommand):
template_context={},
)
try:
send_mail(message.__dict__, stage.pk)
if not stage.use_global_settings:
message.from_email = stage.from_address
send_mail.send(message.__dict__, stage.pk).get_result(block=True)
self.stdout.write(self.style.SUCCESS(f"Test email sent to {options['to']}"))
finally:
if delete_stage:
stage.delete()

View File

@@ -32,6 +32,14 @@ class EmailTemplates(models.TextChoices):
"email/account_confirmation.html",
_("Account Confirmation"),
)
EMAIL_OTP = (
"email/email_otp.html",
_("Email OTP"),
) # nosec
EVENT_NOTIFICATION = (
"email/event_notification.html",
_("Event Notification"),
)
def get_template_choices():

View File

@@ -0,0 +1,66 @@
"""Test email management commands"""
from unittest.mock import patch
from django.core import mail
from django.core.mail.backends.locmem import EmailBackend
from django.core.management import call_command
from django.test import TestCase
from authentik.core.tests.utils import create_test_admin_user
from authentik.stages.email.models import EmailStage
class TestEmailManagementCommands(TestCase):
"""Test email management commands"""
def setUp(self):
self.user = create_test_admin_user()
def test_test_email_command_with_stage(self):
"""Test test_email command with specified stage"""
EmailStage.objects.create(
name="test-stage",
from_address="test@authentik.local",
host="localhost",
port=25,
)
with patch("authentik.stages.email.models.EmailStage.backend_class", EmailBackend):
call_command("test_email", "test@example.com", stage="test-stage")
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "authentik Test-Email")
self.assertEqual(mail.outbox[0].to, ["test@example.com"])
def test_test_email_command_with_global_settings(self):
"""Test test_email command with global settings"""
# Mock the backend to use Django's locmem backend
with patch("authentik.stages.email.models.EmailStage.backend_class", EmailBackend):
call_command("test_email", "test@example.com")
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "authentik Test-Email")
self.assertEqual(mail.outbox[0].to, ["test@example.com"])
def test_test_email_command_invalid_stage(self):
"""Test test_email command with invalid stage"""
call_command("test_email", "test@example.com", stage="nonexistent")
self.assertEqual(len(mail.outbox), 0)
def test_test_email_command_with_custom_from(self):
"""Test test_email command respects custom from address"""
EmailStage.objects.create(
name="test-stage",
from_address="custom@authentik.local",
host="localhost",
port=25,
)
with patch("authentik.stages.email.models.EmailStage.backend_class", EmailBackend):
call_command("test_email", "test@example.com", stage="test-stage")
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, "custom@authentik.local")
self.assertEqual(mail.outbox[0].to, ["test@example.com"])

View File

@@ -54,7 +54,7 @@ class TestEmailStageTemplates(FlowTestCase):
chmod(file2, 0o000) # Remove all permissions so we can't read the file
choices = get_template_choices()
self.assertEqual(choices[-1][0], Path(file).name)
self.assertEqual(len(choices), 3)
self.assertEqual(len(choices), 5)
unlink(file)
unlink(file2)

Some files were not shown because too many files have changed in this diff Show More