Compare commits

...

330 Commits

Author SHA1 Message Date
eec91338ae Merge branch 'main' into navbar-revisions-v2 2025-05-20 02:25:28 +02:00
1c5e906a3e web/NPM Workspaces: ESbuild version cleanup (#14541)
* web: Check JS files. Add types.

* web: Fix issues surrounding Vite/ESBuild types.

* web: Clean up version constants. Tidy types

* web: Clean up docs, types.

* web: Clean up package paths.

* web: (ESLint) no-lonely-if

* web: Render slot before navbar.

* web: Fix line-height alignment.

* web: Truncate long headers.

* web: Clean up page header declarations. Add story. Update paths.

* web: Ignore out directory.

* web: Lint Lit.

* web: Use private alias.

* web: Fix implicit CJS mode.

* web: Update deps.

* web: await all imports.
2025-05-20 02:11:18 +02:00
6e9d8bc101 web: Clean up page header declarations. Add story. Update paths. 2025-05-19 23:34:41 +02:00
c133ba9bd3 enterprise/stages/mtls: update go & web client, fix py client generation (#14576)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-19 23:27:02 +02:00
65517f3b7f enterprise/stages: Add MTLS stage (#14296)
* prepare client auth with inbuilt server

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

* introduce better IPC auth

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

* init

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

* start stage

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

* only allow trusted proxies to set MTLS headers

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

* more stage progress

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

* dont fail if ipc_key doesn't exist

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

* actually install app

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

* fix

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

* add some tests

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

* update API

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

* fix unquote

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

* fix int serial number not jsonable

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

* init ui

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

* add UI

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

* unrelated: fix git pull in makefile

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

* fix parse helper

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

* add test for outpost

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

* more tests and improvements

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

* improve labels

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

* add support for multiple CAs on brand

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

* add support for multiple CAs to MTLS stage

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

* dont log ipcuser secret views

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

* fix go mod

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-19 22:48:17 +02:00
b361dd3b59 lib/sync/outgoing: reduce number of db queries made (#14177) 2025-05-19 22:41:09 +02:00
38e3ed4d05 web: Truncate long headers. 2025-05-19 22:15:32 +02:00
93f54a596c web: Fix line-height alignment. 2025-05-19 22:15:32 +02:00
2cfb6ce17e web: Render slot before navbar. 2025-05-19 22:15:32 +02:00
31d25eaead web: (ESLint) no-lonely-if 2025-05-19 22:14:32 +02:00
7a12fbf8b7 web: Clean up package paths. 2025-05-19 22:14:30 +02:00
c50793133b web: Clean up docs, types. 2025-05-19 22:13:18 +02:00
b8e394227e web: Clean up version constants. Tidy types 2025-05-19 19:42:38 +02:00
e8b1f82c3e web: Fix issues surrounding Vite/ESBuild types. 2025-05-19 19:42:37 +02:00
92629578dd web: Check JS files. Add types. 2025-05-19 19:42:37 +02:00
40f598f3f1 web: (ESLint) No else return (#14558)
web: (ESLint) no-else-return.
2025-05-19 19:34:51 +02:00
b72d0e84c9 web: (ESLint) Use dot notation. (#14557) 2025-05-19 19:33:52 +02:00
d97297e0ce web: (ESLint) Consistent use of triple-equals. (#14554)
web: Consistent use of triple-equals.
2025-05-19 13:25:11 -04:00
1a80353bc0 web: fix description for signing responses in SAML provider (#14573) 2025-05-19 14:56:19 +00:00
beece507fd website/integrations: update paperless ngx instructions to include additional scopes (#14486) 2025-05-19 14:07:06 +02:00
e2bec88403 translate: Updates for file web/xliff/en.xlf in fr (#14570)
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-05-19 12:04:12 +00:00
26b6c2e130 ci: add dependencies label to generated PRs (#14569)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-19 13:52:28 +02:00
1a38679ecf translate: Updates for file web/xliff/en.xlf in it (#14538)
Translate web/xliff/en.xlf in it

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-05-19 13:47:15 +02:00
b2334c3680 core: bump astral-sh/uv from 0.7.4 to 0.7.5 (#14560)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.7.4 to 0.7.5.
- [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.7.4...0.7.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-19 13:38:30 +02:00
13251bb8c4 website: bump @types/postman-collection from 3.5.10 to 3.5.11 in /website (#14561)
website: bump @types/postman-collection in /website

Bumps [@types/postman-collection](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/postman-collection) from 3.5.10 to 3.5.11.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/postman-collection)

---
updated-dependencies:
- dependency-name: "@types/postman-collection"
  dependency-version: 3.5.11
  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-05-19 13:38:16 +02:00
9fe6bac99d lifecycle/aws: bump aws-cdk from 2.1015.0 to 2.1016.0 in /lifecycle/aws (#14563)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1015.0 to 2.1016.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1016.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1016.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-05-19 13:38:06 +02:00
7c9fe53b47 core: bump axllent/mailpit from v1.24.2 to v1.25.0 in /tests/e2e (#14564)
Bumps axllent/mailpit from v1.24.2 to v1.25.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-19 13:37:57 +02:00
b20c4eab29 translate: Updates for file web/xliff/en.xlf in zh_CN (#14565)
Translate web/xliff/en.xlf in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-05-19 13:37:45 +02:00
8ca09a9ece web: Fix issue where Storybook cannot resolve styles. (#14553)
* web: Fix issue where Storybook cannot resolve styles.

* separate sentry config and middleware to prevent circular import

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-05-19 13:37:30 +02:00
856598fc54 translate: Updates for file web/xliff/en.xlf in zh-Hans (#14566)
Translate web/xliff/en.xlf in zh-Hans

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-05-19 13:36:58 +02:00
fdb7b29d9a root: replace raw.githubusercontent.com by checking out repo (#14567)
* root: replace raw.githubusercontent.com by checking out repo

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

* use make from client-go

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

* update instead of delete

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

* unrelated: fix py client install

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

* unrelated: use all absolute paths

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-19 13:18:44 +02:00
3748781368 sources/kerberos: resolve logger warnings (#14540)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2025-05-18 01:31:41 +02:00
99b559893b core, web: update translations (#14530)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-05-16 16:03:21 +02:00
8014088c3a core: bump astral-sh/uv from 0.7.3 to 0.7.4 (#14531)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.7.3 to 0.7.4.
- [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.7.3...0.7.4)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.7.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-05-16 16:03:08 +02:00
3ee353126f core: bump github.com/getsentry/sentry-go from 0.32.0 to 0.33.0 (#14532)
Bumps [github.com/getsentry/sentry-go](https://github.com/getsentry/sentry-go) from 0.32.0 to 0.33.0.
- [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.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: github.com/getsentry/sentry-go
  dependency-version: 0.33.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-05-16 16:02:57 +02:00
db76c5d9e2 core: bump goauthentik.io/api/v3 from 3.2025040.1 to 3.2025041.1 (#14533)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2025040.1 to 3.2025041.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.2025040.1...v3.2025041.1)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2025041.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-05-16 16:02:50 +02:00
61bff69b7d core: bump django-pglock from 1.7.1 to 1.7.2 (#14534)
Bumps [django-pglock](https://github.com/AmbitionEng/django-pglock) from 1.7.1 to 1.7.2.
- [Release notes](https://github.com/AmbitionEng/django-pglock/releases)
- [Changelog](https://github.com/AmbitionEng/django-pglock/blob/main/CHANGELOG.md)
- [Commits](https://github.com/AmbitionEng/django-pglock/compare/1.7.1...1.7.2)

---
updated-dependencies:
- dependency-name: django-pglock
  dependency-version: 1.7.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-16 16:02:42 +02:00
69651323e3 web: bump API Client version (#14528)
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-05-15 20:19:16 +02:00
75a0ac9588 release: 2025.4.1 (#14527)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>

# Conflicts:
#	package.json
2025-05-15 20:12:41 +02:00
941a697397 website/docs: release notes for 2025.4.1 (#14526)
* website/docs: release notes for 2025.4.1

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

* format

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-15 19:26:01 +02:00
4a74db17a1 web: bump undici from 6.21.1 to 6.21.3 in /web (#14524)
Bumps [undici](https://github.com/nodejs/undici) from 6.21.1 to 6.21.3.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.21.1...v6.21.3)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.21.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-15 16:58:28 +02:00
0cf6bff93c tests/e2e: add test for authentication flow in compatibility mode (#14392)
* tests/e2e: add test for authentication flow in compatibility mode

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

* web: Add prefix class to CSS for easier debugging of constructed stylesheets.

- Use CSS variables for highlighter.

* web: Fix issue where MDX components apply styles out of order.

* web: Fix hover color.

* web: Fix CSS module types. Clean up globals.

* web: Fix issues surrounding availability of shadow root in compatibility mode.

* web: Fix typo.

* web: Partial fixes for storybook dark theme.

* web: Fix overflow.

* web: Fix issues surrounding competing interfaces attempting to apply styles.

* fix padding in ak-alert in. markdown

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

* web: Minimize use of sub-module exports.

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Teffen Ellis <teffen@sister.software>
2025-05-15 16:51:11 +02:00
814e438422 stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#14513)
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-05-15 16:25:28 +02:00
2db77a37dd lifecycle/aws: bump aws-cdk from 2.1014.0 to 2.1015.0 in /lifecycle/aws (#14516)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1014.0 to 2.1015.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1015.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1015.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-05-15 15:09:53 +02:00
e40c5ac617 web/admin: Dual select state management, custom event dispatching. (#14490)
* web/admin: Fix issues surrounding dual select state management.

* web: Fix nested path.

* web: Use PatternFly variable.
2025-05-15 14:47:47 +02:00
7440900dac core: fix unable to create group if no enable_group_superuser permission is given (#14510)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-15 14:41:26 +02:00
ca96b27825 web/admin: Fix sidebar toggle synchronization. (#14487)
* web: Fix issue where resizing from tablet or smaller viewport desyncs the sidebar.

* web: Fix issue where focus style overrides hover state style.
2025-05-14 17:19:22 +02:00
ad4a765a80 website: bump the build group in /website with 6 updates (#14502)
Bumps the build group in /website with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@rspack/binding-darwin-arm64](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.9` | `1.3.10` |
| [@rspack/binding-linux-arm64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.9` | `1.3.10` |
| [@rspack/binding-linux-x64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.9` | `1.3.10` |
| [lightningcss-darwin-arm64](https://github.com/parcel-bundler/lightningcss) | `1.30.0` | `1.30.1` |
| [lightningcss-linux-arm64-gnu](https://github.com/parcel-bundler/lightningcss) | `1.30.0` | `1.30.1` |
| [lightningcss-linux-x64-gnu](https://github.com/parcel-bundler/lightningcss) | `1.30.0` | `1.30.1` |


Updates `@rspack/binding-darwin-arm64` from 1.3.9 to 1.3.10
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.10/packages/rspack)

Updates `@rspack/binding-linux-arm64-gnu` from 1.3.9 to 1.3.10
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.10/packages/rspack)

Updates `@rspack/binding-linux-x64-gnu` from 1.3.9 to 1.3.10
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.10/packages/rspack)

Updates `lightningcss-darwin-arm64` from 1.30.0 to 1.30.1
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/compare/v1.30.0...v1.30.1)

Updates `lightningcss-linux-arm64-gnu` from 1.30.0 to 1.30.1
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/compare/v1.30.0...v1.30.1)

Updates `lightningcss-linux-x64-gnu` from 1.30.0 to 1.30.1
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/compare/v1.30.0...v1.30.1)

---
updated-dependencies:
- dependency-name: "@rspack/binding-darwin-arm64"
  dependency-version: 1.3.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-arm64-gnu"
  dependency-version: 1.3.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-x64-gnu"
  dependency-version: 1.3.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: lightningcss-darwin-arm64
  dependency-version: 1.30.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: lightningcss-linux-arm64-gnu
  dependency-version: 1.30.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: lightningcss-linux-x64-gnu
  dependency-version: 1.30.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-14 16:11:52 +02:00
4dcd481010 core: remove OldAuthenticatedSession content type (#14507)
* core: remove `OldAuthenticatedSession` content type

This was left out from https://github.com/goauthentik/authentik/pull/9736

* remove stale content types in `repair_permissions`

Co-authored-by: Jens Langhammer <jens@goauthentik.io>

* run `remove_stale_contenttypes` for each tenant

---------

Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-05-14 15:02:29 +02:00
d0dc14d84d core: bump msgraph-sdk from 1.29.0 to 1.30.0 (#14503)
Bumps [msgraph-sdk](https://github.com/microsoftgraph/msgraph-sdk-python) from 1.29.0 to 1.30.0.
- [Release notes](https://github.com/microsoftgraph/msgraph-sdk-python/releases)
- [Changelog](https://github.com/microsoftgraph/msgraph-sdk-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoftgraph/msgraph-sdk-python/compare/v1.29.0...v1.30.0)

---
updated-dependencies:
- dependency-name: msgraph-sdk
  dependency-version: 1.30.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-05-14 12:22:41 +02:00
7bf960352b core: bump twilio from 9.6.0 to 9.6.1 (#14505)
Bumps [twilio](https://github.com/twilio/twilio-python) from 9.6.0 to 9.6.1.
- [Release notes](https://github.com/twilio/twilio-python/releases)
- [Changelog](https://github.com/twilio/twilio-python/blob/main/CHANGES.md)
- [Commits](https://github.com/twilio/twilio-python/compare/9.6.0...9.6.1)

---
updated-dependencies:
- dependency-name: twilio
  dependency-version: 9.6.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-05-14 12:22:27 +02:00
c07d01661b core: bump psycopg[c,pool] from 3.2.8 to 3.2.9 (#14504)
Bumps [psycopg[c,pool]](https://github.com/psycopg/psycopg) from 3.2.8 to 3.2.9.
- [Changelog](https://github.com/psycopg/psycopg/blob/3.2.9/docs/news.rst)
- [Commits](https://github.com/psycopg/psycopg/compare/3.2.8...3.2.9)

---
updated-dependencies:
- dependency-name: psycopg[c,pool]
  dependency-version: 3.2.9
  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-05-14 12:19:42 +02:00
427597ec14 enterprise: fix expired license's users being counted (#14451)
* enterprise: fix expired license's users being counted

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

* tests to the rescue

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

* hmm

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-13 15:59:17 +02:00
7cc77bd387 website/integrations: fix missing closing brace for semaphore (#14467)
Update index.mdx

Added missing closing bracket

Signed-off-by: ericgu08 <79233593+ericgu08@users.noreply.github.com>
2025-05-13 15:26:10 +02:00
381a1a2c49 tests/e2e: Add E2E tests for Flow SFE (#14484)
* add e2e test for SFE login

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

* add helper text in SFE on password stage

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

* build sfe for e2e

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

* fix ci e2e cache key not considering sfe

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

* fix sfe missing from docker build

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

* sigh I forgot npm

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-13 12:03:12 +02:00
08f8222224 website: bump semver from 7.7.1 to 7.7.2 in /website (#14491)
Bumps [semver](https://github.com/npm/node-semver) from 7.7.1 to 7.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v7.7.1...v7.7.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-13 12:01:13 +02:00
1211c34a18 core: bump django from 5.1.8 to 5.1.9 (#14483)
* build(deps): bump django from 5.1.8 to 5.1.9

Bumps [django](https://github.com/django/django) from 5.1.8 to 5.1.9.
- [Commits](https://github.com/django/django/compare/5.1.8...5.1.9)

---
updated-dependencies:
- dependency-name: django
  dependency-version: 5.1.9
  dependency-type: direct:production
...

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

* bump lock

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-05-12 21:23:10 +02:00
22efb57369 core: bump psycopg[c,pool] from 3.2.7 to 3.2.8 (#14481)
Bumps [psycopg[c,pool]](https://github.com/psycopg/psycopg) from 3.2.7 to 3.2.8.
- [Changelog](https://github.com/psycopg/psycopg/blob/master/docs/news.rst)
- [Commits](https://github.com/psycopg/psycopg/compare/3.2.7...3.2.8)

---
updated-dependencies:
- dependency-name: psycopg[c,pool]
  dependency-version: 3.2.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-05-12 20:55:37 +02:00
3eeda53be6 core: bump sentry-sdk from 2.27.0 to 2.28.0 (#14482)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.27.0 to 2.28.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.27.0...2.28.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-version: 2.28.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-05-12 20:55:34 +02:00
82ace18703 root: pin package version in pyproject for dependabot (#14469)
* root: pin package version in pyproject for dependabot

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

* use exact as we know that works now

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-12 19:32:48 +02:00
8589079252 core: fix session migration when old session can't be loaded (#14466)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-12 15:51:49 +02:00
ae2af6e58e root: temporarily deactivate database pool option (#14443)
* root: temporarily deactivate database pool option

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

* format

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

* deactivate tests

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-12 14:48:01 +02:00
86a7f98ff6 website: bump the build group in /website with 3 updates (#14475)
Bumps the build group in /website with 3 updates: [lightningcss-darwin-arm64](https://github.com/parcel-bundler/lightningcss), [lightningcss-linux-arm64-gnu](https://github.com/parcel-bundler/lightningcss) and [lightningcss-linux-x64-gnu](https://github.com/parcel-bundler/lightningcss).


Updates `lightningcss-darwin-arm64` from 1.29.3 to 1.30.0
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/compare/v1.29.3...v1.30.0)

Updates `lightningcss-linux-arm64-gnu` from 1.29.3 to 1.30.0
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/compare/v1.29.3...v1.30.0)

Updates `lightningcss-linux-x64-gnu` from 1.29.3 to 1.30.0
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/compare/v1.29.3...v1.30.0)

---
updated-dependencies:
- dependency-name: lightningcss-darwin-arm64
  dependency-version: 1.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: lightningcss-linux-arm64-gnu
  dependency-version: 1.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: lightningcss-linux-x64-gnu
  dependency-version: 1.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-12 14:39:18 +02:00
3af45371d3 website/docs: stages: fix-typo (#14477)
Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>
2025-05-12 14:12:33 +02:00
b01ffd934f website/docs: Update Kubernetes Bootstrap Instructions (#14471)
* website/docs: update envFrom block for automated install

* format

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-05-11 15:13:14 +02:00
f11ba94603 root: improve sentry distributed tracing (#14468)
* core: include all sentry headers

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

* remove spotlight patch we dont need anymore

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

* always trace in debug

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

* init sentry earlier

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

* re-add light interface

https://github.com/goauthentik/authentik/pull/14331

removes 2 unneeded API calls

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

* sentry integrated router

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

* use new Sentry middleware to propagate headers

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

* fix missing baggage

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

* cleanup logs

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

* use sanitized URLs for logging/tracing

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-11 02:40:31 +02:00
7d2aa43364 Revert "web/admin: fix enterprise menu display" (#14458)
Revert "web/admin: fix enterprise menu display (#14447)"

This reverts commit 0611eea0e7.
2025-05-10 18:26:07 +02:00
f1351a7577 website/docs: update outdated custom CSS docs (#14441)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-10 11:15:47 -05:00
0611eea0e7 web/admin: fix enterprise menu display (#14447)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-10 00:54:33 +02:00
d0b46fcf9c core: bump msgraph-sdk from 1.28.0 to v1.29.0 (#14454) 2025-05-10 00:51:32 +02:00
dcbdc37d31 core: bump opentelemetry-api from 1.32.1 to v1.33.0 (#14455) 2025-05-10 00:51:29 +02:00
d07f396379 core: bump platformdirs from 4.3.7 to v4.3.8 (#14456) 2025-05-10 00:51:27 +02:00
0972103b83 core: bump ruff from 0.11.8 to v0.11.9 (#14457) 2025-05-10 00:51:24 +02:00
b448e76db4 web/flows/sfe: fix global background image not being loaded (#14442)
* web/flows/sfe: add initial loading spinner

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

* fix brand-level default flow background not working with SFE and loading original image with full flow interface

https://github.com/goauthentik/authentik/pull/13079#issuecomment-2853357407
Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-09 17:58:43 +02:00
f2937bd6dd outposts: fix tmpdir in containers not being set (#14444)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-09 17:57:25 +02:00
53c2e3e77c lifecycle: fix ak dump_config (#14445)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-09 17:56:01 +02:00
7dd62c1f55 lifecycle/aws: bump aws-cdk from 2.1013.0 to 2.1014.0 in /lifecycle/aws (#14436)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1013.0 to 2.1014.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1014.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1014.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-05-09 15:50:56 +02:00
33e3510fba website/integrations: update integration template (#14432)
* Updated indentation and service name formatting.

* Angle brackets for mentions of service name

* Update website/integrations/template/service.md

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

* Fixes issues with <service name> being read as a tag.

* Update website/integrations/template/service.md

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

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-05-09 09:51:11 +01:00
0e5fac2642 website/integrations: fix sonarqube badge (#14434)
Moves the badge to frontmatter.
2025-05-08 20:22:29 +02:00
c53b1fe78a website/integrations: coder: fix period (#14423) 2025-05-08 09:10:39 -05:00
838a7457b2 website: bump the build group in /website with 3 updates (#14427)
Bumps the build group in /website with 3 updates: [@rspack/binding-darwin-arm64](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack), [@rspack/binding-linux-arm64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) and [@rspack/binding-linux-x64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack).


Updates `@rspack/binding-darwin-arm64` from 1.3.8 to 1.3.9
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.9/packages/rspack)

Updates `@rspack/binding-linux-arm64-gnu` from 1.3.8 to 1.3.9
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.9/packages/rspack)

Updates `@rspack/binding-linux-x64-gnu` from 1.3.8 to 1.3.9
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.9/packages/rspack)

---
updated-dependencies:
- dependency-name: "@rspack/binding-darwin-arm64"
  dependency-version: 1.3.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-arm64-gnu"
  dependency-version: 1.3.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-x64-gnu"
  dependency-version: 1.3.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-08 15:03:06 +02:00
a3c07bc9ff core: bump astral-sh/uv from 0.7.2 to 0.7.3 (#14426)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.7.2 to 0.7.3.
- [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.7.2...0.7.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-08 15:02:00 +02:00
121f2c609d website/integrations: update paperless ngx instructions to include correct scopes (#14424)
* Update Paperless NGX instructions to include correct scopes

`openid` scope is required for Paperless NGX

Signed-off-by: Jim Shank <jimshank@gmail.com>

* Update website/integrations/services/paperless-ngx/index.mdx

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

---------

Signed-off-by: Jim Shank <jimshank@gmail.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-05-08 08:55:30 +00:00
365affc28e website/docs: configuration sessions are now stored by default in the database (#14425)
docs: configuration: sessions are now stored by default in the database

Signed-off-by: Dominic R <dominic@sdko.org>
2025-05-08 09:26:27 +01:00
f367822779 root: readme: use right contribution guide link (#14250)
wip

Signed-off-by: Dominic R <dominic@sdko.org>
2025-05-07 21:20:32 +00:00
848198125d website/integrations: add coder (#14385)
* init

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

* init

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

* wip

* what is happening to my lint today?

* Apply suggestions from code review

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

---------

Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-05-07 20:04:34 +01:00
497ac5e3d0 website/integrations: improve grafana docs (#14408)
* Update index.mdx

Better reflected the stuff at https://github.com/goauthentik/authentik/issues/8673

Signed-off-by: andymarden <63465082+andymarden@users.noreply.github.com>

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

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

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

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

---------

Signed-off-by: andymarden <63465082+andymarden@users.noreply.github.com>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-05-07 12:33:42 -05:00
1773d4d681 core: bump geoip2 from 5.0.1 to v5.1.0 (#14417) 2025-05-07 19:25:14 +02:00
4edbb51939 core: bump boto3 from 1.38.7 to v1.38.10 (#14416) 2025-05-07 19:24:58 +02:00
c7e97ab48e core: bump maxminddb from 2.6.3 to v2.7.0 (#14420) 2025-05-07 19:24:44 +02:00
31f7faae1c core: bump azure-identity from 1.21.0 to v1.22.0 (#14415) 2025-05-07 19:24:31 +02:00
f5dae2ae92 core: bump google-auth from 2.39.0 to v2.40.1 (#14418) 2025-05-07 19:24:17 +02:00
2c043dba0b core: bump jsii from 1.111.0 to v1.112.0 (#14419) 2025-05-07 19:24:03 +02:00
bda10e5db1 core: bump pytest-timeout from 2.3.1 to v2.4.0 (#14421) 2025-05-07 19:23:49 +02:00
be9ae7d4f7 web: cleanup/loading attribute always true (#14288)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

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

## Note

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

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

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

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

This reverts commit dddde09be5.

* web: remove Lit syntax from always true attributes

## What

Replaces instances of `?loading=${true}` and `?loading="${true}"` with `loading`

## Why

The Lit syntax is completely unnecessary when the attribute's state is constant, and it's a few
(just a few) extra CPU cycles for Lit to process that.

More to the point, it annoys me.

## How

```
$ perl -pi.bak -e 's/\?loading=\$\{true\}/loading/' $(rg -l '\?loading=\$\{true\}')
$ find . -name '*.bak' -exec rm {} \;
$ perl -pi.bak -e 's/\?loading="\$\{true\}"/loading/' $(rg -l '\?loading="\$\{true\}"')
$ find . -name '*.bak' -exec rm {} \;
```

* Prettier had opinions

* Trigger Build
2025-05-06 08:49:48 -07:00
b4a6189bfa core: bump selenium from 4.31.0 to v4.32.0 (#14394)
* core: bump selenium from 4.31.0 to v4.32.0

* deal with selenium breaking stuff on minor versions

https://github.com/SeleniumHQ/selenium/pull/15641
Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-05-06 16:53:20 +02:00
bfdb827ff9 website/docs: Update Docusaurus config. Prep for version picker. (#14401)
* website/docs: Clean up config. Add types.

* website/docs: Format MDX.

* website: Fix build warnings. Lint badges frontmatter.
2025-05-06 10:04:39 -04:00
488a58e1c5 core: bump golang.org/x/oauth2 from 0.29.0 to 0.30.0 (#14405)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.29.0 to 0.30.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.29.0...v0.30.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-version: 0.30.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-05-06 15:06:15 +02:00
3f83e69453 core: bump golang.org/x/sync from 0.13.0 to 0.14.0 (#14406)
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.13.0 to 0.14.0.
- [Commits](https://github.com/golang/sync/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-version: 0.14.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-05-06 15:02:53 +02:00
e92fa5df0b core: bump selenium/standalone-chrome from 135.0 to 136.0 in /tests/e2e (#14407)
Bumps selenium/standalone-chrome from 135.0 to 136.0.

---
updated-dependencies:
- dependency-name: selenium/standalone-chrome
  dependency-version: '136.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-05-06 15:02:45 +02:00
f8c22170df core, web: update translations (#14402)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-05-06 05:20:31 +02:00
e3d08a8434 core: bump boto3 from 1.38.7 to v1.38.8 (#14393) 2025-05-05 23:50:09 +02:00
97d3e9afdc core: bump setuptools from 80.1.0 to v80.3.1 (#14395) 2025-05-05 23:50:00 +02:00
1eb08def73 core: bump twilio from 9.5.2 to v9.6.0 (#14396) 2025-05-05 23:49:52 +02:00
6e3b379e4a website/docs: add one more reference and link about can view Admin interface (#14399)
* add yet another mention of the can view admin interface

* tweaks

---------

Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-05-05 13:42:41 -05:00
264f59775c website/docs: Update deps. (#14397)
* website/docs: Update deps.

* website/docs: Port partial monorepo fixes. Fix build warnings.

* website/docs: Update Prettier.

* website/docs: Format. Update deps.

* website/docs: Remove empty entry.
2025-05-05 16:59:49 +00:00
d048f1ecbd website/docs: Add pkg-config to the brew dependencies (#14398)
Add pkg-config to the brew dependencies
2025-05-05 16:51:42 +00:00
eb31f31584 web, website: update browserslist (#14386)
web,website: update browserslist

Updates browser list in web and website using `npx
update-browserslist-db@latest`

Our list was more than 7 months outdated.

Why to update:
> This update will bring data about new browsers to polyfill tools like Autoprefixer or Babel and reduce already unnecessary polyfills.
>
> You need to do it regularly for three reasons:
>
> 1. To use the latest browser’s versions and statistics in queries like last 2 versions or >1%. For example, if you created your project 2 years ago and did not update your dependencies, last 1 version will return 2-year-old browsers.
> 2. Actual browser data will lead to using less polyfills. It will reduce size of JS and CSS files and improve website performance.
> 3. caniuse-lite deduplication: to synchronize versions in different tools.
2025-05-05 15:01:59 +02:00
fe5c842e92 core, web: update translations (#14383)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-05-05 14:11:16 +02:00
b82d3100c9 website/integrations: add atlassian (#14209)
* Begin

* Added instructions

* Writtent all required steps

* Atlassian cloud vs atlassian

* Added important information section

* Improved wording, removed temporary placeholders, added more detail to the admin account required in Atlassian, fixed typos

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* Differentiated between external and internal user accounts, fixed typos and improved wording.

* Converted important information section to important block and updated language.

* Typos

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

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

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

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

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

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

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

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

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

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

* Edited as per suggestions from Tana

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-05-05 13:09:32 +01:00
49bb668036 core: bump github.com/pires/go-proxyproto from 0.8.0 to 0.8.1 (#14388)
Bumps [github.com/pires/go-proxyproto](https://github.com/pires/go-proxyproto) from 0.8.0 to 0.8.1.
- [Release notes](https://github.com/pires/go-proxyproto/releases)
- [Commits](https://github.com/pires/go-proxyproto/compare/v0.8.0...v0.8.1)

---
updated-dependencies:
- dependency-name: github.com/pires/go-proxyproto
  dependency-version: 0.8.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 12:55:29 +02:00
52c70c7700 ci: bump golangci/golangci-lint-action from 7 to 8 (#14389)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 7 to 8.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v7...v8)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-version: '8'
  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-05-05 12:55:17 +02:00
b99fd36f86 core: bump axllent/mailpit from v1.24.1 to v1.24.2 in /tests/e2e (#14390)
Bumps axllent/mailpit from v1.24.1 to v1.24.2.

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 12:55:06 +02:00
8a5381eca3 translate: Updates for file web/xliff/en.xlf in it (#14372)
* Translate web/xliff/en.xlf in it

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

* Removing web/xliff/en.xlf in it

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

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-05-05 01:40:03 +02:00
2c77830179 translate: Updates for file web/xliff/en.xlf in zh_CN (#14374)
Translate web/xliff/en.xlf in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-05-05 01:39:42 +02:00
ffcd7def60 translate: Updates for file web/xliff/en.xlf in zh-Hans (#14375)
Translate web/xliff/en.xlf in zh-Hans

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-05-05 01:39:28 +02:00
ed121bc2a3 translate: Updates for file locale/en/LC_MESSAGES/django.po in pt (#14379)
Translate locale/en/LC_MESSAGES/django.po in pt

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-05-05 01:38:16 +02:00
d5ab9d9167 website/integrations: Fix outpost link for Home Assistant configuration (#14382)
Fix outpost link for Home Assistant configuration

Signed-off-by: Jim Shank <jimshank@gmail.com>
2025-05-05 00:02:43 +02:00
a983321ad6 website/docs: fix leftover placeholder in release notes (#14377)
Update v2025.4.md

changed download URL to match version 2025.4. Otherwise it will give a 404

Signed-off-by: finkerle <145992792+finkerle@users.noreply.github.com>
2025-05-04 16:45:55 +02:00
9c3420ede4 website/integrations: minio: fix typo (#14376)
Signed-off-by: Dominic R <dominic@sdko.org>
2025-05-03 23:38:10 +02:00
91b40350aa core: bump goauthentik/fips-python from 3.12.10-slim-bookworm-fips to 3.13.3-slim-bookworm-fips (#12763)
* core: bump goauthentik/fips-python from 3.12.7-slim-bookworm-fips to 3.13.1-slim-bookworm-fips

Dependabot couldn't find the original pull request head commit, 57d3f7b1d72de7f2448d0ce661c74de53412bdd5.

* upgrade the rest

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

* format

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

* update dev env

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

* silence docker build action about env name

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

* bump to 3.13.3

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-05-03 22:04:49 +02:00
1912991682 core: bump axllent/mailpit from v1.6.5 to v1.24.1 in /tests/e2e (#14341)
Bumps axllent/mailpit from v1.6.5 to v1.24.1.

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-03 21:34:51 +02:00
71b9117f53 core: bump selenium/standalone-chrome from 122.0 to 135.0 in /tests/e2e (#14342)
Bumps selenium/standalone-chrome from 122.0 to 135.0.

---
updated-dependencies:
- dependency-name: selenium/standalone-chrome
  dependency-version: '135.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-05-03 21:34:43 +02:00
b5f947f460 core: bump lxml from 5.3.2 to v5.4.0 (#14355)
* core: bump lxml from 5.3.2 to v5.4.0

* fix lxml xmlsec issues

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-05-03 17:37:39 +02:00
3a2f7e9549 core: bump azure-core from 1.33.0 to v1.34.0 (#14345) 2025-05-03 17:20:13 +02:00
1582ce0920 core: bump boto3 from 1.37.35 to v1.38.7 (#14346) 2025-05-03 17:19:47 +02:00
6d3eea5266 core: bump celery from 5.5.1 to v5.5.2 (#14347) 2025-05-03 17:19:35 +02:00
e987208bd1 core: bump certifi from 2025.1.31 to v2025.4.26 (#14348) 2025-05-03 17:19:23 +02:00
0efab8eef7 core: bump charset-normalizer from 3.4.1 to v3.4.2 (#14349) 2025-05-03 17:18:36 +02:00
9402dac8ae core: bump cryptography from 44.0.2 to v44.0.3 (#14350) 2025-05-03 17:18:23 +02:00
f57a290eee core: bump google-api-python-client from 2.167.0 to v2.169.0 (#14351) 2025-05-03 17:18:11 +02:00
5dab0d2b7a core: bump h11 from 0.14.0 to v0.16.0 (#14352) 2025-05-03 17:17:08 +02:00
2da6036248 core: bump humanize from 4.12.2 to v4.12.3 (#14353) 2025-05-03 17:16:37 +02:00
cdba94cea4 core: bump jsonschema-specifications from 2024.10.1 to v2025.4.1 (#14354) 2025-05-03 17:16:30 +02:00
c59eca664a core: bump msal from 1.32.0 to v1.32.3 (#14356) 2025-05-03 17:16:21 +02:00
d5b205f9c0 core: bump mypy-extensions from 1.0.0 to v1.1.0 (#14357) 2025-05-03 17:16:11 +02:00
8ad9ad833e core: bump orjson from 3.10.16 to v3.10.18 (#14358) 2025-05-03 17:16:03 +02:00
599ce15f68 core: bump psycopg from 3.2.6 to v3.2.7 (#14359) 2025-05-03 17:15:54 +02:00
91310eff52 core: bump pydantic from 2.11.3 to v2.11.4 (#14360) 2025-05-03 16:56:57 +02:00
b522d6732a core: bump redis from 5.2.1 to v6.0.0 (#14361) 2025-05-03 16:56:47 +02:00
17d96f204e core: bump ruff from 0.11.5 to v0.11.8 (#14362) 2025-05-03 16:56:15 +02:00
65e4667bc3 core: bump sentry-sdk from 2.26.1 to v2.27.0 (#14363) 2025-05-03 16:55:48 +02:00
f67f9e5ed0 core: bump setproctitle from 1.3.5 to v1.3.6 (#14364) 2025-05-03 16:54:47 +02:00
62dd6a4393 core: bump setuptools from 78.1.0 to v80.1.0 (#14365) 2025-05-03 16:54:38 +02:00
a46eae8276 core: bump structlog from 25.2.0 to v25.3.0 (#14366) 2025-05-03 16:54:27 +02:00
c4acc9fc24 core: bump unidecode from 1.3.8 to v1.4.0 (#14367) 2025-05-03 16:54:18 +02:00
e748a03082 core, web: update translations (#14368)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-05-03 16:54:10 +02:00
e473f28e21 web: NPM workspaces (#14274)
docusaurus-config: v1.0.6
2025-05-02 21:52:54 -04:00
f70635c295 web: Clean up browser-only module imports that crash WebDriverIO. (#14330)
* web: Clean up browser-only module imports that crash WebDriverIO.

* web: Clarify slug format output.
2025-05-02 20:04:05 -04:00
70d60c7ab2 web: Use monorepo package utilities to build packages (#14159)
* web: Format live reload package.

* web: Format package.json.

* web: Revise globals.

* web: Build entrypoints with a single ESBuild context. Clean up entrypoints.

* web: WIP Prepare monorepo package for use.

* web: Update build paths. Fix types.

* web: WIP Add monorepo dependency.

* web: Use monorepo utilities when building.

* web: Fix issue where linters collide. Update ignore file.

- Remove unused sort override for polyfills.

* core: Prepare repo for NPM workspaces.
2025-05-02 19:48:19 -04:00
61a26c02b7 Revert-revert: Safari fixes (#14331)
* Reapply "web: Safari fixes merge branch (#14181)"

This reverts commit a41d45834c.

* web: Fix brand preference order. Adjust header height.
2025-05-02 21:26:40 +02:00
a06645d558 website/docs: remove support badge (#14343)
removed support badge1

Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-05-02 18:15:20 +00:00
7730ecbd37 ci: use dependabot for compose correctly? (#14340)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-02 19:21:55 +02:00
80e1be8db7 website/docs: use Universal Device Trust for GDTC instead of Okta (#14335)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-02 19:11:14 +02:00
c528c74e48 ci: use dependabot for docker-compose files (#14336)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-02 19:05:36 +02:00
6d7bf36afe website/docs: fix dry-run release highlight (#14337)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-05-02 19:05:25 +02:00
44fb59eb18 rbac: fix RoleObjectPermissionTable not showing add_user_to_group (#14312)
fix RoleObjectPermissionTable not showing `add_user_to_group`
2025-05-02 17:42:19 +02:00
8f8d924935 core, web: update translations (#14326)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-05-02 17:41:47 +02:00
602adaa5c5 core: bump github.com/sethvargo/go-envconfig from 1.2.0 to 1.3.0 (#14327)
Bumps [github.com/sethvargo/go-envconfig](https://github.com/sethvargo/go-envconfig) from 1.2.0 to 1.3.0.
- [Release notes](https://github.com/sethvargo/go-envconfig/releases)
- [Commits](https://github.com/sethvargo/go-envconfig/compare/v1.2.0...v1.3.0)

---
updated-dependencies:
- dependency-name: github.com/sethvargo/go-envconfig
  dependency-version: 1.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-05-02 17:30:24 +02:00
5c9e97e11c web: bump vite from 5.4.16 to 5.4.19 in /web (#14324)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.16 to 5.4.19.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.19/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.19/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 5.4.19
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01 22:34:28 +02:00
2e7c620c9c core: bump setuptools from 78.1.0 to v79.0.0 (#14173) 2025-05-01 22:29:49 +02:00
30a2770781 core: bump ruff from 0.11.5 to v0.11.6 (#14171) 2025-05-01 22:29:36 +02:00
ef49fa0e79 core: bump s3transfer from 0.11.4 to v0.11.5 (#14172) 2025-05-01 22:29:03 +02:00
ac524ef425 core: bump packaging from 24.2 to v25.0 (#14169) 2025-05-01 22:28:44 +02:00
6f3c1c4537 core: bump aiohttp from 3.11.16 to v3.11.18 (#14166) 2025-05-01 22:28:35 +02:00
87886ca1b6 core: bump boto3 from 1.37.35 to v1.37.38 (#14167) 2025-05-01 22:28:11 +02:00
7ff96e30f9 core: bump frozenlist from 1.5.0 to v1.6.0 (#14168) 2025-05-01 22:28:02 +02:00
b26271557a core: bump pdoc from 15.0.1 to v15.0.3 (#14170) 2025-05-01 22:27:51 +02:00
15c99ff129 core: bump trio from 0.29.0 to v0.30.0 (#14174) 2025-05-01 22:27:32 +02:00
2a38e08e31 translate: Updates for file locale/en/LC_MESSAGES/django.po in it (#14271)
Translate locale/en/LC_MESSAGES/django.po in it

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-05-01 22:25:59 +02:00
3696706466 website: bump the build group across 1 directory with 9 updates (#14293)
Bumps the build group with 9 updates in the /website directory:

| Package | From | To |
| --- | --- | --- |
| [@rspack/binding-darwin-arm64](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.6` | `1.3.8` |
| [@rspack/binding-linux-arm64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.6` | `1.3.8` |
| [@rspack/binding-linux-x64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.6` | `1.3.8` |
| [@swc/core-darwin-arm64](https://github.com/swc-project/swc) | `1.11.22` | `1.11.24` |
| [@swc/core-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.22` | `1.11.24` |
| [@swc/core-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.22` | `1.11.24` |
| [@swc/html-darwin-arm64](https://github.com/swc-project/swc) | `1.11.22` | `1.11.24` |
| [@swc/html-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.22` | `1.11.24` |
| [@swc/html-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.22` | `1.11.24` |



Updates `@rspack/binding-darwin-arm64` from 1.3.6 to 1.3.8
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.8/packages/rspack)

Updates `@rspack/binding-linux-arm64-gnu` from 1.3.6 to 1.3.8
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.8/packages/rspack)

Updates `@rspack/binding-linux-x64-gnu` from 1.3.6 to 1.3.8
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.8/packages/rspack)

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

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

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

Updates `@swc/html-darwin-arm64` from 1.11.22 to 1.11.24
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.22...v1.11.24)

Updates `@swc/html-linux-arm64-gnu` from 1.11.22 to 1.11.24
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.22...v1.11.24)

Updates `@swc/html-linux-x64-gnu` from 1.11.22 to 1.11.24
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.22...v1.11.24)

---
updated-dependencies:
- dependency-name: "@rspack/binding-darwin-arm64"
  dependency-version: 1.3.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-arm64-gnu"
  dependency-version: 1.3.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-x64-gnu"
  dependency-version: 1.3.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.11.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-version: 1.11.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.11.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-darwin-arm64"
  dependency-version: 1.11.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-arm64-gnu"
  dependency-version: 1.11.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-x64-gnu"
  dependency-version: 1.11.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01 22:20:34 +02:00
d0c9635033 core, web: update translations (#14309)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-05-01 22:20:27 +02:00
7731014e1c stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#14311)
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-05-01 22:20:08 +02:00
d478582a5c core: bump astral-sh/uv from 0.7.0 to 0.7.2 (#14315)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.7.0 to 0.7.2.
- [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.7.0...0.7.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01 22:19:55 +02:00
6255f380aa core: bump goauthentik.io/api/v3 from 3.2025024.9 to 3.2025040.1 (#14316)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2025024.9 to 3.2025040.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.2025024.9...v3.2025040.1)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2025040.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-05-01 22:19:48 +02:00
1f02e67c5c core: bump github.com/redis/go-redis/v9 from 9.7.3 to 9.8.0 (#14317)
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.7.3 to 9.8.0.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.7.3...v9.8.0)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-version: 9.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01 22:19:41 +02:00
d0bfb894b4 lifecycle/aws: bump aws-cdk from 2.1012.0 to 2.1013.0 in /lifecycle/aws (#14318)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1012.0 to 2.1013.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1013.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1013.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-05-01 22:19:31 +02:00
c5dfdc6deb website/integrations: youtrack document (#14264)
* add to sidebar

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

* start ak config

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

* init

* lint

* spelling 

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

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dominic R <dominic@sdko.org>

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dominic R <dominic@sdko.org>

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dominic R <dominic@sdko.org>

---------

Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-05-01 11:13:21 -05:00
d04a66ad9a website/integrations: improve Gitea doc (#14194)
* Updating to new formatting rules, added note based on GH issue, wording improvements.

* Updated formatting, added testing configuration step, numbered steps, imrpoved wording

* Added numbered steps to the Gitea instructions and changed the navigation steps.

* Changed indenting on codeblocks

* Alterations based on feedback

* Altered icon urls and italicization

* changed line 52 to use png instead of svg

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

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

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

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

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

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

* changed <application lsug> to <slug>

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

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

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

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

* Minor changes to wording/formatting and added a resources section

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

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

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

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

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

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

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

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

* Added missing punctuation

* a few tweaks, and bumb to rebuild

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-05-01 09:54:52 -05:00
a5edaabec0 website/docs: "Device code flow" documentation improvements (#14257)
* Improved RFC reference

Replaced "abilities" with "capabilities" to better reflect RFC wording, added extended summary from RFC to ensure complete and clear understanding.

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Improved documentation

Added link for brand keyword, removed repetition

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Improved UX

Marked keywords with Capital letters and proper formatting to clarify those are references to actual values/labels

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* SEO Optimization

Added alternative name to "also known" section to improve searchability

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Added step-by-step tutorial for setup

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* "Relative vs. absolute paths" rule

Removed full link in favor of relative path

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Fixed formatting according to style guide

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Fixed relative path

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Update website/docs/add-secure-apps/providers/oauth2/device_code.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Update website/docs/add-secure-apps/providers/oauth2/device_code.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Update website/docs/add-secure-apps/providers/oauth2/device_code.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Update website/docs/add-secure-apps/providers/oauth2/device_code.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Update website/docs/add-secure-apps/providers/oauth2/device_code.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Update website/docs/add-secure-apps/providers/oauth2/device_code.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Update device_code.md

removed newline as per "prettier --write"

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Update website/docs/add-secure-apps/providers/oauth2/device_code.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>

* Update website/docs/add-secure-apps/providers/oauth2/device_code.md

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

* Update device_code.md

brute forced it here...

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

---------

Signed-off-by: Dametto Luca <45915503+LucaTheHacker@users.noreply.github.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-05-01 08:43:59 -05:00
daa367bc62 website/docs: adds webfinger doc under oauth provider (#14247)
* Added document and modified sidebar

* Update website/docs/add-secure-apps/providers/oauth2/webfinger_support.mdx

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-05-01 08:30:05 -05:00
78345853c2 website/docs: clean up oauth redirect paragraph (#14291)
* website/docs: clean up oauth redirect paragraph

Signed-off-by: Fletcher Heisler <fheisler@users.noreply.github.com>

* Dominic's edit, and yet another typo

---------

Signed-off-by: Fletcher Heisler <fheisler@users.noreply.github.com>
Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-04-30 16:11:16 -05:00
f0fa8a3226 brands: fix CSS Migration not updating brands (#14306)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-04-30 22:39:23 +02:00
3335fdc6ad website/docs: clarify 2025.4 breaking Reputation changes (#14284)
* website/docs: clarify `2025.4` breaking Reputation changes

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

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

* change to bump build checks

* another tweak to bounce after rebase

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-04-30 15:39:16 -05:00
29c2c0f7dc website/docs: clarify some points (i.e. around capitalization after colons) (#14290)
* a few new items

* more on capitalization

* Update website/docs/developer-docs/docs/style-guide.mdx

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

* tweak to bump build

* typo thx fletcher

* remove mention of BR

* final edits in

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Tana M Berry <tana@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-04-30 14:28:08 -05:00
ada4254f52 web: bump API Client version (#14301)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-04-30 13:43:37 +00:00
39035de552 website/docs: initial permissions: fix usage of term admin (#14300)
* website/docs: initial permissions: fix usage of term admin

Should be lowercase and use full word as it refers to an administrator. See pending PR for style guide 

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

* fix2

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

---------

Signed-off-by: Dominic R <dominic@sdko.org>
2025-04-30 13:19:43 +00:00
e76d388ce4 release: 2025.4.0 (#14299)
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-30 13:15:38 +00:00
a52f887692 core, web: update translations (#14273)
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-30 13:00:04 +00:00
d8b12a9a07 core: bump astral-sh/uv from 0.6.17 to 0.7.0 (#14294)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-30 12:59:49 +00:00
ec01f16e99 ci: cleanup post uv migration (#13538) 2025-04-30 12:43:14 +00:00
9e3aaefc20 website/docs: add gateway API to release notes and documentation (#14278) 2025-04-30 14:36:42 +02:00
4454592442 website/docs: Release notes 2025.4.0 (#14281)
* remove rc notice and enterprise tag for the span

* Edit sidebar and security.md

* Add api changes and minor fixes

* Fix linting

* fix netlify linter

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

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

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

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

* remove changelog entries that shouldn't be there

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

* Update v2025.4.md

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

* Update v2025.4.md

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

* fix linting

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-29 20:48:49 +02:00
593c953ecc website/docs: sessions in database (#13507)
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-29 20:33:48 +02:00
bcefe7123c website/docs: add LDAP 'Lookup using user attribute' docs (#13966)
* website/docs: add LDAP 'Lookup using user attribute' docs

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

* Updated the doc to new template, removed incorrect screenshot, clarified instructions

* Change in group field explanation as per Marc's comment

* Added examples for filters and changed some language.

* Removed additional info link

* fixup

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

* Minor formatting changes

* Update website/docs/users-sources/sources/protocols/ldap/index.md

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

* Update website/docs/users-sources/sources/directory-sync/active-directory/index.md

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

* Update website/docs/users-sources/sources/directory-sync/active-directory/index.md

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

* Added more information to service account creation and LDAPS testing

* Added examples for fields based on issue #3801

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-04-29 20:32:59 +02:00
812cf6c4f2 website/docs: add postgres pool configuration (#14060)
* website/docs: add postgres pool configuration

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

* Update website/docs/install-config/configuration/configuration.mdx

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

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-29 20:32:37 +02:00
73b6ef6a73 website/docs: docs about initial perms (#14263)
* basic procedural steps

* more questions, more typos

* more typos

* tweaks

* more content, new links

* fixed link

* tweak

* fix things

* more fixes

* yet more fixes

* Apply suggestions from code review

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

* Update website/docs/users-sources/access-control/initial_permissions.mdx

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

* dewi's edits

* dominic's edits

* gergo edits and more dominic edits

* one more

* yet one more fix

* final gergo observation

* tweak

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tana@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-04-29 20:31:01 +02:00
b58ebcddbf website/docs: Revert "website/docs: revert token_expiry format in example blueprint… (#14280)
Revert "website/docs: revert token_expiry format in example blueprint (#13582)"

This reverts commit 9538cf4690.
2025-04-29 20:30:13 +02:00
8b6ac3c806 website/docs: Password Uniqueness Policy (#13686)
* First draft docs for policies/unique_password

* simplify documentation

* fix styling

* Add clarification about when this policy takes effect

* change wording in how it works

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

* Take the user by the hand and tell them where to go

* Improve wording in Configuration options

* add suggestion from PR

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

* Update website/docs/customize/policies/unique_password.md

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

* Apply suggestions from code review

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>

* fix linting and wording

* Add instructions for binding

* Remove conf options section, add to sidebar

* Update website/docs/customize/policies/unique_password.md

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

---------

Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-04-29 20:29:41 +02:00
c6aa792076 docs/website: Update 2025.4 notes (#14272)
Fix styling
2025-04-29 10:06:22 +01:00
ee4792734e website/docs: update 2025.4 release notes (#14251)
* Update release notes for 2025.4

* fix typo

* Add/improve highlights, features and descriptions

* Fix linting and remove API changes

* remove minor changes

* fix linting

* Add helm chart stuff and integrations guide

* fix linting

* Restore SECURITY.md and sidebar.js

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* password history - add compliance note

Signed-off-by: Fletcher Heisler <fheisler@users.noreply.github.com>

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

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

* please the linter

* use current version

* add .md

* fix badges

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Fletcher Heisler <fheisler@users.noreply.github.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Fletcher Heisler <fheisler@users.noreply.github.com>
2025-04-28 19:37:11 +00:00
445f11ca6b rbac: add name to Permissions search (#14269) 2025-04-28 14:39:42 +00:00
8e4810fb20 website/docs: add device code flow instructions (#14267)
Adds instructions on how to create a device code flow
2025-04-28 14:28:35 +02:00
96a122c5d1 core: bump astral-sh/uv from 0.6.16 to 0.6.17 (#14266)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-28 13:43:35 +02:00
3c6b8b10e5 web: fix bug that was causing charts to be too tall (#14253)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

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

## Note

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

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

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

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

This reverts commit dddde09be5.

* web: fix bug that was causing charts to be too tall

This removes the "aspect-ratio" declaration from the Charts CSS rules.  That declaration
was interacting badly with the charts' own internal tools for manually setting the size
of the canvas, causing the chart to be too tall or take up too much space when one had
a particularly wide monitor.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes
2025-04-25 13:00:02 -07:00
15999caa5d website/integrations: homarr remove redirect uri comment (#14252)
Signed-off-by: Dominic R <dominic@sdko.org>
2025-04-25 13:31:23 -05:00
57d8375de1 website/integrations: adds missing trailing slash in homarr doc (#14249)
Added trailing slash to link
2025-04-25 12:38:52 -05:00
07ec787076 lifecycle: fix test-all in docker (#14244) 2025-04-25 13:49:58 +02:00
bc96bef097 core, web: update translations (#14243)
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-25 13:39:33 +02:00
28869858b5 web/admin: prevent default logo flashing in admin interface (#13960)
* web: elements: SidebarBrand: prevent logo flashing in admin interface

When using a custom SVG file (or mabye other types, TBH I didn't check, I should) for a branded logo, the logo would flash the stock authentik logo for a moment before the custom logo appears on the Admin interface.

This was happening because the brand configuration was being loaded asynchronously through the context provider, causing a brief moment where the default logo was shown.

Closes https://github.com/goauthentik/authentik/issues/3228
Closes https://github.com/goauthentik/authentik/issues/13739

* use globalAK

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-04-25 11:25:40 +02:00
cbc5a1c39d website/docs: Update release notes for 2025.4 (#14158)
* Update release notes for 2025.4

* fix typo

* Add/improve highlights, features and descriptions

* Fix linting and remove API changes

* remove minor changes

* fix linting

* Add helm chart stuff and integrations guide

* fix linting

* Restore SECURITY.md and sidebar.js

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* password history - add compliance note

Signed-off-by: Fletcher Heisler <fheisler@users.noreply.github.com>

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

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

* please the linter

* use current version

* add .md

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Fletcher Heisler <fheisler@users.noreply.github.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Fletcher Heisler <fheisler@users.noreply.github.com>
2025-04-25 06:50:32 +02:00
5f6b69c998 core, web: update translations (#14241)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: melizeche <484773+melizeche@users.noreply.github.com>
2025-04-24 20:49:40 +00:00
cf065db3d5 Updates for file web/xliff/en.xlf in zh_TW [Manual Sync] (#14225)
* Translate web/xliff/en.xlf in zh_TW [Manual Sync]

71% 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

* ci trigger

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

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-24 20:32:42 +00:00
86c65325ce translate: Updates for file web/xliff/en.xlf in nl [Manual Sync] (#14217)
Translate web/xliff/en.xlf in nl [Manual Sync]

66% 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-04-24 22:01:07 +02:00
2b8e10e979 translate: Updates for file web/xliff/en.xlf in fi [Manual Sync] (#14219)
Translate web/xliff/en.xlf in fi [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 22:00:45 +02:00
9298807275 translate: Updates for file web/xliff/en.xlf in de [Manual Sync] (#14220)
Translate web/xliff/en.xlf in de [Manual Sync]

71% 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-04-24 22:00:28 +02:00
ed56d6ac50 translate: Updates for file web/xliff/en.xlf in fr [Manual Sync] (#14221)
Translate web/xliff/en.xlf in fr [Manual Sync]

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 21:59:43 +02:00
8c07b385ad translate: Updates for file web/xliff/en.xlf in pl [Manual Sync] (#14222)
Translate web/xliff/en.xlf in pl [Manual Sync]

84% 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-04-24 21:59:29 +02:00
880db7a86c translate: Updates for file locale/en/LC_MESSAGES/django.po in es [Manual Sync] (#14223)
Translate django.po in es [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 21:59:21 +02:00
99c1250ba5 translate: Updates for file web/xliff/en.xlf in zh-Hans [Manual Sync] (#14224)
Translate en.xlf in zh-Hans [Manual Sync]

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 21:59:14 +02:00
5ce126ac83 translate: Updates for file locale/en/LC_MESSAGES/django.po in de [Manual Sync] (#14226)
Translate django.po in de [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 21:58:57 +02:00
dfa21d0725 translate: Updates for file locale/en/LC_MESSAGES/django.po in fi [Manual Sync] (#14227)
Translate django.po in fi [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 21:58:50 +02:00
e7e4af3894 translate: Updates for file web/xliff/en.xlf in tr [Manual Sync] (#14228)
Translate web/xliff/en.xlf in tr [Manual Sync]

90% 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-04-24 21:58:38 +02:00
931d6ec579 translate: Updates for file locale/en/LC_MESSAGES/django.po in pl [Manual Sync] (#14229)
Translate django.po in pl [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 21:58:17 +02:00
ff45acb25c translate: Updates for file locale/en/LC_MESSAGES/django.po in ko [Manual Sync] (#14230)
Translate django.po in ko [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 21:58:10 +02:00
c96557ff2d translate: Updates for file locale/en/LC_MESSAGES/django.po in it [Manual Sync] (#14231)
Translate django.po in it [Manual Sync]

97% 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-04-24 21:57:59 +02:00
734feac4ae translate: Updates for file locale/en/LC_MESSAGES/django.po in ru [Manual Sync] (#14232)
Translate django.po in ru [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 21:57:38 +02:00
b17a9ed145 translate: Updates for file web/xliff/en.xlf in it [Manual Sync] (#14216)
Translate web/xliff/en.xlf in it [Manual Sync]

98% 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-04-24 21:57:19 +02:00
2bef7695db translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR [Manual Sync] (#14233)
Translate django.po in pt_BR [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 21:45:16 +02:00
df472dd842 Revert "website/docs: Prepare for monorepo. (#14119)" (#14239)
This reverts commit 5bdef1c4f6.
2025-04-24 21:44:13 +02:00
98d201d34c web: bump API Client version (#14236)
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>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-24 19:01:26 +00:00
47e89602ab stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#14237)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-04-24 19:00:09 +00:00
ceb0851452 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_TW [Manual Sync] (#14235)
Translate django.po in zh_TW [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 18:56:13 +00:00
cac2593658 translate: Updates for file locale/en/LC_MESSAGES/django.po in tr [Manual Sync] (#14234)
Translate django.po in tr [Manual Sync]

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

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-24 18:53:54 +00:00
1c9705bfaa web: lock lit/ssr (#14214) 2025-04-24 18:38:32 +00:00
9e2566cec4 ci: fix npm packages publication not running (#14215) 2025-04-24 18:36:55 +00:00
5bdef1c4f6 website/docs: Prepare for monorepo. (#14119)
* docusaurus-theme: Fix header alignment, overscroll, vertical padding.

* docusaurus-theme: Lint.

* website/docs: Prepare for monorepo packages.

* website/docs: Clean up dependencies. Tidy table.

* website/docs: Fix issue where Prettier affects example content.

* website/docs: Temp fix for stale packages.
2025-04-24 18:22:56 +00:00
ae41ccd862 Revert package-lock.json changes from "web: add remember me feature to IdentificationStage (#10397)" (#14212)
Revert package-lock.json changes from "web: add remember me feature to IdentificationStage (#10397)"

This reverts parts of commit 5e6874cc1f.
2025-04-24 18:20:35 +00:00
337956672f Revert "web: Safari fixes merge branch (#14181)" (#14211) 2025-04-24 14:00:29 -04:00
cf160f800d web: Safari fixes merge branch (#14181)
* web/admin: Fix layout centering. Adjust theming.

* web: Fix issue where references to Lit SSR break page styles.

* web: Fix issues surrounding color scheme/theme mixup in UI.
2025-04-24 10:16:04 -04:00
e9822cd937 website: bump the build group in /website with 9 updates (#14204)
Bumps the build group in /website with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [@rspack/binding-darwin-arm64](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.5` | `1.3.6` |
| [@rspack/binding-linux-arm64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.5` | `1.3.6` |
| [@rspack/binding-linux-x64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.5` | `1.3.6` |
| [@swc/core-darwin-arm64](https://github.com/swc-project/swc) | `1.11.21` | `1.11.22` |
| [@swc/core-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.21` | `1.11.22` |
| [@swc/core-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.21` | `1.11.22` |
| [@swc/html-darwin-arm64](https://github.com/swc-project/swc) | `1.11.21` | `1.11.22` |
| [@swc/html-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.21` | `1.11.22` |
| [@swc/html-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.21` | `1.11.22` |


Updates `@rspack/binding-darwin-arm64` from 1.3.5 to 1.3.6
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.6/packages/rspack)

Updates `@rspack/binding-linux-arm64-gnu` from 1.3.5 to 1.3.6
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.6/packages/rspack)

Updates `@rspack/binding-linux-x64-gnu` from 1.3.5 to 1.3.6
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.6/packages/rspack)

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

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

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

Updates `@swc/html-darwin-arm64` from 1.11.21 to 1.11.22
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.21...v1.11.22)

Updates `@swc/html-linux-arm64-gnu` from 1.11.21 to 1.11.22
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.21...v1.11.22)

Updates `@swc/html-linux-x64-gnu` from 1.11.21 to 1.11.22
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.21...v1.11.22)

---
updated-dependencies:
- dependency-name: "@rspack/binding-darwin-arm64"
  dependency-version: 1.3.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-arm64-gnu"
  dependency-version: 1.3.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-x64-gnu"
  dependency-version: 1.3.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.11.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-version: 1.11.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.11.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-darwin-arm64"
  dependency-version: 1.11.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-arm64-gnu"
  dependency-version: 1.11.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-x64-gnu"
  dependency-version: 1.11.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-24 13:52:37 +02:00
5244f64be4 website: bump typescript from 5.8.2 to 5.8.3 in /website (#13786)
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.8.2 to 5.8.3.
- [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/commits)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 5.8.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-24 13:34:43 +02:00
0df4824fd4 lifecycle/migrate: fix migration failing if killed during first startup (#14207)
Co-authored-by: Taylor Jones <bigfootjonesy@gmail.com>
2025-04-24 11:20:37 +00:00
ea22abc75d core, web: update translations (#14203)
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-24 13:03:04 +02:00
b09bab7543 lifecycle/aws: bump aws-cdk from 2.1010.0 to 2.1012.0 in /lifecycle/aws (#14205)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-24 12:59:45 +02:00
5aedc8a5f2 website/integrations: improves netbird documentation (#14191)
* Matches up the doc with the official NetBird documentation. Also fixes order of the sidebar.

* Removed kbd and used angle brackets

* Changed wording of final section to mention filename and script that needs to be run

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

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

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

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* added title to codeblock

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-04-24 08:26:40 +00:00
2f3ae0f607 website/docs: updated user count info (#14186)
* updated user count info

* Update website/docs/enterprise/manage-enterprise.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tana@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-04-23 18:16:09 -05:00
e3674426b7 website/docs: rearranged brands docs (#14116)
* first pass

* fixed links.

* tweaks

* remove extensions in redirects

* added edits from review

* missed an edit

---------

Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-04-23 16:39:06 -05:00
df915d3a5e website: integrations: apache guacamole: remove redirect URI comments (#14113)
* website: integrations: apache guacamole: remove redirect URI comments

Self-evident. + Just follow the docs tbh

* Update website/integrations/services/apache-guacamole/index.mdx

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

---------

Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Jens L. <jens@beryju.org>
2025-04-23 14:15:35 -05:00
4949c31860 packages/docusaurus-theme: Fix header alignment, overscroll, vertical padding. (#14120)
* docusaurus-theme: Fix header alignment, overscroll, vertical padding.

* docusaurus-theme: Lint.

* website/docs: Update package-lock.
2025-04-23 13:19:38 -04:00
4580dec06b outposts: add support for gateway API (#13272) 2025-04-23 16:22:10 +00:00
56de969640 translate: Updates for file web/xliff/en.xlf in fr (#14200)
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-04-23 15:37:48 +00:00
413902508d translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14199)
* Translate locale/en/LC_MESSAGES/django.po in fr

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

* 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-04-23 15:36:58 +00:00
64af0ccba6 website/docs: adds code examples for getting user objects from a group object (#14101)
* Added example of how to get user objects fro a group object

* Updated wording

* Updated wording, added titles to examples, capitalised group, added explanation of examples

* Update website/docs/users-sources/groups/group_ref.md

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

* Update website/docs/users-sources/groups/group_ref.md

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

* Update website/docs/users-sources/groups/group_ref.md

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

* Update website/docs/users-sources/groups/group_ref.md

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

* Update website/docs/users-sources/groups/group_ref.md

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

* Update website/docs/users-sources/groups/group_ref.md

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

* Update website/docs/users-sources/groups/group_ref.md

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

* Changes based on Tana's feedback

* Word

* Capitalization

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-04-23 16:36:19 +01:00
673db53777 translate: Updates for file web/xliff/en.xlf in zh-Hans (#14198)
Translate web/xliff/en.xlf in zh-Hans

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-23 15:32:35 +00:00
8df7716d90 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14195)
Translate locale/en/LC_MESSAGES/django.po in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-23 15:29:05 +00:00
19bb2de13f translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14197)
Translate django.po in zh-Hans

100% translated source file: 'django.po'
on 'zh-Hans'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-23 17:20:01 +02:00
a218fd7628 translate: Updates for file web/xliff/en.xlf in zh_CN (#14196)
Translate web/xliff/en.xlf in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-23 17:19:32 +02:00
78cfb50a90 website/integrations: mealie add integration (#14188)
* Mealie Integration Documentation

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Update configuration text.

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Update to configuration text.

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Update to configuration text.

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Update sidebarsIntegrations.js, add mealie.

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Update for missed service name replacement.

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Updated Mealie description.

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Update to format, in authentik configuration statement.

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Update to format in redirect URI section.

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Change case of Authentik to authentik.

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Mealie updates to correct styles and improve content.

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Removed tip text now part of a new section.

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

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

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

* Update group example format.

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Update to navigation description.

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

* Removed quotes in env.,

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>

---------

Signed-off-by: TrisBits <44067868+TrisBits@users.noreply.github.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-04-23 13:59:53 +01:00
2033d52dc2 core, web: update translations (#14187)
Co-authored-by: melizeche <484773+melizeche@users.noreply.github.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-23 10:57:09 +00:00
be00f47ddc core: bump goauthentik.io/api/v3 from 3.2025024.8 to 3.2025024.9 (#14189)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-23 12:44:09 +02:00
2cc5f4b273 website/docs: update user object doc (#14132)
* Updated formatting, changed examples, added headers, updated django doc link to stable

* Prettier fix

* Update website/docs/users-sources/user/user_ref.mdx

Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/docs/users-sources/user/user_ref.mdx

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

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-04-23 08:26:10 +01:00
4e8f3407a4 website/docs: dev-docs: style guide: no longer using italic for vars (#14185)
We no longer use italic for variables

Signed-off-by: Dominic R <dominic@sdko.org>
2025-04-22 17:30:46 -05:00
7f861cc2a1 website/docs: dev docs: style guide: update style conventions for urls (#14184)
* website/docs: dev docs: style guide: update style conventions for urls

Updates URL styling conventions to use angle bracket surrounded values instead of <em>s and <kbd>s

Part of https://www.notion.so/authentiksecurity/Check-ins-17caee05b24e80a0aec6c7d508406435?pvs=4#1ddaee05b24e80138155e120174c3502

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

* yep

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

---------

Signed-off-by: Dominic R <dominic@sdko.org>
2025-04-22 17:30:02 -05:00
7bf58d0ba2 website/integrations: paperless: use <slug>. instead of hardcoded slug value (#14183)
Closes https://github.com/goauthentik/authentik/issues/13778

Signed-off-by: Dominic R <dominic@sdko.org>
2025-04-22 16:55:53 -05:00
fffcb00f39 website/docs: updates style guide code block section (#14088)
* Removed multiline code block section. Added docusaurus style codeblock section. Fixed some capitalisation.

* Update website/docs/developer-docs/docs/style-guide.mdx

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

* Added highlighting info and fixed formatting.

* Typo and prettier.

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-04-22 12:10:06 -05:00
77ee868573 website: components: delete multilinecodeblock src (#14094)
* Delete website/src/components/MultilineCodeblock/index.tsx

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

* Delete website/src/components/MultilineCodeblock/styles.css

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

---------

Signed-off-by: Dominic R <dominic@sdko.org>
2025-04-22 17:41:41 +01:00
6aaec08496 Revert "policies: buffered policy access view for concurrent authorization attempts when unauthenticated (#13629)" (#14180) 2025-04-22 15:45:45 +00:00
cc15584650 core: bump uvicorn from 0.34.1 to v0.34.2 (#14175) 2025-04-22 17:14:01 +02:00
e55e446b89 website/integrations: add xcreds (#14163)
* Created guide and modified sidebar

* make

* Typo

* Clarified wording

* Added words

* Fixed login to vs log into

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-04-22 14:34:56 +00:00
76088e48b5 core, web: update translations (#14179)
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-22 13:56:32 +00:00
4165a0a6b2 web: update default flow background (#14115)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-04-22 15:02:10 +02:00
647fefe5ce web: bump API Client version (#14176)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-04-22 15:01:42 +02:00
723dccdae3 enterprise/policies: Add Password Uniqueness History Policy (#13453)
Co-authored-by: David Gunter <david@davidgunter.ca>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-22 14:39:07 +02:00
c82f747e5e web/xliff: fix duplicated translations (#14164) 2025-04-22 12:13:34 +00:00
43406e2464 website/docs: fix postgres pool recommended settings (#14149) 2025-04-22 12:01:36 +00:00
a0ff0bef85 core: bump astral-sh/uv from 0.6.14 to 0.6.16 (#14161)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 13:57:29 +02:00
bedf548a5f web: fix scrollbar styling (#12600)
* Fix `.pf-c-card__body` scrollbars

* Fallback scrollbar styling for browsers that don't support `::-webkit-scrollbar`

---------

Co-authored-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
2025-04-22 04:47:02 +02:00
976e81c1dd website: integrations: gravity: fix issuer URL (#14155)
Signed-off-by: Dominic R <dominic@sdko.org>
2025-04-21 20:53:25 +02:00
ad733033d7 web: Packagify live reload plugin. (#14134)
* web: Packagify live reload plugin.

* web: Use shared formatter.

* web: Format.

* web: Use project mode typecheck.

* web: Fix type errors.
2025-04-21 19:07:45 +02:00
ba686f6a93 web: bump API Client version (#14062)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-04-18 17:17:30 +02:00
dc50be1e13 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14146)
Translate django.po in zh-Hans

100% translated source file: 'django.po'
on 'zh-Hans'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-18 17:17:03 +02:00
205686d252 translate: Updates for file web/xliff/en.xlf in zh_CN (#14145)
Translate web/xliff/en.xlf in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-18 17:16:48 +02:00
6d589013e6 core: bump goauthentik.io/api/v3 from 3.2025024.7 to 3.2025024.8 (#14143)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-18 17:16:34 +02:00
2d6433ca9a translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14144)
Translate locale/en/LC_MESSAGES/django.po in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-18 17:16:23 +02:00
b5f07acb26 translate: Updates for file web/xliff/en.xlf in zh-Hans (#14139)
* Translate web/xliff/en.xlf in zh-Hans

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

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

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

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

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

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-18 17:16:10 +02:00
ea8702077c core, web: update translations (#14142)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-18 11:18:32 +02:00
6593357115 core: bump yarl from 1.19.0 to v1.20.0 (#14128) 2025-04-17 13:44:53 -04:00
6daed865c1 core: bump kombu from 5.5.2 to v5.5.3 (#14127) 2025-04-17 13:44:35 -04:00
c48a21707a core: bump boto3 from 1.37.34 to v1.37.35 (#14126) 2025-04-17 13:44:06 -04:00
e857770c0a core: bump automat from 24.8.1 to v25.4.16 (#14125) 2025-04-17 13:43:47 -04:00
add74c8799 website: bump http-proxy-middleware from 2.0.7 to 2.0.9 in /website (#14111)
Bumps [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) from 2.0.7 to 2.0.9.
- [Release notes](https://github.com/chimurai/http-proxy-middleware/releases)
- [Changelog](https://github.com/chimurai/http-proxy-middleware/blob/v2.0.9/CHANGELOG.md)
- [Commits](https://github.com/chimurai/http-proxy-middleware/compare/v2.0.7...v2.0.9)

---
updated-dependencies:
- dependency-name: http-proxy-middleware
  dependency-version: 2.0.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 19:19:25 +02:00
12d854035d website: bump estree-util-value-to-estree from 3.1.1 to 3.3.3 in /website (#13808)
website: bump estree-util-value-to-estree in /website

Bumps [estree-util-value-to-estree](https://github.com/remcohaszing/estree-util-value-to-estree) from 3.1.1 to 3.3.3.
- [Release notes](https://github.com/remcohaszing/estree-util-value-to-estree/releases)
- [Commits](https://github.com/remcohaszing/estree-util-value-to-estree/compare/v3.1.1...v3.3.3)

---
updated-dependencies:
- dependency-name: estree-util-value-to-estree
  dependency-version: 3.3.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 19:02:02 +02:00
57dd4ae91d website: bump wireit from 0.14.11 to 0.14.12 in /website (#14003)
Bumps [wireit](https://github.com/google/wireit) from 0.14.11 to 0.14.12.
- [Changelog](https://github.com/google/wireit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/wireit/compare/v0.14.11...v0.14.12)

---
updated-dependencies:
- dependency-name: wireit
  dependency-version: 0.14.12
  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-04-17 19:01:46 +02:00
37fbc98177 website: bump the build group in /website with 9 updates (#13748)
Bumps the build group in /website with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [@rspack/binding-darwin-arm64](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.0` | `1.3.1` |
| [@rspack/binding-linux-arm64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.0` | `1.3.1` |
| [@rspack/binding-linux-x64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.0` | `1.3.1` |
| [@swc/core-darwin-arm64](https://github.com/swc-project/swc) | `1.11.13` | `1.11.16` |
| [@swc/core-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.13` | `1.11.16` |
| [@swc/core-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.13` | `1.11.16` |
| [@swc/html-darwin-arm64](https://github.com/swc-project/swc) | `1.11.13` | `1.11.16` |
| [@swc/html-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.13` | `1.11.16` |
| [@swc/html-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.13` | `1.11.16` |


Updates `@rspack/binding-darwin-arm64` from 1.3.0 to 1.3.1
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.1/packages/rspack)

Updates `@rspack/binding-linux-arm64-gnu` from 1.3.0 to 1.3.1
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.1/packages/rspack)

Updates `@rspack/binding-linux-x64-gnu` from 1.3.0 to 1.3.1
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.1/packages/rspack)

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

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

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

Updates `@swc/html-darwin-arm64` from 1.11.13 to 1.11.16
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.13...v1.11.16)

Updates `@swc/html-linux-arm64-gnu` from 1.11.13 to 1.11.16
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.13...v1.11.16)

Updates `@swc/html-linux-x64-gnu` from 1.11.13 to 1.11.16
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.13...v1.11.16)

---
updated-dependencies:
- dependency-name: "@rspack/binding-darwin-arm64"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-arm64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-x64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-darwin-arm64"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-darwin-arm64"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-arm64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-x64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 19:00:44 +02:00
14f216eb40 core: bump github.com/go-ldap/ldap/v3 from 3.4.10 to 3.4.11 (#14068)
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.10 to 3.4.11.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.4.10...v3.4.11)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/v3
  dependency-version: 3.4.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 19:00:21 +02:00
1209dd022e translate: Updates for file web/xliff/en.xlf in fr (#14124)
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-04-17 10:58:55 +00:00
c96f13ac66 translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14123)
* Translate locale/en/LC_MESSAGES/django.po in fr

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

* 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-04-17 10:57:24 +00:00
5e6874cc1f web: add remember me feature to IdentificationStage (#10397)
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-17 10:37:49 +00:00
fb5053ec83 core: bump goauthentik.io/api/v3 from 3.2025024.6 to 3.2025024.7 (#14121)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 12:27:24 +02:00
6f7dc2c543 lifecycle/aws: bump aws-cdk from 2.1007.0 to 2.1010.0 in /lifecycle/aws (#14122)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 12:27:17 +02:00
542b69b224 core, web: update translations (#14117)
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-17 12:24:29 +02:00
c15c0cbe86 website: integrations: apache guacamole: Fix deprecated start-of-doc … (#14114)
website: integrations: apache guacamole: Fix deprecated start-of-doc values
2025-04-16 15:45:44 -05:00
c6fe0c1d85 website integrations: actual budget: remove old header and support_level (#14112) 2025-04-16 15:45:20 -05:00
07f0666a6f website/integrations: general cleanup and updates (#12716)
* squash commits for future merge conflict resolution, if any

* adventurelog cleanup + lint

* lint (again)

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

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

* Update website/integrations/services/actual-budget/index.mdx

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

* Update website/integrations/services/apache-guacamole/index.mdx

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

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

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

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

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

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

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

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

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

* Update website/integrations/services/cloudflare-access/index.md

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

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

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

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

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

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

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

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

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

* Update website/integrations/services/fortigate-admin/index.md

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

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

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

* fix

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

* wip: migr actual budget integration to new codeblock

* Replaced multilinecodeblocks with docusaurus style codeblocks

* Fixed linting and removed kbd and em tags from codeblock

---------

Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-04-16 15:16:01 -05:00
51609d696d policies/geoip: fix result when only dynamic results are used (#14107) 2025-04-16 15:50:26 +00:00
c0d08df161 core: bump opentelemetry-api from 1.32.0 to v1.32.1 (#14102) 2025-04-16 15:50:10 +00:00
643a97f0a5 core: bump rsa from 4.9 to v4.9.1 (#14103) 2025-04-16 09:51:53 -04:00
155a31fd70 sources/oauth: introduce authorization code auth method (#14034)
Co-authored-by: Rsgm <rsgm123@gmail.com>
2025-04-16 13:00:08 +00:00
c6f9d5df7b core, web: update translations (#14096)
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-16 13:16:06 +02:00
ea85331a7e web/api: Fix Hoisted exports across entrypoints. Update Axios. (#14089)
* web/api: Fix issue where hoisted exports across entrypoints do not
order.

* web/api: Override OpenAPI transitive dep.
2025-04-15 20:09:41 +02:00
4f4c5253dd translate: Updates for file web/xliff/en.xlf in fr (#14091)
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-04-15 17:11:40 +00:00
83b2fc36df translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14090)
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-04-15 17:08:09 +00:00
d99d2b8bdc translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14087)
Translate django.po in zh-Hans

100% translated source file: 'django.po'
on 'zh-Hans'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-15 18:40:19 +02:00
9b96d04b3a translate: Updates for file web/xliff/en.xlf in zh-Hans (#14086)
Translate web/xliff/en.xlf in zh-Hans

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-15 18:40:02 +02:00
ca5b99eb16 translate: Updates for file web/xliff/en.xlf in zh_CN (#14084)
Translate web/xliff/en.xlf in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-15 18:39:49 +02:00
4c1676e97c translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14083)
Translate locale/en/LC_MESSAGES/django.po in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-04-15 18:39:36 +02:00
81855cf2fe core: bump google-auth from 2.38.0 to v2.39.0 (#14076) 2025-04-15 08:32:54 -04:00
bd904027be core: bump sentry-sdk from 2.25.1 to v2.26.1 (#14079) 2025-04-15 08:32:14 -04:00
0ffc97db15 core: bump prompt-toolkit from 3.0.50 to v3.0.51 (#14078) 2025-04-15 08:31:41 -04:00
2c515b1e17 core: bump boto3 from 1.37.33 to v1.37.34 (#14074) 2025-04-15 08:31:12 -04:00
f8900fbaf3 core: bump msgraph-sdk from 1.27.0 to v1.28.0 (#14077) 2025-04-15 08:30:44 -04:00
0f4a98d9c6 website/docs: fix minor typo in working_with_policies.md (#14071)
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-15 11:40:23 +00:00
8853f25b45 core, web: update translations (#14064)
Co-authored-by: rissson <18313093+rissson@users.noreply.github.com>
2025-04-15 13:26:02 +02:00
1c40f7b95a stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#14065)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-04-15 13:25:13 +02:00
9b5d6ec1af core: bump goauthentik.io/api/v3 from 3.2025024.4 to 3.2025024.6 (#14069)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-15 13:24:28 +02:00
36d29a9ae1 Small fix for Actual-Budget wiki guide (#14066)
Remove ending slash from redirect uri

Signed-off-by: James Armstrong <32995055+jmarmstrong1207@users.noreply.github.com>
2025-04-15 09:43:59 +01:00
0606b1aba4 root: support db pool (#13534) 2025-04-14 16:05:31 +00:00
03d5dad867 rbac: add InitialPermissions (#13795)
* add `InitialPermissions` model to RBAC

This is a powerful construct between Permission and Role to set initial
permissions for newly created objects.

* use safer `request.user`

* fixup! use safer `request.user`

* force all self-defined serializers to descend from our custom one

See https://github.com/goauthentik/authentik/pull/10139

* reorganize initial permission assignment

* fixup! reorganize initial permission assignment
2025-04-14 17:55:49 +02:00
38a9e46af3 web: bump API Client version (#14058)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-04-14 17:24:47 +02:00
697 changed files with 31035 additions and 13946 deletions

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 2025.2.4
current_version = 2025.4.1
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*))?

View File

@ -118,3 +118,15 @@ updates:
prefix: "core:"
labels:
- dependencies
- package-ecosystem: docker-compose
directories:
# - /scripts # Maybe
- /tests/e2e
schedule:
interval: daily
time: "04:00"
open-pull-requests-limit: 10
commit-message:
prefix: "core:"
labels:
- dependencies

View File

@ -53,6 +53,7 @@ jobs:
signoff: true
# ID from https://api.github.com/users/authentik-automation[bot]
author: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
labels: dependencies
- uses: peter-evans/enable-pull-request-automerge@v3
with:
token: ${{ steps.generate_token.outputs.token }}

View File

@ -70,22 +70,18 @@ jobs:
- name: checkout stable
run: |
# Copy current, latest config to local
# Temporarly comment the .github backup while migrating to uv
cp authentik/lib/default.yml local.env.yml
# cp -R .github ..
cp -R .github ..
cp -R scripts ..
git checkout $(git tag --sort=version:refname | grep '^version/' | grep -vE -- '-rc[0-9]+$' | tail -n1)
# rm -rf .github/ scripts/
# mv ../.github ../scripts .
rm -rf scripts/
mv ../scripts .
rm -rf .github/ scripts/
mv ../.github ../scripts .
- name: Setup authentik env (stable)
uses: ./.github/actions/setup
with:
postgresql_version: ${{ matrix.psql }}
continue-on-error: true
- name: run migrations to stable
run: poetry run python -m lifecycle.migrate
run: uv run python -m lifecycle.migrate
- name: checkout current code
run: |
set -x
@ -204,7 +200,7 @@ jobs:
uses: actions/cache@v4
with:
path: web/dist
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**') }}
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
- name: prepare web ui
if: steps.cache-web.outputs.cache-hit != 'true'
working-directory: web
@ -212,6 +208,7 @@ jobs:
npm ci
make -C .. gen-client-ts
npm run build
npm run build:sfe
- name: run e2e
run: |
uv run coverage run manage.py test ${{ matrix.job.glob }}

View File

@ -29,7 +29,7 @@ jobs:
- name: Generate API
run: make gen-client-go
- name: golangci-lint
uses: golangci/golangci-lint-action@v7
uses: golangci/golangci-lint-action@v8
with:
version: latest
args: --timeout 5000s --verbose

View File

@ -37,6 +37,7 @@ jobs:
signoff: true
# ID from https://api.github.com/users/authentik-automation[bot]
author: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
labels: dependencies
- uses: peter-evans/enable-pull-request-automerge@v3
with:
token: ${{ steps.generate_token.outputs.token }}

View File

@ -53,6 +53,7 @@ jobs:
body: ${{ steps.compress.outputs.markdown }}
delete-branch: true
signoff: true
labels: dependencies
- uses: peter-evans/enable-pull-request-automerge@v3
if: "${{ github.event_name != 'pull_request' && steps.compress.outputs.markdown != '' }}"
with:

View File

@ -3,10 +3,10 @@ on:
push:
branches: [main]
paths:
- packages/docusaurus-config
- packages/eslint-config
- packages/prettier-config
- packages/tsconfig
- packages/docusaurus-config/**
- packages/eslint-config/**
- packages/prettier-config/**
- packages/tsconfig/**
workflow_dispatch:
jobs:
publish:

View File

@ -52,3 +52,6 @@ jobs:
body: "core, web: update translations"
delete-branch: true
signoff: true
labels: dependencies
# ID from https://api.github.com/users/authentik-automation[bot]
author: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>

View File

@ -25,23 +25,13 @@ jobs:
env:
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
run: |
title=$(curl -q -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${{ github.event.pull_request.number }} | jq -r .title)
title=$(gh pr view ${{ github.event.pull_request.number }} --json "title" -q ".title")
echo "title=${title}" >> "$GITHUB_OUTPUT"
- name: Rename
env:
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
run: |
curl -L \
-X PATCH \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${{ github.event.pull_request.number }} \
-d "{\"title\":\"translate: ${{ steps.title.outputs.title }}\"}"
gh pr edit -t "translate: ${{ steps.title.outputs.title }}" --add-label dependencies
- uses: peter-evans/enable-pull-request-automerge@v3
with:
token: ${{ steps.generate_token.outputs.token }}

View File

@ -16,7 +16,7 @@
],
"typescript.preferences.importModuleSpecifier": "non-relative",
"typescript.preferences.importModuleSpecifierEnding": "index",
"typescript.tsdk": "./web/node_modules/typescript/lib",
"typescript.tsdk": "./node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"yaml.schemas": {
"./blueprints/schema.json": "blueprints/**/*.yaml"
@ -30,7 +30,5 @@
}
],
"go.testFlags": ["-count=1"],
"github-actions.workflows.pinned.workflows": [
".github/workflows/ci-main.yml"
]
"github-actions.workflows.pinned.workflows": [".github/workflows/ci-main.yml"]
}

View File

@ -40,7 +40,8 @@ COPY ./web /work/web/
COPY ./website /work/website/
COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
RUN npm run build
RUN npm run build && \
npm run build:sfe
# Stage 3: Build go proxy
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder
@ -85,18 +86,17 @@ FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v7.1.0 AS geoip
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
ENV GEOIPUPDATE_VERBOSE="1"
ENV GEOIPUPDATE_ACCOUNT_ID_FILE="/run/secrets/GEOIPUPDATE_ACCOUNT_ID"
ENV GEOIPUPDATE_LICENSE_KEY_FILE="/run/secrets/GEOIPUPDATE_LICENSE_KEY"
USER root
RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
--mount=type=secret,id=GEOIPUPDATE_LICENSE_KEY \
mkdir -p /usr/share/GeoIP && \
/bin/sh -c "/usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
/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 5: Download uv
FROM ghcr.io/astral-sh/uv:0.6.14 AS uv
FROM ghcr.io/astral-sh/uv:0.7.5 AS uv
# Stage 6: Base python image
FROM ghcr.io/goauthentik/fips-python:3.12.10-slim-bookworm-fips AS python-base
FROM ghcr.io/goauthentik/fips-python:3.13.3-slim-bookworm-fips AS python-base
ENV VENV_PATH="/ak-root/.venv" \
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \

View File

@ -1,6 +1,7 @@
.PHONY: gen dev-reset all clean test web website
.SHELLFLAGS += ${SHELLFLAGS} -e
SHELL := /bin/bash
.SHELLFLAGS += ${SHELLFLAGS} -e -o pipefail
PWD = $(shell pwd)
UID = $(shell id -u)
GID = $(shell id -g)
@ -8,9 +9,9 @@ NPM_VERSION = $(shell python -m scripts.generate_semver)
PY_SOURCES = authentik tests scripts lifecycle .github
DOCKER_IMAGE ?= "authentik:test"
GEN_API_TS = "gen-ts-api"
GEN_API_PY = "gen-py-api"
GEN_API_GO = "gen-go-api"
GEN_API_TS = gen-ts-api
GEN_API_PY = gen-py-api
GEN_API_GO = gen-go-api
pg_user := $(shell uv run python -m authentik.lib.config postgresql.user 2>/dev/null)
pg_host := $(shell uv run python -m authentik.lib.config postgresql.host 2>/dev/null)
@ -117,14 +118,19 @@ gen-diff: ## (Release) generate the changelog diff between the current schema a
npx prettier --write diff.md
gen-clean-ts: ## Remove generated API client for Typescript
rm -rf ./${GEN_API_TS}/
rm -rf ./web/node_modules/@goauthentik/api/
rm -rf ${PWD}/${GEN_API_TS}/
rm -rf ${PWD}/web/node_modules/@goauthentik/api/
gen-clean-go: ## Remove generated API client for Go
rm -rf ./${GEN_API_GO}/
mkdir -p ${PWD}/${GEN_API_GO}
ifneq ($(wildcard ${PWD}/${GEN_API_GO}/.*),)
make -C ${PWD}/${GEN_API_GO} clean
else
rm -rf ${PWD}/${GEN_API_GO}
endif
gen-clean-py: ## Remove generated API client for Python
rm -rf ./${GEN_API_PY}/
rm -rf ${PWD}/${GEN_API_PY}/
gen-clean: gen-clean-ts gen-clean-go gen-clean-py ## Remove generated API clients
@ -141,8 +147,8 @@ gen-client-ts: gen-clean-ts ## Build and install the authentik API for Typescri
--git-repo-id authentik \
--git-user-id goauthentik
mkdir -p web/node_modules/@goauthentik/api
cd ./${GEN_API_TS} && npm i
\cp -rf ./${GEN_API_TS}/* web/node_modules/@goauthentik/api
cd ${PWD}/${GEN_API_TS} && npm i
\cp -rf ${PWD}/${GEN_API_TS}/* web/node_modules/@goauthentik/api
gen-client-py: gen-clean-py ## Build and install the authentik API for Python
docker run \
@ -156,24 +162,17 @@ gen-client-py: gen-clean-py ## Build and install the authentik API for Python
--additional-properties=packageVersion=${NPM_VERSION} \
--git-repo-id authentik \
--git-user-id goauthentik
pip install ./${GEN_API_PY}
gen-client-go: gen-clean-go ## Build and install the authentik API for Golang
mkdir -p ./${GEN_API_GO} ./${GEN_API_GO}/templates
wget https://raw.githubusercontent.com/goauthentik/client-go/main/config.yaml -O ./${GEN_API_GO}/config.yaml
wget https://raw.githubusercontent.com/goauthentik/client-go/main/templates/README.mustache -O ./${GEN_API_GO}/templates/README.mustache
wget https://raw.githubusercontent.com/goauthentik/client-go/main/templates/go.mod.mustache -O ./${GEN_API_GO}/templates/go.mod.mustache
cp schema.yml ./${GEN_API_GO}/
docker run \
--rm -v ${PWD}/${GEN_API_GO}:/local \
--user ${UID}:${GID} \
docker.io/openapitools/openapi-generator-cli:v6.5.0 generate \
-i /local/schema.yml \
-g go \
-o /local/ \
-c /local/config.yaml
mkdir -p ${PWD}/${GEN_API_GO}
ifeq ($(wildcard ${PWD}/${GEN_API_GO}/.*),)
git clone --depth 1 https://github.com/goauthentik/client-go.git ${PWD}/${GEN_API_GO}
else
cd ${PWD}/${GEN_API_GO} && git pull
endif
cp ${PWD}/schema.yml ${PWD}/${GEN_API_GO}
make -C ${PWD}/${GEN_API_GO} build
go mod edit -replace goauthentik.io/api/v3=./${GEN_API_GO}
rm -rf ./${GEN_API_GO}/config.yaml ./${GEN_API_GO}/templates/
gen-dev-config: ## Generate a local development config file
uv run scripts/generate_config.py
@ -244,7 +243,7 @@ docker: ## Build a docker image of the current source tree
DOCKER_BUILDKIT=1 docker build . --progress plain --tag ${DOCKER_IMAGE}
test-docker:
BUILD=true ./scripts/test_docker.sh
BUILD=true ${PWD}/scripts/test_docker.sh
#########################
## CI

View File

@ -42,4 +42,4 @@ See [SECURITY.md](SECURITY.md)
## Adoption and Contributions
Your organization uses authentik? We'd love to add your logo to the readme and our website! Email us @ hello@goauthentik.io or open a GitHub Issue/PR! For more information on how to contribute to authentik, please refer to our [CONTRIBUTING.md file](./CONTRIBUTING.md).
Your organization uses authentik? We'd love to add your logo to the readme and our website! Email us @ hello@goauthentik.io or open a GitHub Issue/PR! For more information on how to contribute to authentik, please refer to our [contribution guide](https://docs.goauthentik.io/docs/developer-docs?utm_source=github).

View File

@ -20,8 +20,8 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni
| Version | Supported |
| --------- | --------- |
| 2024.12.x | ✅ |
| 2025.2.x | ✅ |
| 2025.4.x | ✅ |
## Reporting a Vulnerability

View File

@ -2,7 +2,7 @@
from os import environ
__version__ = "2025.2.4"
__version__ = "2025.4.1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -1,9 +1,12 @@
"""API Authentication"""
from hmac import compare_digest
from pathlib import Path
from tempfile import gettempdir
from typing import Any
from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from drf_spectacular.extensions import OpenApiAuthenticationExtension
from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework.exceptions import AuthenticationFailed
@ -11,11 +14,17 @@ from rest_framework.request import Request
from structlog.stdlib import get_logger
from authentik.core.middleware import CTX_AUTH_VIA
from authentik.core.models import Token, TokenIntents, User
from authentik.core.models import Token, TokenIntents, User, UserTypes
from authentik.outposts.models import Outpost
from authentik.providers.oauth2.constants import SCOPE_AUTHENTIK_API
LOGGER = get_logger()
_tmp = Path(gettempdir())
try:
with open(_tmp / "authentik-core-ipc.key") as _f:
ipc_key = _f.read()
except OSError:
ipc_key = None
def validate_auth(header: bytes) -> str | None:
@ -73,6 +82,11 @@ def auth_user_lookup(raw_header: bytes) -> User | None:
if user:
CTX_AUTH_VIA.set("secret_key")
return user
# then try to auth via secret key (for embedded outpost/etc)
user = token_ipc(auth_credentials)
if user:
CTX_AUTH_VIA.set("ipc")
return user
raise AuthenticationFailed("Token invalid/expired")
@ -90,6 +104,43 @@ def token_secret_key(value: str) -> User | None:
return outpost.user
class IPCUser(AnonymousUser):
"""'Virtual' user for IPC communication between authentik core and the authentik router"""
username = "authentik:system"
is_active = True
is_superuser = True
@property
def type(self):
return UserTypes.INTERNAL_SERVICE_ACCOUNT
def has_perm(self, perm, obj=None):
return True
def has_perms(self, perm_list, obj=None):
return True
def has_module_perms(self, module):
return True
@property
def is_anonymous(self):
return False
@property
def is_authenticated(self):
return True
def token_ipc(value: str) -> User | None:
"""Check if the token is the secret key
and return the service account for the managed outpost"""
if not ipc_key or not compare_digest(value, ipc_key):
return None
return IPCUser()
class TokenAuthentication(BaseAuthentication):
"""Token-based authentication using HTTP Bearer authentication"""

View File

@ -54,7 +54,7 @@ def create_component(generator: SchemaGenerator, name, schema, type_=ResolvedCom
return component
def postprocess_schema_responses(result, generator: SchemaGenerator, **kwargs): # noqa: W0613
def postprocess_schema_responses(result, generator: SchemaGenerator, **kwargs):
"""Workaround to set a default response for endpoints.
Workaround suggested at
<https://github.com/tfranzel/drf-spectacular/issues/119#issuecomment-656970357>

View File

@ -7,7 +7,7 @@ from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, DateTimeField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ListSerializer, ModelSerializer
from rest_framework.serializers import ListSerializer
from rest_framework.viewsets import ModelViewSet
from authentik.blueprints.models import BlueprintInstance
@ -15,7 +15,7 @@ from authentik.blueprints.v1.importer import Importer
from authentik.blueprints.v1.oci import OCI_PREFIX
from authentik.blueprints.v1.tasks import apply_blueprint, blueprints_find_dict
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import JSONDictField, PassiveSerializer
from authentik.core.api.utils import JSONDictField, ModelSerializer, PassiveSerializer
from authentik.rbac.decorators import permission_required

View File

@ -164,9 +164,7 @@ class BlueprintEntry:
"""Get the blueprint model, with yaml tags resolved if present"""
return str(self.tag_resolver(self.model, blueprint))
def get_permissions(
self, blueprint: "Blueprint"
) -> Generator[BlueprintEntryPermission, None, None]:
def get_permissions(self, blueprint: "Blueprint") -> Generator[BlueprintEntryPermission]:
"""Get permissions of this entry, with all yaml tags resolved"""
for perm in self.permissions:
yield BlueprintEntryPermission(

View File

@ -59,6 +59,7 @@ class BrandSerializer(ModelSerializer):
"flow_device_code",
"default_application",
"web_certificate",
"client_certificates",
"attributes",
]
extra_kwargs = {
@ -120,6 +121,7 @@ class BrandViewSet(UsedByMixin, ModelViewSet):
"domain",
"branding_title",
"web_certificate__name",
"client_certificates__name",
]
filterset_fields = [
"brand_uuid",
@ -136,6 +138,7 @@ class BrandViewSet(UsedByMixin, ModelViewSet):
"flow_user_settings",
"flow_device_code",
"web_certificate",
"client_certificates",
]
ordering = ["domain"]

View File

@ -16,7 +16,7 @@ def migrate_custom_css(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
if not path.exists():
return
css = path.read_text()
Brand.objects.using(db_alias).update(branding_custom_css=css)
Brand.objects.using(db_alias).all().update(branding_custom_css=css)
class Migration(migrations.Migration):

View File

@ -0,0 +1,37 @@
# Generated by Django 5.1.9 on 2025-05-19 15:09
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_brands", "0009_brand_branding_default_flow_background"),
("authentik_crypto", "0004_alter_certificatekeypair_name"),
]
operations = [
migrations.AddField(
model_name="brand",
name="client_certificates",
field=models.ManyToManyField(
blank=True,
default=None,
help_text="Certificates used for client authentication.",
to="authentik_crypto.certificatekeypair",
),
),
migrations.AlterField(
model_name="brand",
name="web_certificate",
field=models.ForeignKey(
default=None,
help_text="Web Certificate used by the authentik Core webserver.",
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
related_name="+",
to="authentik_crypto.certificatekeypair",
),
),
]

View File

@ -73,6 +73,13 @@ class Brand(SerializerModel):
default=None,
on_delete=models.SET_DEFAULT,
help_text=_("Web Certificate used by the authentik Core webserver."),
related_name="+",
)
client_certificates = models.ManyToManyField(
CertificateKeyPair,
default=None,
blank=True,
help_text=_("Certificates used for client authentication."),
)
attributes = models.JSONField(default=dict, blank=True)

View File

@ -5,10 +5,10 @@ from typing import Any
from django.db.models import F, Q
from django.db.models import Value as V
from django.http.request import HttpRequest
from sentry_sdk import get_current_span
from authentik import get_full_version
from authentik.brands.models import Brand
from authentik.lib.sentry import get_http_meta
from authentik.tenants.models import Tenant
_q_default = Q(default=True)
@ -32,13 +32,9 @@ def context_processor(request: HttpRequest) -> dict[str, Any]:
"""Context Processor that injects brand object into every template"""
brand = getattr(request, "brand", DEFAULT_BRAND)
tenant = getattr(request, "tenant", Tenant())
trace = ""
span = get_current_span()
if span:
trace = span.to_traceparent()
return {
"brand": brand,
"footer_links": tenant.footer_links,
"sentry_trace": trace,
"html_meta": {**get_http_meta()},
"version": get_full_version(),
}

View File

@ -99,18 +99,17 @@ class GroupSerializer(ModelSerializer):
if superuser
else "authentik_core.disable_group_superuser"
)
has_perm = user.has_perm(perm)
if self.instance and not has_perm:
has_perm = user.has_perm(perm, self.instance)
if not has_perm:
raise ValidationError(
_(
(
"User does not have permission to set "
"superuser status to {superuser_status}."
).format_map({"superuser_status": superuser})
if self.instance or superuser:
has_perm = user.has_perm(perm) or user.has_perm(perm, self.instance)
if not has_perm:
raise ValidationError(
_(
(
"User does not have permission to set "
"superuser status to {superuser_status}."
).format_map({"superuser_status": superuser})
)
)
)
return superuser
class Meta:

View File

@ -20,6 +20,8 @@ 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"""
@ -29,6 +31,14 @@ def is_dict(value: Any):
class ModelSerializer(BaseModelSerializer):
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)

View File

@ -2,6 +2,7 @@
from django.apps import apps
from django.contrib.auth.management import create_permissions
from django.core.management import call_command
from django.core.management.base import BaseCommand, no_translations
from guardian.management import create_anonymous_user
@ -16,6 +17,10 @@ class Command(BaseCommand):
"""Check permissions for all apps"""
for tenant in Tenant.objects.filter(ready=True):
with tenant:
# See https://code.djangoproject.com/ticket/28417
# Remove potential lingering old permissions
call_command("remove_stale_contenttypes", "--no-input")
for app in apps.get_app_configs():
self.stdout.write(f"Checking app {app.name} ({app.label})\n")
create_permissions(app, verbosity=0)

View File

@ -31,7 +31,10 @@ class PickleSerializer:
def loads(self, data):
"""Unpickle data to be loaded from redis"""
return pickle.loads(data) # nosec
try:
return pickle.loads(data) # nosec
except Exception:
return {}
def _migrate_session(

View File

@ -0,0 +1,27 @@
# Generated by Django 5.1.9 on 2025-05-14 11:15
from django.apps.registry import Apps
from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def remove_old_authenticated_session_content_type(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
db_alias = schema_editor.connection.alias
ContentType = apps.get_model("contenttypes", "ContentType")
ContentType.objects.using(db_alias).filter(model="oldauthenticatedsession").delete()
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0047_delete_oldauthenticatedsession"),
]
operations = [
migrations.RunPython(
code=remove_old_authenticated_session_content_type,
),
]

View File

@ -21,7 +21,9 @@
<script src="{% versioned_script 'dist/standalone/loading/index-%v.js' %}" type="module"></script>
{% block head %}
{% endblock %}
<meta name="sentry-trace" content="{{ sentry_trace }}" />
{% for key, value in html_meta.items %}
<meta name="{{key}}" content="{{ value }}" />
{% endfor %}
</head>
<body>
{% block body %}

View File

@ -1,9 +1,17 @@
"""Test API Utils"""
from rest_framework.exceptions import ValidationError
from rest_framework.serializers import (
HyperlinkedModelSerializer,
)
from rest_framework.serializers import (
ModelSerializer as BaseModelSerializer,
)
from rest_framework.test import APITestCase
from authentik.core.api.utils import ModelSerializer as CustomModelSerializer
from authentik.core.api.utils import is_dict
from authentik.lib.utils.reflection import all_subclasses
class TestAPIUtils(APITestCase):
@ -14,3 +22,14 @@ class TestAPIUtils(APITestCase):
self.assertIsNone(is_dict({}))
with self.assertRaises(ValidationError):
is_dict("foo")
def test_all_serializers_descend_from_custom(self):
"""Test that every serializer we define descends from our own ModelSerializer"""
# Weirdly, there's only one serializer in `rest_framework` which descends from
# ModelSerializer: HyperlinkedModelSerializer
expected = {CustomModelSerializer, HyperlinkedModelSerializer}
actual = set(all_subclasses(BaseModelSerializer)) - set(
all_subclasses(CustomModelSerializer)
)
self.assertEqual(expected, actual)

View File

@ -124,6 +124,16 @@ class TestGroupsAPI(APITestCase):
{"is_superuser": ["User does not have permission to set superuser status to True."]},
)
def test_superuser_no_perm_no_superuser(self):
"""Test creating a group without permission and without superuser flag"""
assign_perm("authentik_core.add_group", self.login_user)
self.client.force_login(self.login_user)
res = self.client.post(
reverse("authentik_api:group-list"),
data={"name": generate_id(), "is_superuser": False},
)
self.assertEqual(res.status_code, 201)
def test_superuser_update_no_perm(self):
"""Test updating a superuser group without permission"""
group = Group.objects.create(name=generate_id(), is_superuser=True)

View File

@ -13,7 +13,10 @@ from authentik.core.models import (
TokenIntents,
User,
)
from authentik.core.tasks import clean_expired_models, clean_temporary_users
from authentik.core.tasks import (
clean_expired_models,
clean_temporary_users,
)
from authentik.core.tests.utils import create_test_admin_user
from authentik.lib.generators import generate_id

View File

@ -30,6 +30,7 @@ from structlog.stdlib import get_logger
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer, PassiveSerializer
from authentik.core.models import UserTypes
from authentik.crypto.apps import MANAGED_KEY
from authentik.crypto.builder import CertificateBuilder, PrivateKeyAlg
from authentik.crypto.models import CertificateKeyPair
@ -272,11 +273,12 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
def view_certificate(self, request: Request, pk: str) -> Response:
"""Return certificate-key pairs certificate and log access"""
certificate: CertificateKeyPair = self.get_object()
Event.new( # noqa # nosec
EventAction.SECRET_VIEW,
secret=certificate,
type="certificate",
).from_http(request)
if request.user.type != UserTypes.INTERNAL_SERVICE_ACCOUNT:
Event.new( # noqa # nosec
EventAction.SECRET_VIEW,
secret=certificate,
type="certificate",
).from_http(request)
if "download" in request.query_params:
# Mime type from https://pki-tutorial.readthedocs.io/en/latest/mime.html
response = HttpResponse(
@ -302,11 +304,12 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
def view_private_key(self, request: Request, pk: str) -> Response:
"""Return certificate-key pairs private key and log access"""
certificate: CertificateKeyPair = self.get_object()
Event.new( # noqa # nosec
EventAction.SECRET_VIEW,
secret=certificate,
type="private_key",
).from_http(request)
if request.user.type != UserTypes.INTERNAL_SERVICE_ACCOUNT:
Event.new( # noqa # nosec
EventAction.SECRET_VIEW,
secret=certificate,
type="private_key",
).from_http(request)
if "download" in request.query_params:
# Mime type from https://pki-tutorial.readthedocs.io/en/latest/mime.html
response = HttpResponse(certificate.key_data, content_type="application/x-pem-file")

View File

@ -132,13 +132,14 @@ class LicenseKey:
"""Get a summarized version of all (not expired) licenses"""
total = LicenseKey(get_license_aud(), 0, "Summarized license", 0, 0)
for lic in License.objects.all():
total.internal_users += lic.internal_users
total.external_users += lic.external_users
if lic.is_valid:
total.internal_users += lic.internal_users
total.external_users += lic.external_users
total.license_flags.extend(lic.status.license_flags)
exp_ts = int(mktime(lic.expiry.timetuple()))
if total.exp == 0:
total.exp = exp_ts
total.exp = max(total.exp, exp_ts)
total.license_flags.extend(lic.status.license_flags)
return total
@staticmethod

View File

@ -39,6 +39,10 @@ class License(SerializerModel):
internal_users = models.BigIntegerField()
external_users = models.BigIntegerField()
@property
def is_valid(self) -> bool:
return self.expiry >= now()
@property
def serializer(self) -> type[BaseSerializer]:
from authentik.enterprise.api import LicenseSerializer

View File

@ -0,0 +1,27 @@
from rest_framework.viewsets import ModelViewSet
from authentik.core.api.used_by import UsedByMixin
from authentik.enterprise.api import EnterpriseRequiredMixin
from authentik.enterprise.policies.unique_password.models import UniquePasswordPolicy
from authentik.policies.api.policies import PolicySerializer
class UniquePasswordPolicySerializer(EnterpriseRequiredMixin, PolicySerializer):
"""Password Uniqueness Policy Serializer"""
class Meta:
model = UniquePasswordPolicy
fields = PolicySerializer.Meta.fields + [
"password_field",
"num_historical_passwords",
]
class UniquePasswordPolicyViewSet(UsedByMixin, ModelViewSet):
"""Password Uniqueness Policy Viewset"""
queryset = UniquePasswordPolicy.objects.all()
serializer_class = UniquePasswordPolicySerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]

View File

@ -0,0 +1,10 @@
"""authentik Unique Password policy app config"""
from authentik.enterprise.apps import EnterpriseConfig
class AuthentikEnterprisePoliciesUniquePasswordConfig(EnterpriseConfig):
name = "authentik.enterprise.policies.unique_password"
label = "authentik_policies_unique_password"
verbose_name = "authentik Enterprise.Policies.Unique Password"
default = True

View File

@ -0,0 +1,81 @@
# Generated by Django 5.0.13 on 2025-03-26 23:02
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
("authentik_policies", "0011_policybinding_failure_result_and_more"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="UniquePasswordPolicy",
fields=[
(
"policy_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_policies.policy",
),
),
(
"password_field",
models.TextField(
default="password",
help_text="Field key to check, field keys defined in Prompt stages are available.",
),
),
(
"num_historical_passwords",
models.PositiveIntegerField(
default=1, help_text="Number of passwords to check against."
),
),
],
options={
"verbose_name": "Password Uniqueness Policy",
"verbose_name_plural": "Password Uniqueness Policies",
"indexes": [
models.Index(fields=["policy_ptr_id"], name="authentik_p_policy__f559aa_idx")
],
},
bases=("authentik_policies.policy",),
),
migrations.CreateModel(
name="UserPasswordHistory",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("old_password", models.CharField(max_length=128)),
("created_at", models.DateTimeField(auto_now_add=True)),
("hibp_prefix_sha1", models.CharField(max_length=5)),
("hibp_pw_hash", models.TextField()),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="old_passwords",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "User Password History",
},
),
]

View File

@ -0,0 +1,151 @@
from hashlib import sha1
from django.contrib.auth.hashers import identify_hasher, make_password
from django.db import models
from django.utils.translation import gettext as _
from rest_framework.serializers import BaseSerializer
from structlog.stdlib import get_logger
from authentik.core.models import User
from authentik.policies.models import Policy
from authentik.policies.types import PolicyRequest, PolicyResult
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
LOGGER = get_logger()
class UniquePasswordPolicy(Policy):
"""This policy prevents users from reusing old passwords."""
password_field = models.TextField(
default="password",
help_text=_("Field key to check, field keys defined in Prompt stages are available."),
)
# Limit on the number of previous passwords the policy evaluates
# Also controls number of old passwords the system stores.
num_historical_passwords = models.PositiveIntegerField(
default=1,
help_text=_("Number of passwords to check against."),
)
@property
def serializer(self) -> type[BaseSerializer]:
from authentik.enterprise.policies.unique_password.api import UniquePasswordPolicySerializer
return UniquePasswordPolicySerializer
@property
def component(self) -> str:
return "ak-policy-password-uniqueness-form"
def passes(self, request: PolicyRequest) -> PolicyResult:
from authentik.enterprise.policies.unique_password.models import UserPasswordHistory
password = request.context.get(PLAN_CONTEXT_PROMPT, {}).get(
self.password_field, request.context.get(self.password_field)
)
if not password:
LOGGER.warning(
"Password field not found in request when checking UniquePasswordPolicy",
field=self.password_field,
fields=request.context.keys(),
)
return PolicyResult(False, _("Password not set in context"))
password = str(password)
if not self.num_historical_passwords:
# Policy not configured to check against any passwords
return PolicyResult(True)
num_to_check = self.num_historical_passwords
password_history = UserPasswordHistory.objects.filter(user=request.user).order_by(
"-created_at"
)[:num_to_check]
if not password_history:
return PolicyResult(True)
for record in password_history:
if not record.old_password:
continue
if self._passwords_match(new_password=password, old_password=record.old_password):
# Return on first match. Authentik does not consider timing attacks
# on old passwords to be an attack surface.
return PolicyResult(
False,
_("This password has been used previously. Please choose a different one."),
)
return PolicyResult(True)
def _passwords_match(self, *, new_password: str, old_password: str) -> bool:
try:
hasher = identify_hasher(old_password)
except ValueError:
LOGGER.warning(
"Skipping password; could not load hash algorithm",
)
return False
return hasher.verify(new_password, old_password)
@classmethod
def is_in_use(cls):
"""Check if any UniquePasswordPolicy is in use, either through policy bindings
or direct attachment to a PromptStage.
Returns:
bool: True if any policy is in use, False otherwise
"""
from authentik.policies.models import PolicyBinding
# Check if any policy is in use through bindings
if PolicyBinding.in_use.for_policy(cls).exists():
return True
# Check if any policy is attached to a PromptStage
if cls.objects.filter(promptstage__isnull=False).exists():
return True
return False
class Meta(Policy.PolicyMeta):
verbose_name = _("Password Uniqueness Policy")
verbose_name_plural = _("Password Uniqueness Policies")
class UserPasswordHistory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="old_passwords")
# Mimic's column type of AbstractBaseUser.password
old_password = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now_add=True)
hibp_prefix_sha1 = models.CharField(max_length=5)
hibp_pw_hash = models.TextField()
class Meta:
verbose_name = _("User Password History")
def __str__(self) -> str:
timestamp = f"{self.created_at:%Y/%m/%d %X}" if self.created_at else "N/A"
return f"Previous Password (user: {self.user_id}, recorded: {timestamp})"
@classmethod
def create_for_user(cls, user: User, password: str):
# To check users' passwords against Have I been Pwned, we need the first 5 chars
# of the password hashed with SHA1 without a salt...
pw_hash_sha1 = sha1(password.encode("utf-8")).hexdigest() # nosec
# ...however that'll give us a list of hashes from HIBP, and to compare that we still
# need a full unsalted SHA1 of the password. We don't want to save that directly in
# the database, so we hash that SHA1 again with a modern hashing alg,
# and then when we check users' passwords against HIBP we can use `check_password`
# which will take care of this.
hibp_hash_hash = make_password(pw_hash_sha1)
return cls.objects.create(
user=user,
old_password=password,
hibp_prefix_sha1=pw_hash_sha1[:5],
hibp_pw_hash=hibp_hash_hash,
)

View File

@ -0,0 +1,20 @@
"""Unique Password Policy settings"""
from celery.schedules import crontab
from authentik.lib.utils.time import fqdn_rand
CELERY_BEAT_SCHEDULE = {
"policies_unique_password_trim_history": {
"task": "authentik.enterprise.policies.unique_password.tasks.trim_password_histories",
"schedule": crontab(minute=fqdn_rand("policies_unique_password_trim"), hour="*/12"),
"options": {"queue": "authentik_scheduled"},
},
"policies_unique_password_check_purge": {
"task": (
"authentik.enterprise.policies.unique_password.tasks.check_and_purge_password_history"
),
"schedule": crontab(minute=fqdn_rand("policies_unique_password_purge"), hour="*/24"),
"options": {"queue": "authentik_scheduled"},
},
}

View File

@ -0,0 +1,23 @@
"""authentik policy signals"""
from django.dispatch import receiver
from authentik.core.models import User
from authentik.core.signals import password_changed
from authentik.enterprise.policies.unique_password.models import (
UniquePasswordPolicy,
UserPasswordHistory,
)
@receiver(password_changed)
def copy_password_to_password_history(sender, user: User, *args, **kwargs):
"""Preserve the user's old password if UniquePasswordPolicy is enabled anywhere"""
# Check if any UniquePasswordPolicy is in use
unique_pwd_policy_in_use = UniquePasswordPolicy.is_in_use()
if unique_pwd_policy_in_use:
"""NOTE: Because we run this in a signal after saving the user,
we are not atomically guaranteed to save password history.
"""
UserPasswordHistory.create_for_user(user, user.password)

View File

@ -0,0 +1,66 @@
from django.db.models.aggregates import Count
from structlog import get_logger
from authentik.enterprise.policies.unique_password.models import (
UniquePasswordPolicy,
UserPasswordHistory,
)
from authentik.events.system_tasks import SystemTask, TaskStatus, prefill_task
from authentik.root.celery import CELERY_APP
LOGGER = get_logger()
@CELERY_APP.task(bind=True, base=SystemTask)
@prefill_task
def check_and_purge_password_history(self: SystemTask):
"""Check if any UniquePasswordPolicy exists, and if not, purge the password history table.
This is run on a schedule instead of being triggered by policy binding deletion.
"""
if not UniquePasswordPolicy.objects.exists():
UserPasswordHistory.objects.all().delete()
LOGGER.debug("Purged UserPasswordHistory table as no policies are in use")
self.set_status(TaskStatus.SUCCESSFUL, "Successfully purged UserPasswordHistory")
return
self.set_status(
TaskStatus.SUCCESSFUL, "Not purging password histories, a unique password policy exists"
)
@CELERY_APP.task(bind=True, base=SystemTask)
def trim_password_histories(self: SystemTask):
"""Removes rows from UserPasswordHistory older than
the `n` most recent entries.
The `n` is defined by the largest configured value for all bound
UniquePasswordPolicy policies.
"""
# No policy, we'll let the cleanup above do its thing
if not UniquePasswordPolicy.objects.exists():
return
num_rows_to_preserve = 0
for policy in UniquePasswordPolicy.objects.all():
num_rows_to_preserve = max(num_rows_to_preserve, policy.num_historical_passwords)
all_pks_to_keep = []
# Get all users who have password history entries
users_with_history = (
UserPasswordHistory.objects.values("user")
.annotate(count=Count("user"))
.filter(count__gt=0)
.values_list("user", flat=True)
)
for user_pk in users_with_history:
entries = UserPasswordHistory.objects.filter(user__pk=user_pk)
pks_to_keep = entries.order_by("-created_at")[:num_rows_to_preserve].values_list(
"pk", flat=True
)
all_pks_to_keep.extend(pks_to_keep)
num_deleted, _ = UserPasswordHistory.objects.exclude(pk__in=all_pks_to_keep).delete()
LOGGER.debug("Deleted stale password history records", count=num_deleted)
self.set_status(TaskStatus.SUCCESSFUL, f"Delete {num_deleted} stale password history records")

View File

@ -0,0 +1,108 @@
"""Unique Password Policy flow tests"""
from django.contrib.auth.hashers import make_password
from django.urls.base import reverse
from authentik.core.tests.utils import create_test_flow, create_test_user
from authentik.enterprise.policies.unique_password.models import (
UniquePasswordPolicy,
UserPasswordHistory,
)
from authentik.flows.models import FlowDesignation, FlowStageBinding
from authentik.flows.tests import FlowTestCase
from authentik.lib.generators import generate_id
from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage
class TestUniquePasswordPolicyFlow(FlowTestCase):
"""Test Unique Password Policy in a flow"""
REUSED_PASSWORD = "hunter1" # nosec B105
def setUp(self) -> None:
self.user = create_test_user()
self.flow = create_test_flow(FlowDesignation.AUTHENTICATION)
password_prompt = Prompt.objects.create(
name=generate_id(),
field_key="password",
label="PASSWORD_LABEL",
type=FieldTypes.PASSWORD,
required=True,
placeholder="PASSWORD_PLACEHOLDER",
)
self.policy = UniquePasswordPolicy.objects.create(
name="password_must_unique",
password_field=password_prompt.field_key,
num_historical_passwords=1,
)
stage = PromptStage.objects.create(name="prompt-stage")
stage.validation_policies.set([self.policy])
stage.fields.set(
[
password_prompt,
]
)
FlowStageBinding.objects.create(target=self.flow, stage=stage, order=2)
# Seed the user's password history
UserPasswordHistory.create_for_user(self.user, make_password(self.REUSED_PASSWORD))
def test_prompt_data(self):
"""Test policy attached to a prompt stage"""
# Test the policy directly
from authentik.policies.types import PolicyRequest
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
# Create a policy request with the reused password
request = PolicyRequest(user=self.user)
request.context[PLAN_CONTEXT_PROMPT] = {"password": self.REUSED_PASSWORD}
# Test the policy directly
result = self.policy.passes(request)
# Verify that the policy fails (returns False) with the expected error message
self.assertFalse(result.passing, "Policy should fail for reused password")
self.assertEqual(
result.messages[0],
"This password has been used previously. Please choose a different one.",
"Incorrect error message",
)
# API-based testing approach:
self.client.force_login(self.user)
# Send a POST request to the flow executor with the reused password
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
{"password": self.REUSED_PASSWORD},
)
self.assertStageResponse(
response,
self.flow,
component="ak-stage-prompt",
fields=[
{
"choices": None,
"field_key": "password",
"label": "PASSWORD_LABEL",
"order": 0,
"placeholder": "PASSWORD_PLACEHOLDER",
"initial_value": "",
"required": True,
"type": "password",
"sub_text": "",
}
],
response_errors={
"non_field_errors": [
{
"code": "invalid",
"string": "This password has been used previously. "
"Please choose a different one.",
}
]
},
)

View File

@ -0,0 +1,77 @@
"""Unique Password Policy tests"""
from django.contrib.auth.hashers import make_password
from django.test import TestCase
from guardian.shortcuts import get_anonymous_user
from authentik.core.models import User
from authentik.enterprise.policies.unique_password.models import (
UniquePasswordPolicy,
UserPasswordHistory,
)
from authentik.policies.types import PolicyRequest, PolicyResult
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
class TestUniquePasswordPolicy(TestCase):
"""Test Password Uniqueness Policy"""
def setUp(self) -> None:
self.policy = UniquePasswordPolicy.objects.create(
name="test_unique_password", num_historical_passwords=1
)
self.user = User.objects.create(username="test-user")
def test_invalid(self):
"""Test without password present in request"""
request = PolicyRequest(get_anonymous_user())
result: PolicyResult = self.policy.passes(request)
self.assertFalse(result.passing)
self.assertEqual(result.messages[0], "Password not set in context")
def test_passes_no_previous_passwords(self):
request = PolicyRequest(get_anonymous_user())
request.context = {PLAN_CONTEXT_PROMPT: {"password": "hunter2"}}
result: PolicyResult = self.policy.passes(request)
self.assertTrue(result.passing)
def test_passes_passwords_are_different(self):
# Seed database with an old password
UserPasswordHistory.create_for_user(self.user, make_password("hunter1"))
request = PolicyRequest(self.user)
request.context = {PLAN_CONTEXT_PROMPT: {"password": "hunter2"}}
result: PolicyResult = self.policy.passes(request)
self.assertTrue(result.passing)
def test_passes_multiple_old_passwords(self):
# Seed with multiple old passwords
UserPasswordHistory.objects.bulk_create(
[
UserPasswordHistory(user=self.user, old_password=make_password("hunter1")),
UserPasswordHistory(user=self.user, old_password=make_password("hunter2")),
]
)
request = PolicyRequest(self.user)
request.context = {PLAN_CONTEXT_PROMPT: {"password": "hunter3"}}
result: PolicyResult = self.policy.passes(request)
self.assertTrue(result.passing)
def test_fails_password_matches_old_password(self):
# Seed database with an old password
UserPasswordHistory.create_for_user(self.user, make_password("hunter1"))
request = PolicyRequest(self.user)
request.context = {PLAN_CONTEXT_PROMPT: {"password": "hunter1"}}
result: PolicyResult = self.policy.passes(request)
self.assertFalse(result.passing)
def test_fails_if_identical_password_with_different_hash_algos(self):
UserPasswordHistory.create_for_user(
self.user, make_password("hunter2", "somesalt", "scrypt")
)
request = PolicyRequest(self.user)
request.context = {PLAN_CONTEXT_PROMPT: {"password": "hunter2"}}
result: PolicyResult = self.policy.passes(request)
self.assertFalse(result.passing)

View File

@ -0,0 +1,90 @@
from django.urls import reverse
from authentik.core.models import Group, Source, User
from authentik.core.tests.utils import create_test_flow, create_test_user
from authentik.enterprise.policies.unique_password.models import (
UniquePasswordPolicy,
UserPasswordHistory,
)
from authentik.flows.markers import StageMarker
from authentik.flows.models import FlowStageBinding
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
from authentik.flows.tests import FlowTestCase
from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.lib.generators import generate_key
from authentik.policies.models import PolicyBinding, PolicyBindingModel
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
from authentik.stages.user_write.models import UserWriteStage
class TestUserWriteStage(FlowTestCase):
"""Write tests"""
def setUp(self):
super().setUp()
self.flow = create_test_flow()
self.group = Group.objects.create(name="test-group")
self.other_group = Group.objects.create(name="other-group")
self.stage: UserWriteStage = UserWriteStage.objects.create(
name="write", create_users_as_inactive=True, create_users_group=self.group
)
self.binding = FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)
self.source = Source.objects.create(name="fake_source")
def test_save_password_history_if_policy_binding_enforced(self):
"""Test user's new password is recorded when ANY enabled UniquePasswordPolicy exists"""
unique_password_policy = UniquePasswordPolicy.objects.create(num_historical_passwords=5)
pbm = PolicyBindingModel.objects.create()
PolicyBinding.objects.create(
target=pbm, policy=unique_password_policy, order=0, enabled=True
)
test_user = create_test_user()
# Store original password for verification
original_password = test_user.password
# We're changing our own password
self.client.force_login(test_user)
new_password = generate_key()
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
plan.context[PLAN_CONTEXT_PENDING_USER] = test_user
plan.context[PLAN_CONTEXT_PROMPT] = {
"username": test_user.username,
"password": new_password,
}
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
# Password history should be recorded
user_password_history_qs = UserPasswordHistory.objects.filter(user=test_user)
self.assertTrue(user_password_history_qs.exists(), "Password history should be recorded")
self.assertEqual(len(user_password_history_qs), 1, "expected 1 recorded password")
# Create a password history entry manually to simulate the signal behavior
# This is what would happen if the signal worked correctly
UserPasswordHistory.objects.create(user=test_user, old_password=original_password)
user_password_history_qs = UserPasswordHistory.objects.filter(user=test_user)
self.assertTrue(user_password_history_qs.exists(), "Password history should be recorded")
self.assertEqual(len(user_password_history_qs), 2, "expected 2 recorded password")
# Execute the flow by sending a POST request to the flow executor endpoint
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
)
# Verify that the request was successful
self.assertEqual(response.status_code, 200)
user_qs = User.objects.filter(username=plan.context[PLAN_CONTEXT_PROMPT]["username"])
self.assertTrue(user_qs.exists())
# Verify the password history entry exists
user_password_history_qs = UserPasswordHistory.objects.filter(user=test_user)
self.assertTrue(user_password_history_qs.exists(), "Password history should be recorded")
self.assertEqual(len(user_password_history_qs), 3, "expected 3 recorded password")
# Verify that one of the entries contains the original password
self.assertTrue(
any(entry.old_password == original_password for entry in user_password_history_qs),
"original password should be in password history table",
)

View File

@ -0,0 +1,178 @@
from datetime import datetime, timedelta
from django.test import TestCase
from authentik.core.tests.utils import create_test_user
from authentik.enterprise.policies.unique_password.models import (
UniquePasswordPolicy,
UserPasswordHistory,
)
from authentik.enterprise.policies.unique_password.tasks import (
check_and_purge_password_history,
trim_password_histories,
)
from authentik.policies.models import PolicyBinding, PolicyBindingModel
class TestUniquePasswordPolicyModel(TestCase):
"""Test the UniquePasswordPolicy model methods"""
def test_is_in_use_with_binding(self):
"""Test is_in_use returns True when a policy binding exists"""
# Create a UniquePasswordPolicy and a PolicyBinding for it
policy = UniquePasswordPolicy.objects.create(num_historical_passwords=5)
pbm = PolicyBindingModel.objects.create()
PolicyBinding.objects.create(target=pbm, policy=policy, order=0, enabled=True)
# Verify is_in_use returns True
self.assertTrue(UniquePasswordPolicy.is_in_use())
def test_is_in_use_with_promptstage(self):
"""Test is_in_use returns True when attached to a PromptStage"""
from authentik.stages.prompt.models import PromptStage
# Create a UniquePasswordPolicy and attach it to a PromptStage
policy = UniquePasswordPolicy.objects.create(num_historical_passwords=5)
prompt_stage = PromptStage.objects.create(
name="Test Prompt Stage",
)
# Use the set() method for many-to-many relationships
prompt_stage.validation_policies.set([policy])
# Verify is_in_use returns True
self.assertTrue(UniquePasswordPolicy.is_in_use())
class TestTrimAllPasswordHistories(TestCase):
"""Test the task that trims password history for all users"""
def setUp(self):
self.user1 = create_test_user("test-user1")
self.user2 = create_test_user("test-user2")
self.pbm = PolicyBindingModel.objects.create()
# Create a policy with a limit of 1 password
self.policy = UniquePasswordPolicy.objects.create(num_historical_passwords=1)
PolicyBinding.objects.create(
target=self.pbm,
policy=self.policy,
enabled=True,
order=0,
)
class TestCheckAndPurgePasswordHistory(TestCase):
"""Test the scheduled task that checks if any policy is in use and purges if not"""
def setUp(self):
self.user = create_test_user("test-user")
self.pbm = PolicyBindingModel.objects.create()
def test_purge_when_no_policy_in_use(self):
"""Test that the task purges the table when no policy is in use"""
# Create some password history entries
UserPasswordHistory.create_for_user(self.user, "hunter2")
# Verify we have entries
self.assertTrue(UserPasswordHistory.objects.exists())
# Run the task - should purge since no policy is in use
check_and_purge_password_history()
# Verify the table is empty
self.assertFalse(UserPasswordHistory.objects.exists())
def test_no_purge_when_policy_in_use(self):
"""Test that the task doesn't purge when a policy is in use"""
# Create a policy and binding
policy = UniquePasswordPolicy.objects.create(num_historical_passwords=5)
PolicyBinding.objects.create(
target=self.pbm,
policy=policy,
enabled=True,
order=0,
)
# Create some password history entries
UserPasswordHistory.create_for_user(self.user, "hunter2")
# Verify we have entries
self.assertTrue(UserPasswordHistory.objects.exists())
# Run the task - should NOT purge since a policy is in use
check_and_purge_password_history()
# Verify the entries still exist
self.assertTrue(UserPasswordHistory.objects.exists())
class TestTrimPasswordHistory(TestCase):
"""Test password history cleanup task"""
def setUp(self):
self.user = create_test_user("test-user")
self.pbm = PolicyBindingModel.objects.create()
def test_trim_password_history_ok(self):
"""Test passwords over the define limit are deleted"""
_now = datetime.now()
UserPasswordHistory.objects.bulk_create(
[
UserPasswordHistory(
user=self.user,
old_password="hunter1", # nosec B106
created_at=_now - timedelta(days=3),
),
UserPasswordHistory(
user=self.user,
old_password="hunter2", # nosec B106
created_at=_now - timedelta(days=2),
),
UserPasswordHistory(
user=self.user,
old_password="hunter3", # nosec B106
created_at=_now,
),
]
)
policy = UniquePasswordPolicy.objects.create(num_historical_passwords=1)
PolicyBinding.objects.create(
target=self.pbm,
policy=policy,
enabled=True,
order=0,
)
trim_password_histories.delay()
user_pwd_history_qs = UserPasswordHistory.objects.filter(user=self.user)
self.assertEqual(len(user_pwd_history_qs), 1)
def test_trim_password_history_policy_diabled_no_op(self):
"""Test no passwords removed if policy binding is disabled"""
# Insert a record to ensure it's not deleted after executing task
UserPasswordHistory.create_for_user(self.user, "hunter2")
policy = UniquePasswordPolicy.objects.create(num_historical_passwords=1)
PolicyBinding.objects.create(
target=self.pbm,
policy=policy,
enabled=False,
order=0,
)
trim_password_histories.delay()
self.assertTrue(UserPasswordHistory.objects.filter(user=self.user).exists())
def test_trim_password_history_fewer_records_than_maximum_is_no_op(self):
"""Test no passwords deleted if fewer passwords exist than limit"""
UserPasswordHistory.create_for_user(self.user, "hunter2")
policy = UniquePasswordPolicy.objects.create(num_historical_passwords=2)
PolicyBinding.objects.create(
target=self.pbm,
policy=policy,
enabled=True,
order=0,
)
trim_password_histories.delay()
self.assertTrue(UserPasswordHistory.objects.filter(user=self.user).exists())

View File

@ -0,0 +1,7 @@
"""API URLs"""
from authentik.enterprise.policies.unique_password.api import UniquePasswordPolicyViewSet
api_urlpatterns = [
("policies/unique_password", UniquePasswordPolicyViewSet),
]

View File

@ -25,7 +25,7 @@ class GoogleWorkspaceGroupClient(
"""Google client for groups"""
connection_type = GoogleWorkspaceProviderGroup
connection_type_query = "group"
connection_attr = "googleworkspaceprovidergroup_set"
can_discover = True
def __init__(self, provider: GoogleWorkspaceProvider) -> None:

View File

@ -20,7 +20,7 @@ class GoogleWorkspaceUserClient(GoogleWorkspaceSyncClient[User, GoogleWorkspaceP
"""Sync authentik users into google workspace"""
connection_type = GoogleWorkspaceProviderUser
connection_type_query = "user"
connection_attr = "googleworkspaceprovideruser_set"
can_discover = True
def __init__(self, provider: GoogleWorkspaceProvider) -> None:

View File

@ -132,7 +132,11 @@ class GoogleWorkspaceProvider(OutgoingSyncProvider, BackchannelProvider):
if type == User:
# Get queryset of all users with consistent ordering
# according to the provider's settings
base = User.objects.all().exclude_anonymous()
base = (
User.objects.prefetch_related("googleworkspaceprovideruser_set")
.all()
.exclude_anonymous()
)
if self.exclude_users_service_account:
base = base.exclude(type=UserTypes.SERVICE_ACCOUNT).exclude(
type=UserTypes.INTERNAL_SERVICE_ACCOUNT
@ -142,7 +146,11 @@ class GoogleWorkspaceProvider(OutgoingSyncProvider, BackchannelProvider):
return base.order_by("pk")
if type == Group:
# Get queryset of all groups with consistent ordering
return Group.objects.all().order_by("pk")
return (
Group.objects.prefetch_related("googleworkspaceprovidergroup_set")
.all()
.order_by("pk")
)
raise ValueError(f"Invalid type {type}")
def google_credentials(self):

View File

@ -29,7 +29,7 @@ class MicrosoftEntraGroupClient(
"""Microsoft client for groups"""
connection_type = MicrosoftEntraProviderGroup
connection_type_query = "group"
connection_attr = "microsoftentraprovidergroup_set"
can_discover = True
def __init__(self, provider: MicrosoftEntraProvider) -> None:

View File

@ -24,7 +24,7 @@ class MicrosoftEntraUserClient(MicrosoftEntraSyncClient[User, MicrosoftEntraProv
"""Sync authentik users into microsoft entra"""
connection_type = MicrosoftEntraProviderUser
connection_type_query = "user"
connection_attr = "microsoftentraprovideruser_set"
can_discover = True
def __init__(self, provider: MicrosoftEntraProvider) -> None:

View File

@ -121,7 +121,11 @@ class MicrosoftEntraProvider(OutgoingSyncProvider, BackchannelProvider):
if type == User:
# Get queryset of all users with consistent ordering
# according to the provider's settings
base = User.objects.all().exclude_anonymous()
base = (
User.objects.prefetch_related("microsoftentraprovideruser_set")
.all()
.exclude_anonymous()
)
if self.exclude_users_service_account:
base = base.exclude(type=UserTypes.SERVICE_ACCOUNT).exclude(
type=UserTypes.INTERNAL_SERVICE_ACCOUNT
@ -131,7 +135,11 @@ class MicrosoftEntraProvider(OutgoingSyncProvider, BackchannelProvider):
return base.order_by("pk")
if type == Group:
# Get queryset of all groups with consistent ordering
return Group.objects.all().order_by("pk")
return (
Group.objects.prefetch_related("microsoftentraprovidergroup_set")
.all()
.order_by("pk")
)
raise ValueError(f"Invalid type {type}")
def microsoft_credentials(self):

View File

@ -4,10 +4,9 @@ from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.fields import CharField, ChoiceField, ListField, SerializerMethodField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer
from structlog.stdlib import get_logger
from authentik.core.api.utils import PassiveSerializer
from authentik.core.api.utils import ModelSerializer, PassiveSerializer
from authentik.enterprise.providers.ssf.models import (
DeliveryMethods,
EventTypes,

View File

@ -14,10 +14,12 @@ CELERY_BEAT_SCHEDULE = {
TENANT_APPS = [
"authentik.enterprise.audit",
"authentik.enterprise.policies.unique_password",
"authentik.enterprise.providers.google_workspace",
"authentik.enterprise.providers.microsoft_entra",
"authentik.enterprise.providers.ssf",
"authentik.enterprise.stages.authenticator_endpoint_gdtc",
"authentik.enterprise.stages.mtls",
"authentik.enterprise.stages.source",
]

View File

@ -2,11 +2,11 @@
from rest_framework import mixins
from rest_framework.permissions import IsAdminUser
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from structlog.stdlib import get_logger
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer
from authentik.enterprise.api import EnterpriseRequiredMixin
from authentik.enterprise.stages.authenticator_endpoint_gdtc.models import (
AuthenticatorEndpointGDTCStage,

View File

@ -0,0 +1,31 @@
"""Mutual TLS Stage API Views"""
from rest_framework.viewsets import ModelViewSet
from authentik.core.api.used_by import UsedByMixin
from authentik.enterprise.api import EnterpriseRequiredMixin
from authentik.enterprise.stages.mtls.models import MutualTLSStage
from authentik.flows.api.stages import StageSerializer
class MutualTLSStageSerializer(EnterpriseRequiredMixin, StageSerializer):
"""MutualTLSStage Serializer"""
class Meta:
model = MutualTLSStage
fields = StageSerializer.Meta.fields + [
"mode",
"certificate_authorities",
"cert_attribute",
"user_attribute",
]
class MutualTLSStageViewSet(UsedByMixin, ModelViewSet):
"""MutualTLSStage Viewset"""
queryset = MutualTLSStage.objects.all()
serializer_class = MutualTLSStageSerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]

View File

@ -0,0 +1,12 @@
"""authentik stage app config"""
from authentik.enterprise.apps import EnterpriseConfig
class AuthentikEnterpriseStageMTLSConfig(EnterpriseConfig):
"""authentik MTLS stage config"""
name = "authentik.enterprise.stages.mtls"
label = "authentik_stages_mtls"
verbose_name = "authentik Enterprise.Stages.MTLS"
default = True

View File

@ -0,0 +1,68 @@
# Generated by Django 5.1.9 on 2025-05-19 18:29
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
("authentik_crypto", "0004_alter_certificatekeypair_name"),
("authentik_flows", "0027_auto_20231028_1424"),
]
operations = [
migrations.CreateModel(
name="MutualTLSStage",
fields=[
(
"stage_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_flows.stage",
),
),
(
"mode",
models.TextField(choices=[("optional", "Optional"), ("required", "Required")]),
),
(
"cert_attribute",
models.TextField(
choices=[
("subject", "Subject"),
("common_name", "Common Name"),
("email", "Email"),
]
),
),
(
"user_attribute",
models.TextField(choices=[("username", "Username"), ("email", "Email")]),
),
(
"certificate_authorities",
models.ManyToManyField(
blank=True,
default=None,
help_text="Configure certificate authorities to validate the certificate against. This option has a higher priority than the `client_certificate` option on `Brand`.",
to="authentik_crypto.certificatekeypair",
),
),
],
options={
"verbose_name": "Mutual TLS Stage",
"verbose_name_plural": "Mutual TLS Stages",
"permissions": [
("pass_outpost_certificate", "Permissions to pass Certificates for outposts.")
],
},
bases=("authentik_flows.stage",),
),
]

View File

@ -0,0 +1,71 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from rest_framework.serializers import Serializer
from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Stage
from authentik.flows.stage import StageView
class TLSMode(models.TextChoices):
"""Modes the TLS Stage can operate in"""
OPTIONAL = "optional"
REQUIRED = "required"
class CertAttributes(models.TextChoices):
"""Certificate attribute used for user matching"""
SUBJECT = "subject"
COMMON_NAME = "common_name"
EMAIL = "email"
class UserAttributes(models.TextChoices):
"""User attribute for user matching"""
USERNAME = "username"
EMAIL = "email"
class MutualTLSStage(Stage):
"""Authenticate/enroll users using a client-certificate."""
mode = models.TextField(choices=TLSMode.choices)
certificate_authorities = models.ManyToManyField(
CertificateKeyPair,
default=None,
blank=True,
help_text=_(
"Configure certificate authorities to validate the certificate against. "
"This option has a higher priority than the `client_certificate` option on `Brand`."
),
)
cert_attribute = models.TextField(choices=CertAttributes.choices)
user_attribute = models.TextField(choices=UserAttributes.choices)
@property
def view(self) -> type[StageView]:
from authentik.enterprise.stages.mtls.stage import MTLSStageView
return MTLSStageView
@property
def serializer(self) -> type[Serializer]:
from authentik.enterprise.stages.mtls.api import MutualTLSStageSerializer
return MutualTLSStageSerializer
@property
def component(self) -> str:
return "ak-stage-mtls-form"
class Meta:
verbose_name = _("Mutual TLS Stage")
verbose_name_plural = _("Mutual TLS Stages")
permissions = [
("pass_outpost_certificate", _("Permissions to pass Certificates for outposts.")),
]

View File

@ -0,0 +1,215 @@
from binascii import hexlify
from urllib.parse import unquote_plus
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes
from cryptography.x509 import Certificate, NameOID, ObjectIdentifier, load_pem_x509_certificate
from django.utils.translation import gettext_lazy as _
from authentik.brands.models import Brand
from authentik.core.models import User
from authentik.crypto.models import CertificateKeyPair
from authentik.enterprise.stages.mtls.models import (
CertAttributes,
MutualTLSStage,
TLSMode,
UserAttributes,
)
from authentik.flows.challenge import AccessDeniedChallenge
from authentik.flows.models import FlowDesignation
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
from authentik.flows.stage import ChallengeStageView
from authentik.root.middleware import ClientIPMiddleware
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
# All of these headers must only be accepted from "trusted" reverse proxies
# See internal/web/proxy.go:39
HEADER_PROXY_FORWARDED = "X-Forwarded-Client-Cert"
HEADER_NGINX_FORWARDED = "SSL-Client-Cert"
HEADER_TRAEFIK_FORWARDED = "X-Forwarded-TLS-Client-Cert"
HEADER_OUTPOST_FORWARDED = "X-Authentik-Outpost-Certificate"
PLAN_CONTEXT_CERTIFICATE = "certificate"
class MTLSStageView(ChallengeStageView):
def __parse_single_cert(self, raw: str | None) -> list[Certificate]:
"""Helper to parse a single certificate"""
if not raw:
return []
try:
cert = load_pem_x509_certificate(unquote_plus(raw).encode())
return [cert]
except ValueError as exc:
self.logger.info("Failed to parse certificate", exc=exc)
return []
def _parse_cert_xfcc(self) -> list[Certificate]:
"""Parse certificates in the format given to us in
the format of the authentik router/envoy"""
xfcc_raw = self.request.headers.get(HEADER_PROXY_FORWARDED)
if not xfcc_raw:
return []
certs = []
for r_cert in xfcc_raw.split(","):
el = r_cert.split(";")
raw_cert = {k.split("=")[0]: k.split("=")[1] for k in el}
if "Cert" not in raw_cert:
continue
certs.extend(self.__parse_single_cert(raw_cert["Cert"]))
return certs
def _parse_cert_nginx(self) -> list[Certificate]:
"""Parse certificates in the format nginx-ingress gives to us"""
sslcc_raw = self.request.headers.get(HEADER_NGINX_FORWARDED)
return self.__parse_single_cert(sslcc_raw)
def _parse_cert_traefik(self) -> list[Certificate]:
"""Parse certificates in the format traefik gives to us"""
ftcc_raw = self.request.headers.get(HEADER_TRAEFIK_FORWARDED)
return self.__parse_single_cert(ftcc_raw)
def _parse_cert_outpost(self) -> list[Certificate]:
"""Parse certificates in the format outposts give to us. Also authenticates
the outpost to ensure it has the permission to do so"""
user = ClientIPMiddleware.get_outpost_user(self.request)
if not user:
return []
if not user.has_perm(
"pass_outpost_certificate", self.executor.current_stage
) and not user.has_perm("authentik_stages_mtls.pass_outpost_certificate"):
return []
outpost_raw = self.request.headers.get(HEADER_OUTPOST_FORWARDED)
return self.__parse_single_cert(outpost_raw)
def get_authorities(self) -> list[CertificateKeyPair] | None:
# We can't access `certificate_authorities` on `self.executor.current_stage`, as that would
# load the certificate into the directly referenced foreign key, which we have to pickle
# as part of the flow plan, and cryptography certs can't be pickled
stage: MutualTLSStage = (
MutualTLSStage.objects.filter(pk=self.executor.current_stage.pk)
.prefetch_related("certificate_authorities")
.first()
)
if stage.certificate_authorities.exists():
return stage.certificate_authorities.order_by("name")
brand: Brand = self.request.brand
if brand.client_certificates.exists():
return brand.client_certificates.order_by("name")
return None
def validate_cert(self, authorities: list[CertificateKeyPair], certs: list[Certificate]):
for _cert in certs:
for ca in authorities:
try:
_cert.verify_directly_issued_by(ca.certificate)
return _cert
except (InvalidSignature, TypeError, ValueError) as exc:
self.logger.warning(
"Discarding cert not issued by authority", cert=_cert, authority=ca, exc=exc
)
continue
return None
def check_if_user(self, cert: Certificate):
stage: MutualTLSStage = self.executor.current_stage
cert_attr = None
user_attr = None
match stage.cert_attribute:
case CertAttributes.SUBJECT:
cert_attr = cert.subject.rfc4514_string()
case CertAttributes.COMMON_NAME:
cert_attr = self.get_cert_attribute(cert, NameOID.COMMON_NAME)
case CertAttributes.EMAIL:
cert_attr = self.get_cert_attribute(cert, NameOID.EMAIL_ADDRESS)
match stage.user_attribute:
case UserAttributes.USERNAME:
user_attr = "username"
case UserAttributes.EMAIL:
user_attr = "email"
if not user_attr or not cert_attr:
return None
return User.objects.filter(**{user_attr: cert_attr}).first()
def _cert_to_dict(self, cert: Certificate) -> dict:
"""Represent a certificate in a dictionary, as certificate objects cannot be pickled"""
return {
"serial_number": str(cert.serial_number),
"subject": cert.subject.rfc4514_string(),
"issuer": cert.issuer.rfc4514_string(),
"fingerprint_sha256": hexlify(cert.fingerprint(hashes.SHA256()), ":").decode("utf-8"),
"fingerprint_sha1": hexlify(cert.fingerprint(hashes.SHA256()), ":").decode("utf-8"),
}
def auth_user(self, user: User, cert: Certificate):
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = user
self.executor.plan.context.setdefault(PLAN_CONTEXT_METHOD, "mtls")
self.executor.plan.context.setdefault(PLAN_CONTEXT_METHOD_ARGS, {})
self.executor.plan.context[PLAN_CONTEXT_METHOD_ARGS].update(
{"certificate": self._cert_to_dict(cert)}
)
def enroll_prepare_user(self, cert: Certificate):
self.executor.plan.context.setdefault(PLAN_CONTEXT_PROMPT, {})
self.executor.plan.context[PLAN_CONTEXT_PROMPT].update(
{
"email": self.get_cert_attribute(cert, NameOID.EMAIL_ADDRESS),
"name": self.get_cert_attribute(cert, NameOID.COMMON_NAME),
}
)
self.executor.plan.context[PLAN_CONTEXT_CERTIFICATE] = self._cert_to_dict(cert)
def get_cert_attribute(self, cert: Certificate, oid: ObjectIdentifier) -> str | None:
attr = cert.subject.get_attributes_for_oid(oid)
if len(attr) < 1:
return None
return str(attr[0].value)
def dispatch(self, request, *args, **kwargs):
stage: MutualTLSStage = self.executor.current_stage
certs = [
*self._parse_cert_xfcc(),
*self._parse_cert_nginx(),
*self._parse_cert_traefik(),
*self._parse_cert_outpost(),
]
authorities = self.get_authorities()
if not authorities:
self.logger.warning("No Certificate authority found")
if stage.mode == TLSMode.OPTIONAL:
return self.executor.stage_ok()
if stage.mode == TLSMode.REQUIRED:
return super().dispatch(request, *args, **kwargs)
cert = self.validate_cert(authorities, certs)
if not cert and stage.mode == TLSMode.REQUIRED:
self.logger.warning("Client certificate required but no certificates given")
return super().dispatch(
request,
*args,
error_message=_("Certificate required but no certificate was given."),
**kwargs,
)
if not cert and stage.mode == TLSMode.OPTIONAL:
self.logger.info("No certificate given, continuing")
return self.executor.stage_ok()
existing_user = self.check_if_user(cert)
if self.executor.flow.designation == FlowDesignation.ENROLLMENT:
self.enroll_prepare_user(cert)
elif existing_user:
self.auth_user(existing_user, cert)
else:
return super().dispatch(
request, *args, error_message=_("No user found for certificate."), **kwargs
)
return self.executor.stage_ok()
def get_challenge(self, *args, error_message: str | None = None, **kwargs):
return AccessDeniedChallenge(
data={
"component": "ak-stage-access-denied",
"error_message": str(error_message or "Unknown error"),
}
)

View File

@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFXDCCA0SgAwIBAgIUBmV7zREyC1SPr72/75/L9zpwV18wDQYJKoZIhvcNAQEL
BQAwRjEaMBgGA1UEAwwRYXV0aGVudGlrIFRlc3QgQ0ExEjAQBgNVBAoMCWF1dGhl
bnRpazEUMBIGA1UECwwLU2VsZi1zaWduZWQwHhcNMjUwNDI3MTgzMDUwWhcNMzUw
MzA3MTgzMDUwWjBGMRowGAYDVQQDDBFhdXRoZW50aWsgVGVzdCBDQTESMBAGA1UE
CgwJYXV0aGVudGlrMRQwEgYDVQQLDAtTZWxmLXNpZ25lZDCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAMc0NxZj7j1mPu0aRToo8oMPdC3T99xgxnqdr18x
LV4pWyi/YLghgZHqNQY2xNP6JIlSeUZD6KFUYT2sPL4Av/zSg5zO8bl+/lf7ckje
O1/Bt5A8xtL0CpmpMDGiI6ibdDElaywM6AohisbxrV29pygSKGq2wugF/urqGtE+
5z4y5Kt6qMdKkd0iXT+WagbQTIUlykFKgB0+qqTLzDl01lVDa/DoLl8Hqp45mVx2
pqrGsSa3TCErLIv9hUlZklF7A8UV4ZB4JL20UKcP8dKzQClviNie17tpsUpOuy3A
SQ6+guWTHTLJNCSdLn1xIqc5q+f5wd2dIDf8zXCTHj+Xp0bJE3Vgaq5R31K9+b+1
2dDWz1KcNJaLEnw2+b0O8M64wTMLxhqOv7QfLUr6Pmg1ZymghjLcZ6bnU9e31Vza
hlPKhxjqYQUC4Kq+oaYF6qdUeJy+dsYf0iDv5tTC+eReZDWIjxTPrNpwA773ZwT7
WVmL7ULGpuP2g9rNvFBcZiN+i6d7CUoN+jd/iRdo79lrI0dfXiyy4bYgW/2HeZfF
HaOsc1xsoqnJdWbWkX/ooyaCjAfm07kS3HiOzz4q3QW4wgGrwV8lEraLPxYYeOQu
YcGMOM8NfnVkjc8gmyXUxedCje5Vz/Tu5fKrQEInnCmXxVsWbwr/LzEjMKAM/ivY
0TXxAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0G
A1UdDgQWBBTa+Ns6QzqlNvnTGszkouQQtZnVJDANBgkqhkiG9w0BAQsFAAOCAgEA
NpJEDMXjuEIzSzafkxSshvjnt5sMYmzmvjNoRlkxgN2YcWvPoxbalGAYzcpyggT2
6xZY8R4tvB1oNTCArqwf860kkofUoJCr88D/pU3Cv4JhjCWs4pmXTsvSqlBSlJbo
+jPBZwbn6it/6jcit6Be3rW2PtHe8tASd9Lf8/2r1ZvupXwPzcR84R4Z10ve2lqV
xxcWlMmBh51CaYI0b1/WTe9Ua+wgkCVkxbf9zNcDQXjxw2ICWK+nR/4ld4nmqVm2
C7nhvXwU8FAHl7ZgR2Z3PLrwPuhd+kd6NXQqNkS9A+n+1vSRLbRjmV8pwIPpdPEq
nslUAGJJBHDUBArxC3gOJSB+WtmaCfzDu2gepMf9Ng1H2ZhwSF/FH3v3fsJqZkzz
NBstT9KuNGQRYiCmAPJaoVAc9BoLa+BFML1govtWtpdmbFk8PZEcuUsP7iAZqFF1
uuldPyZ8huGpQSR6Oq2bILRHowfGY0npTZAyxg0Vs8UMy1HTwNOp9OuRtArMZmsJ
jFIx1QzRf9S1i6bYpOzOudoXj4ARkS1KmVExGjJFcIT0xlFSSERie2fEKSeEYOyG
G+PA2qRt/F51FGOMm1ZscjPXqk2kt3C4BFbz6Vvxsq7D3lmhvFLn4jVA8+OidsM0
YUrVMtWET/RkjEIbADbgRXxNUNo+jtQZDU9C1IiAdfk=
-----END CERTIFICATE-----

View File

@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFOzCCAyOgAwIBAgIUbnIMy+Ewi5RvK7OBDxWMCk7wi08wDQYJKoZIhvcNAQEL
BQAwRjEaMBgGA1UEAwwRYXV0aGVudGlrIFRlc3QgQ0ExEjAQBgNVBAoMCWF1dGhl
bnRpazEUMBIGA1UECwwLU2VsZi1zaWduZWQwHhcNMjUwNDI3MTgzMTE3WhcNMjYw
NDIzMTgzMTE3WjARMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUA
A4ICDwAwggIKAoICAQCdV+GEa7+7ito1i/z637OZW+0azv1kuF2aDwSzv+FJd+4L
6hCroRbVYTUFS3I3YwanOOZfau64xH0+pFM5Js8aREG68eqKBayx8vT27hyAOFhd
giEVmSQJfla4ogvPie1rJ0HVOL7CiR72HDPQvz+9k1iDX3xQ/4sdAb3XurN13e+M
Gtavhjiyqxmoo/H4WRd8BhD/BZQFWtaxWODDY8aKk5R7omw6Xf7aRv1BlHdE4Ucy
Wozvpsj2Kz0l61rRUhiMlE0D9dpijgaRYFB+M7R2casH3CdhGQbBHTRiqBkZa6iq
SDkTiTwNJQQJov8yPTsR+9P8OOuV6QN+DGm/FXJJFaPnsHw/HDy7EAbA1PcdbSyK
XvJ8nVjdNhCEGbLGVSwAQLO+78hChVIN5YH+QSrP84YBSxKZYArnf4z2e9drqAN3
KmC26TkaUzkXnndnxOXBEIOSmyCdD4Dutg1XPE/bs8rA6rVGIR3pKXbCr29Z8hZn
Cn9jbxwDwTX865ljR1Oc3dnIeCWa9AS/uHaSMdGlbGbDrt4Bj/nyyfu8xc034K/0
uPh3hF3FLWNAomRVZCvtuh/v7IEIQEgUbvQMWBhZJ8hu3HdtV8V9TIAryVKzEzGy
Q72UHuQyK0njRDTmA/T+jn7P8GWOuf9eNdzd0gH0gcEuhCZFxPPRvUAeDuC7DQID
AQABo1YwVDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwFAYDVR0RAQH/
BAowCIIGY2xpZW50MB0GA1UdDgQWBBQ5KZwTD8+4CqLnbM/cBSXg8XeLXTANBgkq
hkiG9w0BAQsFAAOCAgEABDkb3iyEOl1xKq1wxyRzf2L8qfPXAQw71FxMbgHArM+a
e44wJGO3mZgPH0trOaJ+tuN6erB5YbZfsoX+xFacwskj9pKyb4QJLr/ENmJZRgyL
wp5P6PB6IUJhvryvy/GxrG938YGmFtYQ+ikeJw5PWhB6218C1aZ9hsi94wZ1Zzrc
Ry0q0D4QvIEZ0X2HL1Harc7gerE3VqhgQ7EWyImM+lCRtNDduwDQnZauwhr2r6cW
XG4VTe1RCNsDA0xinXQE2Xf9voCd0Zf6wOOXJseQtrXpf+tG4N13cy5heF5ihed1
hDxSeki0KjTM+18kVVfVm4fzxf1Zg0gm54UlzWceIWh9EtnWMUV08H0D1M9YNmW8
hWTupk7M+jAw8Y+suHOe6/RLi0+fb9NSJpIpq4GqJ5UF2kerXHX0SvuAavoXyB0j
CQrUXkRScEKOO2KAbVExSG56Ff7Ee8cRUAQ6rLC5pQRACq/R0sa6RcUsFPXul3Yv
vbO2rTuArAUPkNVFknwkndheN4lOslRd1If02HunZETmsnal6p+nmuMWt2pQ2fDA
vIguG54FyQ1T1IbF/QhfTEY62CQAebcgutnqqJHt9qe7Jr6ev57hMrJDEjotSzkY
OhOVrcYqgLldr1nBqNVlIK/4VrDaWH8H5dNJ72gA9aMNVH4/bSTJhuO7cJkLnHw=
-----END CERTIFICATE-----

View File

@ -0,0 +1,213 @@
from unittest.mock import MagicMock, patch
from urllib.parse import quote_plus
from django.urls import reverse
from guardian.shortcuts import assign_perm
from authentik.core.models import User
from authentik.core.tests.utils import create_test_brand, create_test_flow, create_test_user
from authentik.crypto.models import CertificateKeyPair
from authentik.enterprise.stages.mtls.models import (
CertAttributes,
MutualTLSStage,
TLSMode,
UserAttributes,
)
from authentik.enterprise.stages.mtls.stage import PLAN_CONTEXT_CERTIFICATE
from authentik.flows.models import FlowDesignation, FlowStageBinding
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
from authentik.flows.tests import FlowTestCase
from authentik.lib.generators import generate_id
from authentik.lib.tests.utils import load_fixture
from authentik.outposts.models import Outpost, OutpostType
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
class MTLSStageTests(FlowTestCase):
def setUp(self):
super().setUp()
self.flow = create_test_flow(FlowDesignation.AUTHENTICATION)
self.ca = CertificateKeyPair.objects.create(
name=generate_id(),
certificate_data=load_fixture("fixtures/ca.pem"),
)
self.stage = MutualTLSStage.objects.create(
name=generate_id(),
mode=TLSMode.REQUIRED,
cert_attribute=CertAttributes.COMMON_NAME,
user_attribute=UserAttributes.USERNAME,
)
self.stage.certificate_authorities.add(self.ca)
self.binding = FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=0)
self.client_cert = load_fixture("fixtures/cert_client.pem")
# User matching the certificate
User.objects.filter(username="client").delete()
self.cert_user = create_test_user(username="client")
def test_parse_xfcc(self):
"""Test authentik Proxy/Envoy's XFCC format"""
with self.assertFlowFinishes() as plan:
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Forwarded-Client-Cert": f"Cert={quote_plus(self.client_cert)}"},
)
self.assertEqual(res.status_code, 200)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
self.assertEqual(plan().context[PLAN_CONTEXT_PENDING_USER], self.cert_user)
def test_parse_nginx(self):
"""Test nginx's format"""
with self.assertFlowFinishes() as plan:
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"SSL-Client-Cert": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
self.assertEqual(plan().context[PLAN_CONTEXT_PENDING_USER], self.cert_user)
def test_parse_traefik(self):
"""Test traefik's format"""
with self.assertFlowFinishes() as plan:
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Forwarded-TLS-Client-Cert": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
self.assertEqual(plan().context[PLAN_CONTEXT_PENDING_USER], self.cert_user)
def test_parse_outpost_object(self):
"""Test outposts's format"""
outpost = Outpost.objects.create(name=generate_id(), type=OutpostType.PROXY)
assign_perm("pass_outpost_certificate", outpost.user, self.stage)
with patch(
"authentik.root.middleware.ClientIPMiddleware.get_outpost_user",
MagicMock(return_value=outpost.user),
):
with self.assertFlowFinishes() as plan:
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Authentik-Outpost-Certificate": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
self.assertEqual(plan().context[PLAN_CONTEXT_PENDING_USER], self.cert_user)
def test_parse_outpost_global(self):
"""Test outposts's format"""
outpost = Outpost.objects.create(name=generate_id(), type=OutpostType.PROXY)
assign_perm("authentik_stages_mtls.pass_outpost_certificate", outpost.user)
with patch(
"authentik.root.middleware.ClientIPMiddleware.get_outpost_user",
MagicMock(return_value=outpost.user),
):
with self.assertFlowFinishes() as plan:
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Authentik-Outpost-Certificate": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
self.assertEqual(plan().context[PLAN_CONTEXT_PENDING_USER], self.cert_user)
def test_parse_outpost_no_perm(self):
"""Test outposts's format"""
outpost = Outpost.objects.create(name=generate_id(), type=OutpostType.PROXY)
with patch(
"authentik.root.middleware.ClientIPMiddleware.get_outpost_user",
MagicMock(return_value=outpost.user),
):
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Authentik-Outpost-Certificate": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageResponse(res, self.flow, component="ak-stage-access-denied")
def test_auth_no_user(self):
"""Test auth with no user"""
User.objects.filter(username="client").delete()
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Forwarded-TLS-Client-Cert": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageResponse(res, self.flow, component="ak-stage-access-denied")
def test_brand_ca(self):
"""Test using a CA from the brand"""
self.stage.certificate_authorities.clear()
brand = create_test_brand()
brand.client_certificates.add(self.ca)
with self.assertFlowFinishes() as plan:
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Forwarded-TLS-Client-Cert": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
self.assertEqual(plan().context[PLAN_CONTEXT_PENDING_USER], self.cert_user)
def test_no_ca_optional(self):
"""Test using no CA Set"""
self.stage.mode = TLSMode.OPTIONAL
self.stage.certificate_authorities.clear()
self.stage.save()
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Forwarded-TLS-Client-Cert": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
def test_no_ca_required(self):
"""Test using no CA Set"""
self.stage.certificate_authorities.clear()
self.stage.save()
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Forwarded-TLS-Client-Cert": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageResponse(res, self.flow, component="ak-stage-access-denied")
def test_no_cert_optional(self):
"""Test using no cert Set"""
self.stage.mode = TLSMode.OPTIONAL
self.stage.save()
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
)
self.assertEqual(res.status_code, 200)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
def test_enroll(self):
"""Test Enrollment flow"""
self.flow.designation = FlowDesignation.ENROLLMENT
self.flow.save()
with self.assertFlowFinishes() as plan:
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
headers={"X-Forwarded-TLS-Client-Cert": quote_plus(self.client_cert)},
)
self.assertEqual(res.status_code, 200)
self.assertStageRedirects(res, reverse("authentik_core:root-redirect"))
self.assertEqual(plan().context[PLAN_CONTEXT_PROMPT], {"email": None, "name": "client"})
self.assertEqual(
plan().context[PLAN_CONTEXT_CERTIFICATE],
{
"fingerprint_sha1": (
"08:d4:a4:79:25:ca:c3:51:28:88:bb:30:c2:96:c3:44:5a:eb:18:07:84:ca:b4:75:27:74:61:19:8a:6a:af:fc"
),
"fingerprint_sha256": (
"08:d4:a4:79:25:ca:c3:51:28:88:bb:30:c2:96:c3:44:5a:eb:18:07:84:ca:b4:75:27:74:61:19:8a:6a:af:fc"
),
"issuer": "OU=Self-signed,O=authentik,CN=authentik Test CA",
"serial_number": "630532384467334865093173111400266136879266564943",
"subject": "CN=client",
},
)

View File

@ -0,0 +1,5 @@
"""API URLs"""
from authentik.enterprise.stages.mtls.api import MutualTLSStageViewSet
api_urlpatterns = [("stages/mtls", MutualTLSStageViewSet)]

View File

@ -8,6 +8,7 @@ from django.test import TestCase
from django.utils.timezone import now
from rest_framework.exceptions import ValidationError
from authentik.core.models import User
from authentik.enterprise.license import LicenseKey
from authentik.enterprise.models import (
THRESHOLD_READ_ONLY_WEEKS,
@ -71,9 +72,9 @@ class TestEnterpriseLicense(TestCase):
)
def test_valid_multiple(self):
"""Check license verification"""
lic = License.objects.create(key=generate_id())
lic = License.objects.create(key=generate_id(), expiry=expiry_valid)
self.assertTrue(lic.status.status().is_valid)
lic2 = License.objects.create(key=generate_id())
lic2 = License.objects.create(key=generate_id(), expiry=expiry_valid)
self.assertTrue(lic2.status.status().is_valid)
total = LicenseKey.get_total()
self.assertEqual(total.internal_users, 200)
@ -232,7 +233,9 @@ class TestEnterpriseLicense(TestCase):
)
def test_expiry_expired(self):
"""Check license verification"""
License.objects.create(key=generate_id())
User.objects.all().delete()
License.objects.all().delete()
License.objects.create(key=generate_id(), expiry=expiry_expired)
self.assertEqual(LicenseKey.get_total().summary().status, LicenseUsageStatus.EXPIRED)
@patch(

View File

@ -57,7 +57,7 @@ class LogEventSerializer(PassiveSerializer):
@contextmanager
def capture_logs(log_default_output=True) -> Generator[list[LogEvent], None, None]:
def capture_logs(log_default_output=True) -> Generator[list[LogEvent]]:
"""Capture log entries created"""
logs = []
cap = LogCapture()

View File

@ -15,6 +15,7 @@
{% endblock %}
<link rel="stylesheet" type="text/css" href="{% static 'dist/sfe/bootstrap.min.css' %}">
<meta name="sentry-trace" content="{{ sentry_trace }}" />
<link rel="prefetch" href="{{ flow_background_url }}" />
{% include "base/header_js.html" %}
<style>
html,
@ -22,7 +23,7 @@
height: 100%;
}
body {
background-image: url("{{ flow.background_url }}");
background-image: url("{{ flow_background_url }}");
background-repeat: no-repeat;
background-size: cover;
}

View File

@ -5,9 +5,9 @@
{% block head_before %}
{{ block.super }}
<link rel="prefetch" href="{{ flow.background_url }}" />
<link rel="prefetch" href="{{ flow_background_url }}" />
{% if flow.compatibility_mode and not inspector %}
<script>ShadyDOM = { force: !navigator.webdriver };</script>
<script>ShadyDOM = { force: true };</script>
{% endif %}
{% include "base/header_js.html" %}
<script>
@ -21,7 +21,7 @@ window.authentik.flow = {
<script src="{% versioned_script 'dist/flow/FlowInterface-%v.js' %}" type="module"></script>
<style>
:root {
--ak-flow-background: url("{{ flow.background_url }}");
--ak-flow-background: url("{{ flow_background_url }}");
}
</style>
{% endblock %}

View File

@ -1,7 +1,10 @@
"""Test helpers"""
from collections.abc import Callable, Generator
from contextlib import contextmanager
from json import loads
from typing import Any
from unittest.mock import MagicMock, patch
from django.http.response import HttpResponse
from django.urls.base import reverse
@ -9,6 +12,8 @@ from rest_framework.test import APITestCase
from authentik.core.models import User
from authentik.flows.models import Flow
from authentik.flows.planner import FlowPlan
from authentik.flows.views.executor import SESSION_KEY_PLAN
class FlowTestCase(APITestCase):
@ -44,3 +49,12 @@ class FlowTestCase(APITestCase):
def assertStageRedirects(self, response: HttpResponse, to: str) -> dict[str, Any]:
"""Wrapper around assertStageResponse that checks for a redirect"""
return self.assertStageResponse(response, component="xak-flow-redirect", to=to)
@contextmanager
def assertFlowFinishes(self) -> Generator[Callable[[], FlowPlan]]:
"""Capture the flow plan before the flow finishes and return it"""
try:
with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()):
yield lambda: self.client.session.get(SESSION_KEY_PLAN)
finally:
pass

View File

@ -48,6 +48,7 @@ class TestFlowInspector(APITestCase):
"allow_show_password": False,
"captcha_stage": None,
"component": "ak-stage-identification",
"enable_remember_me": False,
"flow_info": {
"background": "/static/dist/assets/images/flow_background.jpg",
"cancel_url": reverse("authentik_flows:cancel"),

View File

@ -69,7 +69,6 @@ SESSION_KEY_APPLICATION_PRE = "authentik/flows/application_pre"
SESSION_KEY_GET = "authentik/flows/get"
SESSION_KEY_POST = "authentik/flows/post"
SESSION_KEY_HISTORY = "authentik/flows/history"
SESSION_KEY_AUTH_STARTED = "authentik/flows/auth_started"
QS_KEY_TOKEN = "flow_token" # nosec
QS_QUERY = "query"
@ -454,7 +453,6 @@ class FlowExecutorView(APIView):
SESSION_KEY_APPLICATION_PRE,
SESSION_KEY_PLAN,
SESSION_KEY_GET,
SESSION_KEY_AUTH_STARTED,
# We might need the initial POST payloads for later requests
# SESSION_KEY_POST,
# We don't delete the history on purpose, as a user might

View File

@ -6,8 +6,7 @@ from django.shortcuts import get_object_or_404
from ua_parser.user_agent_parser import Parse
from authentik.core.views.interface import InterfaceView
from authentik.flows.models import Flow, FlowDesignation
from authentik.flows.views.executor import SESSION_KEY_AUTH_STARTED
from authentik.flows.models import Flow
class FlowInterfaceView(InterfaceView):
@ -16,12 +15,7 @@ class FlowInterfaceView(InterfaceView):
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
flow = get_object_or_404(Flow, slug=self.kwargs.get("flow_slug"))
kwargs["flow"] = flow
if (
not self.request.user.is_authenticated
and flow.designation == FlowDesignation.AUTHENTICATION
):
self.request.session[SESSION_KEY_AUTH_STARTED] = True
self.request.session.save()
kwargs["flow_background_url"] = flow.background_url(self.request)
kwargs["inspector"] = "inspector" in self.request.GET
return super().get_context_data(**kwargs)

View File

@ -356,6 +356,17 @@ def redis_url(db: int) -> str:
def django_db_config(config: ConfigLoader | None = None) -> dict:
if not config:
config = CONFIG
pool_options = False
use_pool = config.get_bool("postgresql.use_pool", False)
if use_pool:
pool_options = config.get_dict_from_b64_json("postgresql.pool_options", True)
if not pool_options:
pool_options = True
# FIXME: Temporarily force pool to be deactivated.
# See https://github.com/goauthentik/authentik/issues/14320
pool_options = False
db = {
"default": {
"ENGINE": "authentik.root.db",
@ -369,6 +380,7 @@ def django_db_config(config: ConfigLoader | None = None) -> dict:
"sslrootcert": config.get("postgresql.sslrootcert"),
"sslcert": config.get("postgresql.sslcert"),
"sslkey": config.get("postgresql.sslkey"),
"pool": pool_options,
},
"CONN_MAX_AGE": config.get_optional_int("postgresql.conn_max_age", 0),
"CONN_HEALTH_CHECKS": config.get_bool("postgresql.conn_health_checks", False),

View File

@ -21,6 +21,7 @@ postgresql:
user: authentik
port: 5432
password: "env://POSTGRES_PASSWORD"
use_pool: False
test:
name: test_authentik
default_schema: public

View File

@ -17,7 +17,7 @@ from ldap3.core.exceptions import LDAPException
from redis.exceptions import ConnectionError as RedisConnectionError
from redis.exceptions import RedisError, ResponseError
from rest_framework.exceptions import APIException
from sentry_sdk import HttpTransport
from sentry_sdk import HttpTransport, get_current_scope
from sentry_sdk import init as sentry_sdk_init
from sentry_sdk.api import set_tag
from sentry_sdk.integrations.argv import ArgvIntegration
@ -27,6 +27,7 @@ from sentry_sdk.integrations.redis import RedisIntegration
from sentry_sdk.integrations.socket import SocketIntegration
from sentry_sdk.integrations.stdlib import StdlibIntegration
from sentry_sdk.integrations.threading import ThreadingIntegration
from sentry_sdk.tracing import BAGGAGE_HEADER_NAME, SENTRY_TRACE_HEADER_NAME
from structlog.stdlib import get_logger
from websockets.exceptions import WebSocketException
@ -95,6 +96,8 @@ def traces_sampler(sampling_context: dict) -> float:
return 0
if _type == "websocket":
return 0
if CONFIG.get_bool("debug"):
return 1
return float(CONFIG.get("error_reporting.sample_rate", 0.1))
@ -167,3 +170,14 @@ def before_send(event: dict, hint: dict) -> dict | None:
if settings.DEBUG:
return None
return event
def get_http_meta():
"""Get sentry-related meta key-values"""
scope = get_current_scope()
meta = {
SENTRY_TRACE_HEADER_NAME: scope.get_traceparent() or "",
}
if bag := scope.get_baggage():
meta[BAGGAGE_HEADER_NAME] = bag.serialize()
return meta

View File

@ -59,7 +59,7 @@ class PropertyMappingManager:
request: HttpRequest | None,
return_mapping: bool = False,
**kwargs,
) -> Generator[tuple[dict, PropertyMapping], None]:
) -> Generator[tuple[dict, PropertyMapping]]:
"""Iterate over all mappings that were pre-compiled and
execute all of them with the given context"""
if not self.__has_compiled:

View File

@ -23,7 +23,6 @@ if TYPE_CHECKING:
class Direction(StrEnum):
add = "add"
remove = "remove"
@ -37,13 +36,16 @@ SAFE_METHODS = [
class BaseOutgoingSyncClient[
TModel: "Model", TConnection: "Model", TSchema: dict, TProvider: "OutgoingSyncProvider"
TModel: "Model",
TConnection: "Model",
TSchema: dict,
TProvider: "OutgoingSyncProvider",
]:
"""Basic Outgoing sync client Client"""
provider: TProvider
connection_type: type[TConnection]
connection_type_query: str
connection_attr: str
mapper: PropertyMappingManager
can_discover = False
@ -63,9 +65,7 @@ class BaseOutgoingSyncClient[
def write(self, obj: TModel) -> tuple[TConnection, bool]:
"""Write object to destination. Uses self.create and self.update, but
can be overwritten for further logic"""
connection = self.connection_type.objects.filter(
provider=self.provider, **{self.connection_type_query: obj}
).first()
connection = getattr(obj, self.connection_attr).filter(provider=self.provider).first()
try:
if not connection:
connection = self.create(obj)

View File

@ -217,6 +217,7 @@ class TestConfig(TestCase):
"HOST": "foo",
"NAME": "foo",
"OPTIONS": {
"pool": False,
"sslcert": "foo",
"sslkey": "foo",
"sslmode": "foo",
@ -267,6 +268,7 @@ class TestConfig(TestCase):
"HOST": "foo",
"NAME": "foo",
"OPTIONS": {
"pool": False,
"sslcert": "foo",
"sslkey": "foo",
"sslmode": "foo",
@ -285,6 +287,7 @@ class TestConfig(TestCase):
"HOST": "bar",
"NAME": "foo",
"OPTIONS": {
"pool": False,
"sslcert": "foo",
"sslkey": "foo",
"sslmode": "foo",
@ -333,6 +336,7 @@ class TestConfig(TestCase):
"HOST": "foo",
"NAME": "foo",
"OPTIONS": {
"pool": False,
"sslcert": "foo",
"sslkey": "foo",
"sslmode": "foo",
@ -351,6 +355,7 @@ class TestConfig(TestCase):
"HOST": "bar",
"NAME": "foo",
"OPTIONS": {
"pool": False,
"sslcert": "foo",
"sslkey": "foo",
"sslmode": "foo",
@ -394,6 +399,7 @@ class TestConfig(TestCase):
"HOST": "foo",
"NAME": "foo",
"OPTIONS": {
"pool": False,
"sslcert": "foo",
"sslkey": "foo",
"sslmode": "foo",
@ -412,6 +418,7 @@ class TestConfig(TestCase):
"HOST": "bar",
"NAME": "foo",
"OPTIONS": {
"pool": False,
"sslcert": "foo",
"sslkey": "foo",
"sslmode": "foo",
@ -451,6 +458,7 @@ class TestConfig(TestCase):
"HOST": "foo",
"NAME": "foo",
"OPTIONS": {
"pool": False,
"sslcert": "foo",
"sslkey": "foo",
"sslmode": "foo",
@ -469,6 +477,7 @@ class TestConfig(TestCase):
"HOST": "bar",
"NAME": "foo",
"OPTIONS": {
"pool": False,
"sslcert": "bar",
"sslkey": "foo",
"sslmode": "foo",
@ -484,3 +493,89 @@ class TestConfig(TestCase):
},
},
)
# FIXME: Temporarily force pool to be deactivated.
# See https://github.com/goauthentik/authentik/issues/14320
# def test_db_pool(self):
# """Test DB Config with pool"""
# config = ConfigLoader()
# config.set("postgresql.host", "foo")
# config.set("postgresql.name", "foo")
# config.set("postgresql.user", "foo")
# config.set("postgresql.password", "foo")
# config.set("postgresql.port", "foo")
# config.set("postgresql.test.name", "foo")
# config.set("postgresql.use_pool", True)
# conf = django_db_config(config)
# self.assertEqual(
# conf,
# {
# "default": {
# "ENGINE": "authentik.root.db",
# "HOST": "foo",
# "NAME": "foo",
# "OPTIONS": {
# "pool": True,
# "sslcert": None,
# "sslkey": None,
# "sslmode": None,
# "sslrootcert": None,
# },
# "PASSWORD": "foo",
# "PORT": "foo",
# "TEST": {"NAME": "foo"},
# "USER": "foo",
# "CONN_MAX_AGE": 0,
# "CONN_HEALTH_CHECKS": False,
# "DISABLE_SERVER_SIDE_CURSORS": False,
# }
# },
# )
# def test_db_pool_options(self):
# """Test DB Config with pool"""
# config = ConfigLoader()
# config.set("postgresql.host", "foo")
# config.set("postgresql.name", "foo")
# config.set("postgresql.user", "foo")
# config.set("postgresql.password", "foo")
# config.set("postgresql.port", "foo")
# config.set("postgresql.test.name", "foo")
# config.set("postgresql.use_pool", True)
# config.set(
# "postgresql.pool_options",
# base64.b64encode(
# dumps(
# {
# "max_size": 15,
# }
# ).encode()
# ).decode(),
# )
# conf = django_db_config(config)
# self.assertEqual(
# conf,
# {
# "default": {
# "ENGINE": "authentik.root.db",
# "HOST": "foo",
# "NAME": "foo",
# "OPTIONS": {
# "pool": {
# "max_size": 15,
# },
# "sslcert": None,
# "sslkey": None,
# "sslmode": None,
# "sslrootcert": None,
# },
# "PASSWORD": "foo",
# "PORT": "foo",
# "TEST": {"NAME": "foo"},
# "USER": "foo",
# "CONN_MAX_AGE": 0,
# "CONN_HEALTH_CHECKS": False,
# "DISABLE_SERVER_SIDE_CURSORS": False,
# }
# },
# )

View File

@ -74,6 +74,8 @@ 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_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")
kubernetes_disabled_components: list[str] = field(default_factory=list)
kubernetes_image_pull_secrets: list[str] = field(default_factory=list)

View File

@ -1,4 +1,8 @@
"""authentik policies app config"""
"""Authentik policies app config
Every system policy should be its own Django app under the `policies` app.
For example: The 'dummy' policy is available at `authentik.policies.dummy`.
"""
from prometheus_client import Gauge, Histogram
@ -35,4 +39,3 @@ class AuthentikPoliciesConfig(ManagedAppConfig):
label = "authentik_policies"
verbose_name = "authentik Policies"
default = True
mountpoint = "policy/"

View File

@ -66,7 +66,9 @@ class GeoIPPolicy(Policy):
if not static_results and not dynamic_results:
return PolicyResult(True)
passing = any(r.passing for r in static_results) and all(r.passing for r in dynamic_results)
static_passing = any(r.passing for r in static_results) if static_results else True
dynamic_passing = all(r.passing for r in dynamic_results)
passing = static_passing and dynamic_passing
messages = chain(
*[r.messages for r in static_results], *[r.messages for r in dynamic_results]
)
@ -113,13 +115,19 @@ class GeoIPPolicy(Policy):
to previous authentication requests"""
# Get previous login event and GeoIP data
previous_logins = Event.objects.filter(
action=EventAction.LOGIN, user__pk=request.user.pk, context__geo__isnull=False
action=EventAction.LOGIN,
user__pk=request.user.pk, # context__geo__isnull=False
).order_by("-created")[: self.history_login_count]
_now = now()
geoip_data: GeoIPDict | None = request.context.get("geoip")
if not geoip_data:
return PolicyResult(False)
if not previous_logins.exists():
return PolicyResult(True)
result = False
for previous_login in previous_logins:
if "geo" not in previous_login.context:
continue
previous_login_geoip: GeoIPDict = previous_login.context["geo"]
# Figure out distance
@ -142,7 +150,8 @@ class GeoIPPolicy(Policy):
(MAX_DISTANCE_HOUR_KM * rel_time_hours) + self.distance_tolerance_km
):
return PolicyResult(False, _("Distance is further than possible."))
return PolicyResult(True)
result = True
return PolicyResult(result)
class Meta(Policy.PolicyMeta):
verbose_name = _("GeoIP Policy")

View File

@ -163,7 +163,7 @@ class TestGeoIPPolicy(TestCase):
result: PolicyResult = policy.passes(self.request)
self.assertFalse(result.passing)
def test_history_impossible_travel(self):
def test_history_impossible_travel_failing(self):
"""Test history checks"""
Event.objects.create(
action=EventAction.LOGIN,
@ -181,6 +181,24 @@ class TestGeoIPPolicy(TestCase):
result: PolicyResult = policy.passes(self.request)
self.assertFalse(result.passing)
def test_history_impossible_travel_passing(self):
"""Test history checks"""
Event.objects.create(
action=EventAction.LOGIN,
user=get_user(self.user),
context={
# Random location in Canada
"geo": {"lat": 55.868351, "long": -104.441011},
},
)
# Same location
self.request.context["geoip"] = {"lat": 55.868351, "long": -104.441011}
policy = GeoIPPolicy.objects.create(check_impossible_travel=True)
result: PolicyResult = policy.passes(self.request)
self.assertTrue(result.passing)
def test_history_no_geoip(self):
"""Test history checks (previous login with no geoip data)"""
Event.objects.create(
@ -195,3 +213,18 @@ class TestGeoIPPolicy(TestCase):
result: PolicyResult = policy.passes(self.request)
self.assertFalse(result.passing)
def test_impossible_travel_no_geoip(self):
"""Test impossible travel checks (previous login with no geoip data)"""
Event.objects.create(
action=EventAction.LOGIN,
user=get_user(self.user),
context={},
)
# Random location in Poland
self.request.context["geoip"] = {"lat": 50.950613, "long": 20.363679}
policy = GeoIPPolicy.objects.create(check_impossible_travel=True)
result: PolicyResult = policy.passes(self.request)
self.assertFalse(result.passing)

View File

@ -52,6 +52,13 @@ class PolicyBindingModel(models.Model):
return ["policy", "user", "group"]
class BoundPolicyQuerySet(models.QuerySet):
"""QuerySet for filtering enabled bindings for a Policy type"""
def for_policy(self, policy: "Policy"):
return self.filter(policy__in=policy._default_manager.all()).filter(enabled=True)
class PolicyBinding(SerializerModel):
"""Relationship between a Policy and a PolicyBindingModel."""
@ -148,6 +155,9 @@ class PolicyBinding(SerializerModel):
return f"Binding - #{self.order} to {suffix}"
return ""
objects = models.Manager()
in_use = BoundPolicyQuerySet.as_manager()
class Meta:
verbose_name = _("Policy Binding")
verbose_name_plural = _("Policy Bindings")

View File

@ -2,4 +2,6 @@
from authentik.policies.password.api import PasswordPolicyViewSet
api_urlpatterns = [("policies/password", PasswordPolicyViewSet)]
api_urlpatterns = [
("policies/password", PasswordPolicyViewSet),
]

View File

@ -1,89 +0,0 @@
{% extends 'login/base_full.html' %}
{% load static %}
{% load i18n %}
{% block head %}
{{ block.super }}
<script>
let redirecting = false;
const checkAuth = async () => {
if (redirecting) return true;
const url = "{{ check_auth_url }}";
console.debug("authentik/policies/buffer: Checking authentication...");
try {
const result = await fetch(url, {
method: "HEAD",
});
if (result.status >= 400) {
return false
}
console.debug("authentik/policies/buffer: Continuing");
redirecting = true;
if ("{{ auth_req_method }}" === "post") {
document.querySelector("form").submit();
} else {
window.location.assign("{{ continue_url|escapejs }}");
}
} catch {
return false;
}
};
let timeout = 100;
let offset = 20;
let attempt = 0;
const main = async () => {
attempt += 1;
await checkAuth();
console.debug(`authentik/policies/buffer: Waiting ${timeout}ms...`);
setTimeout(main, timeout);
timeout += (offset * attempt);
if (timeout >= 2000) {
timeout = 2000;
}
}
document.addEventListener("visibilitychange", async () => {
if (document.hidden) return;
console.debug("authentik/policies/buffer: Checking authentication on tab activate...");
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

@ -1,121 +0,0 @@
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.views import (
QS_BUFFER_ID,
SESSION_KEY_BUFFER,
BufferedPolicyAccessView,
BufferView,
PolicyAccessView,
)
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")
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")))
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,14 +1,7 @@
"""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,37 +1,23 @@
"""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, QueryDict
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.http import urlencode
from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from django.views.generic.base import TemplateView, View
from django.views.generic.base import View
from structlog.stdlib import get_logger
from authentik.core.models import Application, Provider, User
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_AUTH_STARTED,
SESSION_KEY_PLAN,
SESSION_KEY_POST,
)
from authentik.flows.views.executor import SESSION_KEY_APPLICATION_PRE, SESSION_KEY_POST
from authentik.lib.sentry import SentryIgnoredException
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):
@ -139,65 +125,3 @@ 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)
authenticating = self.request.session.get(SESSION_KEY_AUTH_STARTED)
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 and authenticating is None:
LOGGER.debug("Not buffering request, no flow plan active")
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

@ -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 BufferedPolicyAccessView, RequestValidationError
from authentik.policies.views import PolicyAccessView, RequestValidationError
from authentik.providers.oauth2.constants import (
PKCE_METHOD_PLAIN,
PKCE_METHOD_S256,
@ -326,7 +326,7 @@ class OAuthAuthorizationParams:
return code
class AuthorizationFlowInitView(BufferedPolicyAccessView):
class AuthorizationFlowInitView(PolicyAccessView):
"""OAuth2 Flow initializer, checks access to application and starts flow"""
params: OAuthAuthorizationParams

View File

@ -0,0 +1,234 @@
from dataclasses import asdict, dataclass, field
from typing import TYPE_CHECKING
from urllib.parse import urlparse
from dacite.core import from_dict
from kubernetes.client import ApiextensionsV1Api, CustomObjectsApi, V1ObjectMeta
from authentik.outposts.controllers.base import FIELD_MANAGER
from authentik.outposts.controllers.k8s.base import KubernetesObjectReconciler
from authentik.outposts.controllers.k8s.triggers import NeedsUpdate
from authentik.outposts.controllers.kubernetes import KubernetesController
from authentik.providers.proxy.models import ProxyMode, ProxyProvider
if TYPE_CHECKING:
from authentik.outposts.controllers.kubernetes import KubernetesController
@dataclass(slots=True)
class RouteBackendRef:
name: str
port: int
@dataclass(slots=True)
class RouteSpecParentRefs:
name: str
sectionName: str | None = None
port: int | None = None
namespace: str | None = None
kind: str = "Gateway"
group: str = "gateway.networking.k8s.io"
@dataclass(slots=True)
class HTTPRouteSpecRuleMatchPath:
type: str
value: str
@dataclass(slots=True)
class HTTPRouteSpecRuleMatchHeader:
name: str
value: str
type: str = "Exact"
@dataclass(slots=True)
class HTTPRouteSpecRuleMatch:
path: HTTPRouteSpecRuleMatchPath
headers: list[HTTPRouteSpecRuleMatchHeader]
@dataclass(slots=True)
class HTTPRouteSpecRule:
backendRefs: list[RouteBackendRef]
matches: list[HTTPRouteSpecRuleMatch]
@dataclass(slots=True)
class HTTPRouteSpec:
parentRefs: list[RouteSpecParentRefs]
hostnames: list[str]
rules: list[HTTPRouteSpecRule]
@dataclass(slots=True)
class HTTPRouteMetadata:
name: str
namespace: str
annotations: dict = field(default_factory=dict)
labels: dict = field(default_factory=dict)
@dataclass(slots=True)
class HTTPRoute:
apiVersion: str
kind: str
metadata: HTTPRouteMetadata
spec: HTTPRouteSpec
class HTTPRouteReconciler(KubernetesObjectReconciler):
"""Kubernetes Gateway API HTTPRoute Reconciler"""
def __init__(self, controller: "KubernetesController") -> None:
super().__init__(controller)
self.api_ex = ApiextensionsV1Api(controller.client)
self.api = CustomObjectsApi(controller.client)
self.crd_group = "gateway.networking.k8s.io"
self.crd_version = "v1"
self.crd_plural = "httproutes"
@staticmethod
def reconciler_name() -> str:
return "httproute"
@property
def noop(self) -> bool:
if not self.crd_exists():
self.logger.debug("CRD doesn't exist")
return True
if not self.controller.outpost.config.kubernetes_httproute_parent_refs:
self.logger.debug("HTTPRoute parentRefs not set.")
return True
return False
def crd_exists(self) -> bool:
"""Check if the Gateway API resources exists"""
return bool(
len(
self.api_ex.list_custom_resource_definition(
field_selector=f"metadata.name={self.crd_plural}.{self.crd_group}"
).items
)
)
def reconcile(self, current: HTTPRoute, reference: HTTPRoute):
super().reconcile(current, reference)
if current.metadata.annotations != reference.metadata.annotations:
raise NeedsUpdate()
if current.spec.parentRefs != reference.spec.parentRefs:
raise NeedsUpdate()
if current.spec.hostnames != reference.spec.hostnames:
raise NeedsUpdate()
if current.spec.rules != reference.spec.rules:
raise NeedsUpdate()
def get_object_meta(self, **kwargs) -> V1ObjectMeta:
return super().get_object_meta(
**kwargs,
)
def get_reference_object(self) -> HTTPRoute:
hostnames = []
rules = []
for proxy_provider in ProxyProvider.objects.filter(outpost__in=[self.controller.outpost]):
proxy_provider: ProxyProvider
external_host_name = urlparse(proxy_provider.external_host)
if proxy_provider.mode in [ProxyMode.FORWARD_SINGLE, ProxyMode.FORWARD_DOMAIN]:
rule = HTTPRouteSpecRule(
backendRefs=[RouteBackendRef(name=self.name, port=9000)],
matches=[
HTTPRouteSpecRuleMatch(
headers=[
HTTPRouteSpecRuleMatchHeader(
name="Host",
value=external_host_name.hostname,
)
],
path=HTTPRouteSpecRuleMatchPath(
type="PathPrefix", value="/outpost.goauthentik.io"
),
)
],
)
else:
rule = HTTPRouteSpecRule(
backendRefs=[RouteBackendRef(name=self.name, port=9000)],
matches=[
HTTPRouteSpecRuleMatch(
headers=[
HTTPRouteSpecRuleMatchHeader(
name="Host",
value=external_host_name.hostname,
)
],
path=HTTPRouteSpecRuleMatchPath(type="PathPrefix", value="/"),
)
],
)
hostnames.append(external_host_name.hostname)
rules.append(rule)
return HTTPRoute(
apiVersion=f"{self.crd_group}/{self.crd_version}",
kind="HTTPRoute",
metadata=HTTPRouteMetadata(
name=self.name,
namespace=self.namespace,
annotations=self.controller.outpost.config.kubernetes_httproute_annotations,
labels=self.get_object_meta().labels,
),
spec=HTTPRouteSpec(
parentRefs=[
from_dict(RouteSpecParentRefs, spec)
for spec in self.controller.outpost.config.kubernetes_httproute_parent_refs
],
hostnames=hostnames,
rules=rules,
),
)
def create(self, reference: HTTPRoute):
return self.api.create_namespaced_custom_object(
group=self.crd_group,
version=self.crd_version,
plural=self.crd_plural,
namespace=self.namespace,
body=asdict(reference),
field_manager=FIELD_MANAGER,
)
def delete(self, reference: HTTPRoute):
return self.api.delete_namespaced_custom_object(
group=self.crd_group,
version=self.crd_version,
plural=self.crd_plural,
namespace=self.namespace,
name=self.name,
)
def retrieve(self) -> HTTPRoute:
return from_dict(
HTTPRoute,
self.api.get_namespaced_custom_object(
group=self.crd_group,
version=self.crd_version,
plural=self.crd_plural,
namespace=self.namespace,
name=self.name,
),
)
def update(self, current: HTTPRoute, reference: HTTPRoute):
return self.api.patch_namespaced_custom_object(
group=self.crd_group,
version=self.crd_version,
plural=self.crd_plural,
namespace=self.namespace,
name=self.name,
body=asdict(reference),
field_manager=FIELD_MANAGER,
)

View File

@ -3,6 +3,7 @@
from authentik.outposts.controllers.base import DeploymentPort
from authentik.outposts.controllers.kubernetes import KubernetesController
from authentik.outposts.models import KubernetesServiceConnection, Outpost
from authentik.providers.proxy.controllers.k8s.httproute import HTTPRouteReconciler
from authentik.providers.proxy.controllers.k8s.ingress import IngressReconciler
from authentik.providers.proxy.controllers.k8s.traefik import TraefikMiddlewareReconciler
@ -18,8 +19,10 @@ class ProxyKubernetesController(KubernetesController):
DeploymentPort(9443, "https", "tcp"),
]
self.reconcilers[IngressReconciler.reconciler_name()] = IngressReconciler
self.reconcilers[HTTPRouteReconciler.reconciler_name()] = HTTPRouteReconciler
self.reconcilers[TraefikMiddlewareReconciler.reconciler_name()] = (
TraefikMiddlewareReconciler
)
self.reconcile_order.append(IngressReconciler.reconciler_name())
self.reconcile_order.append(HTTPRouteReconciler.reconciler_name())
self.reconcile_order.append(TraefikMiddlewareReconciler.reconciler_name())

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