Compare commits

...

167 Commits

Author SHA1 Message Date
ab42a62916 wip
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-03-07 19:23:34 +01:00
ef8d2bdd40 wip
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-03-07 16:24:55 +01:00
32f4e08eac writting down thoughts
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-03-07 14:04:21 +01:00
afdf830e8a lifecycle/aws: bump aws-cdk from 2.1002.0 to 2.1003.0 in /lifecycle/aws (#13426)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1002.0 to 2.1003.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1003.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  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-03-07 12:58:28 +01:00
7ab636e103 translate: Updates for file web/xliff/en.xlf in zh_CN (#13428)
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-03-07 12:46:15 +01:00
4efb4d6191 translate: Updates for file web/xliff/en.xlf in zh-Hans (#13429)
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-03-07 12:46:08 +01:00
b855d98b78 core, web: update translations (#13423)
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-03-07 01:32:39 +01:00
354634cdf4 website: add a better edit this page element (#13391)
website/docs: Flesh out contributor footer.

Co-authored-by: Teffen Ellis <teffen@nirri.us>
2025-03-06 19:27:57 +00:00
319f2ef8d1 web/admin: allow user lists to show active only (#13403)
* 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/admin: allow admins to show only active users in Group assignments

## What

Adds a flag and a visible control to the "Add users to groups" dialog to limit the users
shown to only those marked as "active."

## Why

Requested, it was small, it made sense, and it was fairly trivial to implement.  All the
infrastructure already existed.

## Testing

- Ensure you have both "active" and "inactive" users in your sample group.
- Visit Groups -> (One Group) -> Users ->. Click "Add existing user."  Click the `+` symbol.
- A new toggle control, "Show inactive users," should now be visible.
- Click it and note whether or not the visible display corresponds to the stote of the control.

## Note

This commit does not address the second half of the request, "... the ability to add more than one
user to an entitlement." We recommend that if you have a group of people who correspond to a given
entitlement that you create a named group for them.

## Related Issue:

- [Hide disabled users when adding users to a group or entitlement
  #12653](https://github.com/goauthentik/authentik/issues/12653)

* Provided an explanation for the odd expression around `CoreApi.coreUsersList:isActive`

* Use logical CSS; give  room to expand

* Disambiguate variable names
2025-03-06 10:44:19 -08:00
cf58c5617a core: Tidy contributor onboarding, fix typos. (#12700)
core: Tidy contributor onboarding.

- Fixes typos.
- Fixes stale links.
- Tidies Makefile so that Poetry env is optional for hygiene commands.
- Remove mismatched YAML naming.
- Uses shebang on Python scripts.
- Document semver usage.
- Redirect OpenAPI schema.

Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2025-03-06 18:34:54 +00:00
71344d0b6a translate: Updates for file web/xliff/en.xlf in zh-Hans (#13418)
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-03-06 19:03:09 +01:00
696db2ae05 translate: Updates for file web/xliff/en.xlf in zh_CN (#13417)
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-03-06 19:03:04 +01:00
f08da8f295 lib/config: fix conn_max_age parsing (#13370)
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-03-06 13:53:09 +00:00
89106c8131 core: bump golang.org/x/sync from 0.11.0 to 0.12.0 (#13407)
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.11.0 to 0.12.0.
- [Commits](https://github.com/golang/sync/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  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-03-06 12:15:37 +00:00
f6b0eecde7 stages/authenticator_email: Fix Enroll dropdown in the MFA Devices page (#13404)
Implement missing ui_user_settings() in AuthenticatorEmailStage
2025-03-06 12:15:15 +00:00
4ca151ee14 core: bump golang.org/x/oauth2 from 0.27.0 to 0.28.0 (#13408)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.27.0 to 0.28.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.27.0...v0.28.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  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-03-06 12:14:21 +00:00
f66fea4b0a core: bump aws-cdk-lib from 2.181.1 to 2.182.0 (#13409)
Bumps [aws-cdk-lib](https://github.com/aws/aws-cdk) from 2.181.1 to 2.182.0.
- [Release notes](https://github.com/aws/aws-cdk/releases)
- [Changelog](https://github.com/aws/aws-cdk/blob/main/CHANGELOG.v2.md)
- [Commits](https://github.com/aws/aws-cdk/compare/v2.181.1...v2.182.0)

---
updated-dependencies:
- dependency-name: aws-cdk-lib
  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-03-06 12:14:14 +00:00
6d8dc4ac43 core: bump google-api-python-client from 2.162.0 to 2.163.0 (#13410)
Bumps [google-api-python-client](https://github.com/googleapis/google-api-python-client) from 2.162.0 to 2.163.0.
- [Release notes](https://github.com/googleapis/google-api-python-client/releases)
- [Commits](https://github.com/googleapis/google-api-python-client/compare/v2.162.0...v2.163.0)

---
updated-dependencies:
- dependency-name: google-api-python-client
  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-03-06 12:13:48 +00:00
04982c8147 core: bump msgraph-sdk from 1.22.0 to 1.23.0 (#13411)
Bumps [msgraph-sdk](https://github.com/microsoftgraph/msgraph-sdk-python) from 1.22.0 to 1.23.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.22.0...v1.23.0)

---
updated-dependencies:
- dependency-name: msgraph-sdk
  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-03-06 12:13:25 +00:00
2ab68480a0 core: bump jinja2 from 3.1.5 to 3.1.6 (#13412)
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.5 to 3.1.6.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.5...3.1.6)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 12:13:01 +00:00
248d9e48bb web/user: ensure modal container on user-settings page is min-height: 100% (#13402)
* 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/admin: ensure modal container on user-settings page is min-height: 100%

## What

Add a min-height and auto-scroll directives to the CSS for the main section of the user-settings
page.

```
+                .pf-c-page__main {
+                    min-height: 100vw;
+                    overflow-y: auto;
```

## Why

Without this, Safari refused to render any pop-up modals that were "centered" on the viewport but
were "beneath" the rendered content space of the container. As a result, users could not create new
access tokens or app passwords. This is arguably incorrect behavior on Safari's part, but 🤷‍♀️.
Adding `overflow-y: auto` on the container means that if the page is not long enough to host the
pop-up, it will be accessible via scrolling.

## Testing

- Using Safari, Visit the User->User Settings, click "Tokens and App Passwords" tab, and click
  "Create Token" or "Create App Password"
- Observe that the dialog is now accessible.

## Related Issue:

- [Unable to create API token in Safari
  #12891](https://github.com/goauthentik/authentik/issues/12891)

* Fix a really stupid typo.
2025-03-06 12:10:28 +00:00
e58e4bdbae core, web: update translations (#13405)
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-03-06 11:43:27 +01:00
a07ce35985 web/admin: add button to clear application cache (#13399)
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-03-05 20:23:10 +01:00
cfe275a374 blueprints: Adjust title for MFA set up (#13400)
web/blueprints: Adjust copy.
2025-03-05 20:21:49 +01:00
7f474cde19 web/admin: fix markdown being completely whited out in dark mode on proxy provider pages (#13387)
* 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/admin: fix markdown being completely whited out in dark mode on proxy provider pages

## What

Removed the `pf-m-light` hard-code specification from the wrapper for Markdown.

## Why

Color themes backed with CSS custom properties are vulnerable to overspecification, and that's what
this class did; overspecified the background color to always be in "light mode," which the Markdown
component then inherited.

## Testing

Create a proxy provider page for Forward Auth Proxy (Domain-Level). Using the browser's inspector,
choose the "Styles" tab and click on the paintbrush. Alternate between dark mode and light, and
observe that the styled markdown is changing color along with the rest of the application.

## Related Issue:

- [Proxy Provider setup section completely whited out.
  #13335](https://github.com/goauthentik/authentik/issues/13335)

* web/admin: use card background color directly when not in dark mode
2025-03-05 08:39:45 -08:00
0597a3450b web/admin: decorative display in user’s page breaks in other locales (#13393)
* 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/admin: decorative display in user's page breaks in other locales

## What

Move the decorations out of the display string and make them part of the presentation instead:

```
- <small>${item.name === "" ? msg("<No name set>") : item.name}</small>
+ <small>${item.name ? item.name : html`&lt;${msg("No name set")}&gt;`}</small>
```

Also a bit of logic re-arrangement; whenever possible, try to put the fallback condition in the
secondary position. A ternary is appropriate here; the nullish coalescing operator (`??`) is not
triggered by an empty string.

## Why

The decorations are being misinterpreted as HTML markers. The localization function re-interprets
the ampersand a second time, creating the string `&amp;lt;No name set&amp;gt;.

## Testing

- Visit the user administration page in English mode:
  http://localhost:9000/if/admin/#/identity/users
- Create a user but do NOT fill in the Name field (the second field, which lacks an asterisk
  indicating "required.")
- Note that the user shows up, and `<No name set>` is displayed for the user's display name.
- Visit the user administration page in French mode:
  http://localhost:9000/if/admin/?locale=fr#/identity/users
- Note that the user shows up, and `<No name set>` (or, if the field is translated, "Aucun nom
  spécifié") is displayed for the user's display name.

## Related Issue:

- [Users list wrong display when Locale is not "EN - English"
  #12951](https://github.com/goauthentik/authentik/issues/12951)
2025-03-05 16:37:34 +00:00
8191b90126 website: bump the build group in /website with 6 updates (#13396)
Bumps the build group in /website with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@swc/core-darwin-arm64](https://github.com/swc-project/swc) | `1.11.5` | `1.11.7` |
| [@swc/core-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.5` | `1.11.7` |
| [@swc/core-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.5` | `1.11.7` |
| [@swc/html-darwin-arm64](https://github.com/swc-project/swc) | `1.11.5` | `1.11.7` |
| [@swc/html-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.5` | `1.11.7` |
| [@swc/html-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.5` | `1.11.7` |


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

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

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

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

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

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

---
updated-dependencies:
- 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-03-05 14:27:39 +00:00
2613a5da4b core: bump github.com/prometheus/client_golang from 1.21.0 to 1.21.1 (#13397)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.21.0 to 1.21.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.21.0...v1.21.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  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-03-05 14:27:31 +00:00
2c4dd232a1 core: bump debugpy from 1.8.12 to 1.8.13 (#13395)
Bumps [debugpy](https://github.com/microsoft/debugpy) from 1.8.12 to 1.8.13.
- [Release notes](https://github.com/microsoft/debugpy/releases)
- [Commits](https://github.com/microsoft/debugpy/compare/v1.8.12...v1.8.13)

---
updated-dependencies:
- dependency-name: debugpy
  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-03-05 13:23:41 +01:00
6b5c11ccfd website/docs: Update Open Web UI integration (#13392)
website/docs: Update Open Web UI integration with note about adding users and updating URL

Signed-off-by: Rami-Pastrami <25966197+Rami-Pastrami@users.noreply.github.com>
2025-03-04 14:01:01 -06:00
a0b3d37b4a website/integrations: gravity: add (#13258)
* wip

* Update index.md

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

* wip

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-03-04 13:21:39 -06:00
56eca6dc8f website/integrations: Pocketbase (#12906)
* fix conflicts

* Update models.py

Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

---------

Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>
Co-authored-by: nicedevil007 <nicedevil007@users.noreply.github.com>
2025-03-04 12:58:51 -06:00
0377da2779 ci: cache helper docker images (#13390)
* ci: cache helper docker images

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

* pin redis image

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

* ci trigger

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

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-03-04 18:41:59 +00:00
b16c67cc82 providers/proxy: kubernetes outpost: fix reconcile when only annotations changed (#13372)
* providers/proxy: kubernetes outpost: fix reconcile when only annotations changed

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

* fixup

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

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-03-04 16:40:21 +01:00
28f55635be website: bump the build group in /website with 3 updates (#13381)
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.2.6 to 1.2.7
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.2.7/packages/rspack)

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-04 13:50:19 +00:00
8d4b2610b1 core, web: update translations (#13378)
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-03-04 13:44:49 +01:00
419cf80469 web/admin: prefer using datefns over moment.js (#13143)
* 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.

* ## What

Replaces `moment.js` with `date-fns` as a runtime dependency for Chart.js and other features
requiring date manipulation libraries. `date-fns` (and `chartjs-adapter-date-fns`) provides a 1:1
compatible API with Moment.js, is significantly faster and smaller. Moment.js adds
74KB to our bundle; in constrast, using DateFns adds only 18KB.

## Why

[Because ChartJS recommends it](https://github.com/chartjs/chartjs-adapter-moment#overview), and
because DateFns are easier to import and use.

It's worth noting that chartjs-adapter-date-fns was last updated three years ago, but
chartjs-adapter-moment was last updated *four* years ago. Both can be considered stable at this
point, so this cannot be considered an untested swap.

## Testing

1. In the *built* version of the product, assert that in the `./dist/admin/*` folder, no instance of
   `node_modules/moment` is included. `grep "node_modules/moment" ./dist/admin/*` is sufficient for
   this. On the other hand, searching for `date-fns` will get you entries in the maps:

```
// ... many lines of date-fns inclusion; this is near the end, to show the chartjs adapter is
// also included.
admin/chunk-TRZMFVHL.js:// node_modules/date-fns/startOfSecond.js
admin/chunk-TRZMFVHL.js:// node_modules/date-fns/parseISO.js
admin/chunk-TRZMFVHL.js:// node_modules/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.esm.js
admin/chunk-TRZMFVHL.js:  _id: "date-fns",
admin/chunk-TRZMFVHL.js:chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.esm.js:
```

2. Visually inspect and assert that the graphs in Dashboard➜Overview, User➜Statistics, and
   Directory➜Users➜A User are functioning unchanged.

## Documentation Changes Required

None.  No developer or user documentation changes are required.

---------

Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-03-03 20:11:24 +00:00
632dc4b1b2 website/docs: fix typo (#13377)
Signed-off-by: Elijah Passmore <eljpsm@eljpsm.com>
2025-03-03 20:10:30 +00:00
93cfa64f5a stages/authenticator_email: remove flaky assertions (#13371)
* stages/authenticator_email: try fixing flaky tests

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

* ci trigger

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

* remove flaky assertions

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

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-03-03 17:23:39 +01:00
fa8f9d4017 translate: Updates for file web/xliff/en.xlf in fr (#13374)
* Translate web/xliff/en.xlf in fr

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

* 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-03-03 16:20:56 +00:00
d4c0696a8c translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13373)
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-03-03 16:18:10 +00:00
20635a8cc6 website: bump typescript from 5.7.3 to 5.8.2 in /website (#13368)
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.7.3 to 5.8.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.7.3...v5.8.2)

---
updated-dependencies:
- dependency-name: typescript
  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-03-03 15:09:17 +00:00
c621ac0a6f lifecycle/aws: bump aws-cdk from 2.1001.0 to 2.1002.0 in /lifecycle/aws (#13365)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1001.0 to 2.1002.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1002.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  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-03-03 14:31:43 +00:00
0487c8d0f5 website: bump the build group in /website with 11 updates (#13367)
Bumps the build group in /website with 11 updates:

| Package | From | To |
| --- | --- | --- |
| [@rspack/binding-linux-arm64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.1.6` | `1.2.6` |
| [@rspack/binding-linux-x64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.1.6` | `1.2.6` |
| [lightningcss-darwin-arm64](https://github.com/parcel-bundler/lightningcss) | `1.28.2` | `1.29.1` |
| [lightningcss-linux-arm64-gnu](https://github.com/parcel-bundler/lightningcss) | `1.28.2` | `1.29.1` |
| [lightningcss-linux-x64-gnu](https://github.com/parcel-bundler/lightningcss) | `1.28.2` | `1.29.1` |
| [@swc/core-darwin-arm64](https://github.com/swc-project/swc) | `1.10.1` | `1.11.5` |
| [@swc/core-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.10.1` | `1.11.5` |
| [@swc/core-linux-x64-gnu](https://github.com/swc-project/swc) | `1.10.1` | `1.11.5` |
| [@swc/html-darwin-arm64](https://github.com/swc-project/swc) | `1.10.1` | `1.11.5` |
| [@swc/html-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.10.1` | `1.11.5` |
| [@swc/html-linux-x64-gnu](https://github.com/swc-project/swc) | `1.10.1` | `1.11.5` |


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

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

Updates `lightningcss-darwin-arm64` from 1.28.2 to 1.29.1
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/commits)

Updates `lightningcss-linux-arm64-gnu` from 1.28.2 to 1.29.1
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/commits)

Updates `lightningcss-linux-x64-gnu` from 1.28.2 to 1.29.1
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/commits)

Updates `@swc/core-darwin-arm64` from 1.10.1 to 1.11.5
- [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.10.1...v1.11.5)

Updates `@swc/core-linux-arm64-gnu` from 1.10.1 to 1.11.5
- [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.10.1...v1.11.5)

Updates `@swc/core-linux-x64-gnu` from 1.10.1 to 1.11.5
- [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.10.1...v1.11.5)

Updates `@swc/html-darwin-arm64` from 1.10.1 to 1.11.5
- [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.10.1...v1.11.5)

Updates `@swc/html-linux-arm64-gnu` from 1.10.1 to 1.11.5
- [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.10.1...v1.11.5)

Updates `@swc/html-linux-x64-gnu` from 1.10.1 to 1.11.5
- [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.10.1...v1.11.5)

---
updated-dependencies:
- dependency-name: "@rspack/binding-linux-arm64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@rspack/binding-linux-x64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: lightningcss-darwin-arm64
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: lightningcss-linux-arm64-gnu
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: lightningcss-linux-x64-gnu
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/core-darwin-arm64"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/html-darwin-arm64"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/html-linux-arm64-gnu"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/html-linux-x64-gnu"
  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-03-03 14:31:07 +00:00
37511f07a0 ci: bump getsentry/action-release from 1 to 3 (#13366)
Bumps [getsentry/action-release](https://github.com/getsentry/action-release) from 1 to 3.
- [Release notes](https://github.com/getsentry/action-release/releases)
- [Changelog](https://github.com/getsentry/action-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/action-release/compare/v1...v3)

---
updated-dependencies:
- dependency-name: getsentry/action-release
  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-03-03 13:30:05 +00:00
7840a3b52a website: bump @rspack/binding-darwin-arm64 from 1.1.6 to 1.2.6 in /website (#13354)
* website: bump @rspack/binding-darwin-arm64 in /website

Bumps [@rspack/binding-darwin-arm64](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) from 1.1.6 to 1.2.6.
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.2.6/packages/rspack)

---
updated-dependencies:
- dependency-name: "@rspack/binding-darwin-arm64"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

* group it

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-03-03 13:25:09 +00:00
787e9e05e4 core, web: update translations (#13346)
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-03-03 13:22:51 +00:00
3c14b8931f translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13348)
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-03-03 13:22:27 +00:00
e3f1d259cf translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13347)
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-03-03 13:22:11 +00:00
3d981f9391 translate: Updates for file web/xliff/en.xlf in zh-Hans (#13349)
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-03-03 13:21:41 +00:00
ba1c919781 translate: Updates for file web/xliff/en.xlf in zh_CN (#13350)
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-03-03 13:21:28 +00:00
38696d4bd9 ci: update versions for daily full testing (#13303)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-03-03 13:18:20 +00:00
7213a1f27a website: bump prettier from 3.5.2 to 3.5.3 in /website (#13355)
Bumps [prettier](https://github.com/prettier/prettier) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.5.2...3.5.3)

---
updated-dependencies:
- dependency-name: prettier
  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-03-03 13:13:59 +00:00
34b5a51990 core: bump ruff from 0.9.8 to 0.9.9 (#13359)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.9.8 to 0.9.9.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.8...0.9.9)

---
updated-dependencies:
- dependency-name: ruff
  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-03-03 13:13:49 +00:00
79e779b339 ci: bump docker/setup-qemu-action from 3.5.0 to 3.6.0 (#13360)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3.5.0...v3.6.0)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  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-03-03 13:13:18 +00:00
2a35b13ad6 core: bump cryptography from 44.0.1 to 44.0.2 (#13361)
Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.1 to 44.0.2.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/44.0.1...44.0.2)

---
updated-dependencies:
- dependency-name: cryptography
  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-03-03 13:13:07 +00:00
3754f27275 core: bump pytest from 8.3.4 to 8.3.5 (#13362)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.4 to 8.3.5.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.4...8.3.5)

---
updated-dependencies:
- dependency-name: pytest
  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-03-03 13:12:47 +00:00
b0547844b9 core: bump goauthentik.io/api/v3 from 3.2025021.1 to 3.2025021.2 (#13363)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2025021.1 to 3.2025021.2.
- [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.2025021.1...v3.2025021.2)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  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-03-03 13:12:19 +00:00
1b5abd3a3a core, web: update translations (#13339)
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-03-02 19:16:42 +00:00
8244c2340a web: bump API Client version (#13336)
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-03-01 19:47:35 +00:00
28080595d0 core, web: update translations (#13328)
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-03-01 19:47:07 +00:00
3999aa96fb stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#13330)
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-03-01 19:46:11 +00:00
b5a8957720 lib/sync/outgoing: add dry run (#13244)
* lib/sync/outgoing: add dry run

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

* add option to temporarily override dry run

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

* web a

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

* web b

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

* format

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

* add some test

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

* add more tests

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

* add dry run label

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

* add support for entra too

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

* add web

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

* add entra test and improve error handling

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-03-01 19:44:17 +00:00
9b01213990 website: bump remark-directive from 3.0.1 to 4.0.0 in /website (#13315)
Bumps [remark-directive](https://github.com/remarkjs/remark-directive) from 3.0.1 to 4.0.0.
- [Release notes](https://github.com/remarkjs/remark-directive/releases)
- [Commits](https://github.com/remarkjs/remark-directive/compare/3.0.1...4.0.0)

---
updated-dependencies:
- dependency-name: remark-directive
  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-03-01 19:43:01 +00:00
ae64d9f0fd *: fix stage incorrectly being inserted instead of appended (#13304)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-28 22:53:10 +00:00
ea55083929 enterprise/stages/source: fix dispatch method signature (#13321)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-28 21:43:05 +00:00
786c38b4cc website: Revert "website: revert enable docusaurus faster option (#12326) (#13207)" (#13323)
Revert "website: revert enable docusaurus faster option (#12326) (#13207)"

This reverts commit f2e1b6d466.
2025-02-28 21:34:43 +00:00
60521d89cb website/docs: enterprise: add instructions to cancel license renewal (#13320)
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-02-28 11:05:31 -06:00
7e7fc75e77 providers/oauth2: properly support P-384 and P-521 keys (#13317)
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-02-28 16:50:14 +01:00
d0d46299d2 core: bump aws-cdk-lib from 2.181.0 to 2.181.1 (#13313)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-28 13:01:57 +01:00
e025eabdef core: bump ruff from 0.9.7 to 0.9.8 (#13312)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-28 13:01:47 +01:00
44238e6372 core: bump goauthentik.io/api/v3 from 3.2025020.1 to 3.2025021.1 (#13314)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-28 12:37:21 +01:00
be986c8474 core, web: update translations (#13311)
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-02-28 12:20:21 +01:00
afb3623622 website/integrations: Add documentation for Drupal (#12925)
* Add documentation for Drupal

* Alter headings

* address feedback

* address feedback

* address feedback

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Sally Young <github@justa.fish>

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Sally Young <github@justa.fish>

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Sally Young <github@justa.fish>

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Sally Young <github@justa.fish>

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Sally Young <github@justa.fish>

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Sally Young <github@justa.fish>

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

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Sally Young <github@justa.fish>

* address feedback

* address feedback and fix tests

---------

Signed-off-by: Sally Young <github@justa.fish>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-02-28 01:30:42 -06:00
5eb6d62c9c web: ESBuild performance + Live reload (#13026)
* web: Silence ESBuild warning.

* web: Flesh out live reload. Tidy ESBuild.

---------

Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2025-02-27 18:35:56 +01:00
2c802cad63 ci: translation extraction: make sure API client is up-to-date (#13301)
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-02-27 16:44:33 +00:00
c24fd618f5 website/integrations: fix netbox env variables (#13267)
Update index.md

I updated SOCIAL_AUTH_OIDC_SCOPE so it can dynamically be updated in Docker vs authentik.py.  

SOCIAL_AUTH_OIDC_ENDPOINT needs to be SOCIAL_AUTH_OIDC_OIDC_ENDPOINT.  I found the correct variable in venv/lib/python3.12/site-packages/social_core/backends/open_id_connect.py.

Signed-off-by: dustindkoch <63759985+dustindkoch@users.noreply.github.com>
2025-02-27 05:59:57 -06:00
c36434bfc8 *: Auto compress images (#13250)
[create-pull-request] automated change

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: tanberry <9368837+tanberry@users.noreply.github.com>
2025-02-27 11:34:30 +00:00
1751d0ce17 core: bump msgraph-sdk from 1.21.0 to 1.22.0 (#13259)
Bumps [msgraph-sdk](https://github.com/microsoftgraph/msgraph-sdk-python) from 1.21.0 to 1.22.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.21.0...v1.22.0)

---
updated-dependencies:
- dependency-name: msgraph-sdk
  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-02-27 11:31:28 +00:00
7c386da474 core: bump google-api-python-client from 2.161.0 to 2.162.0 (#13260)
Bumps [google-api-python-client](https://github.com/googleapis/google-api-python-client) from 2.161.0 to 2.162.0.
- [Release notes](https://github.com/googleapis/google-api-python-client/releases)
- [Commits](https://github.com/googleapis/google-api-python-client/compare/v2.161.0...v2.162.0)

---
updated-dependencies:
- dependency-name: google-api-python-client
  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-02-27 11:31:18 +00:00
b8112de172 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13293)
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-02-27 11:22:13 +00:00
a2644ca865 core: bump aws-cdk-lib from 2.180.0 to 2.181.0 (#13284)
Bumps [aws-cdk-lib](https://github.com/aws/aws-cdk) from 2.180.0 to 2.181.0.
- [Release notes](https://github.com/aws/aws-cdk/releases)
- [Changelog](https://github.com/aws/aws-cdk/blob/main/CHANGELOG.v2.md)
- [Commits](https://github.com/aws/aws-cdk/compare/v2.180.0...v2.181.0)

---
updated-dependencies:
- dependency-name: aws-cdk-lib
  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-02-27 11:21:57 +00:00
a036513669 core, web: update translations (#13282)
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-02-27 11:21:11 +00:00
44809b8d26 lifecycle/aws: bump aws-cdk from 2.1000.3 to 2.1001.0 in /lifecycle/aws (#13283)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1000.3 to 2.1001.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1001.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  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-02-27 11:21:02 +00:00
73b21a01d1 ci: bump docker/setup-qemu-action from 3.4.0 to 3.5.0 (#13287)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3.4.0...v3.5.0)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  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-02-27 11:20:55 +00:00
1e66a23172 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13290)
* Translate locale/en/LC_MESSAGES/django.po in zh_CN

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

* Translate locale/en/LC_MESSAGES/django.po in zh_CN

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

* 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-02-27 11:20:26 +00:00
44c50157b7 translate: Updates for file web/xliff/en.xlf in zh_CN (#13291)
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-02-27 11:19:36 +00:00
ab631e6d9b translate: Updates for file web/xliff/en.xlf in zh-Hans (#13292)
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-02-27 11:19:26 +00:00
043e57ab2b web: bump API Client version (#13295)
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-02-27 11:13:47 +00:00
989d39b154 release: 2025.2.1 (#13278) 2025-02-27 10:55:18 +00:00
1ed6999994 website/docs: Fix Docusaurus plugin regression in Algolia search (#13281)
website/docs: Fix Docusaurus plugin regression.

- Introduced via https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/issues/1096
2025-02-26 22:39:32 +00:00
3bc8dd40d5 website/docs: prepare for 2025.2.1 (#13277) 2025-02-26 20:14:56 +00:00
802d6a548c translate: Updates for file web/xliff/en.xlf in fr (#13275)
* Translate web/xliff/en.xlf in fr

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

* 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-02-26 19:56:18 +00:00
f82c6eda58 translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13274)
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-02-26 19:51:17 +00:00
05cc64c434 stages/email: Fix email stage serialization (#13256)
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-02-26 19:30:48 +00:00
a22b558143 stages/authenticator_email: fix session cleanup test b (#13264) 2025-02-26 20:09:39 +01:00
bb2b6d163b website/docs: remove Enterprise badge from RAC docs -- again (#13268)
remove Enterprise badge from RAC docs

Again. Changes conflicted in d5572a2570 and a714c781a6.
2025-02-26 17:01:10 +01:00
199a2ff11a ci: fix translation extraction for external PRs (#13266) 2025-02-26 13:17:15 +00:00
cc0659168d website/docs: add enterprise label to SSF docs (#13251)
* added Enterprise label

* fix date to be semantic version

* added Ent label, for real this time

* add Ent to procedural page too

---------

Co-authored-by: Tana M Berry <tana@goauthentik.com>
2025-02-25 18:43:39 +01:00
805332061b website/integrations: add plesk (#13000)
* website: add plesk integration

* fix: pr feedback

* fix: pr feedback

* fix: pr feedback
2025-02-25 09:11:31 -06:00
aa340fbfe0 core: add pre-hydrated relative URL (#13243)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-25 10:05:34 +01:00
91572b8621 lifecycle: add warning regarding supported installation methods (#13190)
* wip

* wip

* wip

* Apply suggestions from code review

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

---------

Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Jens L. <jens@beryju.org>
2025-02-25 09:25:22 +01:00
080d31f189 ci: run translation extraction on PRs too (#13214) 2025-02-25 09:23:46 +01:00
15b59594e2 core: bump golang.org/x/oauth2 from 0.26.0 to 0.27.0 (#13240)
* core: bump golang.org/x/oauth2 from 0.26.0 to 0.27.0

Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

* tidy

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-02-25 08:33:32 +01:00
b4e295a14a web/admin: fix minor typo (#13181)
Fix typo

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-25 07:48:04 +01:00
b590b6be44 core: bump github.com/go-jose/go-jose/v4 from 4.0.2 to 4.0.5 (#13235)
Bumps [github.com/go-jose/go-jose/v4](https://github.com/go-jose/go-jose) from 4.0.2 to 4.0.5.
- [Release notes](https://github.com/go-jose/go-jose/releases)
- [Changelog](https://github.com/go-jose/go-jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-jose/go-jose/compare/v4.0.2...v4.0.5)

---
updated-dependencies:
- dependency-name: github.com/go-jose/go-jose/v4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 07:47:11 +01:00
15ee3d3566 core, web: update translations (#13236)
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-02-25 07:47:01 +01:00
aea6c7adbe lifecycle/aws: bump aws-cdk from 2.1000.2 to 2.1000.3 in /lifecycle/aws (#13239)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1000.2 to 2.1000.3.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1000.3/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  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-02-25 07:46:15 +01:00
42a2337200 core: bump goauthentik.io/api/v3 from 3.2024123.7 to 3.2025020.1 (#13241)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2024123.7 to 3.2025020.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.2024123.7...v3.2025020.1)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  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-02-25 07:46:03 +01:00
ffdd49e176 website: remove images from integrations index page (#12897)
* remove img

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

* Delete website/integrations/sources-logo.png

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

* Delete website/integrations/apps-logo.png

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

---------

Signed-off-by: Dominic R <dominic@sdko.org>
2025-02-24 13:06:56 -06:00
b41231141c web: bump API Client version (#13226)
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-02-24 18:42:08 +01:00
88d3b7f5a4 website/docs: Add Passkeys reference where WebAuthn is mentioned (#13167)
* Add Passkeys reference in several parts where WebAuthn is mentioned for better docs UX and SEO)

* Add version badge to Webauthn / passkeys authenticator

* fix linting issues

* Better wording to differenciate concepts

* Revert to css class for version badge because the ak-version tag don't support versions=<2023
2025-02-24 14:41:08 -03:00
2b39748c84 root: Backport version 2025.2 (#13225)
* release: 2025.2.0-rc1

* release: 2025.2.0-rc2

* release: 2025.2.0-rc3

* release: 2025.2.0
2025-02-24 18:35:13 +01:00
93b93517be website/docs: fix missing breaking entry for 2025.2 release notes (#13223)
* website/docs: fix missing breaking entry for 2025.2 release notes

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

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

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-02-24 16:46:58 +01:00
6da55dc8aa website/docs: update the 2025.2 rel notes (#13213)
* removed rc notice, added links to docs

* remved todo about SSF preview banner

* update sidebar and security

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

* add api diff

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

* fix format

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

* fix link

* bolded H3s

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Tana M Berry <tana@goauthentik.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-02-24 16:01:31 +01:00
b93dc48030 core: bump aws-cdk-lib from 2.179.0 to 2.180.0 (#13204)
Bumps [aws-cdk-lib](https://github.com/aws/aws-cdk) from 2.179.0 to 2.180.0.
- [Release notes](https://github.com/aws/aws-cdk/releases)
- [Changelog](https://github.com/aws/aws-cdk/blob/main/CHANGELOG.v2.md)
- [Commits](https://github.com/aws/aws-cdk/compare/v2.179.0...v2.180.0)

---
updated-dependencies:
- dependency-name: aws-cdk-lib
  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-02-24 15:35:08 +01:00
7aba4b0c01 website/docs: add paragraph about impossible travel (#13125)
* drafty draft

* polish

* tweak

* redraft with new knowledge

* more facts, less fiction

* polish

* tweak to bump build

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

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
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.com>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2025-02-24 13:41:47 +00:00
d5572a2570 website/docs: remove Enterprise badge from RAC docs (#13069)
remove Enterprise badge from RAC docs

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

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-02-24 12:58:37 +00:00
55b1ddff6e website/docs: remove mention of wizard (#13126)
* first pass at removing wizard

* missed one

* Replaced the word modal wth the word box or simply rewrote to avoid saying modal.

* typo

---------

Co-authored-by: Tana M Berry <tana@goauthentik.com>
2025-02-24 06:54:42 -06:00
77c913bfd3 stages/authenticator_email: Email Authenticator Stage Documentation (#12853)
* stages/authenticator_email: Add initial documentation for Email Authenticator Stage

* fix linting/styling

* Apply suggestions from code review

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

* Apply suggestions from code review

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

* rearranged to match the UI

* fix my broken links

* Tweak Emil Authenticator stage, also capitalize names of other stages

* final tweaks

* Add authenticator_validate for Email Authenticator in authenticator_validate documentation

* add version badge

* Fix broken links (.md -> .mdx)

---------

Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tana@goauthentik.com>
2025-02-24 06:54:06 -06:00
69b80e5bb5 website/docs: add info about new perms for super-user in groups (#13188)
* try again

* Update website/docs/users-sources/groups/manage_groups.mdx

Co-authored-by: Jens L. <jens@goauthentik.io>
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.com>
Co-authored-by: Jens L. <jens@goauthentik.io>
2025-02-24 06:33:25 -06:00
ba63399a7b website/docs: add new SSF provider docs (#13102)
* website/docs/add-secure-apps/providers/sff/index.md

* draft

* dir name

* added procedural

* first draft for review

* tweak

* tweak

* backchannel info

* tweak

* edits form Ken and Dominic

* not sure

* tweak to rebuild

* tweak

* added finishing sentence

* tweaks

* typos

---------

Co-authored-by: Tana M Berry <tana@goauthentik.com>
2025-02-24 06:32:32 -06:00
86893d83b8 website/docs: updated debugging docs (#12809)
* lifecycle: much improved debugging experience

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

* Optimised images with calibre/image-actions

* start documenting container debugging

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

* add user: root

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

* update example override file

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

* update env var

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

* Apply suggestions from code review

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

* fix

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-02-24 06:17:46 -06:00
85ab201803 web/user: fix display for RAC tile (#13211)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-24 12:18:07 +01:00
2c96b24b62 web/flow: fix translate extract (#13208)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-24 11:48:40 +01:00
1f2cbca833 website: bump prettier from 3.5.1 to 3.5.2 in /website (#13192)
Bumps [prettier](https://github.com/prettier/prettier) from 3.5.1 to 3.5.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.5.1...3.5.2)

---
updated-dependencies:
- dependency-name: prettier
  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-02-24 09:55:54 +01:00
c2db998041 core: bump setproctitle from 1.3.4 to 1.3.5 (#13202)
Bumps [setproctitle](https://github.com/dvarrazzo/py-setproctitle) from 1.3.4 to 1.3.5.
- [Changelog](https://github.com/dvarrazzo/py-setproctitle/blob/master/HISTORY.rst)
- [Commits](https://github.com/dvarrazzo/py-setproctitle/compare/version-1.3.4...version-1.3.5)

---
updated-dependencies:
- dependency-name: setproctitle
  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-02-24 09:55:18 +01:00
18a70e93a1 core: bump psycopg from 3.2.4 to 3.2.5 (#13203)
Bumps [psycopg](https://github.com/psycopg/psycopg) from 3.2.4 to 3.2.5.
- [Changelog](https://github.com/psycopg/psycopg/blob/master/docs/news.rst)
- [Commits](https://github.com/psycopg/psycopg/compare/3.2.4...3.2.5)

---
updated-dependencies:
- dependency-name: psycopg
  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-02-24 09:55:08 +01:00
3123b3ac5e core: bump github.com/redis/go-redis/v9 from 9.7.0 to 9.7.1 (#13205)
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.7.0 to 9.7.1.
- [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.0...v9.7.1)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  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-02-24 09:52:19 +01:00
f2e1b6d466 website: revert enable docusaurus faster option (#12326) (#13207)
Revert "website: enable docusaurus faster option (#12326)"

This reverts commit 46303cc59f.
2025-02-24 09:34:06 +01:00
6bcacd744b core: add darkreader-lock (#13183)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-23 04:22:29 +01:00
e5af964d9d web/admin: fix default selection for binding policy (#13180)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-23 04:05:36 +01:00
122b95197b web/flows: disambiguate brand links codeblock (#12141)
* 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.

* web/legible/disambiguate-footer-links

# What

- Replaces the "brand links" box at the bottom of FlowExecutor with a component for showing brand
  links.

# Why

- Confusion arose about what "footer links" mean in any given context, and breaking this out,
  labeling it "brand-links," reduces that confusion. It also isolates and reduces the testable
  surface area of the Executor.

* rename

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

* simplify

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-02-23 01:26:29 +01:00
8d4e7f5d55 web/flow: grab focus to uid input field (#13177)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-23 00:29:31 +01:00
9d32ba261a web/flow: update default flow background (#13175)
* web/flow: update default flow background

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

* Optimised images with calibre/image-actions

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-02-22 23:23:01 +01:00
b5a9b645f4 website/docs: fix typo (#13174)
The sentence is broken; fixing typo to clarify that a secure connection is established *before* an LDAP bind.

Signed-off-by: klmmr <35450576+klmmr@users.noreply.github.com>
2025-02-22 23:22:27 +01:00
46303cc59f website: enable docusaurus faster option (#12326)
* website: enable docusaurus faster option

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

* fix build failing in CI

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

* fix lightningcss

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

* fix swc...sigh

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

* fix swc again

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-22 22:00:56 +01:00
4af415f3fd web/user: fix race condition in user settings flow executor (#13163)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-21 20:35:54 +01:00
ef82143811 web/admin: only show message when not editing an application (#13165)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-21 20:35:33 +01:00
c7567e031a root: allow configuring session cookie age (#12389) 2025-02-21 18:21:35 +00:00
3b2cd9e8d6 ci: update poetry sync command (#13161) 2025-02-21 18:19:18 +00:00
261e18b3d6 web/user: fix RAC launch not opening when clicking icon (#13164)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-21 19:18:41 +01:00
51a0f7d314 website/docs: troubleshooting: fix missing command prefix for create admin group command in Docker (#13107) 2025-02-21 18:47:30 +01:00
041ffef812 website: bump disqus-react from 1.1.5 to 1.1.6 in /website (#13152)
Bumps [disqus-react](https://github.com/disqus/disqus-react) from 1.1.5 to 1.1.6.
- [Release notes](https://github.com/disqus/disqus-react/releases)
- [Changelog](https://github.com/disqus/disqus-react/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/disqus/disqus-react/compare/v1.1.5...v1.1.6)

---
updated-dependencies:
- dependency-name: disqus-react
  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-02-21 17:47:30 +01:00
68b4d58ebd website: bump docusaurus-theme-openapi-docs from 4.3.4 to 4.3.5 in /website (#13154)
website: bump docusaurus-theme-openapi-docs in /website

Bumps [docusaurus-theme-openapi-docs](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/tree/HEAD/packages/docusaurus-theme-openapi-docs) from 4.3.4 to 4.3.5.
- [Release notes](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/releases)
- [Changelog](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/commits/v4.3.5/packages/docusaurus-theme-openapi-docs)

---
updated-dependencies:
- dependency-name: docusaurus-theme-openapi-docs
  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-02-21 17:30:49 +01:00
881571bd14 core: bump ruff from 0.9.6 to 0.9.7 (#13150)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.9.6 to 0.9.7.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.6...0.9.7)

---
updated-dependencies:
- dependency-name: ruff
  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-02-21 17:18:01 +01:00
64a0f66e62 core: bump twilio from 9.4.5 to 9.4.6 (#13151)
Bumps [twilio](https://github.com/twilio/twilio-python) from 9.4.5 to 9.4.6.
- [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.4.5...9.4.6)

---
updated-dependencies:
- dependency-name: twilio
  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-02-21 17:17:46 +01:00
7d5cda4c25 website: bump docusaurus-plugin-openapi-docs from 4.3.4 to 4.3.5 in /website (#13153)
website: bump docusaurus-plugin-openapi-docs in /website

Bumps [docusaurus-plugin-openapi-docs](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/tree/HEAD/packages/docusaurus-plugin-openapi-docs) from 4.3.4 to 4.3.5.
- [Release notes](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/releases)
- [Changelog](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/commits/v4.3.5/packages/docusaurus-plugin-openapi-docs)

---
updated-dependencies:
- dependency-name: docusaurus-plugin-openapi-docs
  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-02-21 17:17:26 +01:00
8ba2679036 core: bump selenium from 4.28.1 to 4.29.0 (#13155)
Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.28.1 to 4.29.0.
- [Release notes](https://github.com/SeleniumHQ/Selenium/releases)
- [Commits](https://github.com/SeleniumHQ/Selenium/commits/selenium-4.29.0)

---
updated-dependencies:
- dependency-name: selenium
  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-02-21 17:17:07 +01:00
d98523f243 web/user: fix post MFA creation link being invalid (#13157)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-21 16:43:01 +01:00
6da0548fa2 scripts: fix broken link (#13156)
fix broken link
2025-02-21 12:51:51 +01:00
8734710e61 website: bump semver from 7.7.0 to 7.7.1 in /website (#13129)
Bumps [semver](https://github.com/npm/node-semver) from 7.7.0 to 7.7.1.
- [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.0...v7.7.1)

---
updated-dependencies:
- dependency-name: semver
  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-02-21 01:02:47 +01:00
64b996aa1f website: bump postcss from 8.5.2 to 8.5.3 in /website (#13130)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.2 to 8.5.3.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.2...8.5.3)

---
updated-dependencies:
- dependency-name: postcss
  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-02-21 01:02:37 +01:00
dbe91cbc55 core: bump kubernetes from 32.0.0 to 32.0.1 (#13131)
Bumps [kubernetes](https://github.com/kubernetes-client/python) from 32.0.0 to 32.0.1.
- [Release notes](https://github.com/kubernetes-client/python/releases)
- [Changelog](https://github.com/kubernetes-client/python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes-client/python/compare/v32.0.0...v32.0.1)

---
updated-dependencies:
- dependency-name: kubernetes
  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-02-21 01:02:28 +01:00
a56e037eae core: bump duo-client from 5.3.0 to 5.4.0 (#13132)
Bumps [duo-client](https://github.com/duosecurity/duo_client_python) from 5.3.0 to 5.4.0.
- [Release notes](https://github.com/duosecurity/duo_client_python/releases)
- [Commits](https://github.com/duosecurity/duo_client_python/compare/5.3.0...5.4.0)

---
updated-dependencies:
- dependency-name: duo-client
  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-02-21 01:02:20 +01:00
b8f1e2fac0 lifecycle/aws: bump aws-cdk from 2.179.0 to 2.1000.2 in /lifecycle/aws (#13133)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.179.0 to 2.1000.2.
- [Commits](https://github.com/aws/aws-cdk-cli/commits/HEAD/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  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-02-21 01:02:07 +01:00
e1b56aac05 core: bump goauthentik.io/api/v3 from 3.2024123.6 to 3.2024123.7 (#13134)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2024123.6 to 3.2024123.7.
- [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.2024123.6...v3.2024123.7)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  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-02-21 01:01:58 +01:00
794731eed7 core: bump github.com/prometheus/client_golang from 1.20.5 to 1.21.0 (#13135)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.5 to 1.21.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.5...v1.21.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  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-02-21 01:01:25 +01:00
19fbc2a022 enterprise/stages/source: fix Source stage not executing authentication/enrollment flow (#12875)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-20 23:27:08 +01:00
38e467bf8e policies/geoip: fix math in impossible travel (#13141)
* policies/geoip: fix math in impossible travel

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

* fix threshold

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-20 23:26:26 +01:00
9e32cf361b core: bump zxcvbn from 4.4.28 to 4.5.0 (#13128)
Bumps [zxcvbn](https://github.com/dwolfhub/zxcvbn-python) from 4.4.28 to 4.5.0.
- [Changelog](https://github.com/dwolfhub/zxcvbn-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/dwolfhub/zxcvbn-python/compare/v4.4.28...v4.5.0)

---
updated-dependencies:
- dependency-name: zxcvbn
  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-02-20 16:14:55 +01:00
42a5a43640 revert: rbac: exclude permissions for internal models (#12803) (#13138)
Revert "rbac: exclude permissions for internal models (#12803)"

This reverts commit e08ccf4ca0.
2025-02-20 15:12:23 +01:00
8d5b835c4f web/flows: fix error on interactive Captcha stage when retrying captcha (#13119)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-20 15:00:57 +01:00
ca3b948895 web: Indicate when caps-lock is active during password input. (#12733)
Determining the state of the caps-lock key can be tricky as we're
dependant on a user-provided input to set a value. Thus, our initial
state defaults to not display any warning until the first keystroke.

- Revise to better use lit-html.
2025-02-19 10:38:27 -08:00
a714c781a6 website: Use Docusaurus Frontmatter for badges (#12893)
website/docs: Reduce redundant usage of badges. Move badge logic to components.

- Fix JSX class name warning.
- Remove duplicate titles.
- Flesh out `support_level` frontmatter.
2025-02-19 18:03:05 +00:00
df2e3878d5 sources/oauth: add group sync for azure_ad (#12894)
* sources/oauth: add group sync for azure_ad

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

* make group sync optional

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-19 17:57:47 +01:00
1370c32aea cmd: set version in outposts (#13116)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-02-19 17:56:57 +01:00
402 changed files with 11054 additions and 2268 deletions

View File

@ -1,16 +1,16 @@
[bumpversion] [bumpversion]
current_version = 2024.12.3 current_version = 2025.2.1
tag = True tag = True
commit = 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*))? parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
serialize = serialize =
{major}.{minor}.{patch}-{rc_t}{rc_n} {major}.{minor}.{patch}-{rc_t}{rc_n}
{major}.{minor}.{patch} {major}.{minor}.{patch}
message = release: {new_version} message = release: {new_version}
tag_name = version/{new_version} tag_name = version/{new_version}
[bumpversion:part:rc_t] [bumpversion:part:rc_t]
values = values =
rc rc
final final
optional_value = final optional_value = final

View File

@ -28,7 +28,11 @@ Output of docker-compose logs or kubectl logs respectively
**Version and Deployment (please complete the following information):** **Version and Deployment (please complete the following information):**
- authentik version: [e.g. 2021.8.5] <!--
Notice: authentik supports installation via Docker, Kubernetes, and AWS CloudFormation only. Support is not available for other methods. For detailed installation and configuration instructions, please refer to the official documentation at https://docs.goauthentik.io/docs/install-config/.
-->
- authentik version: [e.g. 2025.2.0]
- Deployment: [e.g. docker-compose, helm] - Deployment: [e.g. docker-compose, helm]
**Additional context** **Additional context**

View File

@ -20,7 +20,12 @@ Output of docker-compose logs or kubectl logs respectively
**Version and Deployment (please complete the following information):** **Version and Deployment (please complete the following information):**
- authentik version: [e.g. 2021.8.5] <!--
Notice: authentik supports installation via Docker, Kubernetes, and AWS CloudFormation only. Support is not available for other methods. For detailed installation and configuration instructions, please refer to the official documentation at https://docs.goauthentik.io/docs/install-config/.
-->
- authentik version: [e.g. 2025.2.0]
- Deployment: [e.g. docker-compose, helm] - Deployment: [e.g. docker-compose, helm]
**Additional context** **Additional context**

View File

@ -30,12 +30,16 @@ runs:
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: Setup docker cache
uses: ScribeMD/docker-cache@0.5.0
with:
key: docker-images-${{ runner.os }}-${{ hashFiles('.github/actions/setup/docker-compose.yml', 'Makefile') }}-${{ inputs.postgresql_version }}
- name: Setup dependencies - name: Setup dependencies
shell: bash shell: bash
run: | run: |
export PSQL_TAG=${{ inputs.postgresql_version }} export PSQL_TAG=${{ inputs.postgresql_version }}
docker compose -f .github/actions/setup/docker-compose.yml up -d docker compose -f .github/actions/setup/docker-compose.yml up -d
poetry install --sync poetry sync
cd web && npm ci cd web && npm ci
- name: Generate config - name: Generate config
shell: poetry run python {0} shell: poetry run python {0}

View File

@ -11,7 +11,7 @@ services:
- 5432:5432 - 5432:5432
restart: always restart: always
redis: redis:
image: docker.io/library/redis image: docker.io/library/redis:7
ports: ports:
- 6379:6379 - 6379:6379
restart: always restart: always

View File

@ -1,7 +1,32 @@
akadmin
asgi
assertIn
authentik
authn
crate
docstrings
entra
goauthentik
gunicorn
hass
jwe
jwks
keypair keypair
keypairs keypairs
hass kubernetes
warmup oidc
ontext ontext
openid
passwordless
plex
saml
scim
singed singed
assertIn slo
sso
totp
traefik
# https://github.com/codespell-project/codespell/issues/1224
upToDate
warmup
webauthn

View File

@ -82,6 +82,12 @@ updates:
docusaurus: docusaurus:
patterns: patterns:
- "@docusaurus/*" - "@docusaurus/*"
build:
patterns:
- "@swc/*"
- "swc-*"
- "lightningcss*"
- "@rspack/binding*"
- package-ecosystem: npm - package-ecosystem: npm
directory: "/lifecycle/aws" directory: "/lifecycle/aws"
schedule: schedule:

View File

@ -40,7 +40,7 @@ jobs:
attestations: write attestations: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: docker/setup-qemu-action@v3.4.0 - uses: docker/setup-qemu-action@v3.6.0
- uses: docker/setup-buildx-action@v3 - uses: docker/setup-buildx-action@v3
- name: prepare variables - name: prepare variables
uses: ./.github/actions/docker-push-variables uses: ./.github/actions/docker-push-variables

View File

@ -15,8 +15,8 @@ jobs:
matrix: matrix:
version: version:
- docs - docs
- version-2025-2
- version-2024-12 - version-2024-12
- version-2024-10
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: | - run: |

View File

@ -82,7 +82,7 @@ jobs:
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3.4.0 uses: docker/setup-qemu-action@v3.6.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: prepare variables - name: prepare variables

View File

@ -42,7 +42,7 @@ jobs:
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3.4.0 uses: docker/setup-qemu-action@v3.6.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: prepare variables - name: prepare variables
@ -186,7 +186,7 @@ jobs:
container=$(docker container create ${{ steps.ev.outputs.imageMainName }}) container=$(docker container create ${{ steps.ev.outputs.imageMainName }})
docker cp ${container}:web/ . docker cp ${container}:web/ .
- name: Create a Sentry.io release - name: Create a Sentry.io release
uses: getsentry/action-release@v1 uses: getsentry/action-release@v3
continue-on-error: true continue-on-error: true
env: env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

View File

@ -1,9 +1,13 @@
--- ---
name: authentik-backend-translate-extract-compile name: authentik-translate-extract-compile
on: on:
schedule: schedule:
- cron: "0 0 * * *" # every day at midnight - cron: "0 0 * * *" # every day at midnight
workflow_dispatch: workflow_dispatch:
pull_request:
branches:
- main
- version-*
env: env:
POSTGRES_DB: authentik POSTGRES_DB: authentik
@ -15,15 +19,21 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- id: generate_token - id: generate_token
if: ${{ github.event_name != 'pull_request' }}
uses: tibdex/github-app-token@v2 uses: tibdex/github-app-token@v2
with: with:
app_id: ${{ secrets.GH_APP_ID }} app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }} private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4 - uses: actions/checkout@v4
if: ${{ github.event_name != 'pull_request' }}
with: with:
token: ${{ steps.generate_token.outputs.token }} token: ${{ steps.generate_token.outputs.token }}
- uses: actions/checkout@v4
if: ${{ github.event_name == 'pull_request' }}
- name: Setup authentik env - name: Setup authentik env
uses: ./.github/actions/setup uses: ./.github/actions/setup
- name: Generate API
run: make gen-client-ts
- name: run extract - name: run extract
run: | run: |
poetry run make i18n-extract poetry run make i18n-extract
@ -32,6 +42,7 @@ jobs:
poetry run ak compilemessages poetry run ak compilemessages
make web-check-compile make web-check-compile
- name: Create Pull Request - name: Create Pull Request
if: ${{ github.event_name != 'pull_request' }}
uses: peter-evans/create-pull-request@v7 uses: peter-evans/create-pull-request@v7
with: with:
token: ${{ steps.generate_token.outputs.token }} token: ${{ steps.generate_token.outputs.token }}

22
.vscode/settings.json vendored
View File

@ -1,26 +1,4 @@
{ {
"cSpell.words": [
"akadmin",
"asgi",
"authentik",
"authn",
"entra",
"goauthentik",
"jwe",
"jwks",
"kubernetes",
"oidc",
"openid",
"passwordless",
"plex",
"saml",
"scim",
"slo",
"sso",
"totp",
"traefik",
"webauthn"
],
"todo-tree.tree.showCountsInTree": true, "todo-tree.tree.showCountsInTree": true,
"todo-tree.tree.showBadges": true, "todo-tree.tree.showBadges": true,
"yaml.customTags": [ "yaml.customTags": [

View File

@ -4,34 +4,17 @@
PWD = $(shell pwd) PWD = $(shell pwd)
UID = $(shell id -u) UID = $(shell id -u)
GID = $(shell id -g) GID = $(shell id -g)
NPM_VERSION = $(shell python -m scripts.npm_version) NPM_VERSION = $(shell poetry run python -m scripts.generate_semver)
PY_SOURCES = authentik tests scripts lifecycle .github PY_SOURCES = authentik tests scripts lifecycle .github
GO_SOURCES = cmd internal
WEB_SOURCES = web/src web/packages
DOCKER_IMAGE ?= "authentik:test" DOCKER_IMAGE ?= "authentik:test"
GEN_API_TS = "gen-ts-api" GEN_API_TS = "gen-ts-api"
GEN_API_PY = "gen-py-api" GEN_API_PY = "gen-py-api"
GEN_API_GO = "gen-go-api" GEN_API_GO = "gen-go-api"
pg_user := $(shell python -m authentik.lib.config postgresql.user 2>/dev/null) pg_user := $(shell poetry run python -m authentik.lib.config postgresql.user 2>/dev/null)
pg_host := $(shell python -m authentik.lib.config postgresql.host 2>/dev/null) pg_host := $(shell poetry run python -m authentik.lib.config postgresql.host 2>/dev/null)
pg_name := $(shell python -m authentik.lib.config postgresql.name 2>/dev/null) pg_name := $(shell poetry run python -m authentik.lib.config postgresql.name 2>/dev/null)
CODESPELL_ARGS = -D - -D .github/codespell-dictionary.txt \
-I .github/codespell-words.txt \
-S 'web/src/locales/**' \
-S 'website/docs/developer-docs/api/reference/**' \
-S '**/node_modules/**' \
-S '**/dist/**' \
$(PY_SOURCES) \
$(GO_SOURCES) \
$(WEB_SOURCES) \
website/src \
website/blog \
website/docs \
website/integrations \
website/src
all: lint-fix lint test gen web ## Lint, build, and test everything all: lint-fix lint test gen web ## Lint, build, and test everything
@ -49,26 +32,26 @@ go-test:
go test -timeout 0 -v -race -cover ./... go test -timeout 0 -v -race -cover ./...
test: ## Run the server tests and produce a coverage report (locally) test: ## Run the server tests and produce a coverage report (locally)
coverage run manage.py test --keepdb authentik poetry run coverage run manage.py test --keepdb authentik
coverage html poetry run coverage html
coverage report poetry run coverage report
lint-fix: lint-codespell ## Lint and automatically fix errors in the python source code. Reports spelling errors. lint-fix: lint-codespell ## Lint and automatically fix errors in the python source code. Reports spelling errors.
black $(PY_SOURCES) poetry run black $(PY_SOURCES)
ruff check --fix $(PY_SOURCES) poetry run ruff check --fix $(PY_SOURCES)
lint-codespell: ## Reports spelling errors. lint-codespell: ## Reports spelling errors.
codespell -w $(CODESPELL_ARGS) poetry run codespell -w
lint: ## Lint the python and golang sources lint: ## Lint the python and golang sources
bandit -r $(PY_SOURCES) -x web/node_modules -x tests/wdio/node_modules -x website/node_modules poetry run bandit -c pyproject.toml -r $(PY_SOURCES)
golangci-lint run -v golangci-lint run -v
core-install: core-install:
poetry install poetry install
migrate: ## Run the Authentik Django server's migrations migrate: ## Run the Authentik Django server's migrations
python -m lifecycle.migrate poetry run python -m lifecycle.migrate
i18n-extract: core-i18n-extract web-i18n-extract ## Extract strings that require translation into files to send to a translation service i18n-extract: core-i18n-extract web-i18n-extract ## Extract strings that require translation into files to send to a translation service
@ -76,7 +59,7 @@ aws-cfn:
cd lifecycle/aws && npm run aws-cfn cd lifecycle/aws && npm run aws-cfn
core-i18n-extract: core-i18n-extract:
ak makemessages \ poetry run ak makemessages \
--add-location file \ --add-location file \
--no-obsolete \ --no-obsolete \
--ignore web \ --ignore web \
@ -107,11 +90,11 @@ gen-build: ## Extract the schema from the database
AUTHENTIK_DEBUG=true \ AUTHENTIK_DEBUG=true \
AUTHENTIK_TENANTS__ENABLED=true \ AUTHENTIK_TENANTS__ENABLED=true \
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \ AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
ak make_blueprint_schema > blueprints/schema.json poetry run ak make_blueprint_schema > blueprints/schema.json
AUTHENTIK_DEBUG=true \ AUTHENTIK_DEBUG=true \
AUTHENTIK_TENANTS__ENABLED=true \ AUTHENTIK_TENANTS__ENABLED=true \
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \ AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
ak spectacular --file schema.yml poetry run ak spectacular --file schema.yml
gen-changelog: ## (Release) generate the changelog based from the commits since the last tag gen-changelog: ## (Release) generate the changelog based from the commits since the last tag
git log --pretty=format:" - %s" $(shell git describe --tags $(shell git rev-list --tags --max-count=1))...$(shell git branch --show-current) | sort > changelog.md git log --pretty=format:" - %s" $(shell git describe --tags $(shell git rev-list --tags --max-count=1))...$(shell git branch --show-current) | sort > changelog.md
@ -190,7 +173,7 @@ gen-client-go: gen-clean-go ## Build and install the authentik API for Golang
rm -rf ./${GEN_API_GO}/config.yaml ./${GEN_API_GO}/templates/ rm -rf ./${GEN_API_GO}/config.yaml ./${GEN_API_GO}/templates/
gen-dev-config: ## Generate a local development config file gen-dev-config: ## Generate a local development config file
python -m scripts.generate_config poetry run scripts/generate_config.py
gen: gen-build gen-client-ts gen: gen-build gen-client-ts
@ -271,21 +254,21 @@ ci--meta-debug:
node --version node --version
ci-black: ci--meta-debug ci-black: ci--meta-debug
black --check $(PY_SOURCES) poetry run black --check $(PY_SOURCES)
ci-ruff: ci--meta-debug ci-ruff: ci--meta-debug
ruff check $(PY_SOURCES) poetry run ruff check $(PY_SOURCES)
ci-codespell: ci--meta-debug ci-codespell: ci--meta-debug
codespell $(CODESPELL_ARGS) -s poetry run codespell -s
ci-bandit: ci--meta-debug ci-bandit: ci--meta-debug
bandit -r $(PY_SOURCES) poetry run bandit -r $(PY_SOURCES)
ci-pending-migrations: ci--meta-debug ci-pending-migrations: ci--meta-debug
ak makemigrations --check poetry run ak makemigrations --check
ci-test: ci--meta-debug ci-test: ci--meta-debug
coverage run manage.py test --keepdb --randomly-seed ${CI_TEST_SEED} authentik poetry run coverage run manage.py test --keepdb --randomly-seed ${CI_TEST_SEED} authentik
coverage report poetry run coverage report
coverage xml poetry run coverage xml

View File

@ -2,7 +2,7 @@ authentik takes security very seriously. We follow the rules of [responsible di
## Independent audits and pentests ## Independent audits and pentests
We are committed to engaging in regular pentesting and security audits of authentik. Defining and adhering to a cadence of external testing ensures a stronger probability that our code base, our features, and our architecture is as secure and non-exploitable as possible. For more details about specfic audits and pentests, refer to "Audits and Certificates" in our [Security documentation](https://docs.goauthentik.io/docs/security). We are committed to engaging in regular pentesting and security audits of authentik. Defining and adhering to a cadence of external testing ensures a stronger probability that our code base, our features, and our architecture is as secure and non-exploitable as possible. For more details about specific audits and pentests, refer to "Audits and Certificates" in our [Security documentation](https://docs.goauthentik.io/docs/security).
## What authentik classifies as a CVE ## What authentik classifies as a CVE
@ -20,8 +20,8 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni
| Version | Supported | | Version | Supported |
| --------- | --------- | | --------- | --------- |
| 2024.10.x | ✅ |
| 2024.12.x | ✅ | | 2024.12.x | ✅ |
| 2025.2.x | ✅ |
## Reporting a Vulnerability ## Reporting a Vulnerability

View File

@ -2,7 +2,7 @@
from os import environ from os import environ
__version__ = "2024.12.3" __version__ = "2025.2.1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -35,8 +35,7 @@ from authentik.flows.planner import (
FlowPlanner, FlowPlanner,
) )
from authentik.flows.stage import StageView from authentik.flows.stage import StageView
from authentik.flows.views.executor import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN from authentik.flows.views.executor import NEXT_ARG_NAME, SESSION_KEY_GET
from authentik.lib.utils.urls import redirect_with_qs
from authentik.lib.views import bad_request_message from authentik.lib.views import bad_request_message
from authentik.policies.denied import AccessDeniedResponse from authentik.policies.denied import AccessDeniedResponse
from authentik.policies.utils import delete_none_values from authentik.policies.utils import delete_none_values
@ -47,8 +46,9 @@ from authentik.stages.user_write.stage import PLAN_CONTEXT_USER_PATH
LOGGER = get_logger() LOGGER = get_logger()
SESSION_KEY_OVERRIDE_FLOW_TOKEN = "authentik/flows/source_override_flow_token" # nosec
PLAN_CONTEXT_SOURCE_GROUPS = "source_groups" PLAN_CONTEXT_SOURCE_GROUPS = "source_groups"
SESSION_KEY_SOURCE_FLOW_STAGES = "authentik/flows/source_flow_stages"
SESSION_KEY_OVERRIDE_FLOW_TOKEN = "authentik/flows/source_override_flow_token" # nosec
class MessageStage(StageView): class MessageStage(StageView):
@ -219,28 +219,28 @@ class SourceFlowManager:
} }
) )
flow_context.update(self.policy_context) flow_context.update(self.policy_context)
if SESSION_KEY_OVERRIDE_FLOW_TOKEN in self.request.session:
token: FlowToken = self.request.session.get(SESSION_KEY_OVERRIDE_FLOW_TOKEN)
self._logger.info("Replacing source flow with overridden flow", flow=token.flow.slug)
plan = token.plan
plan.context[PLAN_CONTEXT_IS_RESTORED] = token
plan.context.update(flow_context)
for stage in self.get_stages_to_append(flow):
plan.append_stage(stage)
if stages:
for stage in stages:
plan.append_stage(stage)
self.request.session[SESSION_KEY_PLAN] = plan
flow_slug = token.flow.slug
token.delete()
return redirect_with_qs(
"authentik_core:if-flow",
self.request.GET,
flow_slug=flow_slug,
)
flow_context.setdefault(PLAN_CONTEXT_REDIRECT, final_redirect) flow_context.setdefault(PLAN_CONTEXT_REDIRECT, final_redirect)
if not flow: if not flow:
# We only check for the flow token here if we don't have a flow, otherwise we rely on
# SESSION_KEY_SOURCE_FLOW_STAGES to delegate the usage of this token and dynamically add
# stages that deal with this token to return to another flow
if SESSION_KEY_OVERRIDE_FLOW_TOKEN in self.request.session:
token: FlowToken = self.request.session.get(SESSION_KEY_OVERRIDE_FLOW_TOKEN)
self._logger.info(
"Replacing source flow with overridden flow", flow=token.flow.slug
)
plan = token.plan
plan.context[PLAN_CONTEXT_IS_RESTORED] = token
plan.context.update(flow_context)
for stage in self.get_stages_to_append(flow):
plan.append_stage(stage)
if stages:
for stage in stages:
plan.append_stage(stage)
redirect = plan.to_redirect(self.request, token.flow)
token.delete()
return redirect
return bad_request_message( return bad_request_message(
self.request, self.request,
_("Configured flow does not exist."), _("Configured flow does not exist."),
@ -259,6 +259,8 @@ class SourceFlowManager:
if stages: if stages:
for stage in stages: for stage in stages:
plan.append_stage(stage) plan.append_stage(stage)
for stage in self.request.session.get(SESSION_KEY_SOURCE_FLOW_STAGES, []):
plan.append_stage(stage)
return plan.to_redirect(self.request, flow) return plan.to_redirect(self.request, flow)
def handle_auth( def handle_auth(
@ -295,6 +297,8 @@ class SourceFlowManager:
# When request isn't authenticated we jump straight to auth # When request isn't authenticated we jump straight to auth
if not self.request.user.is_authenticated: if not self.request.user.is_authenticated:
return self.handle_auth(connection) return self.handle_auth(connection)
# When an override flow token exists we actually still use a flow for link
# to continue the existing flow we came from
if SESSION_KEY_OVERRIDE_FLOW_TOKEN in self.request.session: if SESSION_KEY_OVERRIDE_FLOW_TOKEN in self.request.session:
return self._prepare_flow(None, connection) return self._prepare_flow(None, connection)
connection.save() connection.save()

View File

@ -11,6 +11,7 @@
build: "{{ build }}", build: "{{ build }}",
api: { api: {
base: "{{ base_url }}", base: "{{ base_url }}",
relBase: "{{ base_url_rel }}",
}, },
}; };
window.addEventListener("DOMContentLoaded", function () { window.addEventListener("DOMContentLoaded", function () {

View File

@ -8,6 +8,8 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
{# Darkreader breaks the site regardless of theme as its not compatible with webcomponents, and we default to a dark theme based on preferred colour-scheme #}
<meta name="darkreader-lock">
<title>{% block title %}{% trans title|default:brand.branding_title %}{% endblock %}</title> <title>{% block title %}{% trans title|default:brand.branding_title %}{% endblock %}</title>
<link rel="icon" href="{{ brand.branding_favicon_url }}"> <link rel="icon" href="{{ brand.branding_favicon_url }}">
<link rel="shortcut icon" href="{{ brand.branding_favicon_url }}"> <link rel="shortcut icon" href="{{ brand.branding_favicon_url }}">

View File

@ -55,7 +55,7 @@ class RedirectToAppLaunch(View):
) )
except FlowNonApplicableException: except FlowNonApplicableException:
raise Http404 from None raise Http404 from None
plan.insert_stage(in_memory_stage(RedirectToAppStage)) plan.append_stage(in_memory_stage(RedirectToAppStage))
return plan.to_redirect(request, flow) return plan.to_redirect(request, flow)

View File

@ -53,6 +53,7 @@ class InterfaceView(TemplateView):
kwargs["build"] = get_build_hash() kwargs["build"] = get_build_hash()
kwargs["url_kwargs"] = self.kwargs kwargs["url_kwargs"] = self.kwargs
kwargs["base_url"] = self.request.build_absolute_uri(CONFIG.get("web.path", "/")) kwargs["base_url"] = self.request.build_absolute_uri(CONFIG.get("web.path", "/"))
kwargs["base_url_rel"] = CONFIG.get("web.path", "/")
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)

View File

@ -9,7 +9,7 @@ class AuthentikEnterpriseAuditConfig(EnterpriseConfig):
"""Enterprise app config""" """Enterprise app config"""
name = "authentik.enterprise.audit" name = "authentik.enterprise.audit"
label = "authentik_enterprise_audit" label = "authentik_audit"
verbose_name = "authentik Enterprise.Audit" verbose_name = "authentik Enterprise.Audit"
default = True default = True

View File

@ -0,0 +1,107 @@
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from authentik.lib.models import SerializerModel
from django.db import models
from uuid import uuid4
from authentik.core.models import Group, User
# # Names
# Lifecycle
# Access reviews
# Access lifecycle
# Governance
# Audit
# Compliance
# Lifecycle
# Lifecycle review
# Review
# Access review
# Compliance review
# X Scheduled review
# Only some objects supported?
#
# For disabling support:
# Application
# Provider
# Outpost (simply setting the list of providers to empty in the outpost itself)
# Flow
# Users
# Groups <- will get tricky
# Roles
# Sources
# Tokens (api, app_pass)
# Brands
# Outpost integrations
#
# w/o disabling support
# System Settings
# everything else
# would need to show in an audit dashboard cause not all have pages to get details
# "default" policy for objects, by default, everlasting
class AuditPolicyFailAction(models.TextChoices):
# For preview
NOTHING = "nothing"
# Disable the thing failing, HOW
DISABLE = "disable"
# Emit events
WARN = "warn"
class LifecycleRule(SerializerModel):
pass
class ReviewRule(SerializerModel):
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
# Check every 6 months, allow for daily/weekly/first of month, etc.
interval = models.TextField() # timedelta
# Preventive notification
reminder_interval = models.TextField() # timedelta
# Must be checked by these
groups = models.ManyToManyField(Group)
users = models.ManyToManyField(User)
# How many of the above must approve
required_approvals = models.IntegerField(default=1)
# How long to wait before executing fail action
grace_period = models.TextField() # timedelta
# What to do if not reviewed in time
fail_action = models.CharField(choices=AuditPolicyFailAction)
class AuditPolicyBinding(SerializerModel):
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
# Many to many ? Bind users/groups here instead of on the policy ?
policy = models.ForeignKey(AuditPolicy, on_delete=models.PROTECT)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.TextField(blank=True) # optional to apply on all objects of specific type
content_object = GenericForeignKey("content_type", "object_id")
# valid -> waiting review -> valid
# valid -> waiting review -> review overdue -> valid
# valid -> waiting review -> review overdue -> failed -> valid
# look at django-fsm or django-viewflow
status = models.TextField()
class Meta:
indexes = (
models.Index(fields=["content_type"]),
models.Index(fields=["content_type", "object_id"]),
)
class AuditHistory:
pass

View File

@ -37,6 +37,7 @@ class GoogleWorkspaceProviderSerializer(EnterpriseRequiredMixin, ProviderSeriali
"user_delete_action", "user_delete_action",
"group_delete_action", "group_delete_action",
"default_group_email_domain", "default_group_email_domain",
"dry_run",
] ]
extra_kwargs = {} extra_kwargs = {}

View File

@ -8,9 +8,10 @@ from httplib2 import HttpLib2Error, HttpLib2ErrorWithResponse
from authentik.enterprise.providers.google_workspace.models import GoogleWorkspaceProvider from authentik.enterprise.providers.google_workspace.models import GoogleWorkspaceProvider
from authentik.lib.sync.outgoing import HTTP_CONFLICT from authentik.lib.sync.outgoing import HTTP_CONFLICT
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient from authentik.lib.sync.outgoing.base import SAFE_METHODS, BaseOutgoingSyncClient
from authentik.lib.sync.outgoing.exceptions import ( from authentik.lib.sync.outgoing.exceptions import (
BadRequestSyncException, BadRequestSyncException,
DryRunRejected,
NotFoundSyncException, NotFoundSyncException,
ObjectExistsSyncException, ObjectExistsSyncException,
StopSync, StopSync,
@ -43,6 +44,8 @@ class GoogleWorkspaceSyncClient[TModel: Model, TConnection: Model, TSchema: dict
self.domains.append(domain_name) self.domains.append(domain_name)
def _request(self, request: HttpRequest): def _request(self, request: HttpRequest):
if self.provider.dry_run and request.method.upper() not in SAFE_METHODS:
raise DryRunRejected(request.uri, request.method, request.body)
try: try:
response = request.execute() response = request.execute()
except GoogleAuthError as exc: except GoogleAuthError as exc:

View File

@ -0,0 +1,24 @@
# Generated by Django 5.0.12 on 2025-02-24 19:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
(
"authentik_providers_google_workspace",
"0003_googleworkspaceprovidergroup_attributes_and_more",
),
]
operations = [
migrations.AddField(
model_name="googleworkspaceprovider",
name="dry_run",
field=models.BooleanField(
default=False,
help_text="When enabled, provider will not modify or create objects in the remote system.",
),
),
]

View File

@ -36,6 +36,7 @@ class MicrosoftEntraProviderSerializer(EnterpriseRequiredMixin, ProviderSerializ
"filter_group", "filter_group",
"user_delete_action", "user_delete_action",
"group_delete_action", "group_delete_action",
"dry_run",
] ]
extra_kwargs = {} extra_kwargs = {}

View File

@ -3,6 +3,7 @@ from collections.abc import Coroutine
from dataclasses import asdict from dataclasses import asdict
from typing import Any from typing import Any
import httpx
from azure.core.exceptions import ( from azure.core.exceptions import (
ClientAuthenticationError, ClientAuthenticationError,
ServiceRequestError, ServiceRequestError,
@ -12,6 +13,7 @@ from azure.identity.aio import ClientSecretCredential
from django.db.models import Model from django.db.models import Model
from django.http import HttpResponseBadRequest, HttpResponseNotFound from django.http import HttpResponseBadRequest, HttpResponseNotFound
from kiota_abstractions.api_error import APIError from kiota_abstractions.api_error import APIError
from kiota_abstractions.request_information import RequestInformation
from kiota_authentication_azure.azure_identity_authentication_provider import ( from kiota_authentication_azure.azure_identity_authentication_provider import (
AzureIdentityAuthenticationProvider, AzureIdentityAuthenticationProvider,
) )
@ -21,13 +23,15 @@ from msgraph.generated.models.o_data_errors.o_data_error import ODataError
from msgraph.graph_request_adapter import GraphRequestAdapter, options from msgraph.graph_request_adapter import GraphRequestAdapter, options
from msgraph.graph_service_client import GraphServiceClient from msgraph.graph_service_client import GraphServiceClient
from msgraph_core import GraphClientFactory from msgraph_core import GraphClientFactory
from opentelemetry import trace
from authentik.enterprise.providers.microsoft_entra.models import MicrosoftEntraProvider from authentik.enterprise.providers.microsoft_entra.models import MicrosoftEntraProvider
from authentik.events.utils import sanitize_item from authentik.events.utils import sanitize_item
from authentik.lib.sync.outgoing import HTTP_CONFLICT from authentik.lib.sync.outgoing import HTTP_CONFLICT
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient from authentik.lib.sync.outgoing.base import SAFE_METHODS, BaseOutgoingSyncClient
from authentik.lib.sync.outgoing.exceptions import ( from authentik.lib.sync.outgoing.exceptions import (
BadRequestSyncException, BadRequestSyncException,
DryRunRejected,
NotFoundSyncException, NotFoundSyncException,
ObjectExistsSyncException, ObjectExistsSyncException,
StopSync, StopSync,
@ -35,20 +39,24 @@ from authentik.lib.sync.outgoing.exceptions import (
) )
def get_request_adapter( class AuthentikRequestAdapter(GraphRequestAdapter):
credentials: ClientSecretCredential, scopes: list[str] | None = None def __init__(self, auth_provider, provider: MicrosoftEntraProvider, client=None):
) -> GraphRequestAdapter: super().__init__(auth_provider, client)
if scopes: self._provider = provider
auth_provider = AzureIdentityAuthenticationProvider(credentials=credentials, scopes=scopes)
else:
auth_provider = AzureIdentityAuthenticationProvider(credentials=credentials)
return GraphRequestAdapter( async def get_http_response_message(
auth_provider=auth_provider, self,
client=GraphClientFactory.create_with_default_middleware( request_info: RequestInformation,
options=options, client=KiotaClientFactory.get_default_client() parent_span: trace.Span,
), claims: str = "",
) ) -> httpx.Response:
if self._provider.dry_run and request_info.http_method.value.upper() not in SAFE_METHODS:
raise DryRunRejected(
url=request_info.url,
method=request_info.http_method.value,
body=request_info.content.decode("utf-8"),
)
return await super().get_http_response_message(request_info, parent_span, claims=claims)
class MicrosoftEntraSyncClient[TModel: Model, TConnection: Model, TSchema: dict]( class MicrosoftEntraSyncClient[TModel: Model, TConnection: Model, TSchema: dict](
@ -63,9 +71,27 @@ class MicrosoftEntraSyncClient[TModel: Model, TConnection: Model, TSchema: dict]
self.credentials = provider.microsoft_credentials() self.credentials = provider.microsoft_credentials()
self.__prefetch_domains() self.__prefetch_domains()
def get_request_adapter(
self, credentials: ClientSecretCredential, scopes: list[str] | None = None
) -> AuthentikRequestAdapter:
if scopes:
auth_provider = AzureIdentityAuthenticationProvider(
credentials=credentials, scopes=scopes
)
else:
auth_provider = AzureIdentityAuthenticationProvider(credentials=credentials)
return AuthentikRequestAdapter(
auth_provider=auth_provider,
provider=self.provider,
client=GraphClientFactory.create_with_default_middleware(
options=options, client=KiotaClientFactory.get_default_client()
),
)
@property @property
def client(self): def client(self):
return GraphServiceClient(request_adapter=get_request_adapter(**self.credentials)) return GraphServiceClient(request_adapter=self.get_request_adapter(**self.credentials))
def _request[T](self, request: Coroutine[Any, Any, T]) -> T: def _request[T](self, request: Coroutine[Any, Any, T]) -> T:
try: try:

View File

@ -0,0 +1,24 @@
# Generated by Django 5.0.12 on 2025-02-24 19:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
(
"authentik_providers_microsoft_entra",
"0002_microsoftentraprovidergroup_attributes_and_more",
),
]
operations = [
migrations.AddField(
model_name="microsoftentraprovider",
name="dry_run",
field=models.BooleanField(
default=False,
help_text="When enabled, provider will not modify or create objects in the remote system.",
),
),
]

View File

@ -32,7 +32,6 @@ class MicrosoftEntraUserTests(APITestCase):
@apply_blueprint("system/providers-microsoft-entra.yaml") @apply_blueprint("system/providers-microsoft-entra.yaml")
def setUp(self) -> None: def setUp(self) -> None:
# Delete all users and groups as the mocked HTTP responses only return one ID # Delete all users and groups as the mocked HTTP responses only return one ID
# which will cause errors with multiple users # which will cause errors with multiple users
Tenant.objects.update(avatars="none") Tenant.objects.update(avatars="none")
@ -97,6 +96,38 @@ class MicrosoftEntraUserTests(APITestCase):
self.assertFalse(Event.objects.filter(action=EventAction.SYSTEM_EXCEPTION).exists()) self.assertFalse(Event.objects.filter(action=EventAction.SYSTEM_EXCEPTION).exists())
user_create.assert_called_once() user_create.assert_called_once()
def test_user_create_dry_run(self):
"""Test user creation (dry run)"""
self.provider.dry_run = True
self.provider.save()
uid = generate_id()
with (
patch(
"authentik.enterprise.providers.microsoft_entra.models.MicrosoftEntraProvider.microsoft_credentials",
MagicMock(return_value={"credentials": self.creds}),
),
patch(
"msgraph.generated.organization.organization_request_builder.OrganizationRequestBuilder.get",
AsyncMock(
return_value=OrganizationCollectionResponse(
value=[
Organization(verified_domains=[VerifiedDomain(name="goauthentik.io")])
]
)
),
),
):
user = User.objects.create(
username=uid,
name=f"{uid} {uid}",
email=f"{uid}@goauthentik.io",
)
microsoft_user = MicrosoftEntraProviderUser.objects.filter(
provider=self.provider, user=user
).first()
self.assertIsNone(microsoft_user)
self.assertFalse(Event.objects.filter(action=EventAction.SYSTEM_EXCEPTION).exists())
def test_user_not_created(self): def test_user_not_created(self):
"""Test without property mappings, no group is created""" """Test without property mappings, no group is created"""
self.provider.property_mappings.clear() self.provider.property_mappings.clear()

View File

@ -9,13 +9,16 @@ from django.utils.timezone import now
from guardian.shortcuts import get_anonymous_user from guardian.shortcuts import get_anonymous_user
from authentik.core.models import Source, User from authentik.core.models import Source, User
from authentik.core.sources.flow_manager import SESSION_KEY_OVERRIDE_FLOW_TOKEN from authentik.core.sources.flow_manager import (
SESSION_KEY_OVERRIDE_FLOW_TOKEN,
SESSION_KEY_SOURCE_FLOW_STAGES,
)
from authentik.core.types import UILoginButton from authentik.core.types import UILoginButton
from authentik.enterprise.stages.source.models import SourceStage from authentik.enterprise.stages.source.models import SourceStage
from authentik.flows.challenge import Challenge, ChallengeResponse from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.flows.models import FlowToken from authentik.flows.models import FlowToken, in_memory_stage
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView, StageView
from authentik.lib.utils.time import timedelta_from_string from authentik.lib.utils.time import timedelta_from_string
PLAN_CONTEXT_RESUME_TOKEN = "resume_token" # nosec PLAN_CONTEXT_RESUME_TOKEN = "resume_token" # nosec
@ -49,6 +52,7 @@ class SourceStageView(ChallengeStageView):
def get_challenge(self, *args, **kwargs) -> Challenge: def get_challenge(self, *args, **kwargs) -> Challenge:
resume_token = self.create_flow_token() resume_token = self.create_flow_token()
self.request.session[SESSION_KEY_OVERRIDE_FLOW_TOKEN] = resume_token self.request.session[SESSION_KEY_OVERRIDE_FLOW_TOKEN] = resume_token
self.request.session[SESSION_KEY_SOURCE_FLOW_STAGES] = [in_memory_stage(SourceStageFinal)]
return self.login_button.challenge return self.login_button.challenge
def create_flow_token(self) -> FlowToken: def create_flow_token(self) -> FlowToken:
@ -77,3 +81,19 @@ class SourceStageView(ChallengeStageView):
def challenge_valid(self, response: ChallengeResponse) -> HttpResponse: def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
return self.executor.stage_ok() return self.executor.stage_ok()
class SourceStageFinal(StageView):
"""Dynamic stage injected in the source flow manager. This is injected in the
flow the source flow manager picks (authentication or enrollment), and will run at the end.
This stage uses the override flow token to resume execution of the initial flow the
source stage is bound to."""
def dispatch(self, *args, **kwargs):
token: FlowToken = self.request.session.get(SESSION_KEY_OVERRIDE_FLOW_TOKEN)
self.logger.info("Replacing source flow with overridden flow", flow=token.flow.slug)
plan = token.plan
plan.context[PLAN_CONTEXT_IS_RESTORED] = token
response = plan.to_redirect(self.request, token.flow)
token.delete()
return response

View File

@ -4,7 +4,8 @@ from django.urls import reverse
from authentik.core.tests.utils import create_test_flow, create_test_user from authentik.core.tests.utils import create_test_flow, create_test_user
from authentik.enterprise.stages.source.models import SourceStage from authentik.enterprise.stages.source.models import SourceStage
from authentik.flows.models import FlowDesignation, FlowStageBinding, FlowToken from authentik.enterprise.stages.source.stage import SourceStageFinal
from authentik.flows.models import FlowDesignation, FlowStageBinding, FlowToken, in_memory_stage
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, FlowPlan from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, FlowPlan
from authentik.flows.tests import FlowTestCase from authentik.flows.tests import FlowTestCase
from authentik.flows.views.executor import SESSION_KEY_PLAN from authentik.flows.views.executor import SESSION_KEY_PLAN
@ -87,6 +88,7 @@ class TestSourceStage(FlowTestCase):
self.assertIsNotNone(flow_token) self.assertIsNotNone(flow_token)
session = self.client.session session = self.client.session
plan: FlowPlan = session[SESSION_KEY_PLAN] plan: FlowPlan = session[SESSION_KEY_PLAN]
plan.insert_stage(in_memory_stage(SourceStageFinal), index=0)
plan.context[PLAN_CONTEXT_IS_RESTORED] = flow_token plan.context[PLAN_CONTEXT_IS_RESTORED] = flow_token
session[SESSION_KEY_PLAN] = plan session[SESSION_KEY_PLAN] = plan
session.save() session.save()
@ -96,4 +98,6 @@ class TestSourceStage(FlowTestCase):
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}), follow=True reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}), follow=True
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect")) self.assertStageRedirects(
response, reverse("authentik_core:if-flow", kwargs={"flow_slug": flow.slug})
)

View File

@ -76,10 +76,10 @@ class FlowPlan:
self.bindings.append(binding) self.bindings.append(binding)
self.markers.append(marker or StageMarker()) self.markers.append(marker or StageMarker())
def insert_stage(self, stage: Stage, marker: StageMarker | None = None): def insert_stage(self, stage: Stage, marker: StageMarker | None = None, index=1):
"""Insert stage into plan, as immediate next stage""" """Insert stage into plan, as immediate next stage"""
self.bindings.insert(1, FlowStageBinding(stage=stage, order=0)) self.bindings.insert(index, FlowStageBinding(stage=stage, order=0))
self.markers.insert(1, marker or StageMarker()) self.markers.insert(index, marker or StageMarker())
def redirect(self, destination: str): def redirect(self, destination: str):
"""Insert a redirect stage as next stage""" """Insert a redirect stage as next stage"""

View File

@ -282,16 +282,14 @@ class ConfigLoader:
def get_optional_int(self, path: str, default=None) -> int | None: def get_optional_int(self, path: str, default=None) -> int | None:
"""Wrapper for get that converts value into int or None if set""" """Wrapper for get that converts value into int or None if set"""
value = self.get(path, default) value = self.get(path, UNSET)
if value is UNSET: if value is UNSET:
return default return default
try: try:
return int(value) return int(value)
except (ValueError, TypeError) as exc: except (ValueError, TypeError) as exc:
if value is None or (isinstance(value, str) and value.lower() == "null"): if value is None or (isinstance(value, str) and value.lower() == "null"):
return default return None
if value is UNSET:
return default
self.log("warning", "Failed to parse config as int", path=path, exc=str(exc)) self.log("warning", "Failed to parse config as int", path=path, exc=str(exc))
return default return default
@ -372,9 +370,9 @@ def django_db_config(config: ConfigLoader | None = None) -> dict:
"sslcert": config.get("postgresql.sslcert"), "sslcert": config.get("postgresql.sslcert"),
"sslkey": config.get("postgresql.sslkey"), "sslkey": config.get("postgresql.sslkey"),
}, },
"CONN_MAX_AGE": CONFIG.get_optional_int("postgresql.conn_max_age", 0), "CONN_MAX_AGE": config.get_optional_int("postgresql.conn_max_age", 0),
"CONN_HEALTH_CHECKS": CONFIG.get_bool("postgresql.conn_health_checks", False), "CONN_HEALTH_CHECKS": config.get_bool("postgresql.conn_health_checks", False),
"DISABLE_SERVER_SIDE_CURSORS": CONFIG.get_bool( "DISABLE_SERVER_SIDE_CURSORS": config.get_bool(
"postgresql.disable_server_side_cursors", False "postgresql.disable_server_side_cursors", False
), ),
"TEST": { "TEST": {
@ -383,8 +381,8 @@ def django_db_config(config: ConfigLoader | None = None) -> dict:
} }
} }
conn_max_age = CONFIG.get_optional_int("postgresql.conn_max_age", UNSET) conn_max_age = config.get_optional_int("postgresql.conn_max_age", UNSET)
disable_server_side_cursors = CONFIG.get_bool("postgresql.disable_server_side_cursors", UNSET) disable_server_side_cursors = config.get_bool("postgresql.disable_server_side_cursors", UNSET)
if config.get_bool("postgresql.use_pgpool", False): if config.get_bool("postgresql.use_pgpool", False):
db["default"]["DISABLE_SERVER_SIDE_CURSORS"] = True db["default"]["DISABLE_SERVER_SIDE_CURSORS"] = True
if disable_server_side_cursors is not UNSET: if disable_server_side_cursors is not UNSET:

View File

@ -64,6 +64,8 @@ debugger: false
log_level: info log_level: info
session_storage: cache session_storage: cache
sessions:
unauthenticated_age: days=1
error_reporting: error_reporting:
enabled: false enabled: false

View File

@ -33,6 +33,7 @@ class SyncObjectSerializer(PassiveSerializer):
) )
) )
sync_object_id = CharField() sync_object_id = CharField()
override_dry_run = BooleanField(default=False)
class SyncObjectResultSerializer(PassiveSerializer): class SyncObjectResultSerializer(PassiveSerializer):
@ -98,6 +99,7 @@ class OutgoingSyncProviderStatusMixin:
page=1, page=1,
provider_pk=provider.pk, provider_pk=provider.pk,
pk=params.validated_data["sync_object_id"], pk=params.validated_data["sync_object_id"],
override_dry_run=params.validated_data["override_dry_run"],
).get() ).get()
return Response(SyncObjectResultSerializer(instance={"messages": res}).data) return Response(SyncObjectResultSerializer(instance={"messages": res}).data)

View File

@ -28,6 +28,14 @@ class Direction(StrEnum):
remove = "remove" remove = "remove"
SAFE_METHODS = [
"GET",
"HEAD",
"OPTIONS",
"TRACE",
]
class BaseOutgoingSyncClient[ class BaseOutgoingSyncClient[
TModel: "Model", TConnection: "Model", TSchema: dict, TProvider: "OutgoingSyncProvider" TModel: "Model", TConnection: "Model", TSchema: dict, TProvider: "OutgoingSyncProvider"
]: ]:

View File

@ -21,6 +21,22 @@ class BadRequestSyncException(BaseSyncException):
"""Exception when invalid data was sent to the remote system""" """Exception when invalid data was sent to the remote system"""
class DryRunRejected(BaseSyncException):
"""When dry_run is enabled and a provider dropped a mutating request"""
def __init__(self, url: str, method: str, body: dict):
super().__init__()
self.url = url
self.method = method
self.body = body
def __repr__(self):
return self.__str__()
def __str__(self):
return f"Dry-run rejected request: {self.method} {self.url}"
class StopSync(BaseSyncException): class StopSync(BaseSyncException):
"""Exception raised when a configuration error should stop the sync process""" """Exception raised when a configuration error should stop the sync process"""

View File

@ -1,8 +1,9 @@
from typing import Any, Self from typing import Any, Self
import pglock import pglock
from django.db import connection from django.db import connection, models
from django.db.models import Model, QuerySet, TextChoices from django.db.models import Model, QuerySet, TextChoices
from django.utils.translation import gettext_lazy as _
from authentik.core.models import Group, User from authentik.core.models import Group, User
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient
@ -18,6 +19,14 @@ class OutgoingSyncDeleteAction(TextChoices):
class OutgoingSyncProvider(Model): class OutgoingSyncProvider(Model):
"""Base abstract models for providers implementing outgoing sync"""
dry_run = models.BooleanField(
default=False,
help_text=_(
"When enabled, provider will not modify or create objects in the remote system."
),
)
class Meta: class Meta:
abstract = True abstract = True
@ -32,7 +41,7 @@ class OutgoingSyncProvider(Model):
@property @property
def sync_lock(self) -> pglock.advisory: def sync_lock(self) -> pglock.advisory:
"""Postgres lock for syncing SCIM to prevent multiple parallel syncs happening""" """Postgres lock for syncing to prevent multiple parallel syncs happening"""
return pglock.advisory( return pglock.advisory(
lock_id=f"goauthentik.io/{connection.schema_name}/providers/outgoing-sync/{str(self.pk)}", lock_id=f"goauthentik.io/{connection.schema_name}/providers/outgoing-sync/{str(self.pk)}",
timeout=0, timeout=0,

View File

@ -20,6 +20,7 @@ from authentik.lib.sync.outgoing import PAGE_SIZE, PAGE_TIMEOUT
from authentik.lib.sync.outgoing.base import Direction from authentik.lib.sync.outgoing.base import Direction
from authentik.lib.sync.outgoing.exceptions import ( from authentik.lib.sync.outgoing.exceptions import (
BadRequestSyncException, BadRequestSyncException,
DryRunRejected,
StopSync, StopSync,
TransientSyncException, TransientSyncException,
) )
@ -105,7 +106,9 @@ class SyncTasks:
return return
task.set_status(TaskStatus.SUCCESSFUL, *messages) task.set_status(TaskStatus.SUCCESSFUL, *messages)
def sync_objects(self, object_type: str, page: int, provider_pk: int, **filter): def sync_objects(
self, object_type: str, page: int, provider_pk: int, override_dry_run=False, **filter
):
_object_type = path_to_class(object_type) _object_type = path_to_class(object_type)
self.logger = get_logger().bind( self.logger = get_logger().bind(
provider_type=class_to_path(self._provider_model), provider_type=class_to_path(self._provider_model),
@ -116,6 +119,10 @@ class SyncTasks:
provider = self._provider_model.objects.filter(pk=provider_pk).first() provider = self._provider_model.objects.filter(pk=provider_pk).first()
if not provider: if not provider:
return messages return messages
# Override dry run mode if requested, however don't save the provider
# so that scheduled sync tasks still run in dry_run mode
if override_dry_run:
provider.dry_run = False
try: try:
client = provider.client_for_model(_object_type) client = provider.client_for_model(_object_type)
except TransientSyncException: except TransientSyncException:
@ -132,6 +139,22 @@ class SyncTasks:
except SkipObjectException: except SkipObjectException:
self.logger.debug("skipping object due to SkipObject", obj=obj) self.logger.debug("skipping object due to SkipObject", obj=obj)
continue continue
except DryRunRejected as exc:
messages.append(
asdict(
LogEvent(
_("Dropping mutating request due to dry run"),
log_level="info",
logger=f"{provider._meta.verbose_name}@{object_type}",
attributes={
"obj": sanitize_item(obj),
"method": exc.method,
"url": exc.url,
"body": exc.body,
},
)
)
)
except BadRequestSyncException as exc: except BadRequestSyncException as exc:
self.logger.warning("failed to sync object", exc=exc, obj=obj) self.logger.warning("failed to sync object", exc=exc, obj=obj)
messages.append( messages.append(
@ -231,8 +254,10 @@ class SyncTasks:
raise Retry() from exc raise Retry() from exc
except SkipObjectException: except SkipObjectException:
continue continue
except DryRunRejected as exc:
self.logger.info("Rejected dry-run event", exc=exc)
except StopSync as exc: except StopSync as exc:
self.logger.warning(exc, provider_pk=provider.pk) self.logger.warning("Stopping sync", exc=exc, provider_pk=provider.pk)
def sync_signal_m2m(self, group_pk: str, action: str, pk_set: list[int]): def sync_signal_m2m(self, group_pk: str, action: str, pk_set: list[int]):
self.logger = get_logger().bind( self.logger = get_logger().bind(
@ -263,5 +288,7 @@ class SyncTasks:
raise Retry() from exc raise Retry() from exc
except SkipObjectException: except SkipObjectException:
continue continue
except DryRunRejected as exc:
self.logger.info("Rejected dry-run event", exc=exc)
except StopSync as exc: except StopSync as exc:
self.logger.warning(exc, provider_pk=provider.pk) self.logger.warning("Stopping sync", exc=exc, provider_pk=provider.pk)

View File

@ -158,6 +158,18 @@ class TestConfig(TestCase):
test_obj = Test() test_obj = Test()
dumps(test_obj, indent=4, cls=AttrEncoder) dumps(test_obj, indent=4, cls=AttrEncoder)
def test_get_optional_int(self):
config = ConfigLoader()
self.assertEqual(config.get_optional_int("foo", 21), 21)
self.assertEqual(config.get_optional_int("foo"), None)
config.set("foo", "21")
self.assertEqual(config.get_optional_int("foo"), 21)
self.assertEqual(config.get_optional_int("foo", 0), 21)
self.assertEqual(config.get_optional_int("foo", "null"), 21)
config.set("foo", "null")
self.assertEqual(config.get_optional_int("foo"), None)
self.assertEqual(config.get_optional_int("foo", 21), None)
@mock.patch.dict(environ, check_deprecations_env_vars) @mock.patch.dict(environ, check_deprecations_env_vars)
def test_check_deprecations(self): def test_check_deprecations(self):
"""Test config key re-write for deprecated env vars""" """Test config key re-write for deprecated env vars"""
@ -221,6 +233,16 @@ class TestConfig(TestCase):
}, },
) )
def test_db_conn_max_age(self):
"""Test DB conn_max_age Config"""
config = ConfigLoader()
config.set("postgresql.conn_max_age", "null")
conf = django_db_config(config)
self.assertEqual(
conf["default"]["CONN_MAX_AGE"],
None,
)
def test_db_read_replicas(self): def test_db_read_replicas(self):
"""Test read replicas""" """Test read replicas"""
config = ConfigLoader() config = ConfigLoader()

View File

@ -128,7 +128,7 @@ class GeoIPPolicy(Policy):
(geoip_data["lat"], geoip_data["long"]), (geoip_data["lat"], geoip_data["long"]),
) )
if self.check_history_distance and dist.km >= ( if self.check_history_distance and dist.km >= (
self.history_max_distance_km - self.distance_tolerance_km self.history_max_distance_km + self.distance_tolerance_km
): ):
return PolicyResult( return PolicyResult(
False, _("Distance from previous authentication is larger than threshold.") False, _("Distance from previous authentication is larger than threshold.")
@ -139,7 +139,7 @@ class GeoIPPolicy(Policy):
# clamped to be at least 1 hour # clamped to be at least 1 hour
rel_time_hours = max(int((_now - previous_login.created).total_seconds() / 3600), 1) rel_time_hours = max(int((_now - previous_login.created).total_seconds() / 3600), 1)
if self.check_impossible_travel and dist.km >= ( if self.check_impossible_travel and dist.km >= (
(MAX_DISTANCE_HOUR_KM * rel_time_hours) - self.distance_tolerance_km (MAX_DISTANCE_HOUR_KM * rel_time_hours) + self.distance_tolerance_km
): ):
return PolicyResult(False, _("Distance is further than possible.")) return PolicyResult(False, _("Distance is further than possible."))
return PolicyResult(True) return PolicyResult(True)

View File

@ -148,10 +148,10 @@ class PasswordPolicy(Policy):
user_inputs.append(request.user.email) user_inputs.append(request.user.email)
if request.http_request: if request.http_request:
user_inputs.append(request.http_request.brand.branding_title) user_inputs.append(request.http_request.brand.branding_title)
# Only calculate result for the first 100 characters, as with over 100 char # Only calculate result for the first 72 characters, as with over 100 char
# long passwords we can be reasonably sure that they'll surpass the score anyways # long passwords we can be reasonably sure that they'll surpass the score anyways
# See https://github.com/dropbox/zxcvbn#runtime-latency # See https://github.com/dropbox/zxcvbn#runtime-latency
results = zxcvbn(password[:100], user_inputs) results = zxcvbn(password[:72], user_inputs)
LOGGER.debug("password failed", check="zxcvbn", score=results["score"]) LOGGER.debug("password failed", check="zxcvbn", score=results["score"])
result = PolicyResult(results["score"] > self.zxcvbn_score_threshold) result = PolicyResult(results["score"] > self.zxcvbn_score_threshold)
if not result.passing: if not result.passing:

View File

@ -9,7 +9,12 @@ from hashlib import sha256
from typing import Any from typing import Any
from urllib.parse import urlparse, urlunparse from urllib.parse import urlparse, urlunparse
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey from cryptography.hazmat.primitives.asymmetric.ec import (
SECP256R1,
SECP384R1,
SECP521R1,
EllipticCurvePrivateKey,
)
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes
from dacite import Config from dacite import Config
@ -114,6 +119,22 @@ class JWTAlgorithms(models.TextChoices):
HS256 = "HS256", _("HS256 (Symmetric Encryption)") HS256 = "HS256", _("HS256 (Symmetric Encryption)")
RS256 = "RS256", _("RS256 (Asymmetric Encryption)") RS256 = "RS256", _("RS256 (Asymmetric Encryption)")
ES256 = "ES256", _("ES256 (Asymmetric Encryption)") ES256 = "ES256", _("ES256 (Asymmetric Encryption)")
ES384 = "ES384", _("ES384 (Asymmetric Encryption)")
ES512 = "ES512", _("ES512 (Asymmetric Encryption)")
@classmethod
def from_private_key(cls, private_key: PrivateKeyTypes | None) -> str:
if isinstance(private_key, RSAPrivateKey):
return cls.RS256
if isinstance(private_key, EllipticCurvePrivateKey):
curve = private_key.curve
if isinstance(curve, SECP256R1):
return cls.ES256
if isinstance(curve, SECP384R1):
return cls.ES384
if isinstance(curve, SECP521R1):
return cls.ES512
raise ValueError(f"Invalid private key type: {type(private_key)}")
class ScopeMapping(PropertyMapping): class ScopeMapping(PropertyMapping):
@ -263,11 +284,7 @@ class OAuth2Provider(WebfingerProvider, Provider):
return self.client_secret, JWTAlgorithms.HS256 return self.client_secret, JWTAlgorithms.HS256
key: CertificateKeyPair = self.signing_key key: CertificateKeyPair = self.signing_key
private_key = key.private_key private_key = key.private_key
if isinstance(private_key, RSAPrivateKey): return private_key, JWTAlgorithms.from_private_key(private_key)
return private_key, JWTAlgorithms.RS256
if isinstance(private_key, EllipticCurvePrivateKey):
return private_key, JWTAlgorithms.ES256
raise ValueError(f"Invalid private key type: {type(private_key)}")
def get_issuer(self, request: HttpRequest) -> str | None: def get_issuer(self, request: HttpRequest) -> str | None:
"""Get issuer, based on request""" """Get issuer, based on request"""

View File

@ -71,7 +71,7 @@ class CodeValidatorView(PolicyAccessView):
except FlowNonApplicableException: except FlowNonApplicableException:
LOGGER.warning("Flow not applicable to user") LOGGER.warning("Flow not applicable to user")
return None return None
plan.insert_stage(in_memory_stage(OAuthDeviceCodeFinishStage)) plan.append_stage(in_memory_stage(OAuthDeviceCodeFinishStage))
return plan.to_redirect(self.request, self.token.provider.authorization_flow) return plan.to_redirect(self.request, self.token.provider.authorization_flow)

View File

@ -34,5 +34,5 @@ class EndSessionView(PolicyAccessView):
PLAN_CONTEXT_APPLICATION: self.application, PLAN_CONTEXT_APPLICATION: self.application,
}, },
) )
plan.insert_stage(in_memory_stage(SessionEndStage)) plan.append_stage(in_memory_stage(SessionEndStage))
return plan.to_redirect(self.request, self.flow) return plan.to_redirect(self.request, self.flow)

View File

@ -75,10 +75,7 @@ class JWKSView(View):
key_data = {} key_data = {}
if use == "sig": if use == "sig":
if isinstance(private_key, RSAPrivateKey): key_data["alg"] = JWTAlgorithms.from_private_key(private_key)
key_data["alg"] = JWTAlgorithms.RS256
elif isinstance(private_key, EllipticCurvePrivateKey):
key_data["alg"] = JWTAlgorithms.ES256
elif use == "enc": elif use == "enc":
key_data["alg"] = "RSA-OAEP-256" key_data["alg"] = "RSA-OAEP-256"
key_data["enc"] = "A256CBC-HS512" key_data["enc"] = "A256CBC-HS512"

View File

@ -36,17 +36,17 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
def reconciler_name() -> str: def reconciler_name() -> str:
return "ingress" return "ingress"
def _check_annotations(self, reference: V1Ingress): def _check_annotations(self, current: V1Ingress, reference: V1Ingress):
"""Check that all annotations *we* set are correct""" """Check that all annotations *we* set are correct"""
for key, value in self.get_ingress_annotations().items(): for key, value in reference.metadata.annotations.items():
if key not in reference.metadata.annotations: if key not in current.metadata.annotations:
raise NeedsUpdate() raise NeedsUpdate()
if reference.metadata.annotations[key] != value: if current.metadata.annotations[key] != value:
raise NeedsUpdate() raise NeedsUpdate()
def reconcile(self, current: V1Ingress, reference: V1Ingress): def reconcile(self, current: V1Ingress, reference: V1Ingress):
super().reconcile(current, reference) super().reconcile(current, reference)
self._check_annotations(reference) self._check_annotations(current, reference)
# Create a list of all expected host and tls hosts # Create a list of all expected host and tls hosts
expected_hosts = [] expected_hosts = []
expected_hosts_tls = [] expected_hosts_tls = []

View File

@ -46,7 +46,7 @@ class RACStartView(PolicyAccessView):
) )
except FlowNonApplicableException: except FlowNonApplicableException:
raise Http404 from None raise Http404 from None
plan.insert_stage( plan.append_stage(
in_memory_stage( in_memory_stage(
RACFinalStage, RACFinalStage,
application=self.application, application=self.application,

View File

@ -61,7 +61,7 @@ class SAMLSLOView(PolicyAccessView):
PLAN_CONTEXT_APPLICATION: self.application, PLAN_CONTEXT_APPLICATION: self.application,
}, },
) )
plan.insert_stage(in_memory_stage(SessionEndStage)) plan.append_stage(in_memory_stage(SessionEndStage))
return plan.to_redirect(self.request, self.flow) return plan.to_redirect(self.request, self.flow)
def post(self, request: HttpRequest, application_slug: str) -> HttpResponse: def post(self, request: HttpRequest, application_slug: str) -> HttpResponse:

View File

@ -30,6 +30,7 @@ class SCIMProviderSerializer(ProviderSerializer):
"token", "token",
"exclude_users_service_account", "exclude_users_service_account",
"filter_group", "filter_group",
"dry_run",
] ]
extra_kwargs = {} extra_kwargs = {}

View File

@ -12,8 +12,9 @@ from authentik.lib.sync.outgoing import (
HTTP_SERVICE_UNAVAILABLE, HTTP_SERVICE_UNAVAILABLE,
HTTP_TOO_MANY_REQUESTS, HTTP_TOO_MANY_REQUESTS,
) )
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient from authentik.lib.sync.outgoing.base import SAFE_METHODS, BaseOutgoingSyncClient
from authentik.lib.sync.outgoing.exceptions import ( from authentik.lib.sync.outgoing.exceptions import (
DryRunRejected,
NotFoundSyncException, NotFoundSyncException,
ObjectExistsSyncException, ObjectExistsSyncException,
TransientSyncException, TransientSyncException,
@ -54,6 +55,8 @@ class SCIMClient[TModel: "Model", TConnection: "Model", TSchema: "BaseModel"](
def _request(self, method: str, path: str, **kwargs) -> dict: def _request(self, method: str, path: str, **kwargs) -> dict:
"""Wrapper to send a request to the full URL""" """Wrapper to send a request to the full URL"""
if self.provider.dry_run and method.upper() not in SAFE_METHODS:
raise DryRunRejected(f"{self.base_url}{path}", method, body=kwargs.get("json"))
try: try:
response = self._session.request( response = self._session.request(
method, method,

View File

@ -0,0 +1,21 @@
# Generated by Django 5.0.12 on 2025-02-24 19:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_scim", "0010_scimprovider_verify_certificates"),
]
operations = [
migrations.AddField(
model_name="scimprovider",
name="dry_run",
field=models.BooleanField(
default=False,
help_text="When enabled, provider will not modify or create objects in the remote system.",
),
),
]

View File

@ -3,12 +3,15 @@
from json import loads from json import loads
from django.test import TestCase from django.test import TestCase
from django.utils.text import slugify
from jsonschema import validate from jsonschema import validate
from requests_mock import Mocker from requests_mock import Mocker
from authentik.blueprints.tests import apply_blueprint from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import Application, Group, User from authentik.core.models import Application, Group, User
from authentik.events.models import SystemTask
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
from authentik.lib.sync.outgoing.base import SAFE_METHODS
from authentik.providers.scim.models import SCIMMapping, SCIMProvider from authentik.providers.scim.models import SCIMMapping, SCIMProvider
from authentik.providers.scim.tasks import scim_sync, sync_tasks from authentik.providers.scim.tasks import scim_sync, sync_tasks
from authentik.tenants.models import Tenant from authentik.tenants.models import Tenant
@ -330,3 +333,59 @@ class SCIMUserTests(TestCase):
"userName": uid, "userName": uid,
}, },
) )
def test_user_create_dry_run(self):
"""Test user creation (dry_run)"""
# Update the provider before we start mocking as saving the provider triggers a full sync
self.provider.dry_run = True
self.provider.save()
with Mocker() as mock:
scim_id = generate_id()
mock.get(
"https://localhost/ServiceProviderConfig",
json={},
)
mock.post(
"https://localhost/Users",
json={
"id": scim_id,
},
)
uid = generate_id()
User.objects.create(
username=uid,
name=f"{uid} {uid}",
email=f"{uid}@goauthentik.io",
)
self.assertEqual(mock.call_count, 1, mock.request_history)
self.assertEqual(mock.request_history[0].method, "GET")
def test_sync_task_dry_run(self):
"""Test sync tasks"""
# Update the provider before we start mocking as saving the provider triggers a full sync
self.provider.dry_run = True
self.provider.save()
with Mocker() as mock:
uid = generate_id()
mock.get(
"https://localhost/ServiceProviderConfig",
json={},
)
User.objects.create(
username=uid,
name=f"{uid} {uid}",
email=f"{uid}@goauthentik.io",
)
sync_tasks.trigger_single_task(self.provider, scim_sync).get()
self.assertEqual(mock.call_count, 3)
for request in mock.request_history:
self.assertIn(request.method, SAFE_METHODS)
task = SystemTask.objects.filter(uid=slugify(self.provider.name)).first()
self.assertIsNotNone(task)
drop_msg = task.messages[2]
self.assertEqual(drop_msg["event"], "Dropping mutating request due to dry run")
self.assertIsNotNone(drop_msg["attributes"]["url"])
self.assertIsNotNone(drop_msg["attributes"]["body"])
self.assertIsNotNone(drop_msg["attributes"]["method"])

View File

@ -2,7 +2,7 @@
from django.apps import apps from django.apps import apps
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.db.models import Q, QuerySet from django.db.models import QuerySet
from django_filters.filters import ModelChoiceFilter from django_filters.filters import ModelChoiceFilter
from django_filters.filterset import FilterSet from django_filters.filterset import FilterSet
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
@ -18,7 +18,6 @@ from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ReadOnlyModelViewSet from rest_framework.viewsets import ReadOnlyModelViewSet
from authentik.blueprints.v1.importer import excluded_models
from authentik.core.api.utils import ModelSerializer, PassiveSerializer from authentik.core.api.utils import ModelSerializer, PassiveSerializer
from authentik.core.models import User from authentik.core.models import User
from authentik.lib.validators import RequiredTogetherValidator from authentik.lib.validators import RequiredTogetherValidator
@ -106,13 +105,13 @@ class RBACPermissionViewSet(ReadOnlyModelViewSet):
] ]
def get_queryset(self) -> QuerySet: def get_queryset(self) -> QuerySet:
query = Q() return (
for model in excluded_models(): Permission.objects.all()
query |= Q( .select_related("content_type")
content_type__app_label=model._meta.app_label, .filter(
content_type__model=model._meta.model_name, content_type__app_label__startswith="authentik",
) )
return Permission.objects.all().select_related("content_type").exclude(query) )
class PermissionAssignSerializer(PassiveSerializer): class PermissionAssignSerializer(PassiveSerializer):

View File

@ -16,6 +16,7 @@ from authentik.lib.config import CONFIG, django_db_config, redis_url
from authentik.lib.logging import get_logger_config, structlog_configure from authentik.lib.logging import get_logger_config, structlog_configure
from authentik.lib.sentry import sentry_init from authentik.lib.sentry import sentry_init
from authentik.lib.utils.reflection import get_env from authentik.lib.utils.reflection import get_env
from authentik.lib.utils.time import timedelta_from_string
from authentik.stages.password import BACKEND_APP_PASSWORD, BACKEND_INBUILT, BACKEND_LDAP from authentik.stages.password import BACKEND_APP_PASSWORD, BACKEND_INBUILT, BACKEND_LDAP
BASE_DIR = Path(__file__).absolute().parent.parent.parent BASE_DIR = Path(__file__).absolute().parent.parent.parent
@ -242,6 +243,9 @@ SESSION_CACHE_ALIAS = "default"
# Configured via custom SessionMiddleware # Configured via custom SessionMiddleware
# SESSION_COOKIE_SAMESITE = "None" # SESSION_COOKIE_SAMESITE = "None"
# SESSION_COOKIE_SECURE = True # SESSION_COOKIE_SECURE = True
SESSION_COOKIE_AGE = timedelta_from_string(
CONFIG.get("sessions.unauthenticated_age", "days=1")
).total_seconds()
SESSION_EXPIRE_AT_BROWSER_CLOSE = True SESSION_EXPIRE_AT_BROWSER_CLOSE = True
MESSAGE_STORAGE = "authentik.root.messages.storage.ChannelsStorage" MESSAGE_STORAGE = "authentik.root.messages.storage.ChannelsStorage"

View File

@ -2,6 +2,7 @@
from typing import Any from typing import Any
from requests import RequestException
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient
@ -21,10 +22,35 @@ class AzureADOAuthRedirect(OAuthRedirect):
} }
class AzureADClient(UserprofileHeaderAuthClient):
"""Fetch AzureAD group information"""
def get_profile_info(self, token):
profile_data = super().get_profile_info(token)
if "https://graph.microsoft.com/GroupMember.Read.All" not in self.source.additional_scopes:
return profile_data
group_response = self.session.request(
"get",
"https://graph.microsoft.com/v1.0/me/memberOf",
headers={"Authorization": f"{token['token_type']} {token['access_token']}"},
)
try:
group_response.raise_for_status()
except RequestException as exc:
LOGGER.warning(
"Unable to fetch user profile",
exc=exc,
response=exc.response.text if exc.response else str(exc),
)
return None
profile_data["raw_groups"] = group_response.json()
return profile_data
class AzureADOAuthCallback(OpenIDConnectOAuth2Callback): class AzureADOAuthCallback(OpenIDConnectOAuth2Callback):
"""AzureAD OAuth2 Callback""" """AzureAD OAuth2 Callback"""
client_class = UserprofileHeaderAuthClient client_class = AzureADClient
def get_user_id(self, info: dict[str, str]) -> str: def get_user_id(self, info: dict[str, str]) -> str:
# Default try to get `id` for the Graph API endpoint # Default try to get `id` for the Graph API endpoint
@ -53,8 +79,24 @@ class AzureADType(SourceType):
def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]: def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]:
mail = info.get("mail", None) or info.get("otherMails", [None])[0] mail = info.get("mail", None) or info.get("otherMails", [None])[0]
# Format group info
groups = []
group_id_dict = {}
for group in info.get("raw_groups", {}).get("value", []):
if group["@odata.type"] != "#microsoft.graph.group":
continue
groups.append(group["id"])
group_id_dict[group["id"]] = group
info["raw_groups"] = group_id_dict
return { return {
"username": info.get("userPrincipalName"), "username": info.get("userPrincipalName"),
"email": mail, "email": mail,
"name": info.get("displayName"), "name": info.get("displayName"),
"groups": groups,
}
def get_base_group_properties(self, source, group_id, **kwargs):
raw_group = kwargs["info"]["raw_groups"][group_id]
return {
"name": raw_group["displayName"],
} }

View File

@ -7,6 +7,7 @@ from django.utils.translation import gettext_lazy as _
from django.views import View from django.views import View
from rest_framework.serializers import BaseSerializer from rest_framework.serializers import BaseSerializer
from authentik.core.types import UserSettingSerializer
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.flows.exceptions import StageInvalidException from authentik.flows.exceptions import StageInvalidException
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
@ -71,6 +72,14 @@ class AuthenticatorEmailStage(ConfigurableStage, FriendlyNamedStage, Stage):
def component(self) -> str: def component(self) -> str:
return "ak-stage-authenticator-email-form" return "ak-stage-authenticator-email-form"
def ui_user_settings(self) -> UserSettingSerializer | None:
return UserSettingSerializer(
data={
"title": self.friendly_name or str(self._meta.verbose_name),
"component": "ak-user-settings-authenticator-email",
}
)
@property @property
def backend_class(self) -> type[BaseEmailBackend]: def backend_class(self) -> type[BaseEmailBackend]:
"""Get the email backend class to use""" """Get the email backend class to use"""

View File

@ -299,10 +299,6 @@ class TestAuthenticatorEmailStage(FlowTestCase):
data={"component": "ak-stage-authenticator-email", "code": device.token}, data={"component": "ak-stage-authenticator-email", "code": device.token},
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTrue(device.confirmed)
# Session key should be removed after device is saved
device.save()
self.assertNotIn(SESSION_KEY_EMAIL_DEVICE, self.client.session)
def test_model_properties_and_methods(self): def test_model_properties_and_methods(self):
"""Test model properties""" """Test model properties"""
@ -329,7 +325,6 @@ class TestAuthenticatorEmailStage(FlowTestCase):
self.stage.send(device) self.stage.send(device)
def test_email_tasks(self): def test_email_tasks(self):
email_send_mock = MagicMock() email_send_mock = MagicMock()
with patch( with patch(
"authentik.stages.email.tasks.send_mails", "authentik.stages.email.tasks.send_mails",

View File

@ -146,5 +146,10 @@
"name": "LogMeOnce", "name": "LogMeOnce",
"icon_dark": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgMjA0OCAyMDQ4IiB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTSAwIDAgTCAtNSAxIEwgLTE1IDQgTCAtMzggMTEgTCAtNTcgMTggTCAtNzYgMjkgTCAtOTAgMzggTCAtMTA5IDUyIEwgLTExNiA1OSBMIC0xMjcgNjggTCAtMTQwIDgxIEwgLTE0OCA4OCBMIC0xNDkgOTEgTCAtMTUxIDkxIEwgLTE2MSAxMDEgTCAtMTY5IDEwOCBMIC0xNjkgMTEwIEwgLTE3MSAxMTAgTCAtMTgwIDExOSBMIC0xODggMTI2IEwgLTIwMSAxMzcgTCAtMjEyIDE0NiBMIC0yMjYgMTU3IEwgLTIzOSAxNjcgTCAtMjUwIDE3NSBMIC0yNzAgMTg4IEwgLTI5MSAyMDIgTCAtMzA5IDIxMiBMIC0zMzAgMjI0IEwgLTM1MyAyMzUgTCAtMzg2IDI1MCBMIC00MDcgMjU5IEwgLTQ0OSAyNzMgTCAtNDcyIDI4MSBMIC01MDIgMjg5IEwgLTU1MSAyOTggTCAtNjE1IDMwOSBMIC02NDcgMzE2IEwgLTY4MSAzMjQgTCAtNjk4IDMzMCBMIC03MTQgMzM4IEwgLTczNSAzNTEgTCAtNzQ1IDM1OCBMIC03NTYgMzY3IEwgLTc2NCAzNzUgTCAtNzY2IDM3OSBMIC03NjggMzc5IEwgLTc3MyAzODUgTCAtNzgxIDM5NSBMIC03OTEgNDEwIEwgLTgwMSA0MjggTCAtODEwIDQ0NyBMIC04MTYgNDY1IEwgLTgyMiA1MDAgTCAtODI3IDU0NSBMIC04MzAgNTkyIEwgLTgzMiA2NTMgTCAtODMyIDcxMiBMIC04MzEgNzQyIEwgLTgyOCA3OTQgTCAtODIyIDg2NiBMIC04MTYgOTI4IEwgLTgxMiA5NTcgTCAtODAwIDEwMjAgTCAtNzg5IDEwNzIgTCAtNzgzIDEwOTggTCAtNzY1IDExNjIgTCAtNzUxIDEyMDcgTCAtNzQ0IDEyMjUgTCAtNzM0IDEyNTQgTCAtNzIwIDEyOTAgTCAtNzA0IDEzMjggTCAtNjg5IDEzNjEgTCAtNjY4IDE0MDMgTCAtNjUzIDE0MzEgTCAtNjM5IDE0NTYgTCAtNjIwIDE0ODggTCAtNjA3IDE1MDkgTCAtNTk0IDE1MjkgTCAtNTg0IDE1NDQgTCAtNTcxIDE1NjMgTCAtNTU4IDE1ODEgTCAtNTQ0IDE2MDAgTCAtNTMzIDE2MTUgTCAtNTIwIDE2MzIgTCAtNTA3IDE2NDggTCAtNDc5IDE2ODIgTCAtNDcwIDE2OTMgTCAtNDYwIDE3MDQgTCAtNDQ5IDE3MTYgTCAtNDQyIDE3MjQgTCAtNDMyIDE3MzQgTCAtNDI1IDE3NDIgTCAtMzY4IDE3OTkgTCAtMzUxIDE4MTUgTCAtMzM1IDE4MzAgTCAtMzI3IDE4MzcgTCAtMzE0IDE4NDkgTCAtMjg4IDE4NzEgTCAtMjcxIDE4ODUgTCAtMjYxIDE4OTMgTCAtMjQ0IDE5MDcgTCAtMjI4IDE5MTkgTCAtMjE1IDE5MjkgTCAtMTk2IDE5NDMgTCAtMTg0IDE5NTIgTCAtMTY4IDE5NjMgTCAtMTQ4IDE5NzcgTCAtMTMzIDE5ODcgTCAtMTEyIDIwMDAgTCAtODggMjAxMyBMIC03MiAyMDIxIEwgLTUyIDIwMzAgTCAtMzIgMjAzNyBMIDEyIDIwNDggTCA2MCAyMDQ4IEwgNjEgMjA0NyBMIDczIDIwNDQgTCAxMDAgMjAzNyBMIDEyMSAyMDI5IEwgMTQ5IDIwMTUgTCAxNjcgMjAwNSBMIDE4NiAxOTk0IEwgMjEwIDE5NzkgTCAyMzEgMTk2NSBMIDI2NiAxOTQxIEwgMjg0IDE5MjggTCAyOTUgMTkyMCBMIDMwNiAxOTExIEwgMzI0IDE4OTggTCAzMzggMTg4NyBMIDM0OSAxODc3IEwgMzU4IDE4NzAgTCAzNjkgMTg2MCBMIDM4MCAxODUxIEwgMzgwIDE4NDkgTCAzODIgMTg0OSBMIDM4NSAxODQ2IEwgMzk2IDE4MzcgTCA0MDMgMTgzMCBMIDQxMSAxODIzIEwgNDE4IDE4MTYgTCA0MjYgMTgwOSBMIDQ3NSAxNzYwIEwgNDc3IDE3NTYgTCA0NzkgMTc1NiBMIDQ4NyAxNzQ3IEwgNTAzIDE3MzAgTCA1MTAgMTcyMiBMIDUxOSAxNzEyIEwgNTI2IDE3MDQgTCA1MzggMTY5MSBMIDU0NyAxNjgwIEwgNTU4IDE2NjcgTCA1NjYgMTY1NiBMIDU3OSAxNjQwIEwgNTkwIDE2MjYgTCA2MDYgMTYwNSBMIDYyMSAxNTgzIEwgNjMxIDE1NjkgTCA2NDUgMTU0OSBMIDY1NSAxNTMzIEwgNjcwIDE1MTAgTCA2ODUgMTQ4NSBMIDY5NiAxNDY3IEwgNzA2IDE0NDkgTCA3MzAgMTQwNSBMIDc0NSAxMzc0IEwgNzYyIDEzMzggTCA3NzQgMTMxMCBMIDc5MiAxMjY3IEwgODExIDEyMTYgTCA4MjcgMTE2NiBMIDg0MiAxMTE3IEwgODU4IDEwNTEgTCA4NzAgOTk2IEwgODc1IDk2NyBMIDg4MSA5MTcgTCA4ODYgODgyIEwgODkxIDg0NiBMIDg5NCA4MTIgTCA4OTYgNzc0IEwgODk2IDY1NSBMIDg5NSA2MzAgTCA4OTIgNTkzIEwgODg4IDU1OSBMIDg3NyA0NzAgTCA4NzIgNDQ1IEwgODY1IDQyNiBMIDg1NyA0MTEgTCA4NDcgMzk1IEwgODM0IDM3OCBMIDgxNCAzNTggTCA4MDAgMzQ3IEwgNzg1IDMzNyBMIDc2NiAzMjcgTCA3NTAgMzIxIEwgNzI3IDMxNSBMIDY5MyAzMDggTCA2NTAgMzAxIEwgNTk3IDI5MiBMIDU3MCAyODYgTCA1NDggMjgwIEwgNTE1IDI3MCBMIDQ4NyAyNjEgTCA0NTkgMjUwIEwgNDM4IDI0MSBMIDQxNCAyMzAgTCAzODIgMjEzIEwgMzU4IDE5OSBMIDM0NyAxOTIgTCAzMzAgMTgwIEwgMzEyIDE2NyBMIDMwMCAxNTcgTCAyODYgMTQ2IEwgMjcxIDEzMyBMIDI2MyAxMjYgTCAyNTEgMTE1IEwgMjQwIDEwNiBMIDIyOCA5NSBMIDIwMCA3MSBMIDE4OSA2MiBMIDE3NCA1MCBMIDE1OCAzOCBMIDE0MiAyNyBMIDEyNyAxOSBMIDExNSAxNCBMIDk1IDggTCA3MSAwIEwgMCAwIHogTSAzMCA2MjIgTCA1MSA2MjMgTCA3OSA2MjcgTCAxMDAgNjMzIEwgMTIxIDY0MSBMIDE0MSA2NTIgTCAxNTcgNjYzIEwgMTcyIDY3NiBMIDE4NiA2OTAgTCAxODYgNjkyIEwgMTg4IDY5MiBMIDIwNiA3MTYgTCAyMTYgNzM0IEwgMjIxIDc0NSBMIDIyNiA3NTggTCAyMzMgNzg0IEwgMjM2IDc5OCBMIDIzNyA4MDggTCAyMzcgODQwIEwgMjMzIDg2NSBMIDIyNiA4OTEgTCAyMTkgOTA5IEwgMjA5IDkyOCBMIDE5NSA5NDkgTCAxODYgOTU5IEwgMTc5IDk2NyBMIDE2NiA5ODAgTCAxNTUgOTg5IEwgMTQyIDk5OCBMIDEyNiAxMDA3IEwgMTEzIDEwMTIgTCAxMTQgMTAyNCBMIDEyMiAxMDYwIEwgMTM3IDExMjMgTCAxNTYgMTIwOCBMIDE3MCAxMjcxIEwgMTc0IDEyOTYgTCAxNzYgMTMxMCBMIDE3NiAxMzM1IEwgMTczIDEzNDkgTCAxNjYgMTM1OSBMIDE1NyAxMzY3IEwgMTQ2IDEzNzIgTCAxNDAgMTM3NCBMIDExOSAxMzc2IEwgNTEgMTM3NiBMIC0zMiAxMzc3IEwgLTY0IDEzNzcgTCAtNzggMTM3NCBMIC04NSAxMzcwIEwgLTk4IDEzNTkgTCAtMTA2IDEzNDkgTCAtMTEwIDEzNDEgTCAtMTEyIDEzMzMgTCAtMTEyIDEzMTggTCAtMTA3IDEyODggTCAtMTAwIDEyNTYgTCAtODUgMTE5NiBMIC02OSAxMTI0IEwgLTU3IDEwNzIgTCAtNTAgMTAzNiBMIC00NyAxMDExIEwgLTUzIDEwMDkgTCAtNjkgMTAwMSBMIC04MSA5OTQgTCAtOTMgOTg1IEwgLTEwMyA5NzYgTCAtMTExIDk2OSBMIC0xMjAgOTYwIEwgLTEzMSA5NDYgTCAtMTQyIDkyOSBMIC0xNTIgOTEwIEwgLTE2MCA4OTAgTCAtMTY2IDg3MCBMIC0xNjkgODUzIEwgLTE3MCA4NDQgTCAtMTcwIDgxNCBMIC0xNjcgNzk0IEwgLTE2MSA3NjcgTCAtMTU0IDc0NiBMIC0xMzcgNzEzIEwgLTEyNiA2OTggTCAtMTE5IDY5MCBMIC0xMDggNjc4IEwgLTkzIDY2NSBMIC03NyA2NTMgTCAtNTYgNjQxIEwgLTM4IDYzMyBMIC0xNiA2MjcgTCAzIDYyNCBMIDMwIDYyMiB6ICIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoOTkxKSIgc3R5bGU9ImZpbGw6I2ZmZmZmZiIgLz4KPC9zdmc+Cg==", "icon_dark": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgMjA0OCAyMDQ4IiB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTSAwIDAgTCAtNSAxIEwgLTE1IDQgTCAtMzggMTEgTCAtNTcgMTggTCAtNzYgMjkgTCAtOTAgMzggTCAtMTA5IDUyIEwgLTExNiA1OSBMIC0xMjcgNjggTCAtMTQwIDgxIEwgLTE0OCA4OCBMIC0xNDkgOTEgTCAtMTUxIDkxIEwgLTE2MSAxMDEgTCAtMTY5IDEwOCBMIC0xNjkgMTEwIEwgLTE3MSAxMTAgTCAtMTgwIDExOSBMIC0xODggMTI2IEwgLTIwMSAxMzcgTCAtMjEyIDE0NiBMIC0yMjYgMTU3IEwgLTIzOSAxNjcgTCAtMjUwIDE3NSBMIC0yNzAgMTg4IEwgLTI5MSAyMDIgTCAtMzA5IDIxMiBMIC0zMzAgMjI0IEwgLTM1MyAyMzUgTCAtMzg2IDI1MCBMIC00MDcgMjU5IEwgLTQ0OSAyNzMgTCAtNDcyIDI4MSBMIC01MDIgMjg5IEwgLTU1MSAyOTggTCAtNjE1IDMwOSBMIC02NDcgMzE2IEwgLTY4MSAzMjQgTCAtNjk4IDMzMCBMIC03MTQgMzM4IEwgLTczNSAzNTEgTCAtNzQ1IDM1OCBMIC03NTYgMzY3IEwgLTc2NCAzNzUgTCAtNzY2IDM3OSBMIC03NjggMzc5IEwgLTc3MyAzODUgTCAtNzgxIDM5NSBMIC03OTEgNDEwIEwgLTgwMSA0MjggTCAtODEwIDQ0NyBMIC04MTYgNDY1IEwgLTgyMiA1MDAgTCAtODI3IDU0NSBMIC04MzAgNTkyIEwgLTgzMiA2NTMgTCAtODMyIDcxMiBMIC04MzEgNzQyIEwgLTgyOCA3OTQgTCAtODIyIDg2NiBMIC04MTYgOTI4IEwgLTgxMiA5NTcgTCAtODAwIDEwMjAgTCAtNzg5IDEwNzIgTCAtNzgzIDEwOTggTCAtNzY1IDExNjIgTCAtNzUxIDEyMDcgTCAtNzQ0IDEyMjUgTCAtNzM0IDEyNTQgTCAtNzIwIDEyOTAgTCAtNzA0IDEzMjggTCAtNjg5IDEzNjEgTCAtNjY4IDE0MDMgTCAtNjUzIDE0MzEgTCAtNjM5IDE0NTYgTCAtNjIwIDE0ODggTCAtNjA3IDE1MDkgTCAtNTk0IDE1MjkgTCAtNTg0IDE1NDQgTCAtNTcxIDE1NjMgTCAtNTU4IDE1ODEgTCAtNTQ0IDE2MDAgTCAtNTMzIDE2MTUgTCAtNTIwIDE2MzIgTCAtNTA3IDE2NDggTCAtNDc5IDE2ODIgTCAtNDcwIDE2OTMgTCAtNDYwIDE3MDQgTCAtNDQ5IDE3MTYgTCAtNDQyIDE3MjQgTCAtNDMyIDE3MzQgTCAtNDI1IDE3NDIgTCAtMzY4IDE3OTkgTCAtMzUxIDE4MTUgTCAtMzM1IDE4MzAgTCAtMzI3IDE4MzcgTCAtMzE0IDE4NDkgTCAtMjg4IDE4NzEgTCAtMjcxIDE4ODUgTCAtMjYxIDE4OTMgTCAtMjQ0IDE5MDcgTCAtMjI4IDE5MTkgTCAtMjE1IDE5MjkgTCAtMTk2IDE5NDMgTCAtMTg0IDE5NTIgTCAtMTY4IDE5NjMgTCAtMTQ4IDE5NzcgTCAtMTMzIDE5ODcgTCAtMTEyIDIwMDAgTCAtODggMjAxMyBMIC03MiAyMDIxIEwgLTUyIDIwMzAgTCAtMzIgMjAzNyBMIDEyIDIwNDggTCA2MCAyMDQ4IEwgNjEgMjA0NyBMIDczIDIwNDQgTCAxMDAgMjAzNyBMIDEyMSAyMDI5IEwgMTQ5IDIwMTUgTCAxNjcgMjAwNSBMIDE4NiAxOTk0IEwgMjEwIDE5NzkgTCAyMzEgMTk2NSBMIDI2NiAxOTQxIEwgMjg0IDE5MjggTCAyOTUgMTkyMCBMIDMwNiAxOTExIEwgMzI0IDE4OTggTCAzMzggMTg4NyBMIDM0OSAxODc3IEwgMzU4IDE4NzAgTCAzNjkgMTg2MCBMIDM4MCAxODUxIEwgMzgwIDE4NDkgTCAzODIgMTg0OSBMIDM4NSAxODQ2IEwgMzk2IDE4MzcgTCA0MDMgMTgzMCBMIDQxMSAxODIzIEwgNDE4IDE4MTYgTCA0MjYgMTgwOSBMIDQ3NSAxNzYwIEwgNDc3IDE3NTYgTCA0NzkgMTc1NiBMIDQ4NyAxNzQ3IEwgNTAzIDE3MzAgTCA1MTAgMTcyMiBMIDUxOSAxNzEyIEwgNTI2IDE3MDQgTCA1MzggMTY5MSBMIDU0NyAxNjgwIEwgNTU4IDE2NjcgTCA1NjYgMTY1NiBMIDU3OSAxNjQwIEwgNTkwIDE2MjYgTCA2MDYgMTYwNSBMIDYyMSAxNTgzIEwgNjMxIDE1NjkgTCA2NDUgMTU0OSBMIDY1NSAxNTMzIEwgNjcwIDE1MTAgTCA2ODUgMTQ4NSBMIDY5NiAxNDY3IEwgNzA2IDE0NDkgTCA3MzAgMTQwNSBMIDc0NSAxMzc0IEwgNzYyIDEzMzggTCA3NzQgMTMxMCBMIDc5MiAxMjY3IEwgODExIDEyMTYgTCA4MjcgMTE2NiBMIDg0MiAxMTE3IEwgODU4IDEwNTEgTCA4NzAgOTk2IEwgODc1IDk2NyBMIDg4MSA5MTcgTCA4ODYgODgyIEwgODkxIDg0NiBMIDg5NCA4MTIgTCA4OTYgNzc0IEwgODk2IDY1NSBMIDg5NSA2MzAgTCA4OTIgNTkzIEwgODg4IDU1OSBMIDg3NyA0NzAgTCA4NzIgNDQ1IEwgODY1IDQyNiBMIDg1NyA0MTEgTCA4NDcgMzk1IEwgODM0IDM3OCBMIDgxNCAzNTggTCA4MDAgMzQ3IEwgNzg1IDMzNyBMIDc2NiAzMjcgTCA3NTAgMzIxIEwgNzI3IDMxNSBMIDY5MyAzMDggTCA2NTAgMzAxIEwgNTk3IDI5MiBMIDU3MCAyODYgTCA1NDggMjgwIEwgNTE1IDI3MCBMIDQ4NyAyNjEgTCA0NTkgMjUwIEwgNDM4IDI0MSBMIDQxNCAyMzAgTCAzODIgMjEzIEwgMzU4IDE5OSBMIDM0NyAxOTIgTCAzMzAgMTgwIEwgMzEyIDE2NyBMIDMwMCAxNTcgTCAyODYgMTQ2IEwgMjcxIDEzMyBMIDI2MyAxMjYgTCAyNTEgMTE1IEwgMjQwIDEwNiBMIDIyOCA5NSBMIDIwMCA3MSBMIDE4OSA2MiBMIDE3NCA1MCBMIDE1OCAzOCBMIDE0MiAyNyBMIDEyNyAxOSBMIDExNSAxNCBMIDk1IDggTCA3MSAwIEwgMCAwIHogTSAzMCA2MjIgTCA1MSA2MjMgTCA3OSA2MjcgTCAxMDAgNjMzIEwgMTIxIDY0MSBMIDE0MSA2NTIgTCAxNTcgNjYzIEwgMTcyIDY3NiBMIDE4NiA2OTAgTCAxODYgNjkyIEwgMTg4IDY5MiBMIDIwNiA3MTYgTCAyMTYgNzM0IEwgMjIxIDc0NSBMIDIyNiA3NTggTCAyMzMgNzg0IEwgMjM2IDc5OCBMIDIzNyA4MDggTCAyMzcgODQwIEwgMjMzIDg2NSBMIDIyNiA4OTEgTCAyMTkgOTA5IEwgMjA5IDkyOCBMIDE5NSA5NDkgTCAxODYgOTU5IEwgMTc5IDk2NyBMIDE2NiA5ODAgTCAxNTUgOTg5IEwgMTQyIDk5OCBMIDEyNiAxMDA3IEwgMTEzIDEwMTIgTCAxMTQgMTAyNCBMIDEyMiAxMDYwIEwgMTM3IDExMjMgTCAxNTYgMTIwOCBMIDE3MCAxMjcxIEwgMTc0IDEyOTYgTCAxNzYgMTMxMCBMIDE3NiAxMzM1IEwgMTczIDEzNDkgTCAxNjYgMTM1OSBMIDE1NyAxMzY3IEwgMTQ2IDEzNzIgTCAxNDAgMTM3NCBMIDExOSAxMzc2IEwgNTEgMTM3NiBMIC0zMiAxMzc3IEwgLTY0IDEzNzcgTCAtNzggMTM3NCBMIC04NSAxMzcwIEwgLTk4IDEzNTkgTCAtMTA2IDEzNDkgTCAtMTEwIDEzNDEgTCAtMTEyIDEzMzMgTCAtMTEyIDEzMTggTCAtMTA3IDEyODggTCAtMTAwIDEyNTYgTCAtODUgMTE5NiBMIC02OSAxMTI0IEwgLTU3IDEwNzIgTCAtNTAgMTAzNiBMIC00NyAxMDExIEwgLTUzIDEwMDkgTCAtNjkgMTAwMSBMIC04MSA5OTQgTCAtOTMgOTg1IEwgLTEwMyA5NzYgTCAtMTExIDk2OSBMIC0xMjAgOTYwIEwgLTEzMSA5NDYgTCAtMTQyIDkyOSBMIC0xNTIgOTEwIEwgLTE2MCA4OTAgTCAtMTY2IDg3MCBMIC0xNjkgODUzIEwgLTE3MCA4NDQgTCAtMTcwIDgxNCBMIC0xNjcgNzk0IEwgLTE2MSA3NjcgTCAtMTU0IDc0NiBMIC0xMzcgNzEzIEwgLTEyNiA2OTggTCAtMTE5IDY5MCBMIC0xMDggNjc4IEwgLTkzIDY2NSBMIC03NyA2NTMgTCAtNTYgNjQxIEwgLTM4IDYzMyBMIC0xNiA2MjcgTCAzIDYyNCBMIDMwIDYyMiB6ICIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoOTkxKSIgc3R5bGU9ImZpbGw6I2ZmZmZmZiIgLz4KPC9zdmc+Cg==",
"icon_light": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyMDQ4IDIwNDgiIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSg5OTEpIiBkPSJtMCAwaDcxbDI0IDggMjAgNiAxMiA1IDE1IDggMTYgMTEgMTYgMTIgMTUgMTIgMTEgOSAyOCAyNCAxMiAxMSAxMSA5IDEyIDExIDggNyAxNSAxMyAxNCAxMSAxMiAxMCAxOCAxMyAxNyAxMiAxMSA3IDI0IDE0IDMyIDE3IDI0IDExIDIxIDkgMjggMTEgMjggOSAzMyAxMCAyMiA2IDI3IDYgNTMgOSA0MyA3IDM0IDcgMjMgNiAxNiA2IDE5IDEwIDE1IDEwIDE0IDExIDIwIDIwIDEzIDE3IDEwIDE2IDggMTUgNyAxOSA1IDI1IDExIDg5IDQgMzQgMyAzNyAxIDI1djExOWwtMiAzOC0zIDM0LTUgMzYtNSAzNS02IDUwLTUgMjktMTIgNTUtMTYgNjYtMTUgNDktMTYgNTAtMTkgNTEtMTggNDMtMTIgMjgtMTcgMzYtMTUgMzEtMjQgNDQtMTAgMTgtMTEgMTgtMTUgMjUtMTUgMjMtMTAgMTYtMTQgMjAtMTAgMTQtMTUgMjItMTYgMjEtMTEgMTQtMTMgMTYtOCAxMS0xMSAxMy05IDExLTEyIDEzLTcgOC05IDEwLTcgOC0xNiAxNy04IDloLTJsLTIgNC00OSA0OS04IDctNyA3LTggNy03IDctMTEgOS0zIDNoLTJ2MmwtMTEgOS0xMSAxMC05IDctMTEgMTAtMTQgMTEtMTggMTMtMTEgOS0xMSA4LTE4IDEzLTM1IDI0LTIxIDE0LTI0IDE1LTE5IDExLTE4IDEwLTI4IDE0LTIxIDgtMjcgNy0xMiAzLTEgMWgtNDhsLTQ0LTExLTIwLTctMjAtOS0xNi04LTI0LTEzLTIxLTEzLTE1LTEwLTIwLTE0LTE2LTExLTEyLTktMTktMTQtMTMtMTAtMTYtMTItMTctMTQtMTAtOC0xNy0xNC0yNi0yMi0xMy0xMi04LTctMTYtMTUtMTctMTYtNTctNTctNy04LTEwLTEwLTctOC0xMS0xMi0xMC0xMS05LTExLTI4LTM0LTEzLTE2LTEzLTE3LTExLTE1LTE0LTE5LTEzLTE4LTEzLTE5LTEwLTE1LTEzLTIwLTEzLTIxLTE5LTMyLTE0LTI1LTE1LTI4LTIxLTQyLTE1LTMzLTE2LTM4LTE0LTM2LTEwLTI5LTctMTgtMTQtNDUtMTgtNjQtNi0yNi0xMS01Mi0xMi02My00LTI5LTYtNjItNi03Mi0zLTUyLTEtMzB2LTU5bDItNjEgMy00NyA1LTQ1IDYtMzUgNi0xOCA5LTE5IDEwLTE4IDEwLTE1IDgtMTAgNS02aDJsMi00IDgtOCAxMS05IDEwLTcgMjEtMTMgMTYtOCAxNy02IDM0LTggMzItNyA2NC0xMSA0OS05IDMwLTggMjMtOCA0Mi0xNCAyMS05IDMzLTE1IDIzLTExIDIxLTEyIDE4LTEwIDIxLTE0IDIwLTEzIDExLTggMTMtMTAgMTQtMTEgMTEtOSAxMy0xMSA4LTcgOS05aDJ2LTJsOC03IDEwLTEwaDJsMS0zIDgtNyAxMy0xMyAxMS05IDctNyAxOS0xNCAxNC05IDE5LTExIDE5LTcgMjMtNyAxMC0zeiIgZmlsbD0iI0YxODQyOSIvPgo8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDIxLDYyMikiIGQ9Im0wIDAgMjEgMSAyOCA0IDIxIDYgMjEgOCAyMCAxMSAxNiAxMSAxNSAxMyAxNCAxNHYyaDJsMTggMjQgMTAgMTggNSAxMSA1IDEzIDcgMjYgMyAxNCAxIDEwdjMybC00IDI1LTcgMjYtNyAxOC0xMCAxOS0xNCAyMS05IDEwLTcgOC0xMyAxMy0xMSA5LTEzIDktMTYgOS0xMyA1IDEgMTIgOCAzNiAxNSA2MyAxOSA4NSAxNCA2MyA0IDI1IDIgMTR2MjVsLTMgMTQtNyAxMC05IDgtMTEgNS02IDItMjEgMmgtNjhsLTgzIDFoLTMybC0xNC0zLTctNC0xMy0xMS04LTEwLTQtOC0yLTh2LTE1bDUtMzAgNy0zMiAxNS02MCAxNi03MiAxMi01MiA3LTM2IDMtMjUtNi0yLTE2LTgtMTItNy0xMi05LTEwLTktOC03LTktOS0xMS0xNC0xMS0xNy0xMC0xOS04LTIwLTYtMjAtMy0xNy0xLTl2LTMwbDMtMjAgNi0yNyA3LTIxIDE3LTMzIDExLTE1IDctOCAxMS0xMiAxNS0xMyAxNi0xMiAyMS0xMiAxOC04IDIyLTYgMTktM3oiIGZpbGw9IiNGRUZGRkUiLz4KPC9zdmc+Cg==" "icon_light": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyMDQ4IDIwNDgiIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSg5OTEpIiBkPSJtMCAwaDcxbDI0IDggMjAgNiAxMiA1IDE1IDggMTYgMTEgMTYgMTIgMTUgMTIgMTEgOSAyOCAyNCAxMiAxMSAxMSA5IDEyIDExIDggNyAxNSAxMyAxNCAxMSAxMiAxMCAxOCAxMyAxNyAxMiAxMSA3IDI0IDE0IDMyIDE3IDI0IDExIDIxIDkgMjggMTEgMjggOSAzMyAxMCAyMiA2IDI3IDYgNTMgOSA0MyA3IDM0IDcgMjMgNiAxNiA2IDE5IDEwIDE1IDEwIDE0IDExIDIwIDIwIDEzIDE3IDEwIDE2IDggMTUgNyAxOSA1IDI1IDExIDg5IDQgMzQgMyAzNyAxIDI1djExOWwtMiAzOC0zIDM0LTUgMzYtNSAzNS02IDUwLTUgMjktMTIgNTUtMTYgNjYtMTUgNDktMTYgNTAtMTkgNTEtMTggNDMtMTIgMjgtMTcgMzYtMTUgMzEtMjQgNDQtMTAgMTgtMTEgMTgtMTUgMjUtMTUgMjMtMTAgMTYtMTQgMjAtMTAgMTQtMTUgMjItMTYgMjEtMTEgMTQtMTMgMTYtOCAxMS0xMSAxMy05IDExLTEyIDEzLTcgOC05IDEwLTcgOC0xNiAxNy04IDloLTJsLTIgNC00OSA0OS04IDctNyA3LTggNy03IDctMTEgOS0zIDNoLTJ2MmwtMTEgOS0xMSAxMC05IDctMTEgMTAtMTQgMTEtMTggMTMtMTEgOS0xMSA4LTE4IDEzLTM1IDI0LTIxIDE0LTI0IDE1LTE5IDExLTE4IDEwLTI4IDE0LTIxIDgtMjcgNy0xMiAzLTEgMWgtNDhsLTQ0LTExLTIwLTctMjAtOS0xNi04LTI0LTEzLTIxLTEzLTE1LTEwLTIwLTE0LTE2LTExLTEyLTktMTktMTQtMTMtMTAtMTYtMTItMTctMTQtMTAtOC0xNy0xNC0yNi0yMi0xMy0xMi04LTctMTYtMTUtMTctMTYtNTctNTctNy04LTEwLTEwLTctOC0xMS0xMi0xMC0xMS05LTExLTI4LTM0LTEzLTE2LTEzLTE3LTExLTE1LTE0LTE5LTEzLTE4LTEzLTE5LTEwLTE1LTEzLTIwLTEzLTIxLTE5LTMyLTE0LTI1LTE1LTI4LTIxLTQyLTE1LTMzLTE2LTM4LTE0LTM2LTEwLTI5LTctMTgtMTQtNDUtMTgtNjQtNi0yNi0xMS01Mi0xMi02My00LTI5LTYtNjItNi03Mi0zLTUyLTEtMzB2LTU5bDItNjEgMy00NyA1LTQ1IDYtMzUgNi0xOCA5LTE5IDEwLTE4IDEwLTE1IDgtMTAgNS02aDJsMi00IDgtOCAxMS05IDEwLTcgMjEtMTMgMTYtOCAxNy02IDM0LTggMzItNyA2NC0xMSA0OS05IDMwLTggMjMtOCA0Mi0xNCAyMS05IDMzLTE1IDIzLTExIDIxLTEyIDE4LTEwIDIxLTE0IDIwLTEzIDExLTggMTMtMTAgMTQtMTEgMTEtOSAxMy0xMSA4LTcgOS05aDJ2LTJsOC03IDEwLTEwaDJsMS0zIDgtNyAxMy0xMyAxMS05IDctNyAxOS0xNCAxNC05IDE5LTExIDE5LTcgMjMtNyAxMC0zeiIgZmlsbD0iI0YxODQyOSIvPgo8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDIxLDYyMikiIGQ9Im0wIDAgMjEgMSAyOCA0IDIxIDYgMjEgOCAyMCAxMSAxNiAxMSAxNSAxMyAxNCAxNHYyaDJsMTggMjQgMTAgMTggNSAxMSA1IDEzIDcgMjYgMyAxNCAxIDEwdjMybC00IDI1LTcgMjYtNyAxOC0xMCAxOS0xNCAyMS05IDEwLTcgOC0xMyAxMy0xMSA5LTEzIDktMTYgOS0xMyA1IDEgMTIgOCAzNiAxNSA2MyAxOSA4NSAxNCA2MyA0IDI1IDIgMTR2MjVsLTMgMTQtNyAxMC05IDgtMTEgNS02IDItMjEgMmgtNjhsLTgzIDFoLTMybC0xNC0zLTctNC0xMy0xMS04LTEwLTQtOC0yLTh2LTE1bDUtMzAgNy0zMiAxNS02MCAxNi03MiAxMi01MiA3LTM2IDMtMjUtNi0yLTE2LTgtMTItNy0xMi05LTEwLTktOC03LTktOS0xMS0xNC0xMS0xNy0xMC0xOS04LTIwLTYtMjAtMy0xNy0xLTl2LTMwbDMtMjAgNi0yNyA3LTIxIDE3LTMzIDExLTE1IDctOCAxMS0xMiAxNS0xMyAxNi0xMiAyMS0xMiAxOC04IDIyLTYgMTktM3oiIGZpbGw9IiNGRUZGRkUiLz4KPC9zdmc+Cg=="
} },
} "a10c6dd9-465e-4226-8198-c7c44b91c555": {
"name": "Kaspersky Password Manager",
"icon_dark": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzc0ODRfODc0NSkiPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMV83NDg0Xzg3NDUpIj48ZyBjbGlwLXBhdGg9InVybCgjY2xpcDJfNzQ4NF84NzQ1KSI+PHBhdGggZD0iTTI4MS45NjQgNi45NjE3MUMyNjUuODkzIC0yLjI5OTc0IDI0Ni4xMDcgLTIuMjk5NzQgMjMwLjAzNiA2Ljk2MTcxTDQ2LjAzNjUgMTEzLjAwMkMyOS45MjcxIDEyMi4yODYgMjAgMTM5LjQ2NiAyMCAxNTguMDZWMzUzLjk3MkMyMCAzNzIuNTY2IDI5LjkyNzEgMzg5Ljc0NSA0Ni4wMzY1IDM5OS4wMjlMMjMwLjAzNiA1MDUuMDdDMjQ2LjEwNyA1MTQuMzMxIDI2NS44OTMgNTE0LjMzMSAyODEuOTY0IDUwNS4wN0w0NjUuOTY0IDM5OS4wMjlDNDgyLjA3MyAzODkuNzQ1IDQ5MiAzNzIuNTY2IDQ5MiAzNTMuOTcyVjE1OC4wNkM0OTIgMTM5LjQ2NiA0ODIuMDczIDEyMi4yODYgNDY1Ljk2NCAxMTMuMDAyTDI4MS45NjQgNi45NjE3MVoiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl83NDg0Xzg3NDUpIi8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00NTMuOTggMTMzLjc5OEwyNjkuOTggMjcuNzU3NEMyNjEuMzI3IDIyLjc3MDQgMjUwLjY3MyAyMi43NzA0IDI0Mi4wMiAyNy43NTc0TDU4LjAxOTYgMTMzLjc5OEM0OS4zNDUzIDEzOC43OTcgNDQgMTQ4LjA0NyA0NCAxNTguMDZWMzUzLjk3MkM0NCAzNjMuOTg0IDQ5LjM0NTMgMzczLjIzNCA1OC4wMTk2IDM3OC4yMzNMMjQyLjAyIDQ4NC4yNzRDMjUwLjY3MyA0ODkuMjYxIDI2MS4zMjcgNDg5LjI2MSAyNjkuOTggNDg0LjI3NEw0NTMuOTggMzc4LjIzM0M0NjIuNjU1IDM3My4yMzQgNDY4IDM2My45ODQgNDY4IDM1My45NzJWMTU4LjA2QzQ2OCAxNDguMDQ3IDQ2Mi42NTUgMTM4Ljc5NyA0NTMuOTggMTMzLjc5OFpNMjgxLjk2NCA2Ljk2MTcxQzI2NS44OTMgLTIuMjk5NzQgMjQ2LjEwNyAtMi4yOTk3NCAyMzAuMDM2IDYuOTYxNzFMNDYuMDM2NSAxMTMuMDAyQzI5LjkyNzEgMTIyLjI4NiAyMCAxMzkuNDY2IDIwIDE1OC4wNlYzNTMuOTcyQzIwIDM3Mi41NjYgMjkuOTI3MSAzODkuNzQ1IDQ2LjAzNjUgMzk5LjAyOUwyMzAuMDM2IDUwNS4wN0MyNDYuMTA3IDUxNC4zMzEgMjY1Ljg5MyA1MTQuMzMxIDI4MS45NjQgNTA1LjA3TDQ2NS45NjQgMzk5LjAyOUM0ODIuMDczIDM4OS43NDUgNDkyIDM3Mi41NjYgNDkyIDM1My45NzJWMTU4LjA2QzQ5MiAxMzkuNDY2IDQ4Mi4wNzMgMTIyLjI4NiA0NjUuOTY0IDExMy4wMDJMMjgxLjk2NCA2Ljk2MTcxWiIgZmlsbD0iYmxhY2siLz48L2c+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNTYgMTQwQzI0Mi43NDUgMTQwIDIzMiAxNTAuNzQ1IDIzMiAxNjRDMjMyIDE3Ny4yNTUgMjQyLjc0NSAxODggMjU2IDE4OEMyNjkuMjU1IDE4OCAyODAgMTc3LjI1NSAyODAgMTY0QzI4MCAxNTAuNzQ1IDI2OS4yNTUgMTQwIDI1NiAxNDBaTTI0OCAxNjRDMjQ4IDE1OS41ODIgMjUxLjU4MiAxNTYgMjU2IDE1NkMyNjAuNDE4IDE1NiAyNjQgMTU5LjU4MiAyNjQgMTY0QzI2NCAxNjguNDE4IDI2MC40MTggMTcyIDI1NiAxNzJDMjUxLjU4MiAxNzIgMjQ4IDE2OC40MTggMjQ4IDE2NFoiIGZpbGw9ImJsYWNrIi8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNzIgMTkyQzE3MiAxNDUuNjA4IDIwOS42MDggMTA4IDI1NiAxMDhDMzAyLjM5MiAxMDggMzQwIDE0NS42MDggMzQwIDE5MkMzNDAgMjI3LjA2MSAzMTguNTE5IDI1Ny4xMDUgMjg4IDI2OS42OVYzODYuNjdDMjg4IDM5Mi4zOTEgMjg0Ljk0NiAzOTcuNjc2IDI3OS45ODkgNDAwLjUzM0wyNjMuOTg5IDQwOS43NTNDMjU5LjA0NCA0MTIuNjAzIDI1Mi45NTYgNDEyLjYwMyAyNDguMDExIDQwOS43NTNMMjMyLjAxMSA0MDAuNTMzQzIyNy4wNTQgMzk3LjY3NiAyMjQgMzkyLjM5MSAyMjQgMzg2LjY3VjM3MkMyMjQgMzY5Ljg3OCAyMjQuODQzIDM2Ny44NDQgMjI2LjM0MyAzNjYuMzQzTDIzNiAzNTYuNjg2VjM1NS4zMTRMMjI2LjM0MyAzNDUuNjU3QzIyNC44NDMgMzQ0LjE1NyAyMjQgMzQyLjEyMiAyMjQgMzQwVjMzMkMyMjQgMzI5Ljg3OCAyMjQuODQzIDMyNy44NDQgMjI2LjM0MyAzMjYuMzQzTDIzNiAzMTYuNjg2VjMxNS4zMTRMMjI2LjM0MyAzMDUuNjU3QzIyNC44NDMgMzA0LjE1NyAyMjQgMzAyLjEyMiAyMjQgMzAwVjI2OS42OUMxOTMuNDgxIDI1Ny4xMDUgMTcyIDIyNy4wNjEgMTcyIDE5MlpNMjU2IDEyNEMyMTguNDQ1IDEyNCAxODggMTU0LjQ0NSAxODggMTkyQzE4OCAyMjkuNTU1IDIxOC40NDUgMjYwIDI1NiAyNjBDMjkzLjU1NSAyNjAgMzI0IDIyOS41NTUgMzI0IDE5MkMzMjQgMTU0LjQ0NSAyOTMuNTU1IDEyNCAyNTYgMTI0Wk0yNTYgMjc2QzI2MS40NzEgMjc2IDI2Ni44MiAyNzUuNDc3IDI3MiAyNzQuNDc4VjM4Ni42N0wyNTYgMzk1Ljg5TDI0MCAzODYuNjdWMzc1LjMxNEwyNDkuNjU3IDM2NS42NTdDMjUxLjE1NyAzNjQuMTU3IDI1MiAzNjIuMTIyIDI1MiAzNjBWMzUyQzI1MiAzNDkuODc4IDI1MS4xNTcgMzQ3Ljg0NCAyNDkuNjU3IDM0Ni4zNDNMMjQwIDMzNi42ODZWMzM1LjMxNEwyNDkuNjU3IDMyNS42NTdDMjUxLjE1NyAzMjQuMTU3IDI1MiAzMjIuMTIyIDI1MiAzMjBWMzEyQzI1MiAzMDkuODc4IDI1MS4xNTcgMzA3Ljg0NCAyNDkuNjU3IDMwNi4zNDNMMjQwIDI5Ni42ODZWMjc0LjQ3OEMyNDUuMTggMjc1LjQ3NyAyNTAuNTI5IDI3NiAyNTYgMjc2WiIgZmlsbD0iYmxhY2siLz48L2c+PC9nPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl83NDg0Xzg3NDUiIHgxPSIzOTMuODY1IiB5MT0iNjMuMjc5NiIgeDI9Ijk5LjIwNDMiIHkyPSI0MjkuOTk4IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agc3RvcC1jb2xvcj0iIzRERkY4OCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzNERThDQSIvPjwvbGluZWFyR3JhZGllbnQ+PGNsaXBQYXRoIGlkPSJjbGlwMF83NDg0Xzg3NDUiPjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPjwvY2xpcFBhdGg+PGNsaXBQYXRoIGlkPSJjbGlwMV83NDg0Xzg3NDUiPjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPjwvY2xpcFBhdGg+PGNsaXBQYXRoIGlkPSJjbGlwMl83NDg0Xzg3NDUiPjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg==",
"icon_light": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzc0ODRfODc0NSkiPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMV83NDg0Xzg3NDUpIj48ZyBjbGlwLXBhdGg9InVybCgjY2xpcDJfNzQ4NF84NzQ1KSI+PHBhdGggZD0iTTI4MS45NjQgNi45NjE3MUMyNjUuODkzIC0yLjI5OTc0IDI0Ni4xMDcgLTIuMjk5NzQgMjMwLjAzNiA2Ljk2MTcxTDQ2LjAzNjUgMTEzLjAwMkMyOS45MjcxIDEyMi4yODYgMjAgMTM5LjQ2NiAyMCAxNTguMDZWMzUzLjk3MkMyMCAzNzIuNTY2IDI5LjkyNzEgMzg5Ljc0NSA0Ni4wMzY1IDM5OS4wMjlMMjMwLjAzNiA1MDUuMDdDMjQ2LjEwNyA1MTQuMzMxIDI2NS44OTMgNTE0LjMzMSAyODEuOTY0IDUwNS4wN0w0NjUuOTY0IDM5OS4wMjlDNDgyLjA3MyAzODkuNzQ1IDQ5MiAzNzIuNTY2IDQ5MiAzNTMuOTcyVjE1OC4wNkM0OTIgMTM5LjQ2NiA0ODIuMDczIDEyMi4yODYgNDY1Ljk2NCAxMTMuMDAyTDI4MS45NjQgNi45NjE3MVoiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl83NDg0Xzg3NDUpIi8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00NTMuOTggMTMzLjc5OEwyNjkuOTggMjcuNzU3NEMyNjEuMzI3IDIyLjc3MDQgMjUwLjY3MyAyMi43NzA0IDI0Mi4wMiAyNy43NTc0TDU4LjAxOTYgMTMzLjc5OEM0OS4zNDUzIDEzOC43OTcgNDQgMTQ4LjA0NyA0NCAxNTguMDZWMzUzLjk3MkM0NCAzNjMuOTg0IDQ5LjM0NTMgMzczLjIzNCA1OC4wMTk2IDM3OC4yMzNMMjQyLjAyIDQ4NC4yNzRDMjUwLjY3MyA0ODkuMjYxIDI2MS4zMjcgNDg5LjI2MSAyNjkuOTggNDg0LjI3NEw0NTMuOTggMzc4LjIzM0M0NjIuNjU1IDM3My4yMzQgNDY4IDM2My45ODQgNDY4IDM1My45NzJWMTU4LjA2QzQ2OCAxNDguMDQ3IDQ2Mi42NTUgMTM4Ljc5NyA0NTMuOTggMTMzLjc5OFpNMjgxLjk2NCA2Ljk2MTcxQzI2NS44OTMgLTIuMjk5NzQgMjQ2LjEwNyAtMi4yOTk3NCAyMzAuMDM2IDYuOTYxNzFMNDYuMDM2NSAxMTMuMDAyQzI5LjkyNzEgMTIyLjI4NiAyMCAxMzkuNDY2IDIwIDE1OC4wNlYzNTMuOTcyQzIwIDM3Mi41NjYgMjkuOTI3MSAzODkuNzQ1IDQ2LjAzNjUgMzk5LjAyOUwyMzAuMDM2IDUwNS4wN0MyNDYuMTA3IDUxNC4zMzEgMjY1Ljg5MyA1MTQuMzMxIDI4MS45NjQgNTA1LjA3TDQ2NS45NjQgMzk5LjAyOUM0ODIuMDczIDM4OS43NDUgNDkyIDM3Mi41NjYgNDkyIDM1My45NzJWMTU4LjA2QzQ5MiAxMzkuNDY2IDQ4Mi4wNzMgMTIyLjI4NiA0NjUuOTY0IDExMy4wMDJMMjgxLjk2NCA2Ljk2MTcxWiIgZmlsbD0iYmxhY2siLz48L2c+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNTYgMTQwQzI0Mi43NDUgMTQwIDIzMiAxNTAuNzQ1IDIzMiAxNjRDMjMyIDE3Ny4yNTUgMjQyLjc0NSAxODggMjU2IDE4OEMyNjkuMjU1IDE4OCAyODAgMTc3LjI1NSAyODAgMTY0QzI4MCAxNTAuNzQ1IDI2OS4yNTUgMTQwIDI1NiAxNDBaTTI0OCAxNjRDMjQ4IDE1OS41ODIgMjUxLjU4MiAxNTYgMjU2IDE1NkMyNjAuNDE4IDE1NiAyNjQgMTU5LjU4MiAyNjQgMTY0QzI2NCAxNjguNDE4IDI2MC40MTggMTcyIDI1NiAxNzJDMjUxLjU4MiAxNzIgMjQ4IDE2OC40MTggMjQ4IDE2NFoiIGZpbGw9ImJsYWNrIi8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNzIgMTkyQzE3MiAxNDUuNjA4IDIwOS42MDggMTA4IDI1NiAxMDhDMzAyLjM5MiAxMDggMzQwIDE0NS42MDggMzQwIDE5MkMzNDAgMjI3LjA2MSAzMTguNTE5IDI1Ny4xMDUgMjg4IDI2OS42OVYzODYuNjdDMjg4IDM5Mi4zOTEgMjg0Ljk0NiAzOTcuNjc2IDI3OS45ODkgNDAwLjUzM0wyNjMuOTg5IDQwOS43NTNDMjU5LjA0NCA0MTIuNjAzIDI1Mi45NTYgNDEyLjYwMyAyNDguMDExIDQwOS43NTNMMjMyLjAxMSA0MDAuNTMzQzIyNy4wNTQgMzk3LjY3NiAyMjQgMzkyLjM5MSAyMjQgMzg2LjY3VjM3MkMyMjQgMzY5Ljg3OCAyMjQuODQzIDM2Ny44NDQgMjI2LjM0MyAzNjYuMzQzTDIzNiAzNTYuNjg2VjM1NS4zMTRMMjI2LjM0MyAzNDUuNjU3QzIyNC44NDMgMzQ0LjE1NyAyMjQgMzQyLjEyMiAyMjQgMzQwVjMzMkMyMjQgMzI5Ljg3OCAyMjQuODQzIDMyNy44NDQgMjI2LjM0MyAzMjYuMzQzTDIzNiAzMTYuNjg2VjMxNS4zMTRMMjI2LjM0MyAzMDUuNjU3QzIyNC44NDMgMzA0LjE1NyAyMjQgMzAyLjEyMiAyMjQgMzAwVjI2OS42OUMxOTMuNDgxIDI1Ny4xMDUgMTcyIDIyNy4wNjEgMTcyIDE5MlpNMjU2IDEyNEMyMTguNDQ1IDEyNCAxODggMTU0LjQ0NSAxODggMTkyQzE4OCAyMjkuNTU1IDIxOC40NDUgMjYwIDI1NiAyNjBDMjkzLjU1NSAyNjAgMzI0IDIyOS41NTUgMzI0IDE5MkMzMjQgMTU0LjQ0NSAyOTMuNTU1IDEyNCAyNTYgMTI0Wk0yNTYgMjc2QzI2MS40NzEgMjc2IDI2Ni44MiAyNzUuNDc3IDI3MiAyNzQuNDc4VjM4Ni42N0wyNTYgMzk1Ljg5TDI0MCAzODYuNjdWMzc1LjMxNEwyNDkuNjU3IDM2NS42NTdDMjUxLjE1NyAzNjQuMTU3IDI1MiAzNjIuMTIyIDI1MiAzNjBWMzUyQzI1MiAzNDkuODc4IDI1MS4xNTcgMzQ3Ljg0NCAyNDkuNjU3IDM0Ni4zNDNMMjQwIDMzNi42ODZWMzM1LjMxNEwyNDkuNjU3IDMyNS42NTdDMjUxLjE1NyAzMjQuMTU3IDI1MiAzMjIuMTIyIDI1MiAzMjBWMzEyQzI1MiAzMDkuODc4IDI1MS4xNTcgMzA3Ljg0NCAyNDkuNjU3IDMwNi4zNDNMMjQwIDI5Ni42ODZWMjc0LjQ3OEMyNDUuMTggMjc1LjQ3NyAyNTAuNTI5IDI3NiAyNTYgMjc2WiIgZmlsbD0iYmxhY2siLz48L2c+PC9nPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl83NDg0Xzg3NDUiIHgxPSIzOTMuODY1IiB5MT0iNjMuMjc5NiIgeDI9Ijk5LjIwNDMiIHkyPSI0MjkuOTk4IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agc3RvcC1jb2xvcj0iIzRERkY4OCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzNERThDQSIvPjwvbGluZWFyR3JhZGllbnQ+PGNsaXBQYXRoIGlkPSJjbGlwMF83NDg0Xzg3NDUiPjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPjwvY2xpcFBhdGg+PGNsaXBQYXRoIGlkPSJjbGlwMV83NDg0Xzg3NDUiPjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPjwvY2xpcFBhdGg+PGNsaXBQYXRoIGlkPSJjbGlwMl83NDg0Xzg3NDUiPjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg=="
}
}

File diff suppressed because one or more lines are too long

View File

@ -12,6 +12,7 @@ from structlog.stdlib import get_logger
from authentik.events.models import Event, EventAction, TaskStatus from authentik.events.models import Event, EventAction, TaskStatus
from authentik.events.system_tasks import SystemTask from authentik.events.system_tasks import SystemTask
from authentik.lib.utils.reflection import class_to_path, path_to_class
from authentik.root.celery import CELERY_APP from authentik.root.celery import CELERY_APP
from authentik.stages.authenticator_email.models import AuthenticatorEmailStage from authentik.stages.authenticator_email.models import AuthenticatorEmailStage
from authentik.stages.email.models import EmailStage from authentik.stages.email.models import EmailStage
@ -32,9 +33,10 @@ def send_mails(
Celery group promise for the email sending tasks Celery group promise for the email sending tasks
""" """
tasks = [] tasks = []
stage_class = stage.__class__ # Use the class path instead of the class itself for serialization
stage_class_path = class_to_path(stage.__class__)
for message in messages: for message in messages:
tasks.append(send_mail.s(message.__dict__, stage_class, str(stage.pk))) tasks.append(send_mail.s(message.__dict__, stage_class_path, str(stage.pk)))
lazy_group = group(*tasks) lazy_group = group(*tasks)
promise = lazy_group() promise = lazy_group()
return promise return promise
@ -61,7 +63,7 @@ def get_email_body(email: EmailMultiAlternatives) -> str:
def send_mail( def send_mail(
self: SystemTask, self: SystemTask,
message: dict[Any, Any], message: dict[Any, Any],
stage_class: EmailStage | AuthenticatorEmailStage = EmailStage, stage_class_path: str | None = None,
email_stage_pk: str | None = None, email_stage_pk: str | None = None,
): ):
"""Send Email for Email Stage. Retries are scheduled automatically.""" """Send Email for Email Stage. Retries are scheduled automatically."""
@ -69,9 +71,10 @@ def send_mail(
message_id = make_msgid(domain=DNS_NAME) message_id = make_msgid(domain=DNS_NAME)
self.set_uid(slugify(message_id.replace(".", "_").replace("@", "_"))) self.set_uid(slugify(message_id.replace(".", "_").replace("@", "_")))
try: try:
if not email_stage_pk: if not stage_class_path or not email_stage_pk:
stage: EmailStage | AuthenticatorEmailStage = stage_class(use_global_settings=True) stage = EmailStage(use_global_settings=True)
else: else:
stage_class = path_to_class(stage_class_path)
stages = stage_class.objects.filter(pk=email_stage_pk) stages = stage_class.objects.filter(pk=email_stage_pk)
if not stages.exists(): if not stages.exists():
self.set_status( self.set_status(

View File

@ -0,0 +1,58 @@
"""Test email stage tasks"""
from unittest.mock import patch
from django.core.mail import EmailMultiAlternatives
from django.test import TestCase
from authentik.core.tests.utils import create_test_admin_user
from authentik.lib.utils.reflection import class_to_path
from authentik.stages.authenticator_email.models import AuthenticatorEmailStage
from authentik.stages.email.models import EmailStage
from authentik.stages.email.tasks import get_email_body, send_mails
class TestEmailTasks(TestCase):
"""Test email stage tasks"""
def setUp(self):
self.user = create_test_admin_user()
self.stage = EmailStage.objects.create(
name="test-email",
use_global_settings=True,
)
self.auth_stage = AuthenticatorEmailStage.objects.create(
name="test-auth-email",
use_global_settings=True,
)
def test_get_email_body_html(self):
"""Test get_email_body with HTML alternative"""
message = EmailMultiAlternatives()
message.body = "plain text"
message.attach_alternative("<p>html content</p>", "text/html")
self.assertEqual(get_email_body(message), "<p>html content</p>")
def test_get_email_body_plain(self):
"""Test get_email_body with plain text only"""
message = EmailMultiAlternatives()
message.body = "plain text"
self.assertEqual(get_email_body(message), "plain text")
def test_send_mails_email_stage(self):
"""Test send_mails with EmailStage"""
message = EmailMultiAlternatives()
with patch("authentik.stages.email.tasks.send_mail") as mock_send:
send_mails(self.stage, message)
mock_send.s.assert_called_once_with(
message.__dict__, class_to_path(EmailStage), str(self.stage.pk)
)
def test_send_mails_authenticator_stage(self):
"""Test send_mails with AuthenticatorEmailStage"""
message = EmailMultiAlternatives()
with patch("authentik.stages.email.tasks.send_mail") as mock_send:
send_mails(self.auth_stage, message)
mock_send.s.assert_called_once_with(
message.__dict__, class_to_path(AuthenticatorEmailStage), str(self.auth_stage.pk)
)

View File

@ -5,7 +5,7 @@ entries:
- attrs: - attrs:
designation: stage_configuration designation: stage_configuration
name: default-authenticator-totp-setup name: default-authenticator-totp-setup
title: Setup Two-Factor authentication title: Set up Two-Factor authentication
authentication: require_authenticated authentication: require_authenticated
identifiers: identifiers:
slug: default-authenticator-totp-setup slug: default-authenticator-totp-setup

View File

@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-07/schema", "$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://goauthentik.io/blueprints/schema.json", "$id": "https://goauthentik.io/blueprints/schema.json",
"type": "object", "type": "object",
"title": "authentik 2024.12.3 Blueprint schema", "title": "authentik 2025.2.1 Blueprint schema",
"required": [ "required": [
"version", "version",
"entries" "entries"
@ -6669,6 +6669,11 @@
"type": "string", "type": "string",
"format": "uuid", "format": "uuid",
"title": "Filter group" "title": "Filter group"
},
"dry_run": {
"type": "boolean",
"title": "Dry run",
"description": "When enabled, provider will not modify or create objects in the remote system."
} }
}, },
"required": [] "required": []
@ -14196,6 +14201,11 @@
"type": "string", "type": "string",
"minLength": 1, "minLength": 1,
"title": "Default group email domain" "title": "Default group email domain"
},
"dry_run": {
"type": "boolean",
"title": "Dry run",
"description": "When enabled, provider will not modify or create objects in the remote system."
} }
}, },
"required": [] "required": []
@ -14344,6 +14354,11 @@
"suspend" "suspend"
], ],
"title": "Group delete action" "title": "Group delete action"
},
"dry_run": {
"type": "boolean",
"title": "Dry run",
"description": "When enabled, provider will not modify or create objects in the remote system."
} }
}, },
"required": [] "required": []

View File

@ -10,6 +10,7 @@ import (
"goauthentik.io/internal/common" "goauthentik.io/internal/common"
"goauthentik.io/internal/config" "goauthentik.io/internal/config"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/debug" "goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/healthcheck" "goauthentik.io/internal/outpost/ak/healthcheck"
@ -24,7 +25,8 @@ Required environment variables:
- AUTHENTIK_INSECURE: Skip SSL Certificate verification` - AUTHENTIK_INSECURE: Skip SSL Certificate verification`
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Long: helpMessage, Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: func(cmd *cobra.Command, args []string) { PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{ log.SetFormatter(&log.JSONFormatter{

View File

@ -10,6 +10,7 @@ import (
"goauthentik.io/internal/common" "goauthentik.io/internal/common"
"goauthentik.io/internal/config" "goauthentik.io/internal/config"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/debug" "goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/healthcheck" "goauthentik.io/internal/outpost/ak/healthcheck"
@ -27,7 +28,8 @@ Optionally, you can set these:
- AUTHENTIK_HOST_BROWSER: URL to use in the browser, when it differs from AUTHENTIK_HOST` - AUTHENTIK_HOST_BROWSER: URL to use in the browser, when it differs from AUTHENTIK_HOST`
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Long: helpMessage, Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: func(cmd *cobra.Command, args []string) { PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{ log.SetFormatter(&log.JSONFormatter{

View File

@ -9,6 +9,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"goauthentik.io/internal/common" "goauthentik.io/internal/common"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/debug" "goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/healthcheck" "goauthentik.io/internal/outpost/ak/healthcheck"
@ -23,7 +24,8 @@ Required environment variables:
- AUTHENTIK_INSECURE: Skip SSL Certificate verification` - AUTHENTIK_INSECURE: Skip SSL Certificate verification`
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Long: helpMessage, Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: func(cmd *cobra.Command, args []string) { PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{ log.SetFormatter(&log.JSONFormatter{

View File

@ -9,6 +9,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"goauthentik.io/internal/common" "goauthentik.io/internal/common"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/debug" "goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak" "goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/healthcheck" "goauthentik.io/internal/outpost/ak/healthcheck"
@ -23,7 +24,8 @@ Required environment variables:
- AUTHENTIK_INSECURE: Skip SSL Certificate verification` - AUTHENTIK_INSECURE: Skip SSL Certificate verification`
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Long: helpMessage, Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: func(cmd *cobra.Command, args []string) { PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{ log.SetFormatter(&log.JSONFormatter{

View File

@ -31,7 +31,7 @@ services:
volumes: volumes:
- redis:/data - redis:/data
server: server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.12.3} image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.2.1}
restart: unless-stopped restart: unless-stopped
command: server command: server
environment: environment:
@ -54,7 +54,7 @@ services:
redis: redis:
condition: service_healthy condition: service_healthy
worker: worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.12.3} image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.2.1}
restart: unless-stopped restart: unless-stopped
command: worker command: worker
environment: environment:

26
go.mod
View File

@ -1,8 +1,8 @@
module goauthentik.io module goauthentik.io
go 1.23 go 1.23.0
toolchain go1.23.0 toolchain go1.24.0
require ( require (
beryju.io/ldap v0.1.0 beryju.io/ldap v0.1.0
@ -22,17 +22,17 @@ require (
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
github.com/pires/go-proxyproto v0.8.0 github.com/pires/go-proxyproto v0.8.0
github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_golang v1.21.1
github.com/redis/go-redis/v9 v9.7.0 github.com/redis/go-redis/v9 v9.7.1
github.com/sethvargo/go-envconfig v1.1.1 github.com/sethvargo/go-envconfig v1.1.1
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.9.1 github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/wwt/guac v1.3.2 github.com/wwt/guac v1.3.2
goauthentik.io/api/v3 v3.2024123.6 goauthentik.io/api/v3 v3.2025021.2
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
golang.org/x/oauth2 v0.26.0 golang.org/x/oauth2 v0.28.0
golang.org/x/sync v0.11.0 golang.org/x/sync v0.12.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
) )
@ -48,7 +48,7 @@ require (
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 // indirect github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 // indirect
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a // indirect github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect github.com/go-openapi/analysis v0.23.0 // indirect
@ -62,23 +62,23 @@ require (
github.com/go-openapi/validate v0.24.0 // indirect github.com/go-openapi/validate v0.24.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/compress v1.17.11 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/ulid v1.3.1 // indirect github.com/oklog/ulid v1.3.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect github.com/spf13/pflag v1.0.6 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/crypto v0.31.0 // indirect golang.org/x/crypto v0.32.0 // indirect
golang.org/x/sys v0.28.0 // indirect golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.21.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

42
go.sum
View File

@ -84,8 +84,8 @@ github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 h1:O6yi4xa9b2D
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27/go.mod h1:AYvN8omj7nKLmbcXS2dyABYU6JB1Lz1bHmkkq1kf4I4= github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27/go.mod h1:AYvN8omj7nKLmbcXS2dyABYU6JB1Lz1bHmkkq1kf4I4=
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno= github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno=
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw= github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw=
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-ldap/ldap/v3 v3.4.10 h1:ot/iwPOhfpNVgB1o+AVXljizWZ9JTp7YF5oeyONmcJU= github.com/go-ldap/ldap/v3 v3.4.10 h1:ot/iwPOhfpNVgB1o+AVXljizWZ9JTp7YF5oeyONmcJU=
github.com/go-ldap/ldap/v3 v3.4.10/go.mod h1:JXh4Uxgi40P6E9rdsYqpUtbW46D9UTjJ9QSwGRznplY= github.com/go-ldap/ldap/v3 v3.4.10/go.mod h1:JXh4Uxgi40P6E9rdsYqpUtbW46D9UTjJ9QSwGRznplY=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@ -207,8 +207,8 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -239,17 +239,17 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= github.com/redis/go-redis/v9 v9.7.1 h1:4LhKRCIduqXqtvCUlaq9c8bdHOkICjDMrr1+Zb3osAc=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
@ -299,8 +299,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
goauthentik.io/api/v3 v3.2024123.6 h1:AGOCa7Fc/9eONCPEW4sEhTiyEBvxN57Lfqz1zm6Gy98= goauthentik.io/api/v3 v3.2025021.2 h1:9y87piH47omtkWxQpKZaKai/+jh+cJdLxj5MC2Y/ZLI=
goauthentik.io/api/v3 v3.2024123.6/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= goauthentik.io/api/v3 v3.2025021.2/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -312,8 +312,9 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -393,8 +394,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -409,8 +410,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -447,8 +448,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -595,8 +597,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

View File

@ -29,4 +29,4 @@ func UserAgent() string {
return fmt.Sprintf("authentik@%s", FullVersion()) return fmt.Sprintf("authentik@%s", FullVersion())
} }
const VERSION = "2024.12.3" const VERSION = "2025.2.1"

View File

@ -9,7 +9,7 @@
"version": "0.0.0", "version": "0.0.0",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"aws-cdk": "^2.179.0", "aws-cdk": "^2.1003.0",
"cross-env": "^7.0.3" "cross-env": "^7.0.3"
}, },
"engines": { "engines": {
@ -17,9 +17,9 @@
} }
}, },
"node_modules/aws-cdk": { "node_modules/aws-cdk": {
"version": "2.179.0", "version": "2.1003.0",
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.179.0.tgz", "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1003.0.tgz",
"integrity": "sha512-aA2+8S2g4UBQHkUEt0mYd16VLt/ucR+QfyUJi34LDKRAhOCNDjPCZ4z9z/JEDyuni0BdzsYA55pnpDN9tMULpA==", "integrity": "sha512-FORPDGW8oUg4tXFlhX+lv/j+152LO9wwi3/CwNr1WY3c3HwJUtc0fZGb2B3+Fzy6NhLWGHJclUsJPEhjEt8Nhg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {

View File

@ -10,7 +10,7 @@
"node": ">=20" "node": ">=20"
}, },
"devDependencies": { "devDependencies": {
"aws-cdk": "^2.179.0", "aws-cdk": "^2.1003.0",
"cross-env": "^7.0.3" "cross-env": "^7.0.3"
} }
} }

View File

@ -26,7 +26,7 @@ Parameters:
Description: authentik Docker image Description: authentik Docker image
AuthentikVersion: AuthentikVersion:
Type: String Type: String
Default: 2024.12.3 Default: 2025.2.1
Description: authentik Docker image tag Description: authentik Docker image tag
AuthentikServerCPU: AuthentikServerCPU:
Type: Number Type: Number

View File

@ -63,7 +63,9 @@ def wait_for_db():
# Sanity check, ensure SECRET_KEY is set before we even check for database connectivity # Sanity check, ensure SECRET_KEY is set before we even check for database connectivity
if CONFIG.get("secret_key") is None or len(CONFIG.get("secret_key")) == 0: if CONFIG.get("secret_key") is None or len(CONFIG.get("secret_key")) == 0:
CONFIG.log("info", "----------------------------------------------------------------------") CONFIG.log("info", "----------------------------------------------------------------------")
CONFIG.log("info", "Secret key missing, check https://goauthentik.io/docs/installation/.") CONFIG.log(
"info", "Secret key missing, check https://docs.goauthentik.io/docs/install-config/"
)
CONFIG.log("info", "----------------------------------------------------------------------") CONFIG.log("info", "----------------------------------------------------------------------")
sysexit(1) sysexit(1)
check_postgres() check_postgres()

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-14 14:49+0000\n" "POT-Creation-Date: 2025-03-02 00:10+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -109,6 +109,10 @@ msgstr ""
msgid "Extra description not available" msgid "Extra description not available"
msgstr "" msgstr ""
#: authentik/core/api/groups.py
msgid "Cannot set group as parent of itself."
msgstr ""
#: authentik/core/api/providers.py #: authentik/core/api/providers.py
msgid "" msgid ""
"When not set all providers are returned. When set to true, only backchannel " "When not set all providers are returned. When set to true, only backchannel "
@ -152,6 +156,14 @@ msgstr ""
msgid "Remove user from group" msgid "Remove user from group"
msgstr "" msgstr ""
#: authentik/core/models.py
msgid "Enable superuser status"
msgstr ""
#: authentik/core/models.py
msgid "Disable superuser status"
msgstr ""
#: authentik/core/models.py #: authentik/core/models.py
msgid "User's display name." msgid "User's display name."
msgstr "" msgstr ""
@ -500,57 +512,6 @@ msgstr ""
msgid "Microsoft Entra Provider Mappings" msgid "Microsoft Entra Provider Mappings"
msgstr "" msgstr ""
#: authentik/enterprise/providers/rac/models.py
#: authentik/stages/user_login/models.py
msgid ""
"Determines how long a session lasts. Default of 0 means that the sessions "
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr ""
#: authentik/enterprise/providers/rac/models.py
msgid "When set to true, connection tokens will be deleted upon disconnect."
msgstr ""
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider"
msgstr ""
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Providers"
msgstr ""
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Endpoint"
msgstr ""
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Endpoints"
msgstr ""
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider Property Mapping"
msgstr ""
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider Property Mappings"
msgstr ""
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Connection token"
msgstr ""
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Connection tokens"
msgstr ""
#: authentik/enterprise/providers/rac/views.py
msgid "Maximum connection limit reached."
msgstr ""
#: authentik/enterprise/providers/rac/views.py
msgid "(You are already connected in another tab/window)"
msgstr ""
#: authentik/enterprise/providers/ssf/models.py #: authentik/enterprise/providers/ssf/models.py
#: authentik/providers/oauth2/models.py #: authentik/providers/oauth2/models.py
msgid "Signing Key" msgid "Signing Key"
@ -651,7 +612,7 @@ msgstr ""
msgid "Slack Webhook (Slack/Discord)" msgid "Slack Webhook (Slack/Discord)"
msgstr "" msgstr ""
#: authentik/events/models.py #: authentik/events/models.py authentik/stages/authenticator_validate/models.py
msgid "Email" msgid "Email"
msgstr "" msgstr ""
@ -904,6 +865,12 @@ msgstr ""
msgid "Invalid next URL" msgid "Invalid next URL"
msgstr "" msgstr ""
#: authentik/lib/sync/outgoing/models.py
msgid ""
"When enabled, provider will not modify or create objects in the remote "
"system."
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Starting full provider sync" msgid "Starting full provider sync"
msgstr "" msgstr ""
@ -918,6 +885,10 @@ msgstr ""
msgid "Syncing page {page} of groups" msgid "Syncing page {page} of groups"
msgstr "" msgstr ""
#: authentik/lib/sync/outgoing/tasks.py
msgid "Dropping mutating request due to dry run"
msgstr ""
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
msgid "Stopping sync due to error: {error}" msgid "Stopping sync due to error: {error}"
@ -1105,6 +1076,14 @@ msgstr ""
msgid "Client IP is not in an allowed country." msgid "Client IP is not in an allowed country."
msgstr "" msgstr ""
#: authentik/policies/geoip/models.py
msgid "Distance from previous authentication is larger than threshold."
msgstr ""
#: authentik/policies/geoip/models.py
msgid "Distance is further than possible."
msgstr ""
#: authentik/policies/geoip/models.py #: authentik/policies/geoip/models.py
msgid "GeoIP Policy" msgid "GeoIP Policy"
msgstr "" msgstr ""
@ -1396,6 +1375,14 @@ msgstr ""
msgid "ES256 (Asymmetric Encryption)" msgid "ES256 (Asymmetric Encryption)"
msgstr "" msgstr ""
#: authentik/providers/oauth2/models.py
msgid "ES384 (Asymmetric Encryption)"
msgstr ""
#: authentik/providers/oauth2/models.py
msgid "ES512 (Asymmetric Encryption)"
msgstr ""
#: authentik/providers/oauth2/models.py #: authentik/providers/oauth2/models.py
msgid "Scope used by the client" msgid "Scope used by the client"
msgstr "" msgstr ""
@ -1643,6 +1630,56 @@ msgstr ""
msgid "Proxy Providers" msgid "Proxy Providers"
msgstr "" msgstr ""
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
msgid ""
"Determines how long a session lasts. Default of 0 means that the sessions "
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr ""
#: authentik/providers/rac/models.py
msgid "When set to true, connection tokens will be deleted upon disconnect."
msgstr ""
#: authentik/providers/rac/models.py
msgid "RAC Provider"
msgstr ""
#: authentik/providers/rac/models.py
msgid "RAC Providers"
msgstr ""
#: authentik/providers/rac/models.py
msgid "RAC Endpoint"
msgstr ""
#: authentik/providers/rac/models.py
msgid "RAC Endpoints"
msgstr ""
#: authentik/providers/rac/models.py
msgid "RAC Provider Property Mapping"
msgstr ""
#: authentik/providers/rac/models.py
msgid "RAC Provider Property Mappings"
msgstr ""
#: authentik/providers/rac/models.py
msgid "RAC Connection token"
msgstr ""
#: authentik/providers/rac/models.py
msgid "RAC Connection tokens"
msgstr ""
#: authentik/providers/rac/views.py
msgid "Maximum connection limit reached."
msgstr ""
#: authentik/providers/rac/views.py
msgid "(You are already connected in another tab/window)"
msgstr ""
#: authentik/providers/radius/models.py #: authentik/providers/radius/models.py
msgid "Shared secret between clients and server to hash packets." msgid "Shared secret between clients and server to hash packets."
msgstr "" msgstr ""
@ -2486,6 +2523,98 @@ msgstr ""
msgid "Duo Devices" msgid "Duo Devices"
msgstr "" msgstr ""
#: authentik/stages/authenticator_email/models.py
msgid "Email OTP"
msgstr ""
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/email/models.py
msgid ""
"When enabled, global Email connection settings will be used and connection "
"settings below will be ignored."
msgstr ""
#: authentik/stages/authenticator_email/models.py
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
msgstr ""
#: authentik/stages/authenticator_email/models.py
msgid "Email Authenticator Setup Stage"
msgstr ""
#: authentik/stages/authenticator_email/models.py
msgid "Email Authenticator Setup Stages"
msgstr ""
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/authenticator_email/stage.py
#: authentik/stages/email/stage.py
msgid "Exception occurred while rendering E-mail template"
msgstr ""
#: authentik/stages/authenticator_email/models.py
msgid "Email Device"
msgstr ""
#: authentik/stages/authenticator_email/models.py
msgid "Email Devices"
msgstr ""
#: authentik/stages/authenticator_email/stage.py
#: authentik/stages/authenticator_sms/stage.py
#: authentik/stages/authenticator_totp/stage.py
msgid "Code does not match"
msgstr ""
#: authentik/stages/authenticator_email/stage.py
msgid "Invalid email"
msgstr ""
#: authentik/stages/authenticator_email/templates/email/email_otp.html
#: authentik/stages/email/templates/email/password_reset.html
#, python-format
msgid ""
"\n"
" Hi %(username)s,\n"
" "
msgstr ""
#: authentik/stages/authenticator_email/templates/email/email_otp.html
msgid ""
"\n"
" Email MFA code.\n"
" "
msgstr ""
#: authentik/stages/authenticator_email/templates/email/email_otp.html
#, python-format
msgid ""
"\n"
" If you did not request this code, please ignore this email. The code "
"above is valid for %(expires)s.\n"
" "
msgstr ""
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
#: authentik/stages/email/templates/email/password_reset.txt
#, python-format
msgid "Hi %(username)s,"
msgstr ""
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
msgid ""
"\n"
"Email MFA code\n"
msgstr ""
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
#, python-format
msgid ""
"\n"
"If you did not request this code, please ignore this email. The code above "
"is valid for %(expires)s.\n"
msgstr ""
#: authentik/stages/authenticator_sms/models.py #: authentik/stages/authenticator_sms/models.py
msgid "" msgid ""
"When enabled, the Phone number is only used during enrollment to verify the " "When enabled, the Phone number is only used during enrollment to verify the "
@ -2518,11 +2647,6 @@ msgstr ""
msgid "SMS Devices" msgid "SMS Devices"
msgstr "" msgstr ""
#: authentik/stages/authenticator_sms/stage.py
#: authentik/stages/authenticator_totp/stage.py
msgid "Code does not match"
msgstr ""
#: authentik/stages/authenticator_sms/stage.py #: authentik/stages/authenticator_sms/stage.py
msgid "Invalid phone number" msgid "Invalid phone number"
msgstr "" msgstr ""
@ -2745,12 +2869,6 @@ msgstr ""
msgid "Account Confirmation" msgid "Account Confirmation"
msgstr "" msgstr ""
#: authentik/stages/email/models.py
msgid ""
"When enabled, global Email connection settings will be used and connection "
"settings below will be ignored."
msgstr ""
#: authentik/stages/email/models.py #: authentik/stages/email/models.py
msgid "Activate users upon completion of stage." msgid "Activate users upon completion of stage."
msgstr "" msgstr ""
@ -2767,10 +2885,6 @@ msgstr ""
msgid "Email Stages" msgid "Email Stages"
msgstr "" msgstr ""
#: authentik/stages/email/stage.py
msgid "Exception occurred while rendering E-mail template"
msgstr ""
#: authentik/stages/email/stage.py #: authentik/stages/email/stage.py
msgid "Successfully verified Email." msgid "Successfully verified Email."
msgstr "" msgstr ""
@ -2845,14 +2959,6 @@ msgid ""
"This email was sent from the notification transport %(name)s.\n" "This email was sent from the notification transport %(name)s.\n"
msgstr "" msgstr ""
#: authentik/stages/email/templates/email/password_reset.html
#, python-format
msgid ""
"\n"
" Hi %(username)s,\n"
" "
msgstr ""
#: authentik/stages/email/templates/email/password_reset.html #: authentik/stages/email/templates/email/password_reset.html
msgid "" msgid ""
"\n" "\n"
@ -2870,11 +2976,6 @@ msgid ""
" " " "
msgstr "" msgstr ""
#: authentik/stages/email/templates/email/password_reset.txt
#, python-format
msgid "Hi %(username)s,"
msgstr ""
#: authentik/stages/email/templates/email/password_reset.txt #: authentik/stages/email/templates/email/password_reset.txt
msgid "" msgid ""
"\n" "\n"

Binary file not shown.

View File

@ -19,7 +19,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-14 14:49+0000\n" "POT-Creation-Date: 2025-03-02 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Marc Schmitt, 2025\n" "Last-Translator: Marc Schmitt, 2025\n"
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n" "Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
@ -129,6 +129,10 @@ msgstr "L'utilisateur n'a pas accès à l'application."
msgid "Extra description not available" msgid "Extra description not available"
msgstr "Description supplémentaire indisponible" msgstr "Description supplémentaire indisponible"
#: authentik/core/api/groups.py
msgid "Cannot set group as parent of itself."
msgstr "Impossible de définir le groupe en tant que parent de lui-même."
#: authentik/core/api/providers.py #: authentik/core/api/providers.py
msgid "" msgid ""
"When not set all providers are returned. When set to true, only backchannel " "When not set all providers are returned. When set to true, only backchannel "
@ -177,6 +181,14 @@ msgstr "Ajouter un utilisateur au groupe"
msgid "Remove user from group" msgid "Remove user from group"
msgstr "Retirer l'utilisateur du groupe" msgstr "Retirer l'utilisateur du groupe"
#: authentik/core/models.py
msgid "Enable superuser status"
msgstr "Activer le statut super-utilisateur"
#: authentik/core/models.py
msgid "Disable superuser status"
msgstr "Désactiver le statut super-utilisateur"
#: authentik/core/models.py #: authentik/core/models.py
msgid "User's display name." msgid "User's display name."
msgstr "Nom d'affichage de l'utilisateur" msgstr "Nom d'affichage de l'utilisateur"
@ -553,61 +565,6 @@ msgstr "Mappage de propriété Microsoft Entra"
msgid "Microsoft Entra Provider Mappings" msgid "Microsoft Entra Provider Mappings"
msgstr "Mappages de propriété Microsoft Entra" msgstr "Mappages de propriété Microsoft Entra"
#: authentik/enterprise/providers/rac/models.py
#: authentik/stages/user_login/models.py
msgid ""
"Determines how long a session lasts. Default of 0 means that the sessions "
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr ""
"Détermine la durée de la session. La valeur par défaut de 0 signifie que la "
"session dure jusqu'à la fermeture du navigateur. (Format : "
"hours=-1;minutes=-2;seconds=-3)"
#: authentik/enterprise/providers/rac/models.py
msgid "When set to true, connection tokens will be deleted upon disconnect."
msgstr ""
"Si activé, les jetons de connexion seront supprimés lors de la déconnexion."
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider"
msgstr "Fournisseur RAC"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Providers"
msgstr "Fournisseurs RAC"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Endpoint"
msgstr "Point de terminaison RAC"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Endpoints"
msgstr "Points de terminaison RAC"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider Property Mapping"
msgstr "Mappage de propriété fournisseur RAC"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider Property Mappings"
msgstr "Mappages de propriété fournisseur RAC"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Connection token"
msgstr "Jeton de connexion RAC"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Connection tokens"
msgstr "Jeton de connexions RAC"
#: authentik/enterprise/providers/rac/views.py
msgid "Maximum connection limit reached."
msgstr "Limite maximum de connection atteinte."
#: authentik/enterprise/providers/rac/views.py
msgid "(You are already connected in another tab/window)"
msgstr "(Vous êtes déjà connecté dans un autre onglet/une autre fenêtre)"
#: authentik/enterprise/providers/ssf/models.py #: authentik/enterprise/providers/ssf/models.py
#: authentik/providers/oauth2/models.py #: authentik/providers/oauth2/models.py
msgid "Signing Key" msgid "Signing Key"
@ -715,6 +672,7 @@ msgid "Slack Webhook (Slack/Discord)"
msgstr "Webhook Slack (ou Discord)" msgstr "Webhook Slack (ou Discord)"
#: authentik/events/models.py #: authentik/events/models.py
#: authentik/stages/authenticator_validate/models.py
msgid "Email" msgid "Email"
msgstr "Courriel" msgstr "Courriel"
@ -990,6 +948,14 @@ msgstr "Jetons du flux"
msgid "Invalid next URL" msgid "Invalid next URL"
msgstr "URL suivante invalide" msgstr "URL suivante invalide"
#: authentik/lib/sync/outgoing/models.py
msgid ""
"When enabled, provider will not modify or create objects in the remote "
"system."
msgstr ""
"Si activé, le fournisseur ne changera ou ne créera pas d'objets auprès du "
"système distant."
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Starting full provider sync" msgid "Starting full provider sync"
msgstr "Démarrage d'une synchronisation complète du fournisseur" msgstr "Démarrage d'une synchronisation complète du fournisseur"
@ -1004,6 +970,10 @@ msgstr "Synchronisation de la page {page} d'utilisateurs"
msgid "Syncing page {page} of groups" msgid "Syncing page {page} of groups"
msgstr "Synchronisation de la page {page} de groupes" msgstr "Synchronisation de la page {page} de groupes"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Dropping mutating request due to dry run"
msgstr "Abandon de la requête de mutation en raison d'une simulation"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
msgid "Stopping sync due to error: {error}" msgid "Stopping sync due to error: {error}"
@ -1219,6 +1189,16 @@ msgstr ""
msgid "Client IP is not in an allowed country." msgid "Client IP is not in an allowed country."
msgstr "L'IP du client ne fait pas partie d'un pays autorisé." msgstr "L'IP du client ne fait pas partie d'un pays autorisé."
#: authentik/policies/geoip/models.py
msgid "Distance from previous authentication is larger than threshold."
msgstr ""
"La distance par rapport à l'authentification précédente est supérieure au "
"seuil."
#: authentik/policies/geoip/models.py
msgid "Distance is further than possible."
msgstr "La distance est plus grande que possible."
#: authentik/policies/geoip/models.py #: authentik/policies/geoip/models.py
msgid "GeoIP Policy" msgid "GeoIP Policy"
msgstr "Politique GeoIP" msgstr "Politique GeoIP"
@ -1542,6 +1522,14 @@ msgstr "RS256 (chiffrement asymétrique)"
msgid "ES256 (Asymmetric Encryption)" msgid "ES256 (Asymmetric Encryption)"
msgstr "ES256 (Chiffrement Asymétrique)" msgstr "ES256 (Chiffrement Asymétrique)"
#: authentik/providers/oauth2/models.py
msgid "ES384 (Asymmetric Encryption)"
msgstr "ES384 (chiffrement asymétrique)"
#: authentik/providers/oauth2/models.py
msgid "ES512 (Asymmetric Encryption)"
msgstr "ES512 (chiffrement asymétrique)"
#: authentik/providers/oauth2/models.py #: authentik/providers/oauth2/models.py
msgid "Scope used by the client" msgid "Scope used by the client"
msgstr "Portées utilisées par le client" msgstr "Portées utilisées par le client"
@ -1825,6 +1813,60 @@ msgstr "Fournisseur Proxy"
msgid "Proxy Providers" msgid "Proxy Providers"
msgstr "Fournisseur de Proxy" msgstr "Fournisseur de Proxy"
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
msgid ""
"Determines how long a session lasts. Default of 0 means that the sessions "
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr ""
"Détermine la durée de la session. La valeur par défaut de 0 signifie que la "
"session dure jusqu'à la fermeture du navigateur. (Format : "
"hours=-1;minutes=-2;seconds=-3)"
#: authentik/providers/rac/models.py
msgid "When set to true, connection tokens will be deleted upon disconnect."
msgstr ""
"Si activé, les jetons de connexion seront supprimés lors de la déconnexion."
#: authentik/providers/rac/models.py
msgid "RAC Provider"
msgstr "Fournisseur RAC"
#: authentik/providers/rac/models.py
msgid "RAC Providers"
msgstr "Fournisseurs RAC"
#: authentik/providers/rac/models.py
msgid "RAC Endpoint"
msgstr "Point de terminaison RAC"
#: authentik/providers/rac/models.py
msgid "RAC Endpoints"
msgstr "Points de terminaison RAC"
#: authentik/providers/rac/models.py
msgid "RAC Provider Property Mapping"
msgstr "Mappage de propriété fournisseur RAC"
#: authentik/providers/rac/models.py
msgid "RAC Provider Property Mappings"
msgstr "Mappages de propriété fournisseur RAC"
#: authentik/providers/rac/models.py
msgid "RAC Connection token"
msgstr "Jeton de connexion RAC"
#: authentik/providers/rac/models.py
msgid "RAC Connection tokens"
msgstr "Jeton de connexions RAC"
#: authentik/providers/rac/views.py
msgid "Maximum connection limit reached."
msgstr "Limite maximum de connection atteinte."
#: authentik/providers/rac/views.py
msgid "(You are already connected in another tab/window)"
msgstr "(Vous êtes déjà connecté dans un autre onglet/une autre fenêtre)"
#: authentik/providers/radius/models.py #: authentik/providers/radius/models.py
msgid "Shared secret between clients and server to hash packets." msgid "Shared secret between clients and server to hash packets."
msgstr "" msgstr ""
@ -2741,6 +2783,112 @@ msgstr "Appareil Duo"
msgid "Duo Devices" msgid "Duo Devices"
msgstr "Appareils Duo" msgstr "Appareils Duo"
#: authentik/stages/authenticator_email/models.py
msgid "Email OTP"
msgstr "OTP Courriel"
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/email/models.py
msgid ""
"When enabled, global Email connection settings will be used and connection "
"settings below will be ignored."
msgstr ""
"Si activé, les paramètres globaux de connexion courriel seront utilisés et "
"les paramètres de connexion ci-dessous seront ignorés."
#: authentik/stages/authenticator_email/models.py
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
msgstr ""
"Durée de validité du jeton envoyé (Format : hours=3,minutes=17,seconds=300)."
#: authentik/stages/authenticator_email/models.py
msgid "Email Authenticator Setup Stage"
msgstr "Étape de configuration de l'authentificateur courriel"
#: authentik/stages/authenticator_email/models.py
msgid "Email Authenticator Setup Stages"
msgstr "Étapes de configuration de l'authentificateur courriel"
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/authenticator_email/stage.py
#: authentik/stages/email/stage.py
msgid "Exception occurred while rendering E-mail template"
msgstr "Une erreur s'est produite lors de la modélisation du couriel"
#: authentik/stages/authenticator_email/models.py
msgid "Email Device"
msgstr "Équipement courriel"
#: authentik/stages/authenticator_email/models.py
msgid "Email Devices"
msgstr "Équipements courriel"
#: authentik/stages/authenticator_email/stage.py
#: authentik/stages/authenticator_sms/stage.py
#: authentik/stages/authenticator_totp/stage.py
msgid "Code does not match"
msgstr "Le Code ne correspond pas"
#: authentik/stages/authenticator_email/stage.py
msgid "Invalid email"
msgstr "Courriel invalide"
#: authentik/stages/authenticator_email/templates/email/email_otp.html
#: authentik/stages/email/templates/email/password_reset.html
#, python-format
msgid ""
"\n"
" Hi %(username)s,\n"
" "
msgstr ""
"\n"
" Salut %(username)s,\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.html
msgid ""
"\n"
" Email MFA code.\n"
" "
msgstr ""
"\n"
" Code MFA envoyé par courriel.\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.html
#, python-format
msgid ""
"\n"
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
" "
msgstr ""
"\n"
" Si vous n'avez pas demandé ce code, veuillez ignorer ce courriel. Le code ci-dessus est valid pendant %(expires)s.\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
#: authentik/stages/email/templates/email/password_reset.txt
#, python-format
msgid "Hi %(username)s,"
msgstr "Bonjour %(username)s,"
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
msgid ""
"\n"
"Email MFA code\n"
msgstr ""
"\n"
"Code MFA envoyé par e-mail\n"
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
#, python-format
msgid ""
"\n"
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
msgstr ""
"\n"
"Si vous n'avez pas demandé ce code, veuillez ignorer ce courriel. Le code ci-dessus est valid pendant %(expires)s.\n"
#: authentik/stages/authenticator_sms/models.py #: authentik/stages/authenticator_sms/models.py
msgid "" msgid ""
"When enabled, the Phone number is only used during enrollment to verify the " "When enabled, the Phone number is only used during enrollment to verify the "
@ -2778,11 +2926,6 @@ msgstr "Appareil SMS"
msgid "SMS Devices" msgid "SMS Devices"
msgstr "Appareils SMS" msgstr "Appareils SMS"
#: authentik/stages/authenticator_sms/stage.py
#: authentik/stages/authenticator_totp/stage.py
msgid "Code does not match"
msgstr "Le Code ne correspond pas"
#: authentik/stages/authenticator_sms/stage.py #: authentik/stages/authenticator_sms/stage.py
msgid "Invalid phone number" msgid "Invalid phone number"
msgstr "Numéro de téléphone invalide" msgstr "Numéro de téléphone invalide"
@ -3021,14 +3164,6 @@ msgstr "Réinitialiser le Mot de Passe"
msgid "Account Confirmation" msgid "Account Confirmation"
msgstr "Confirmation du Compte" msgstr "Confirmation du Compte"
#: authentik/stages/email/models.py
msgid ""
"When enabled, global Email connection settings will be used and connection "
"settings below will be ignored."
msgstr ""
"Si activé, les paramètres globaux de connexion courriel seront utilisés et "
"les paramètres de connexion ci-dessous seront ignorés."
#: authentik/stages/email/models.py #: authentik/stages/email/models.py
msgid "Activate users upon completion of stage." msgid "Activate users upon completion of stage."
msgstr "Activer les utilisateurs à la complétion de l'étape." msgstr "Activer les utilisateurs à la complétion de l'étape."
@ -3045,10 +3180,6 @@ msgstr "Étape Email"
msgid "Email Stages" msgid "Email Stages"
msgstr "Étape Email" msgstr "Étape Email"
#: authentik/stages/email/stage.py
msgid "Exception occurred while rendering E-mail template"
msgstr "Une erreur s'est produite lors de la modélisation du couriel"
#: authentik/stages/email/stage.py #: authentik/stages/email/stage.py
msgid "Successfully verified Email." msgid "Successfully verified Email."
msgstr "Email vérifié avec succès." msgstr "Email vérifié avec succès."
@ -3133,17 +3264,6 @@ msgstr ""
"\n" "\n"
"Cet email a été envoyé depuis le transport de notification %(name)s.\n" "Cet email a été envoyé depuis le transport de notification %(name)s.\n"
#: authentik/stages/email/templates/email/password_reset.html
#, python-format
msgid ""
"\n"
" Hi %(username)s,\n"
" "
msgstr ""
"\n"
" Salut %(username)s,\n"
" "
#: authentik/stages/email/templates/email/password_reset.html #: authentik/stages/email/templates/email/password_reset.html
msgid "" msgid ""
"\n" "\n"
@ -3165,11 +3285,6 @@ msgstr ""
" Si vous n'avez pas requis de changement de mot de passe, veuillez ignorer cet e-mail. Le lien ci-dessus est valide pendant %(expires)s.\n" " Si vous n'avez pas requis de changement de mot de passe, veuillez ignorer cet e-mail. Le lien ci-dessus est valide pendant %(expires)s.\n"
" " " "
#: authentik/stages/email/templates/email/password_reset.txt
#, python-format
msgid "Hi %(username)s,"
msgstr "Bonjour %(username)s,"
#: authentik/stages/email/templates/email/password_reset.txt #: authentik/stages/email/templates/email/password_reset.txt
msgid "" msgid ""
"\n" "\n"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -15,7 +15,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-14 14:49+0000\n" "POT-Creation-Date: 2025-03-02 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2025\n" "Last-Translator: deluxghost, 2025\n"
"Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n" "Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n"
@ -118,6 +118,10 @@ msgstr "用户没有访问此应用程序的权限。"
msgid "Extra description not available" msgid "Extra description not available"
msgstr "额外描述不可用" msgstr "额外描述不可用"
#: authentik/core/api/groups.py
msgid "Cannot set group as parent of itself."
msgstr "无法设置组自身为父级。"
#: authentik/core/api/providers.py #: authentik/core/api/providers.py
msgid "" msgid ""
"When not set all providers are returned. When set to true, only backchannel " "When not set all providers are returned. When set to true, only backchannel "
@ -162,6 +166,14 @@ msgstr "添加用户到组"
msgid "Remove user from group" msgid "Remove user from group"
msgstr "从组中删除用户" msgstr "从组中删除用户"
#: authentik/core/models.py
msgid "Enable superuser status"
msgstr "启用超级用户状态"
#: authentik/core/models.py
msgid "Disable superuser status"
msgstr "禁用超级用户状态"
#: authentik/core/models.py #: authentik/core/models.py
msgid "User's display name." msgid "User's display name."
msgstr "用户的显示名称。" msgstr "用户的显示名称。"
@ -510,57 +522,6 @@ msgstr "Microsoft Entra 提供程序映射"
msgid "Microsoft Entra Provider Mappings" msgid "Microsoft Entra Provider Mappings"
msgstr "Microsoft Entra 提供程序映射" msgstr "Microsoft Entra 提供程序映射"
#: authentik/enterprise/providers/rac/models.py
#: authentik/stages/user_login/models.py
msgid ""
"Determines how long a session lasts. Default of 0 means that the sessions "
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr "确定会话持续多长时间。默认值为 0 表示会话持续到浏览器关闭为止。格式hours=-1;minutes=-2;seconds=-3"
#: authentik/enterprise/providers/rac/models.py
msgid "When set to true, connection tokens will be deleted upon disconnect."
msgstr "启用时,连接令牌将会在断开连接时被删除。"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider"
msgstr "RAC 提供程序"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Providers"
msgstr "RAC 提供程序"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Endpoint"
msgstr "RAC 端点"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Endpoints"
msgstr "RAC 端点"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider Property Mapping"
msgstr "RAC 提供程序属性映射"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider Property Mappings"
msgstr "RAC 提供程序属性映射"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Connection token"
msgstr "RAC 连接令牌"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Connection tokens"
msgstr "RAC 连接令牌"
#: authentik/enterprise/providers/rac/views.py
msgid "Maximum connection limit reached."
msgstr "已达到最大连接数。"
#: authentik/enterprise/providers/rac/views.py
msgid "(You are already connected in another tab/window)"
msgstr "(您已经在另一个标签页/窗口连接了)"
#: authentik/enterprise/providers/ssf/models.py #: authentik/enterprise/providers/ssf/models.py
#: authentik/providers/oauth2/models.py #: authentik/providers/oauth2/models.py
msgid "Signing Key" msgid "Signing Key"
@ -662,6 +623,7 @@ msgid "Slack Webhook (Slack/Discord)"
msgstr "Slack WebhookSlack/Discord" msgstr "Slack WebhookSlack/Discord"
#: authentik/events/models.py #: authentik/events/models.py
#: authentik/stages/authenticator_validate/models.py
msgid "Email" msgid "Email"
msgstr "电子邮箱" msgstr "电子邮箱"
@ -916,6 +878,12 @@ msgstr "流程令牌"
msgid "Invalid next URL" msgid "Invalid next URL"
msgstr "无效的 next URL" msgstr "无效的 next URL"
#: authentik/lib/sync/outgoing/models.py
msgid ""
"When enabled, provider will not modify or create objects in the remote "
"system."
msgstr "启用时,提供程序将不会在远程系统上修改或创建对象。"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Starting full provider sync" msgid "Starting full provider sync"
msgstr "开始全量提供程序同步" msgstr "开始全量提供程序同步"
@ -930,6 +898,10 @@ msgstr "正在同步用户页面 {page}"
msgid "Syncing page {page} of groups" msgid "Syncing page {page} of groups"
msgstr "正在同步群组页面 {page}" msgstr "正在同步群组页面 {page}"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Dropping mutating request due to dry run"
msgstr "由于启用了试运行,已放弃变更请求"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
msgid "Stopping sync due to error: {error}" msgid "Stopping sync due to error: {error}"
@ -1119,6 +1091,14 @@ msgstr "GeoIP无法在城市数据库中找到客户端 IP。"
msgid "Client IP is not in an allowed country." msgid "Client IP is not in an allowed country."
msgstr "客户端 IP 不在受允许的地区。" msgstr "客户端 IP 不在受允许的地区。"
#: authentik/policies/geoip/models.py
msgid "Distance from previous authentication is larger than threshold."
msgstr "与上一次身份验证的距离超过阈值。"
#: authentik/policies/geoip/models.py
msgid "Distance is further than possible."
msgstr "距离大幅超过可能值。"
#: authentik/policies/geoip/models.py #: authentik/policies/geoip/models.py
msgid "GeoIP Policy" msgid "GeoIP Policy"
msgstr "GeoIP 策略" msgstr "GeoIP 策略"
@ -1419,6 +1399,14 @@ msgstr "RS256非对称加密"
msgid "ES256 (Asymmetric Encryption)" msgid "ES256 (Asymmetric Encryption)"
msgstr "ES256非对称加密" msgstr "ES256非对称加密"
#: authentik/providers/oauth2/models.py
msgid "ES384 (Asymmetric Encryption)"
msgstr "ES384非对称加密"
#: authentik/providers/oauth2/models.py
msgid "ES512 (Asymmetric Encryption)"
msgstr "ES512非对称加密"
#: authentik/providers/oauth2/models.py #: authentik/providers/oauth2/models.py
msgid "Scope used by the client" msgid "Scope used by the client"
msgstr "客户端使用的作用域" msgstr "客户端使用的作用域"
@ -1668,6 +1656,56 @@ msgstr "代理提供程序"
msgid "Proxy Providers" msgid "Proxy Providers"
msgstr "代理提供程序" msgstr "代理提供程序"
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
msgid ""
"Determines how long a session lasts. Default of 0 means that the sessions "
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr "确定会话持续多长时间。默认值为 0 表示会话持续到浏览器关闭为止。格式hours=-1;minutes=-2;seconds=-3"
#: authentik/providers/rac/models.py
msgid "When set to true, connection tokens will be deleted upon disconnect."
msgstr "启用时,连接令牌将会在断开连接时被删除。"
#: authentik/providers/rac/models.py
msgid "RAC Provider"
msgstr "RAC 提供程序"
#: authentik/providers/rac/models.py
msgid "RAC Providers"
msgstr "RAC 提供程序"
#: authentik/providers/rac/models.py
msgid "RAC Endpoint"
msgstr "RAC 端点"
#: authentik/providers/rac/models.py
msgid "RAC Endpoints"
msgstr "RAC 端点"
#: authentik/providers/rac/models.py
msgid "RAC Provider Property Mapping"
msgstr "RAC 提供程序属性映射"
#: authentik/providers/rac/models.py
msgid "RAC Provider Property Mappings"
msgstr "RAC 提供程序属性映射"
#: authentik/providers/rac/models.py
msgid "RAC Connection token"
msgstr "RAC 连接令牌"
#: authentik/providers/rac/models.py
msgid "RAC Connection tokens"
msgstr "RAC 连接令牌"
#: authentik/providers/rac/views.py
msgid "Maximum connection limit reached."
msgstr "已达到最大连接数。"
#: authentik/providers/rac/views.py
msgid "(You are already connected in another tab/window)"
msgstr "(您已经在另一个标签页/窗口连接了)"
#: authentik/providers/radius/models.py #: authentik/providers/radius/models.py
msgid "Shared secret between clients and server to hash packets." msgid "Shared secret between clients and server to hash packets."
msgstr "用于哈希处理数据包的客户端服务端共享密钥。" msgstr "用于哈希处理数据包的客户端服务端共享密钥。"
@ -2521,6 +2559,109 @@ msgstr "Duo 设备"
msgid "Duo Devices" msgid "Duo Devices"
msgstr "Duo 设备" msgstr "Duo 设备"
#: authentik/stages/authenticator_email/models.py
msgid "Email OTP"
msgstr "电子邮件 OTP"
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/email/models.py
msgid ""
"When enabled, global Email connection settings will be used and connection "
"settings below will be ignored."
msgstr "启用后,将使用全局电子邮件连接设置,下面的连接设置将被忽略。"
#: authentik/stages/authenticator_email/models.py
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
msgstr "发出令牌有效的时间格式hours=3,minutes=17,seconds=300。"
#: authentik/stages/authenticator_email/models.py
msgid "Email Authenticator Setup Stage"
msgstr "电子邮件身份验证器设置阶段"
#: authentik/stages/authenticator_email/models.py
msgid "Email Authenticator Setup Stages"
msgstr "电子邮件身份验证器设置阶段"
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/authenticator_email/stage.py
#: authentik/stages/email/stage.py
msgid "Exception occurred while rendering E-mail template"
msgstr "渲染电子邮件模板时发生异常"
#: authentik/stages/authenticator_email/models.py
msgid "Email Device"
msgstr "电子邮件设备"
#: authentik/stages/authenticator_email/models.py
msgid "Email Devices"
msgstr "电子邮件设备"
#: authentik/stages/authenticator_email/stage.py
#: authentik/stages/authenticator_sms/stage.py
#: authentik/stages/authenticator_totp/stage.py
msgid "Code does not match"
msgstr "代码不匹配"
#: authentik/stages/authenticator_email/stage.py
msgid "Invalid email"
msgstr "无效电子邮件"
#: authentik/stages/authenticator_email/templates/email/email_otp.html
#: authentik/stages/email/templates/email/password_reset.html
#, python-format
msgid ""
"\n"
" Hi %(username)s,\n"
" "
msgstr ""
"\n"
" %(username)s 您好,\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.html
msgid ""
"\n"
" Email MFA code.\n"
" "
msgstr ""
"\n"
" 电子邮件 MFA 代码。\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.html
#, python-format
msgid ""
"\n"
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
" "
msgstr ""
"\n"
" 如果您没有请求此代码,请忽略此电子邮件。上面的代码在 %(expires)s 内有效。\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
#: authentik/stages/email/templates/email/password_reset.txt
#, python-format
msgid "Hi %(username)s,"
msgstr "您好 %(username)s"
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
msgid ""
"\n"
"Email MFA code\n"
msgstr ""
"\n"
"电子邮件 MFA 代码\n"
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
#, python-format
msgid ""
"\n"
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
msgstr ""
"\n"
"如果您没有请求此代码,请忽略此电子邮件。上面的代码在 %(expires)s 内有效。\n"
#: authentik/stages/authenticator_sms/models.py #: authentik/stages/authenticator_sms/models.py
msgid "" msgid ""
"When enabled, the Phone number is only used during enrollment to verify the " "When enabled, the Phone number is only used during enrollment to verify the "
@ -2553,11 +2694,6 @@ msgstr "短信设备"
msgid "SMS Devices" msgid "SMS Devices"
msgstr "短信设备" msgstr "短信设备"
#: authentik/stages/authenticator_sms/stage.py
#: authentik/stages/authenticator_totp/stage.py
msgid "Code does not match"
msgstr "代码不匹配"
#: authentik/stages/authenticator_sms/stage.py #: authentik/stages/authenticator_sms/stage.py
msgid "Invalid phone number" msgid "Invalid phone number"
msgstr "无效电话号码" msgstr "无效电话号码"
@ -2780,12 +2916,6 @@ msgstr "密码重置"
msgid "Account Confirmation" msgid "Account Confirmation"
msgstr "账户确认" msgstr "账户确认"
#: authentik/stages/email/models.py
msgid ""
"When enabled, global Email connection settings will be used and connection "
"settings below will be ignored."
msgstr "启用后,将使用全局电子邮件连接设置,下面的连接设置将被忽略。"
#: authentik/stages/email/models.py #: authentik/stages/email/models.py
msgid "Activate users upon completion of stage." msgid "Activate users upon completion of stage."
msgstr "完成阶段后激活用户。" msgstr "完成阶段后激活用户。"
@ -2802,10 +2932,6 @@ msgstr "电子邮件阶段"
msgid "Email Stages" msgid "Email Stages"
msgstr "电子邮件阶段" msgstr "电子邮件阶段"
#: authentik/stages/email/stage.py
msgid "Exception occurred while rendering E-mail template"
msgstr "渲染电子邮件模板时发生异常"
#: authentik/stages/email/stage.py #: authentik/stages/email/stage.py
msgid "Successfully verified Email." msgid "Successfully verified Email."
msgstr "已成功验证电子邮件。" msgstr "已成功验证电子邮件。"
@ -2886,17 +3012,6 @@ msgstr ""
"\n" "\n"
"此邮件由通知递送 %(name)s 发送。\n" "此邮件由通知递送 %(name)s 发送。\n"
#: authentik/stages/email/templates/email/password_reset.html
#, python-format
msgid ""
"\n"
" Hi %(username)s,\n"
" "
msgstr ""
"\n"
" %(username)s 您好,\n"
" "
#: authentik/stages/email/templates/email/password_reset.html #: authentik/stages/email/templates/email/password_reset.html
msgid "" msgid ""
"\n" "\n"
@ -2918,11 +3033,6 @@ msgstr ""
" 如果您没有请求更改密码,请忽略此电子邮件。上面的链接在 %(expires)s 内有效。\n" " 如果您没有请求更改密码,请忽略此电子邮件。上面的链接在 %(expires)s 内有效。\n"
" " " "
#: authentik/stages/email/templates/email/password_reset.txt
#, python-format
msgid "Hi %(username)s,"
msgstr "您好 %(username)s"
#: authentik/stages/email/templates/email/password_reset.txt #: authentik/stages/email/templates/email/password_reset.txt
msgid "" msgid ""
"\n" "\n"

Binary file not shown.

View File

@ -14,7 +14,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-14 14:49+0000\n" "POT-Creation-Date: 2025-03-02 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2025\n" "Last-Translator: deluxghost, 2025\n"
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n" "Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n"
@ -117,6 +117,10 @@ msgstr "用户没有访问此应用程序的权限。"
msgid "Extra description not available" msgid "Extra description not available"
msgstr "额外描述不可用" msgstr "额外描述不可用"
#: authentik/core/api/groups.py
msgid "Cannot set group as parent of itself."
msgstr "无法设置组自身为父级。"
#: authentik/core/api/providers.py #: authentik/core/api/providers.py
msgid "" msgid ""
"When not set all providers are returned. When set to true, only backchannel " "When not set all providers are returned. When set to true, only backchannel "
@ -161,6 +165,14 @@ msgstr "添加用户到组"
msgid "Remove user from group" msgid "Remove user from group"
msgstr "从组中删除用户" msgstr "从组中删除用户"
#: authentik/core/models.py
msgid "Enable superuser status"
msgstr "启用超级用户状态"
#: authentik/core/models.py
msgid "Disable superuser status"
msgstr "禁用超级用户状态"
#: authentik/core/models.py #: authentik/core/models.py
msgid "User's display name." msgid "User's display name."
msgstr "用户的显示名称。" msgstr "用户的显示名称。"
@ -509,57 +521,6 @@ msgstr "Microsoft Entra 提供程序映射"
msgid "Microsoft Entra Provider Mappings" msgid "Microsoft Entra Provider Mappings"
msgstr "Microsoft Entra 提供程序映射" msgstr "Microsoft Entra 提供程序映射"
#: authentik/enterprise/providers/rac/models.py
#: authentik/stages/user_login/models.py
msgid ""
"Determines how long a session lasts. Default of 0 means that the sessions "
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr "确定会话持续多长时间。默认值为 0 表示会话持续到浏览器关闭为止。格式hours=-1;minutes=-2;seconds=-3"
#: authentik/enterprise/providers/rac/models.py
msgid "When set to true, connection tokens will be deleted upon disconnect."
msgstr "启用时,连接令牌将会在断开连接时被删除。"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider"
msgstr "RAC 提供程序"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Providers"
msgstr "RAC 提供程序"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Endpoint"
msgstr "RAC 端点"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Endpoints"
msgstr "RAC 端点"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider Property Mapping"
msgstr "RAC 提供程序属性映射"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Provider Property Mappings"
msgstr "RAC 提供程序属性映射"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Connection token"
msgstr "RAC 连接令牌"
#: authentik/enterprise/providers/rac/models.py
msgid "RAC Connection tokens"
msgstr "RAC 连接令牌"
#: authentik/enterprise/providers/rac/views.py
msgid "Maximum connection limit reached."
msgstr "已达到最大连接数。"
#: authentik/enterprise/providers/rac/views.py
msgid "(You are already connected in another tab/window)"
msgstr "(您已经在另一个标签页/窗口连接了)"
#: authentik/enterprise/providers/ssf/models.py #: authentik/enterprise/providers/ssf/models.py
#: authentik/providers/oauth2/models.py #: authentik/providers/oauth2/models.py
msgid "Signing Key" msgid "Signing Key"
@ -661,6 +622,7 @@ msgid "Slack Webhook (Slack/Discord)"
msgstr "Slack WebhookSlack/Discord" msgstr "Slack WebhookSlack/Discord"
#: authentik/events/models.py #: authentik/events/models.py
#: authentik/stages/authenticator_validate/models.py
msgid "Email" msgid "Email"
msgstr "电子邮箱" msgstr "电子邮箱"
@ -915,6 +877,12 @@ msgstr "流程令牌"
msgid "Invalid next URL" msgid "Invalid next URL"
msgstr "无效的 next URL" msgstr "无效的 next URL"
#: authentik/lib/sync/outgoing/models.py
msgid ""
"When enabled, provider will not modify or create objects in the remote "
"system."
msgstr "启用时,提供程序将不会在远程系统上修改或创建对象。"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
msgid "Starting full provider sync" msgid "Starting full provider sync"
msgstr "开始全量提供程序同步" msgstr "开始全量提供程序同步"
@ -929,6 +897,10 @@ msgstr "正在同步用户页面 {page}"
msgid "Syncing page {page} of groups" msgid "Syncing page {page} of groups"
msgstr "正在同步群组页面 {page}" msgstr "正在同步群组页面 {page}"
#: authentik/lib/sync/outgoing/tasks.py
msgid "Dropping mutating request due to dry run"
msgstr "由于启用了试运行,已放弃变更请求"
#: authentik/lib/sync/outgoing/tasks.py #: authentik/lib/sync/outgoing/tasks.py
#, python-brace-format #, python-brace-format
msgid "Stopping sync due to error: {error}" msgid "Stopping sync due to error: {error}"
@ -1118,6 +1090,14 @@ msgstr "GeoIP无法在城市数据库中找到客户端 IP。"
msgid "Client IP is not in an allowed country." msgid "Client IP is not in an allowed country."
msgstr "客户端 IP 不在受允许的地区。" msgstr "客户端 IP 不在受允许的地区。"
#: authentik/policies/geoip/models.py
msgid "Distance from previous authentication is larger than threshold."
msgstr "与上一次身份验证的距离超过阈值。"
#: authentik/policies/geoip/models.py
msgid "Distance is further than possible."
msgstr "距离大幅超过可能值。"
#: authentik/policies/geoip/models.py #: authentik/policies/geoip/models.py
msgid "GeoIP Policy" msgid "GeoIP Policy"
msgstr "GeoIP 策略" msgstr "GeoIP 策略"
@ -1418,6 +1398,14 @@ msgstr "RS256非对称加密"
msgid "ES256 (Asymmetric Encryption)" msgid "ES256 (Asymmetric Encryption)"
msgstr "ES256非对称加密" msgstr "ES256非对称加密"
#: authentik/providers/oauth2/models.py
msgid "ES384 (Asymmetric Encryption)"
msgstr "ES384非对称加密"
#: authentik/providers/oauth2/models.py
msgid "ES512 (Asymmetric Encryption)"
msgstr "ES512非对称加密"
#: authentik/providers/oauth2/models.py #: authentik/providers/oauth2/models.py
msgid "Scope used by the client" msgid "Scope used by the client"
msgstr "客户端使用的作用域" msgstr "客户端使用的作用域"
@ -1667,6 +1655,56 @@ msgstr "代理提供程序"
msgid "Proxy Providers" msgid "Proxy Providers"
msgstr "代理提供程序" msgstr "代理提供程序"
#: authentik/providers/rac/models.py authentik/stages/user_login/models.py
msgid ""
"Determines how long a session lasts. Default of 0 means that the sessions "
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr "确定会话持续多长时间。默认值为 0 表示会话持续到浏览器关闭为止。格式hours=-1;minutes=-2;seconds=-3"
#: authentik/providers/rac/models.py
msgid "When set to true, connection tokens will be deleted upon disconnect."
msgstr "启用时,连接令牌将会在断开连接时被删除。"
#: authentik/providers/rac/models.py
msgid "RAC Provider"
msgstr "RAC 提供程序"
#: authentik/providers/rac/models.py
msgid "RAC Providers"
msgstr "RAC 提供程序"
#: authentik/providers/rac/models.py
msgid "RAC Endpoint"
msgstr "RAC 端点"
#: authentik/providers/rac/models.py
msgid "RAC Endpoints"
msgstr "RAC 端点"
#: authentik/providers/rac/models.py
msgid "RAC Provider Property Mapping"
msgstr "RAC 提供程序属性映射"
#: authentik/providers/rac/models.py
msgid "RAC Provider Property Mappings"
msgstr "RAC 提供程序属性映射"
#: authentik/providers/rac/models.py
msgid "RAC Connection token"
msgstr "RAC 连接令牌"
#: authentik/providers/rac/models.py
msgid "RAC Connection tokens"
msgstr "RAC 连接令牌"
#: authentik/providers/rac/views.py
msgid "Maximum connection limit reached."
msgstr "已达到最大连接数。"
#: authentik/providers/rac/views.py
msgid "(You are already connected in another tab/window)"
msgstr "(您已经在另一个标签页/窗口连接了)"
#: authentik/providers/radius/models.py #: authentik/providers/radius/models.py
msgid "Shared secret between clients and server to hash packets." msgid "Shared secret between clients and server to hash packets."
msgstr "在客户端和服务端之间共享密钥以哈希数据包。" msgstr "在客户端和服务端之间共享密钥以哈希数据包。"
@ -2520,6 +2558,109 @@ msgstr "Duo 设备"
msgid "Duo Devices" msgid "Duo Devices"
msgstr "Duo 设备" msgstr "Duo 设备"
#: authentik/stages/authenticator_email/models.py
msgid "Email OTP"
msgstr "电子邮件 OTP"
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/email/models.py
msgid ""
"When enabled, global Email connection settings will be used and connection "
"settings below will be ignored."
msgstr "启用后,将使用全局电子邮件连接设置,下面的连接设置将被忽略。"
#: authentik/stages/authenticator_email/models.py
msgid "Time the token sent is valid (Format: hours=3,minutes=17,seconds=300)."
msgstr "发出令牌有效的时间格式hours=3,minutes=17,seconds=300。"
#: authentik/stages/authenticator_email/models.py
msgid "Email Authenticator Setup Stage"
msgstr "电子邮件身份验证器设置阶段"
#: authentik/stages/authenticator_email/models.py
msgid "Email Authenticator Setup Stages"
msgstr "电子邮件身份验证器设置阶段"
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/authenticator_email/stage.py
#: authentik/stages/email/stage.py
msgid "Exception occurred while rendering E-mail template"
msgstr "渲染电子邮件模板时发生异常"
#: authentik/stages/authenticator_email/models.py
msgid "Email Device"
msgstr "电子邮件设备"
#: authentik/stages/authenticator_email/models.py
msgid "Email Devices"
msgstr "电子邮件设备"
#: authentik/stages/authenticator_email/stage.py
#: authentik/stages/authenticator_sms/stage.py
#: authentik/stages/authenticator_totp/stage.py
msgid "Code does not match"
msgstr "代码不匹配"
#: authentik/stages/authenticator_email/stage.py
msgid "Invalid email"
msgstr "无效电子邮件"
#: authentik/stages/authenticator_email/templates/email/email_otp.html
#: authentik/stages/email/templates/email/password_reset.html
#, python-format
msgid ""
"\n"
" Hi %(username)s,\n"
" "
msgstr ""
"\n"
" %(username)s 您好,\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.html
msgid ""
"\n"
" Email MFA code.\n"
" "
msgstr ""
"\n"
" 电子邮件 MFA 代码。\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.html
#, python-format
msgid ""
"\n"
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
" "
msgstr ""
"\n"
" 如果您没有请求此代码,请忽略此电子邮件。上面的代码在 %(expires)s 内有效。\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
#: authentik/stages/email/templates/email/password_reset.txt
#, python-format
msgid "Hi %(username)s,"
msgstr "您好 %(username)s"
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
msgid ""
"\n"
"Email MFA code\n"
msgstr ""
"\n"
"电子邮件 MFA 代码\n"
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
#, python-format
msgid ""
"\n"
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
msgstr ""
"\n"
"如果您没有请求此代码,请忽略此电子邮件。上面的代码在 %(expires)s 内有效。\n"
#: authentik/stages/authenticator_sms/models.py #: authentik/stages/authenticator_sms/models.py
msgid "" msgid ""
"When enabled, the Phone number is only used during enrollment to verify the " "When enabled, the Phone number is only used during enrollment to verify the "
@ -2552,11 +2693,6 @@ msgstr "短信设备"
msgid "SMS Devices" msgid "SMS Devices"
msgstr "短信设备" msgstr "短信设备"
#: authentik/stages/authenticator_sms/stage.py
#: authentik/stages/authenticator_totp/stage.py
msgid "Code does not match"
msgstr "代码不匹配"
#: authentik/stages/authenticator_sms/stage.py #: authentik/stages/authenticator_sms/stage.py
msgid "Invalid phone number" msgid "Invalid phone number"
msgstr "无效电话号码" msgstr "无效电话号码"
@ -2779,12 +2915,6 @@ msgstr "密码重置"
msgid "Account Confirmation" msgid "Account Confirmation"
msgstr "账户确认" msgstr "账户确认"
#: authentik/stages/email/models.py
msgid ""
"When enabled, global Email connection settings will be used and connection "
"settings below will be ignored."
msgstr "启用后,将使用全局电子邮件连接设置,下面的连接设置将被忽略。"
#: authentik/stages/email/models.py #: authentik/stages/email/models.py
msgid "Activate users upon completion of stage." msgid "Activate users upon completion of stage."
msgstr "完成阶段后激活用户。" msgstr "完成阶段后激活用户。"
@ -2801,10 +2931,6 @@ msgstr "电子邮件阶段"
msgid "Email Stages" msgid "Email Stages"
msgstr "电子邮件阶段" msgstr "电子邮件阶段"
#: authentik/stages/email/stage.py
msgid "Exception occurred while rendering E-mail template"
msgstr "渲染电子邮件模板时发生异常"
#: authentik/stages/email/stage.py #: authentik/stages/email/stage.py
msgid "Successfully verified Email." msgid "Successfully verified Email."
msgstr "已成功验证电子邮件。" msgstr "已成功验证电子邮件。"
@ -2885,17 +3011,6 @@ msgstr ""
"\n" "\n"
"此邮件由通知递送 %(name)s 发送。\n" "此邮件由通知递送 %(name)s 发送。\n"
#: authentik/stages/email/templates/email/password_reset.html
#, python-format
msgid ""
"\n"
" Hi %(username)s,\n"
" "
msgstr ""
"\n"
" %(username)s 您好,\n"
" "
#: authentik/stages/email/templates/email/password_reset.html #: authentik/stages/email/templates/email/password_reset.html
msgid "" msgid ""
"\n" "\n"
@ -2917,11 +3032,6 @@ msgstr ""
" 如果您没有请求更改密码,请忽略此电子邮件。上面的链接在 %(expires)s 内有效。\n" " 如果您没有请求更改密码,请忽略此电子邮件。上面的链接在 %(expires)s 内有效。\n"
" " " "
#: authentik/stages/email/templates/email/password_reset.txt
#, python-format
msgid "Hi %(username)s,"
msgstr "您好 %(username)s"
#: authentik/stages/email/templates/email/password_reset.txt #: authentik/stages/email/templates/email/password_reset.txt
msgid "" msgid ""
"\n" "\n"

View File

@ -1,5 +1,5 @@
{ {
"name": "@goauthentik/authentik", "name": "@goauthentik/authentik",
"version": "2024.12.3", "version": "2025.2.1",
"private": true "private": true
} }

783
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,30 @@
[tool.poetry] [tool.poetry]
name = "authentik" name = "authentik"
version = "2024.12.3" version = "2025.2.1"
description = "" description = ""
authors = ["authentik Team <hello@goauthentik.io>"] authors = ["authentik Team <hello@goauthentik.io>"]
[tool.bandit]
exclude_dirs = ["**/node_modules/**"]
[tool.codespell]
skip = [
"**/node_modules",
"**/package-lock.json",
"schema.yml",
"unittest.xml",
"./blueprints/schema.json",
"go.sum",
"locale",
"**/dist",
"**/web/src/locales",
"**/web/xliff",
"./website/build",
"./gen-ts-api",
"*.api.mdx",
]
dictionary = ".github/codespell-dictionary.txt,-"
ignore-words = ".github/codespell-words.txt"
[tool.black] [tool.black]
line-length = 100 line-length = 100
target-version = ['py312'] target-version = ['py312']
@ -123,7 +144,9 @@ kubernetes = "*"
ldap3 = "*" ldap3 = "*"
lxml = "*" lxml = "*"
msgraph-sdk = "*" msgraph-sdk = "*"
opencontainers = { git = "https://github.com/vsoch/oci-python", rev = "20d69d9cc50a0fef31605b46f06da0c94f1ec3cf", extras = ["reggie"] } opencontainers = { git = "https://github.com/vsoch/oci-python", rev = "20d69d9cc50a0fef31605b46f06da0c94f1ec3cf", extras = [
"reggie",
] }
packaging = "*" packaging = "*"
paramiko = "*" paramiko = "*"
psycopg = { extras = ["c"], version = "*" } psycopg = { extras = ["c"], version = "*" }

View File

@ -1,7 +1,7 @@
openapi: 3.0.3 openapi: 3.0.3
info: info:
title: authentik title: authentik
version: 2024.12.3 version: 2025.2.1
description: Making authentication simple. description: Making authentication simple.
contact: contact:
email: hello@goauthentik.io email: hello@goauthentik.io
@ -44154,6 +44154,10 @@ components:
$ref: '#/components/schemas/OutgoingSyncDeleteAction' $ref: '#/components/schemas/OutgoingSyncDeleteAction'
default_group_email_domain: default_group_email_domain:
type: string type: string
dry_run:
type: boolean
description: When enabled, provider will not modify or create objects in
the remote system.
required: required:
- assigned_backchannel_application_name - assigned_backchannel_application_name
- assigned_backchannel_application_slug - assigned_backchannel_application_slug
@ -44317,6 +44321,10 @@ components:
default_group_email_domain: default_group_email_domain:
type: string type: string
minLength: 1 minLength: 1
dry_run:
type: boolean
description: When enabled, provider will not modify or create objects in
the remote system.
required: required:
- credentials - credentials
- default_group_email_domain - default_group_email_domain
@ -46397,6 +46405,10 @@ components:
$ref: '#/components/schemas/OutgoingSyncDeleteAction' $ref: '#/components/schemas/OutgoingSyncDeleteAction'
group_delete_action: group_delete_action:
$ref: '#/components/schemas/OutgoingSyncDeleteAction' $ref: '#/components/schemas/OutgoingSyncDeleteAction'
dry_run:
type: boolean
description: When enabled, provider will not modify or create objects in
the remote system.
required: required:
- assigned_backchannel_application_name - assigned_backchannel_application_name
- assigned_backchannel_application_slug - assigned_backchannel_application_slug
@ -46557,6 +46569,10 @@ components:
$ref: '#/components/schemas/OutgoingSyncDeleteAction' $ref: '#/components/schemas/OutgoingSyncDeleteAction'
group_delete_action: group_delete_action:
$ref: '#/components/schemas/OutgoingSyncDeleteAction' $ref: '#/components/schemas/OutgoingSyncDeleteAction'
dry_run:
type: boolean
description: When enabled, provider will not modify or create objects in
the remote system.
required: required:
- client_id - client_id
- client_secret - client_secret
@ -50679,6 +50695,10 @@ components:
default_group_email_domain: default_group_email_domain:
type: string type: string
minLength: 1 minLength: 1
dry_run:
type: boolean
description: When enabled, provider will not modify or create objects in
the remote system.
PatchedGroupKerberosSourceConnectionRequest: PatchedGroupKerberosSourceConnectionRequest:
type: object type: object
description: OAuth Group-Source connection Serializer description: OAuth Group-Source connection Serializer
@ -51260,6 +51280,10 @@ components:
$ref: '#/components/schemas/OutgoingSyncDeleteAction' $ref: '#/components/schemas/OutgoingSyncDeleteAction'
group_delete_action: group_delete_action:
$ref: '#/components/schemas/OutgoingSyncDeleteAction' $ref: '#/components/schemas/OutgoingSyncDeleteAction'
dry_run:
type: boolean
description: When enabled, provider will not modify or create objects in
the remote system.
PatchedNotificationRequest: PatchedNotificationRequest:
type: object type: object
description: Notification Serializer description: Notification Serializer
@ -52427,6 +52451,10 @@ components:
type: string type: string
format: uuid format: uuid
nullable: true nullable: true
dry_run:
type: boolean
description: When enabled, provider will not modify or create objects in
the remote system.
PatchedSCIMSourceGroupRequest: PatchedSCIMSourceGroupRequest:
type: object type: object
description: SCIMSourceGroup Serializer description: SCIMSourceGroup Serializer
@ -55823,6 +55851,10 @@ components:
type: string type: string
format: uuid format: uuid
nullable: true nullable: true
dry_run:
type: boolean
description: When enabled, provider will not modify or create objects in
the remote system.
required: required:
- assigned_backchannel_application_name - assigned_backchannel_application_name
- assigned_backchannel_application_slug - assigned_backchannel_application_slug
@ -55909,6 +55941,10 @@ components:
type: string type: string
format: uuid format: uuid
nullable: true nullable: true
dry_run:
type: boolean
description: When enabled, provider will not modify or create objects in
the remote system.
required: required:
- name - name
- token - token
@ -57105,6 +57141,9 @@ components:
sync_object_id: sync_object_id:
type: string type: string
minLength: 1 minLength: 1
override_dry_run:
type: boolean
default: false
required: required:
- sync_object_id - sync_object_id
- sync_object_model - sync_object_model

View File

@ -4,7 +4,7 @@ This package provides a generated API Client for [authentik](https://goauthentik
### Building ### Building
See https://docs.goauthentik.io/docs/developer-docs/making-schema-changes See https://docs.goauthentik.io/docs/developer-docs/api/making-schema-changes#building-the-web-client
### Consuming ### Consuming

1
scripts/generate_config.py Normal file → Executable file
View File

@ -1,3 +1,4 @@
#!/usr/bin/env python3
"""Generate config for development""" """Generate config for development"""
from yaml import safe_dump from yaml import safe_dump

15
scripts/generate_semver.py Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env python3
"""
Generates a Semantic Versioning identifier, suffixed with a timestamp.
"""
from time import time
from authentik import __version__ as package_version
"""
See: https://semver.org/#spec-item-9 (Pre-release spec)
"""
pre_release_timestamp = int(time())
print(f"{package_version}-{pre_release_timestamp}")

View File

@ -1,7 +0,0 @@
"""Helper script to generate an NPM Version"""
from time import time
from authentik import __version__
print(f"{__version__}-{int(time())}")

View File

@ -0,0 +1,141 @@
import * as http from "http";
import path from "path";
/**
* Serializes a custom event to a text stream.
* a
* @param {Event} event
* @returns {string}
*/
export function serializeCustomEventToStream(event) {
// @ts-ignore
const data = event.detail ?? {};
const eventContent = [`event: ${event.type}`, `data: ${JSON.stringify(data)}`];
return eventContent.join("\n") + "\n\n";
}
/**
* Options for the build observer plugin.
*
* @typedef {Object} BuildObserverOptions
*
* @property {URL} serverURL
* @property {string} logPrefix
* @property {string} relativeRoot
*/
/**
* Creates a plugin that listens for build events and sends them to a server-sent event stream.
*
* @param {BuildObserverOptions} options
* @returns {import('esbuild').Plugin}
*/
export function buildObserverPlugin({ serverURL, logPrefix, relativeRoot }) {
const timerLabel = `[${logPrefix}] Build`;
const endpoint = serverURL.pathname;
const dispatcher = new EventTarget();
const eventServer = http.createServer((req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET");
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
if (req.url !== endpoint) {
console.log(`🚫 Invalid request to ${req.url}`);
res.writeHead(404);
res.end();
return;
}
console.log("🔌 Client connected");
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
});
/**
* @param {Event} event
*/
const listener = (event) => {
const body = serializeCustomEventToStream(event);
res.write(body);
};
dispatcher.addEventListener("esbuild:start", listener);
dispatcher.addEventListener("esbuild:error", listener);
dispatcher.addEventListener("esbuild:end", listener);
req.on("close", () => {
console.log("🔌 Client disconnected");
clearInterval(keepAliveInterval);
dispatcher.removeEventListener("esbuild:start", listener);
dispatcher.removeEventListener("esbuild:error", listener);
dispatcher.removeEventListener("esbuild:end", listener);
});
const keepAliveInterval = setInterval(() => {
console.timeStamp("🏓 Keep-alive");
res.write("event: keep-alive\n\n");
res.write(serializeCustomEventToStream(new CustomEvent("esbuild:keep-alive")));
}, 15_000);
});
return {
name: "build-watcher",
setup: (build) => {
eventServer.listen(parseInt(serverURL.port, 10), serverURL.hostname);
build.onDispose(() => {
eventServer.close();
});
build.onStart(() => {
console.time(timerLabel);
dispatcher.dispatchEvent(
new CustomEvent("esbuild:start", {
detail: new Date().toISOString(),
}),
);
});
build.onEnd((buildResult) => {
console.timeEnd(timerLabel);
if (!buildResult.errors.length) {
dispatcher.dispatchEvent(
new CustomEvent("esbuild:end", {
detail: new Date().toISOString(),
}),
);
return;
}
console.warn(`Build ended with ${buildResult.errors.length} errors`);
dispatcher.dispatchEvent(
new CustomEvent("esbuild:error", {
detail: buildResult.errors.map((error) => ({
...error,
location: error.location
? {
...error.location,
file: path.resolve(relativeRoot, error.location.file),
}
: null,
})),
}),
);
});
},
};
}

View File

@ -1,45 +1,54 @@
import { execFileSync } from "child_process"; import { execFileSync } from "child_process";
import * as chokidar from "chokidar";
import esbuild from "esbuild"; import esbuild from "esbuild";
import fs from "fs"; import findFreePorts from "find-free-ports";
import { copyFileSync, mkdirSync, readFileSync, statSync } from "fs";
import { globSync } from "glob"; import { globSync } from "glob";
import path from "path"; import path from "path";
import { cwd } from "process"; import { cwd } from "process";
import process from "process"; import process from "process";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
const __dirname = fileURLToPath(new URL(".", import.meta.url)); import { buildObserverPlugin } from "./build-observer-plugin.mjs";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
let authentikProjectRoot = __dirname + "../"; let authentikProjectRoot = __dirname + "../";
try { try {
// Use the package.json file in the root folder, as it has the current version information. // Use the package.json file in the root folder, as it has the current version information.
authentikProjectRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], { authentikProjectRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], {
encoding: "utf8", encoding: "utf8",
}).replace("\n", ""); }).replace("\n", "");
} catch (_exc) { } catch (_error) {
// We probably don't have a .git folder, which could happen in container builds // We probably don't have a .git folder, which could happen in container builds.
} }
const rootPackage = JSON.parse(fs.readFileSync(path.join(authentikProjectRoot, "./package.json")));
const isProdBuild = process.env.NODE_ENV === "production"; const packageJSONPath = path.join(authentikProjectRoot, "./package.json");
const rootPackage = JSON.parse(readFileSync(packageJSONPath, "utf8"));
const apiBasePath = process.env.AK_API_BASE_PATH || ""; const NODE_ENV = process.env.NODE_ENV || "development";
const AK_API_BASE_PATH = process.env.AK_API_BASE_PATH || "";
const envGitHashKey = "GIT_BUILD_HASH"; const environmentVars = new Map([
["NODE_ENV", NODE_ENV],
["CWD", cwd()],
["AK_API_BASE_PATH", AK_API_BASE_PATH],
]);
const definitions = { const definitions = Object.fromEntries(
"process.env.NODE_ENV": JSON.stringify(isProdBuild ? "production" : "development"), Array.from(environmentVars).map(([key, value]) => {
"process.env.CWD": JSON.stringify(cwd()), return [`process.env.${key}`, JSON.stringify(value)];
"process.env.AK_API_BASE_PATH": JSON.stringify(apiBasePath), }),
}; );
// All is magic is just to make sure the assets are copied into the right places. This is a very /**
// stripped down version of what the rollup-copy-plugin does, without any of the features we don't * All is magic is just to make sure the assets are copied into the right places. This is a very
// use, and using globSync instead of globby since we already had globSync lying around thanks to * stripped down version of what the rollup-copy-plugin does, without any of the features we don't
// Typescript. If there's a third argument in an array entry, it's used to replace the internal path * use, and using globSync instead of globby since we already had globSync lying around thanks to
// before concatenating it all together as the destination target. * Typescript. If there's a third argument in an array entry, it's used to replace the internal path
* before concatenating it all together as the destination target.
const otherFiles = [ * @type {Array<[string, string, string?]>}
*/
const assetsFileMappings = [
["node_modules/@patternfly/patternfly/patternfly.min.css", "."], ["node_modules/@patternfly/patternfly/patternfly.min.css", "."],
["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"], ["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"],
["src/custom.css", "."], ["src/custom.css", "."],
@ -48,28 +57,47 @@ const otherFiles = [
["./icons/*", "./assets/icons"], ["./icons/*", "./assets/icons"],
]; ];
const isFile = (filePath) => fs.statSync(filePath).isFile(); /**
* @param {string} filePath
*/
const isFile = (filePath) => statSync(filePath).isFile();
/**
* @param {string} src Source file
* @param {string} dest Destination folder
* @param {string} [strip] Path to strip from the source file
*/
function nameCopyTarget(src, dest, strip) { function nameCopyTarget(src, dest, strip) {
const target = path.join(dest, strip ? src.replace(strip, "") : path.parse(src).base); const target = path.join(dest, strip ? src.replace(strip, "") : path.parse(src).base);
return [src, target]; return [src, target];
} }
for (const [source, rawdest, strip] of otherFiles) { for (const [source, rawdest, strip] of assetsFileMappings) {
const matchedPaths = globSync(source); const matchedPaths = globSync(source);
const dest = path.join("dist", rawdest); const dest = path.join("dist", rawdest);
const copyTargets = matchedPaths.map((path) => nameCopyTarget(path, dest, strip)); const copyTargets = matchedPaths.map((path) => nameCopyTarget(path, dest, strip));
for (const [src, dest] of copyTargets) { for (const [src, dest] of copyTargets) {
if (isFile(src)) { if (isFile(src)) {
fs.mkdirSync(path.dirname(dest), { recursive: true }); mkdirSync(path.dirname(dest), { recursive: true });
fs.copyFileSync(src, dest); copyFileSync(src, dest);
} }
} }
} }
// This starts the definitions used for esbuild: Our targets, our arguments, the function for /**
// running a build, and three options for building: watching, building, and building the proxy. * @typedef {[source: string, destination: string]} EntryPoint
// Ordered by largest to smallest interface to build even faster */
const interfaces = [
/**
* This starts the definitions used for esbuild: Our targets, our arguments, the function for
* running a build, and three options for building: watching, building, and building the proxy.
* Ordered by largest to smallest interface to build even faster
*
* @type {EntryPoint[]}
*/
const entryPoints = [
["admin/AdminInterface/AdminInterface.ts", "admin"], ["admin/AdminInterface/AdminInterface.ts", "admin"],
["user/UserInterface.ts", "user"], ["user/UserInterface.ts", "user"],
["flow/FlowInterface.ts", "flow"], ["flow/FlowInterface.ts", "flow"],
@ -79,18 +107,26 @@ const interfaces = [
["polyfill/poly.ts", "."], ["polyfill/poly.ts", "."],
]; ];
const baseArgs = { /**
* @satisfies {import("esbuild").BuildOptions}
*/
const BASE_ESBUILD_OPTIONS = {
bundle: true, bundle: true,
write: true, write: true,
sourcemap: true, sourcemap: true,
minify: isProdBuild, minify: NODE_ENV === "production",
splitting: true, splitting: true,
treeShaking: true, treeShaking: true,
external: ["*.woff", "*.woff2"], external: ["*.woff", "*.woff2"],
tsconfig: "./tsconfig.json", tsconfig: "./tsconfig.json",
loader: { ".css": "text", ".md": "text" }, loader: {
".css": "text",
".md": "text",
".mdx": "text",
},
define: definitions, define: definitions,
format: "esm", format: "esm",
plugins: [],
logOverride: { logOverride: {
/** /**
* HACK: Silences issue originating in ESBuild. * HACK: Silences issue originating in ESBuild.
@ -102,91 +138,144 @@ const baseArgs = {
}, },
}; };
function getVersion() { /**
let version = rootPackage.version; * Creates a version ID for the build.
if (process.env[envGitHashKey]) { * @returns {string}
version = `${version}+${process.env[envGitHashKey]}`; */
function composeVersionID() {
const { version } = rootPackage;
const buildHash = process.env.GIT_BUILD_HASH;
if (buildHash) {
return `${version}+${buildHash}`;
} }
return version; return version;
} }
async function buildOneSource(source, dest) { /**
const DIST = path.join(__dirname, "./dist", dest); * Build a single entry point.
console.log(`[${new Date(Date.now()).toISOString()}] Starting build for target ${source}`); *
* @param {EntryPoint} buildTarget
* @param {Partial<esbuild.BuildOptions>} [overrides]
* @throws {Error} on build failure
*/
function createEntryPointOptions([source, dest], overrides = {}) {
const outdir = path.join(__dirname, "./dist", dest);
try { return {
const start = Date.now(); ...BASE_ESBUILD_OPTIONS,
await esbuild.build({ entryPoints: [`./src/${source}`],
...baseArgs, entryNames: `[dir]/[name]-${composeVersionID()}`,
entryPoints: [`./src/${source}`], outdir,
entryNames: `[dir]/[name]-${getVersion()}`, ...overrides,
outdir: DIST, };
});
const end = Date.now();
console.log(
`[${new Date(end).toISOString()}] Finished build for target ${source} in ${
Date.now() - start
}ms`,
);
return 0;
} catch (exc) {
console.error(`[${new Date(Date.now()).toISOString()}] Failed to build ${source}: ${exc}`);
return 1;
}
} }
async function buildAuthentik(interfaces) { /**
const code = await Promise.allSettled( * Build all entry points in parallel.
interfaces.map(([source, dest]) => buildOneSource(source, dest)), *
* @param {EntryPoint[]} entryPoints
*/
async function buildParallel(entryPoints) {
await Promise.allSettled(
entryPoints.map((entryPoint) => {
return esbuild.build(createEntryPointOptions(entryPoint));
}),
); );
const finalCode = code.reduce((a, res) => a + res.value, 0);
if (finalCode > 0) {
return 1;
}
return 0;
} }
let timeoutId = null; function doHelp() {
function debouncedBuild() { console.log(`Build the authentik UI
if (timeoutId !== null) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
console.clear();
buildAuthentik(interfaces);
}, 250);
}
if (process.argv.length > 2 && (process.argv[2] === "-h" || process.argv[2] === "--help")) { options:
console.log(`Build the authentikUI -w, --watch: Build all ${entryPoints.length} interfaces
-p, --proxy: Build only the polyfills and the loading application
options: -h, --help: This help message
-w, --watch: Build all ${interfaces.length} interfaces
-p, --proxy: Build only the polyfills and the loading application
-h, --help: This help message
`); `);
process.exit(0); process.exit(0);
} }
if (process.argv.length > 2 && (process.argv[2] === "-w" || process.argv[2] === "--watch")) { async function doWatch() {
console.log("Watching ./src for changes"); console.log("Watching all entry points...");
chokidar.watch("./src").on("all", (event, path) => {
if (!["add", "change", "unlink"].includes(event)) { const wathcherPorts = await findFreePorts(entryPoints.length);
return;
} const buildContexts = await Promise.all(
if (!/(\.css|\.ts|\.js)$/.test(path)) { entryPoints.map((entryPoint, i) => {
return; const port = wathcherPorts[i];
} const serverURL = new URL(`http://localhost:${port}/events`);
debouncedBuild();
}); return esbuild.context(
} else if (process.argv.length > 2 && (process.argv[2] === "-p" || process.argv[2] === "--proxy")) { createEntryPointOptions(entryPoint, {
// There's no watch-for-proxy, sorry. plugins: [
process.exit( ...BASE_ESBUILD_OPTIONS.plugins,
await buildAuthentik( buildObserverPlugin({
interfaces.filter(([_, dest]) => ["standalone/loading", "."].includes(dest)), serverURL,
), logPrefix: entryPoint[1],
relativeRoot: __dirname,
}),
],
define: {
...definitions,
"process.env.WATCHER_URL": JSON.stringify(serverURL.toString()),
},
}),
);
}),
);
await Promise.all(buildContexts.map((context) => context.rebuild()));
await Promise.allSettled(buildContexts.map((context) => context.watch()));
return /** @type {Promise<void>} */ (
new Promise((resolve) => {
process.on("SIGINT", () => {
resolve();
});
})
); );
} else {
// And the fallback: just build it.
process.exit(await buildAuthentik(interfaces));
} }
async function doBuild() {
console.log("Building all entry points");
return buildParallel(entryPoints);
}
async function doProxy() {
return buildParallel(
entryPoints.filter(([_, dest]) => ["standalone/loading", "."].includes(dest)),
);
}
async function delegateCommand() {
const command = process.argv[2];
switch (command) {
case "-h":
case "--help":
return doHelp();
case "-w":
case "--watch":
return doWatch();
// There's no watch-for-proxy, sorry.
case "-p":
case "--proxy":
return doProxy();
default:
return doBuild();
}
}
await delegateCommand()
.then(() => {
console.log("Build complete");
process.exit(0);
})
.catch((error) => {
console.error(error);
process.exit(1);
});

41
web/package-lock.json generated
View File

@ -23,7 +23,7 @@
"@floating-ui/dom": "^1.6.11", "@floating-ui/dom": "^1.6.11",
"@formatjs/intl-listformat": "^7.5.7", "@formatjs/intl-listformat": "^7.5.7",
"@fortawesome/fontawesome-free": "^6.6.0", "@fortawesome/fontawesome-free": "^6.6.0",
"@goauthentik/api": "^2024.12.3-1739965710", "@goauthentik/api": "^2025.2.1-1740858273",
"@lit-labs/ssr": "^3.2.2", "@lit-labs/ssr": "^3.2.2",
"@lit/context": "^1.1.2", "@lit/context": "^1.1.2",
"@lit/localize": "^0.12.2", "@lit/localize": "^0.12.2",
@ -37,11 +37,12 @@
"@webcomponents/webcomponentsjs": "^2.8.0", "@webcomponents/webcomponentsjs": "^2.8.0",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"chart.js": "^4.4.4", "chart.js": "^4.4.4",
"chartjs-adapter-moment": "^1.0.1", "chartjs-adapter-date-fns": "^3.0.0",
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"construct-style-sheets-polyfill": "^3.1.0", "construct-style-sheets-polyfill": "^3.1.0",
"core-js": "^3.38.1", "core-js": "^3.38.1",
"country-flag-icons": "^1.5.13", "country-flag-icons": "^1.5.13",
"date-fns": "^4.1.0",
"dompurify": "^3.2.4", "dompurify": "^3.2.4",
"fuse.js": "^7.0.0", "fuse.js": "^7.0.0",
"guacamole-common-js": "^1.5.0", "guacamole-common-js": "^1.5.0",
@ -89,6 +90,7 @@
"eslint": "^9.11.1", "eslint": "^9.11.1",
"eslint-plugin-lit": "^1.15.0", "eslint-plugin-lit": "^1.15.0",
"eslint-plugin-wc": "^2.1.1", "eslint-plugin-wc": "^2.1.1",
"find-free-ports": "^3.1.1",
"github-slugger": "^2.0.0", "github-slugger": "^2.0.0",
"glob": "^11.0.0", "glob": "^11.0.0",
"globals": "^15.10.0", "globals": "^15.10.0",
@ -1814,9 +1816,9 @@
} }
}, },
"node_modules/@goauthentik/api": { "node_modules/@goauthentik/api": {
"version": "2024.12.3-1739965710", "version": "2025.2.1-1740858273",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.12.3-1739965710.tgz", "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2025.2.1-1740858273.tgz",
"integrity": "sha512-16zoQWeJhAFSwttvqLRoXoQA43tMW1ZXDEihW6r8rtWtlxqPh7n36RtcWYraYiLcjmJskI90zdgz6k1kmY5AXw==" "integrity": "sha512-dOY32RKJSy3fYteuL4h13NaRVznq0O9Z0IXdwUDwkCQ4GoBfqUaPIFb55tFvRNrdNZG0efor0PIGISxoHpRJwA=="
}, },
"node_modules/@goauthentik/web": { "node_modules/@goauthentik/web": {
"resolved": "", "resolved": "",
@ -9531,13 +9533,13 @@
"pnpm": ">=8" "pnpm": ">=8"
} }
}, },
"node_modules/chartjs-adapter-moment": { "node_modules/chartjs-adapter-date-fns": {
"version": "1.0.1", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/chartjs-adapter-moment/-/chartjs-adapter-moment-1.0.1.tgz", "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz",
"integrity": "sha512-Uz+nTX/GxocuqXpGylxK19YG4R3OSVf8326D+HwSTsNw1LgzyIGRo+Qujwro1wy6X+soNSnfj5t2vZ+r6EaDmA==", "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==",
"peerDependencies": { "peerDependencies": {
"chart.js": ">=3.0.0", "chart.js": ">=2.8.0",
"moment": "^2.10.2" "date-fns": ">=2.0.0"
} }
}, },
"node_modules/cheerio": { "node_modules/cheerio": {
@ -10769,6 +10771,15 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/dayjs": { "node_modules/dayjs": {
"version": "1.11.13", "version": "1.11.13",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
@ -12892,6 +12903,13 @@
"url": "https://github.com/avajs/find-cache-dir?sponsor=1" "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
} }
}, },
"node_modules/find-free-ports": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/find-free-ports/-/find-free-ports-3.1.1.tgz",
"integrity": "sha512-hQebewth9i5qkf0a0u06iFaxQssk5ZnPBBggsa1vk8zCYaZoz9IZXpoRLTbEOrYdqfrjvcxU00gYoCPgmXugKA==",
"dev": true,
"license": "MIT"
},
"node_modules/find-up": { "node_modules/find-up": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@ -16572,6 +16590,7 @@
"version": "2.30.1", "version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"dev": true,
"engines": { "engines": {
"node": "*" "node": "*"
} }

View File

@ -11,7 +11,7 @@
"@floating-ui/dom": "^1.6.11", "@floating-ui/dom": "^1.6.11",
"@formatjs/intl-listformat": "^7.5.7", "@formatjs/intl-listformat": "^7.5.7",
"@fortawesome/fontawesome-free": "^6.6.0", "@fortawesome/fontawesome-free": "^6.6.0",
"@goauthentik/api": "^2024.12.3-1739965710", "@goauthentik/api": "^2025.2.1-1740858273",
"@lit-labs/ssr": "^3.2.2", "@lit-labs/ssr": "^3.2.2",
"@lit/context": "^1.1.2", "@lit/context": "^1.1.2",
"@lit/localize": "^0.12.2", "@lit/localize": "^0.12.2",
@ -25,11 +25,12 @@
"@webcomponents/webcomponentsjs": "^2.8.0", "@webcomponents/webcomponentsjs": "^2.8.0",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"chart.js": "^4.4.4", "chart.js": "^4.4.4",
"chartjs-adapter-moment": "^1.0.1", "chartjs-adapter-date-fns": "^3.0.0",
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"construct-style-sheets-polyfill": "^3.1.0", "construct-style-sheets-polyfill": "^3.1.0",
"core-js": "^3.38.1", "core-js": "^3.38.1",
"country-flag-icons": "^1.5.13", "country-flag-icons": "^1.5.13",
"date-fns": "^4.1.0",
"dompurify": "^3.2.4", "dompurify": "^3.2.4",
"fuse.js": "^7.0.0", "fuse.js": "^7.0.0",
"guacamole-common-js": "^1.5.0", "guacamole-common-js": "^1.5.0",
@ -77,6 +78,7 @@
"eslint": "^9.11.1", "eslint": "^9.11.1",
"eslint-plugin-lit": "^1.15.0", "eslint-plugin-lit": "^1.15.0",
"eslint-plugin-wc": "^2.1.1", "eslint-plugin-wc": "^2.1.1",
"find-free-ports": "^3.1.1",
"github-slugger": "^2.0.0", "github-slugger": "^2.0.0",
"glob": "^11.0.0", "glob": "^11.0.0",
"globals": "^15.10.0", "globals": "^15.10.0",

View File

@ -90,12 +90,14 @@ export class AdminInterface extends AuthenticatedInterface {
constructor() { constructor() {
super(); super();
this.ws = new WebsocketClient(); this.ws = new WebsocketClient();
window.addEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, () => { window.addEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, () => {
this.notificationDrawerOpen = !this.notificationDrawerOpen; this.notificationDrawerOpen = !this.notificationDrawerOpen;
updateURLParams({ updateURLParams({
notificationDrawerOpen: this.notificationDrawerOpen, notificationDrawerOpen: this.notificationDrawerOpen,
}); });
}); });
window.addEventListener(EVENT_API_DRAWER_TOGGLE, () => { window.addEventListener(EVENT_API_DRAWER_TOGGLE, () => {
this.apiDrawerOpen = !this.apiDrawerOpen; this.apiDrawerOpen = !this.apiDrawerOpen;
updateURLParams({ updateURLParams({
@ -107,6 +109,7 @@ export class AdminInterface extends AuthenticatedInterface {
async firstUpdated(): Promise<void> { async firstUpdated(): Promise<void> {
configureSentry(true); configureSentry(true);
this.user = await me(); this.user = await me();
const canAccessAdmin = const canAccessAdmin =
this.user.user.isSuperuser || this.user.user.isSuperuser ||
// TODO: somehow add `access_admin_interface` to the API schema // TODO: somehow add `access_admin_interface` to the API schema
@ -116,6 +119,16 @@ export class AdminInterface extends AuthenticatedInterface {
} }
} }
async connectedCallback(): Promise<void> {
super.connectedCallback();
if (process.env.NODE_ENV === "development" && process.env.WATCHER_URL) {
const { ESBuildObserver } = await import("@goauthentik/common/client");
new ESBuildObserver(process.env.WATCHER_URL);
}
}
render(): TemplateResult { render(): TemplateResult {
const sidebarClasses = { const sidebarClasses = {
"pf-m-light": this.activeTheme === UiThemeEnum.Light, "pf-m-light": this.activeTheme === UiThemeEnum.Light,

View File

@ -22,7 +22,7 @@ import "@goauthentik/elements/forms/SearchSelect";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit"; import { TemplateResult, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
@ -126,7 +126,7 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
); );
return html`<form class="pf-c-form pf-m-horizontal"> return html`<form class="pf-c-form pf-m-horizontal">
<ak-alert level="pf-m-info">${alertMsg}</ak-alert> ${this.instance ? nothing : html`<ak-alert level="pf-m-info">${alertMsg}</ak-alert>`}
<ak-text-input <ak-text-input
name="name" name="name"
value=${ifDefined(this.instance?.name)} value=${ifDefined(this.instance?.name)}

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