Compare commits

..

115 Commits

Author SHA1 Message Date
Ken Sternberg
37957608a7 web/bug/hidden-secrets-not-propagating
# What

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

# Why

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

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

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

Object-oriented state management sometimes bites.
2025-12-29 10:06:30 -08:00
Ken Sternberg
63b67f9e23 Merge branch 'web/maintenance/no-unknown-attributes' into web/maintenance/no-unknown-attributes-2
* web/maintenance/no-unknown-attributes: (36 commits)
  website/docs: endpoint devices: add path to macos setup (#19093)
  website/docs: endpoint devices: update features table (#19094)
  website/docs: rel notes .12: add wallos (#19063)
  website/docs: endpoints: mention connector key required for stage to work (#19084)
  web/admin: fix button alignment on user view page (#19079)
  web: bump @formatjs/intl-listformat from 7.7.13 to 8.1.0 in /web (#19054)
  internal: update TLS Suite (#19076)
  web: bump @lit/localize-tools from 0.8.0 to 0.8.1 in /web (#19040)
  web: bump knip from 5.77.0 to 5.77.1 in /web (#19049)
  core, web: update translations (#18991)
  tests/e2e: add endpoint tests (#19072)
  website/integrations: owncloud: fix php (#19073)
  web: fix file search input not resetting results properly (#19034)
  blueprints: fix deadlock and task context error in MetaApplyBlueprint (#19033)
  *: Auto compress images (#19065)
  website/docs: FreeIPA documentation updates (#15183)
  website/integrations: Add Wallos (#19013)
  blueprints: set enrollment token key (#19061)
  endpoints/devices: cleanup  (#19047)
  lib/sync: fix sync_dispatch (#19053)
  ...
2025-12-29 09:03:53 -08:00
Ken Sternberg
1a943be65a Merge branch 'main' into web/maintenance/no-unknown-attributes
* main: (29 commits)
  website/docs: endpoint devices: add path to macos setup (#19093)
  website/docs: endpoint devices: update features table (#19094)
  website/docs: rel notes .12: add wallos (#19063)
  website/docs: endpoints: mention connector key required for stage to work (#19084)
  web/admin: fix button alignment on user view page (#19079)
  web: bump @formatjs/intl-listformat from 7.7.13 to 8.1.0 in /web (#19054)
  internal: update TLS Suite (#19076)
  web: bump @lit/localize-tools from 0.8.0 to 0.8.1 in /web (#19040)
  web: bump knip from 5.77.0 to 5.77.1 in /web (#19049)
  core, web: update translations (#18991)
  tests/e2e: add endpoint tests (#19072)
  website/integrations: owncloud: fix php (#19073)
  web: fix file search input not resetting results properly (#19034)
  blueprints: fix deadlock and task context error in MetaApplyBlueprint (#19033)
  *: Auto compress images (#19065)
  website/docs: FreeIPA documentation updates (#15183)
  website/integrations: Add Wallos (#19013)
  blueprints: set enrollment token key (#19061)
  endpoints/devices: cleanup  (#19047)
  lib/sync: fix sync_dispatch (#19053)
  ...
2025-12-29 08:41:22 -08:00
Ken Sternberg
387bc8a409 Merge branch 'main' into web/maintenance/no-unknown-attributes
* main:
  website/docs: Prioritize "Release Candidate" over "Current Release" (#18975)
  core: bump goauthentik.io/api/v3 from 3.2026020.4 to 3.2026020.5 (#19017)
  web: bump the eslint group across 1 directory with 3 updates (#19019)
  web/admin: prevent file upload attempt when backend not managed (#18646)
  api: rework schema generation (#18977)
  web: bump globby from 16.0.0 to 16.1.0 in /web (#18995)
  core: bump openapitools/openapi-generator-cli from v7.16.0 to v7.18.0 in /scripts/api (#19018)
2025-12-23 08:10:36 -08:00
Ken Sternberg
a2441258ea Merge branch 'web/maintenance/no-unknown-attributes' into web/maintenance/no-unknown-attributes-2
* web/maintenance/no-unknown-attributes:
  web: bump the rollup group across 1 directory with 4 updates (#18994)
2025-12-22 16:00:31 -08:00
Ken Sternberg
205cd63cad Merge branch 'main' into web/maintenance/no-unknown-attributes
* main:
  web: bump the rollup group across 1 directory with 4 updates (#18994)
  website/docs: improve endpoint devices docs (#19007)
  enterprise/search: add static autocomplete structure (#19008)
  enterprise/reports: improve export list, confirmation (#18981)
  providers/oauth2: Automated OpenID Conformance tests (#14785)
2025-12-22 16:00:15 -08:00
Ken Sternberg
d7f32957cb web/maintenance/no-unknown-attributes-2
# What

This commit is a collection of fixes and adaptations discovered while running lit-analyzer in a stricter role than usual.

- `src/admin/endpoints/connectors/agent/AgentConnectorSetup.ts`

After talking to @beryju, we determined that these labels aren’t shown and aren’t used.

- `src/admin/admin-overview/AdminOverviewPage.ts`
- `src/admin/admin-overview/DashboardUserPage.ts`
- `src/elements/cards/AggregatePromiseCard.ts`
- `src/elements/cards/stories/AggregatePromiseCard.stories.ts`

The `Promise` version of our card is not used by any client code. The Dashboard pages that were importing it want the vanilla `AggregateCard` instead.

- `./src/flow/stages/identification/IdentificationStage.ts`

Anchors do not have a `name` attribute, I cannot find any code using the name attributes as lookups, nor any CSS that might use the name attributes as guides. `ak-flow-password-input` is always required; the flag is unsupported and unnecessary.

- `./src/flow/stages/password/PasswordStage.ts`

Anchors do not have a `name` attribute, I cannot find any code using the name attributes as lookups, nor any CSS that might use the name attributes as guides. `ak-flow-password-input` is always required; the flag is unsupported and unnecessary.

- `src/user/user-settings/UserSettingsPage.ts`

This change to the `UserSettingsPage`:

``` diff
-                                userId=${ifPresent(currentUser?.pk)}
+                                user-id=${ifPresent(currentUser?.pk)}
```

… corresponds correctly with:

``` typescript
    @property({ type: Number, attribute: "user-id" })
    public userId?: number;
```

I find it odd (and remarkable) that nobody has complained about this yet. I even went so far as to [confirm my understanding](https://codepen.io/kensternberg-authentik/pen/raLNBwO) and, yes:

- when an attribute is truthy, property syntax does not set the field
- when an attribute is deliberately given a kebab-case name, using the camelCase variant does not set the field

However, when the attribute is truthy, attribute names are case-insensitive: ‘user-id’ and ‘User-Id’ in client code would work just fine.

## Note

A large enough number of warnings remain. Some of those are due to `lit-analyzer` not being updated to recognize newly Baseline global DOM properties like `inert` or `popover`. The rest are from RapiDoc and QrCode, which do not supply sufficient documentation or metadata for Lit-anaylzer to read correctly.
2025-12-22 15:58:29 -08:00
Ken Sternberg
be5918e69d Merge branch 'web/maintenance/no-unknown-attributes' into web/maintenance/no-unknown-attributes-2
* web/maintenance/no-unknown-attributes:
  Update web/src/components/ak-text-input.ts
  Update web/src/admin/providers/oauth2/OAuth2ProviderRedirectURI.ts
  web/maintenance/no-unknown-attributes-1
2025-12-22 13:51:57 -08:00
Ken Sternberg
8d29ae4dd8 Merge branch 'main' into dev
* main:
  website/docs: improve endpoint devices docs (#19007)
  enterprise/search: add static autocomplete structure (#19008)
  enterprise/reports: improve export list, confirmation (#18981)
  providers/oauth2: Automated OpenID Conformance tests (#14785)
  ci: bump docker/setup-buildx-action from 3.11.1 to 3.12.0 (#18999)
  blueprints: fix flaky tests (#19002)
  web: fix Open button selecting row instead of navigating (#18992)
  events: notifications live update (#18980)
  web/admin: Fix haveibeenpwned link in PasswordPolicyForm (#18984)
  web/admin: fix dark theme on map (#18985)
  blueprints: add InternallyManagedMixin instead of large list (#18983)
  website/integrations: Fix path for Cloudflare Access (#18979)
2025-12-22 13:43:32 -08:00
Ken Sternberg
89135f9701 Merge remote-tracking branch 'refs/remotes/origin/web/maintenance/no-unknown-attributes' into web/maintenance/no-unknown-attributes
* refs/remotes/origin/web/maintenance/no-unknown-attributes:
  Update web/src/components/ak-text-input.ts
  Update web/src/admin/providers/oauth2/OAuth2ProviderRedirectURI.ts
2025-12-22 08:53:59 -08:00
Ken Sternberg
1326fda688 Merge branch 'main' into web/maintenance/no-unknown-attributes
* main:
  ci: bump docker/setup-buildx-action from 3.11.1 to 3.12.0 (#18999)
  blueprints: fix flaky tests (#19002)
  web: fix Open button selecting row instead of navigating (#18992)
  events: notifications live update (#18980)
  web/admin: Fix haveibeenpwned link in PasswordPolicyForm (#18984)
  web/admin: fix dark theme on map (#18985)
  blueprints: add InternallyManagedMixin instead of large list (#18983)
  website/integrations: Fix path for Cloudflare Access (#18979)
2025-12-22 08:52:48 -08:00
Ken Sternberg
8437038b05 Update web/src/components/ak-text-input.ts
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
2025-12-22 08:16:50 -08:00
Ken Sternberg
4cdb2d553e Update web/src/admin/providers/oauth2/OAuth2ProviderRedirectURI.ts
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
2025-12-22 08:15:28 -08:00
Ken Sternberg
23262cab8a web/maintenance/no-unknown-attributes-1
# What

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

The following issues were uncovered.

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

These guideposts will be placed on the PR.
2025-12-19 15:59:09 -08:00
Ken Sternberg
1521ade889 Merge branch 'main' into dev
* main: (60 commits)
  web/maintenance: no unknown tag names (#18944)
  web/maintenance: fix missing custom web component imports (#18942)
  website/docs: add note to active directory source doc (#18787)
  ci: bump actions/attest-build-provenance from 3.0.0 to 3.1.0 (#18960)
  web: bump @sentry/browser from 10.31.0 to 10.32.0 in /web in the sentry group across 1 directory (#18957)
  web: bump the swc group across 1 directory with 11 updates (#18958)
  web: bump chromedriver from 143.0.2 to 143.0.3 in /web (#18959)
  core: bump goauthentik.io/api/v3 from 3.2026020.3 to 3.2026020.4 (#18956)
  root: move docker files to lifecycle/containers and change docker-compose to compose (#16624)
  flows/executor: fix KeyError when session has no existing plan (#18951)
  web/admin: fix endpoints user binding (#18935)
  website/docs: Fix version parsing. (#18948)
  website/docs: release notes: add endpoint device links to 2025.12 notes (#18940)
  website/docs: Fix labels, Pre-Release detection (#18945)
  website/docs: endpoint devices (#18634)
  stages/identification: replace sleep with make_password (#18883)
  web/elements: progress-bar and table loading header (#18934)
  crypto: fix extra cert data in db migration (#18937)
  website/integrations: Add launch URL for Immich (#18921)
  web/flow: Fix spurious double submit  on ak-stage-autosubmit (#18727)
  ...
2025-12-19 08:55:37 -08:00
Ken Sternberg
9a4c56e6b2 Merge branch 'main' into dev
* main: (54 commits)
  website/docs: 2025.10.3 release notes (#18868)
  website/docs: Add docs for passkey autofill (WebauthN Conditional UI) (#18805)
  website/docs: adjust RBAC-related details in 2025.12 release notes (#18863)
  outposts: fix permission errors for related certificates (#18861)
  web/admin/rbac: misc object permission fixes (#18859)
  core: bump library/golang from `5d35fb8` to `8e8f9c8` (#18855)
  rbac: alter migrated direct permission roles (#18860)
  core: add skip s3_test_server_available to TestResolveFileUrlS3Backend (#18858)
  ci: replace codecov test-results action (#18862)
  core: bump goauthentik/fips-debian from `c10cd2c` to `2f19fc1` (#18856)
  admin/files: fix get_objects_for_user queryset argument in FileUsedByView (#18845)
  core: skip s3 tests if endpoint isn't available (#18841)
  crypto: Store details parsed from includeDetails in database instead (#18013)
  website/docs: add jellyseer integration doc (#18812)
  admin/files: revert add check for /media existence (#18636) (#18829)
  core: bump goauthentik.io/api/v3 from 3.2025120.26 to 3.2026020.1 (#18815)
  packages/django-dramatiq-postgres: broker: close django connections on consumer close (#18833)
  core: remove superuser check from `Token` list (#18684)
  website/docs: add icon info to style guide (#18832)
  core: list applications fix (#18798)
  ...
2025-12-16 08:05:51 -08:00
Ken Sternberg
4f1126ea99 Merge branch 'main' into dev
* main: (69 commits)
  website/docs: fix incorrect menu reference in data exports doc (#18752)
  translate: Updates for project authentik and language zh-Hans (#18756)
  translate: Updates for project authentik and language tr_TR (#18758)
  translate: Updates for project authentik and language fi_FI (#18759)
  translate: Updates for project authentik and language pl_PL (#18754)
  translate: Updates for project authentik and language ru_RU (#18745)
  translate: Updates for project authentik and language ko_KR (#18760)
  translate: Updates for project authentik and language ja_JP (#18755)
  translate: Updates for project authentik and language de_DE (#18749)
  translate: Updates for project authentik and language nl_NL (#18751)
  translate: Updates for project authentik and language pt_BR (#18746)
  translate: Updates for project authentik and language es_ES (#18748)
  translate: Updates for project authentik and language it_IT (#18750)
  translate: Updates for project authentik and language cs_CZ (#18753)
  translate: Updates for project authentik and language fr_FR (#18747)
  stages/identification: Add WebAuthn conditional UI (passkey autofill) support (#18377)
  api: allow configuring default page_size and max_page_size (#18165)
  root: do not require backend approval for npm workspace dependencies (#18738)
  outpost/proxyv2: more tests, fix pg password with spaces, and existing session on restart (#18211)
  web: bump @types/guacamole-common-js from 1.5.4 to 1.5.5 in /web (#18717)
  ...
2025-12-11 13:08:08 -08:00
Ken Sternberg
d15e360a74 Merge branch 'main' into dev
* main: (23 commits)
  *: Auto compress images (#18673)
  website/integrations: update kimai doc (#18629)
  root: skip current tab when refreshing others (#18674)
  core: add digraph group hierarchy (#17050)
  core: bump astral-sh/uv from 0.9.15 to 0.9.16 (#18668)
  core: bump goauthentik.io/api/v3 from 3.2025120.16 to 3.2025120.18 (#18661)
  web: bump type-fest from 5.3.0 to 5.3.1 in /web (#18663)
  ci: bump peter-evans/create-pull-request from 7.0.9 to 7.0.11 (#18666)
  web: bump vite from 7.2.6 to 7.2.7 in /web (#18662)
  core: bump goauthentik/fips-debian from `a80dbbd` to `10c8086` (#18665)
  ci: bump actions/create-github-app-token from 2.2.0 to 2.2.1 (#18664)
  ci: bump astral-sh/setup-uv from 7.1.4 to 7.1.5 in /.github/actions/setup (#18667)
  website/docs: background tasks: add more detail about "next run" (#18660)
  website/docs: install-config: fix dump_config command (#18659)
  website/integrations: wordpress: fix redirect uri (#18658)
  stages/mtls: always include cert in flow plan (#18657)
  endpoints: fix UI bugs, add user binding, etc (#18609)
  sources/ldap: make server info optional (#18648)
  web/admin: fix event volume chart not updating with query (#18649)
  web: Bump types, fix ESLint errors (#17546)
  ...
2025-12-08 08:35:20 -08:00
Ken Sternberg
2cd358d5e1 Merge branch 'main' into dev
* main: (40 commits)
  enterprise/stages/mtls: fix traefik certificate parsing (#18607)
  wed/admin: change s to S in "Stage" (#18632)
  flows: refresh unauthenticated tabs (#18621)
  flows: keep ?next url when using cancel (#18619)
  core, web: update translations (#18620)
  ci: bump actions/setup-node from 6.0.0 to 6.1.0 (#18552)
  core: bump goauthentik/fips-debian from `cf233be` to `a80dbbd` (#18594)
  web: bump @sentry/browser from 10.28.0 to 10.29.0 in /web in the sentry group across 1 directory (#18623)
  website/docs: adds note about ak_create_jwt function (#18614)
  api: fix IPC auth (#18612)
  web: bump mermaid from 11.12.1 to 11.12.2 in /web (#18602)
  web: Codemirror fixes (#18610)
  web: bump packages in /web (#18604)
  website/docs: expressions: fix markdown (#18613)
  website/docs: add missing API sidebar entry (#18586)
  web: bump yaml from 2.8.1 to 2.8.2 in /web (#18605)
  web/elements: update AppIcon story with files change (#18608)
  api: test action decorator (#18583)
  crypto: separate permissions for certificate and private keydownload (#18588)
  core: bump github.com/spf13/cobra from 1.10.1 to 1.10.2 (#18592)
  ...
2025-12-05 15:58:42 -08:00
Ken Sternberg
9fbc76098a Merge branch 'main' into dev
* main: (44 commits)
  build(deps): bump django from 5.2.8 to 5.2.9 (#18566)
  web: Adjust colors (#18427)
  admin/files: delete applications cache on migration (#18565)
  core: bump astral-sh/uv from 0.9.14 to 0.9.15 (#18555)
  core: bump goauthentik.io/api/v3 from 3.2025120.11 to 3.2025120.15 (#18551)
  core: bump goauthentik/fips-debian from `c718f60` to `cf233be` (#18553)
  ci: bump actions/checkout from 6.0.0 to 6.0.1 (#18554)
  ci: bump actions/stale from 10.1.0 to 10.1.1 (#18556)
  ci: bump golangci/golangci-lint-action from 9.1.0 to 9.2.0 (#18557)
  ci: bump actions/setup-node from 6.0.0 to 6.1.0 in /.github/actions/setup (#18559)
  core: bump library/golang from 1.25.4-trixie to 1.25.5-trixie (#18558)
  providers/scim: cache ServiceProviderConfig (#18047)
  web/i18n: Locale Context Merge Branch (#18426)
  website: Glossary (#16007)
  endpoints/stage: v2, better error handling, more settings (#18545)
  website: Docusaurus 3.9.2 (#18506)
  website/integrations: add hoop.dev (#17868)
  web/flows: update default background image (#18540)
  endpoints: implement endpoint stage (#18468)
  website/integrations: add salesforce (#18516)
  ...
2025-12-03 10:42:52 -08:00
Ken Sternberg
be3f35c58f Merge branch 'main' into dev
* main: (53 commits)
  core, web: update translations (#18380)
  web: re-add en.xlf locale (#18469)
  stages/user_write: Fix user attributes are not sanitized under certains conditions (#17890)
  providers/scim: compare users/groups before sending update request (#18456)
  enterprise/endpoints/connectors/agent: fix Apple JWE encryption when FIPS is enabled (#18464)
  website: bump @types/react from 19.2.6 to 19.2.7 in /website (#18357)
  core: bump goauthentik/fips-debian from `ac4c80b` to `de70579` (#18419)
  core: bump github.com/getsentry/sentry-go from 0.39.0 to 0.40.0 (#18416)
  website: bump prettier-plugin-packagejson from 2.5.19 to 2.5.20 in /website (#18460)
  core: bump goauthentik.io/api/v3 from 3.2025120.7 to 3.2025120.11 (#18461)
  website/integrations: add GLPI (#17937)
  website/integrations: small fixes (#18423)
  enterprise: Apple Platform SSO (#15318)
  crypto: only generate managed keypair if non-existent (#18457)
  ci: remove translation-rename (#18444)
  translate: Updates for project authentik and language tr (#18438)
  translate: Updates for project authentik and language fr (#18431)
  translate: Updates for project authentik and language ru (#18442)
  translate: Updates for project authentik and language cs_CZ (#18443)
  translate: Updates for project authentik and language pt (#18437)
  ...
2025-12-01 08:31:12 -08:00
Ken Sternberg
ac31137c97 Merge branch 'main' into dev
* main: (58 commits)
  core: bump goauthentik.io/api/v3 from 3.2025120.5 to 3.2025120.7 (#18381)
  web/admin: add entitlement search (#18291)
  core: bump goauthentik/fips-debian from `8b7e8d0` to `8c4ec98` (#18361)
  website: bump the build group in /website with 3 updates (#18382)
  core: bump astral-sh/uv from 0.9.11 to 0.9.12 (#18383)
  root: improve testing helpers (#18379)
  website: bump the goauthentik group across 1 directory with 4 updates (#18378)
  website: bump the eslint group in /website with 3 updates (#18356)
  policies: use flow planner directly in PolicyAccessView to directly set flow context (#18372)
  providers/scim: fix PATCH for AWS (#18230)
  enterprise/providers/scim: fix OAuth (#18358)
  web: Fix stale table rows (#17940)
  web: Bump packages. (#18371)
  *: convert slugfields to textfields (#17411)
  outposts: set container healthcheck inline (#18298)
  web:  ESLint Typing Fixes  (#18362)
  core: bump golang.org/x/crypto from 0.43.0 to 0.45.0 (#18275)
  lifecycle/aws: bump aws-cdk from 2.1032.0 to 2.1033.0 in /lifecycle/aws (#18278)
  core: bump github.com/getsentry/sentry-go from 0.38.0 to 0.39.0 (#18353)
  ci: bump actions/setup-python from 6.0.0 to 6.1.0 in /.github/actions/setup (#18360)
  ...
2025-11-26 07:47:43 -08:00
Ken Sternberg
8509056e21 Merge branch 'main' into dev
* main: (55 commits)
  Makefile: Fix kerberos tests for brew users (#17223)
  website/docs: add 2025.8.5 and 2025.10.2 release notes (#18268)
  internal: Automated internal backport: 5000-sidebar.sec.patch to authentik-main (#18266)
  internal: Automated internal backport: 1498-oauth2-cc-user-active.sec.patch to authentik-main (#18265)
  internal: Automated internal backport: 1487-invitation-expiry.sec.patch to authentik-main (#18264)
  core, web: update translations (#18241)
  web: bump ts-pattern from 5.8.0 to 5.9.0 in /web (#18247)
  web: bump the react group across 2 directories with 1 update (#18244)
  web: bump knip from 5.66.2 to 5.70.0 in /web (#18245)
  core: bump library/nginx from `b5b9e01` to `553f64a` in /website (#18253)
  core: bump library/golang from `27e1c92` to `728cbef` (#18252)
  core: bump goauthentik/fips-debian from `65a9f1f` to `55c1514` (#18251)
  web: Bump Vitest, TypeScript config (#18238)
  web: bump js-yaml from 4.1.0 to 4.1.1 in /packages/esbuild-plugin-live-reload (#18237)
  web/i18n: Remove English Locale (#18164)
  web: bump js-yaml from 3.14.1 to 3.14.2 in /packages/docusaurus-config (#18239)
  web/i18n: Clean up locale scripts (#18163)
  stages/prompt: fix choices with labels causing error on submit (#18183)
  web: Patternfly 5 Prep: Part 2 (#18085)
  lifecycle/aws: bump aws-cdk from 2.1031.2 to 2.1032.0 in /lifecycle/aws (#18218)
  ...
2025-11-20 09:18:17 -08:00
Ken Sternberg
63e188773f Merge branch 'main' into dev
* main:
  website/integrations: FortiMail (#17900)
  web/sfe: downgrade bootstrap that was accidentally upgraded (#18157)
  web: Fix ESBuild hanging process (#18162)
  website/integrations: macmon NAC (#17898)
2025-11-17 08:51:59 -08:00
Ken Sternberg
8585c646a2 Merge branch 'main' into dev
* main: (74 commits)
  packages/django-channels-postgres/layer: fix query when subscribed to multiple channels (#18152)
  core: deduplicate user attribute constant definitions (#18138)
  web: bump @trivago/prettier-plugin-sort-imports from 5.2.2 to 6.0.0 in /web (#18146)
  crypto: update certificates on fs event (#18129)
  github: converts issue templates to forms (#18133)
  core: bump github.com/getsentry/sentry-go from 0.36.2 to 0.37.0 (#18140)
  web: bump type-fest from 5.1.0 to 5.2.0 in /web (#18144)
  web: bump vite from 7.1.12 to 7.2.2 in /web (#18143)
  website: bump the build group in /website with 3 updates (#18141)
  web: bump globals from 16.4.0 to 16.5.0 in /web (#18145)
  core: bump astral-sh/uv from 0.9.8 to 0.9.9 (#18148)
  core: bump goauthentik/fips-debian from `5017d65` to `40a1f32` (#18149)
  website/integrations: Add ezBookkeeping integration (#18040)
  website/integrations: Add Joplin (#18042)
  web: Disable library `<datalist>` on Firefox. (#18103)
  web/admin: link to user on invitation list page (#18132)
  web/admin: update stage descriptions (#18118)
  website/integrations: add SeaTable (#18115)
  website/integrations: stripe: fix markdown (#18126)
  web/flows: improvements for hCaptcha (#16882)
  ...
2025-11-14 08:06:43 -08:00
Ken Sternberg
5c66e50205 website: fix bad escaping of URLs in release notes
## What

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

v2024.6.4 had entries that looked like this:

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

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

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

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

## Notes

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

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

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.
2025-11-10 09:20:22 -08:00
Ken Sternberg
2c658e2ee6 Merge branch 'main' into dev
* main: (42 commits)
  core, web: update translations (#17943)
  web: bump @types/node from 24.9.1 to 24.10.0 in /packages/prettier-config (#17949)
  core: bump library/nginx from `f547e3d` to `1beed3c` in /website (#17955)
  core: bump goauthentik.io/api/v3 from 3.2025120.2 to 3.2025120.3 (#17945)
  web: bump @types/node from 22.15.19 to 24.10.0 in /web (#17950)
  ci: bump docker/setup-qemu-action from 3.6.0 to 3.7.0 (#17999)
  lifecycle/aws: bump aws-cdk from 2.1031.1 to 2.1031.2 in /lifecycle/aws (#18014)
  core: bump golang.org/x/sync from 0.17.0 to 0.18.0 (#18033)
  core: bump astral-sh/uv from 0.9.7 to 0.9.8 (#18037)
  core: bump golang.org/x/oauth2 from 0.32.0 to 0.33.0 (#18034)
  core: bump axllent/mailpit from v1.27.10 to v1.27.11 in /tests/e2e (#18035)
  ci: bump golangci/golangci-lint-action from 8.0.0 to 9.0.0 (#18036)
  core: bump library/golang from `a13297b` to `27e1c92` (#18038)
  ci: fix migrate-from-stable for old versions (#18019)
  core: bump library/golang from 1.25.3-trixie to 1.25.4-trixie (#18000)
  website/docs: updates img-src csp (#18010)
  providers/saml: move sp binding location and default value (#17609)
  core: Add example invitation blueprint (#17661)
  root: settings.py: fix comment (#18006)
  core: bump google-auth-httplib2 from 0.2.0 to v0.2.1 (#17978)
  ...
2025-11-10 08:42:07 -08:00
Ken Sternberg
2c52a19a44 Merge branch 'main' into dev
* main:
  webiste/docs: remove broken info box and fix sentence (#17963)
  web/admin: fixes capitalization in application wizard title (#17959)
  website/docs: added Note about email_verified scope mapping is set to false by default (#17942)
  crypto: update certificate api and component (#17921)
  core: bump openapitools/openapi-diff from 2.1.4 to 2.1.5 in /scripts/api (#17929)
  ci: bump getsentry/action-release from 3.3.0 to 3.4.0 (#17931)
  ci: bump helm/kind-action from 1.12.0 to 1.13.0 (#17930)
  tasks/schedules: fix rel obj not being associated or updated (#17934)
  core, web: update translations (#17807)
  brands: sort matched brand by match length (#17920)
  web: bump the storybook group across 1 directory with 5 updates (#17787)
  brands: add more matching tests (#16185)
2025-11-05 08:42:36 -08:00
Ken Sternberg
bc2a07156b Merge branch 'main' into dev
* main: (32 commits)
  website/docs: 2025.10.1 release notes (#17918)
  providers/oauth2: fix kid always required for federation (#17914)
  providers/radius: revert fix inverted message authenticator validation (#17855) (#17915)
  website: bump @types/node from 24.9.1 to 24.9.2 in /website (#17786)
  web: bump @rollup/plugin-commonjs from 28.0.8 to 28.0.9 in /web in the rollup group across 1 directory (#17788)
  web: bump validator from 13.15.15 to 13.15.20 in /packages/docusaurus-config (#17866)
  internal: add default go http server timeouts (#17858)
  providers/radius: fix inverted message authenticator validation (#17855)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#17871)
  web: fix package-lock.json (#17809)
  website/integrations: oracle cloud: cleanup (#17808)
  website/integrations: Add Keycloak integration (#17813)
  website: bump the build group across 1 directory with 9 updates (#17849)
  lifecycle/aws: bump aws-cdk from 2.1031.0 to 2.1031.1 in /lifecycle/aws (#17850)
  core: bump astral-sh/uv from 0.9.6 to 0.9.7 (#17851)
  internal: full openssl path (#17856)
  outpost: revert breaking signals change (#17847)
  web/a11y: Isolated Outpost Error Page (#17683)
  provider/saml: make signing kp singleton (#17703)
  tasks: sanitize log attributes (#17833)
  ...
2025-11-03 08:23:26 -08:00
Ken Sternberg
0845cc400c Merge branch 'main' into dev
* main: (28 commits)
  ci: use hashes for actions everywhere (#17803)
  website/integrations: fixed paperless-ngx yml syntax issue and added additional info (#17739)
  core, web: update translations (#17782)
  ci: rework internal repo (#17797)
  root: use hashes for dockerfile FROM (#17795)
  web: bump validator from 13.15.15 to 13.15.20 in /packages/prettier-config (#17776)
  tasks: delay startup signals (#17769)
  website: bump the build group in /website with 6 updates (#17712)
  core, web: update translations (#17660)
  web: bump vite from 7.1.11 to 7.1.12 in /web (#17689)
  website: bump validator from 13.15.15 to 13.15.20 in /website (#17741)
  web: bump eslint-plugin-react-hooks from 7.0.0 to 7.0.1 in /packages/eslint-config in the eslint group across 1 directory (#17714)
  web: bump validator from 13.15.15 to 13.15.20 in /packages/eslint-config (#17742)
  packages/django-postgres-cache: use upsert instead of select/update in a transaction (#17760)
  providers/radius: fix panic when no cert is configured (#17762)
  sources/oauth: Make PKCE verifier 128 characters (#17763)
  providers/proxy: fix missing JWT/claims header (#17759)
  providers/proxy: add gorm logging (#17758)
  web: bump the sentry group across 1 directory with 2 updates (#17743)
  root: Add Dockerfile label org.opencontainers.image.source (#17756)
  ...
2025-10-29 10:07:10 -07:00
Ken Sternberg
91bbf0e449 Merge branch 'main' into dev
* main: (25 commits)
  ci: bump astral-sh/setup-uv from 7.1.1 to 7.1.2 in /.github/actions/setup (#17718)
  web: bump the storybook group across 1 directory with 5 updates (#17715)
  ci: bump actions/upload-artifact from 4.6.2 to 5.0.0 (#17720)
  ci: bump actions/download-artifact from 5.0.0 to 6.0.0 (#17719)
  website/integrations: grafana: replace deprecated redirect_uris usage by allowed_redirect_uris (#17710)
  web: bump @types/codemirror from 5.60.16 to 5.60.17 in /web (#17685)
  web: bump @types/node from 22.15.19 to 24.9.1 in /web (#17687)
  web: bump hono from 4.10.2 to 4.10.3 in /web (#17698)
  website/docs: blueprints: add a bit more info (#17704)
  website/docs: release notes: Add Zot integration (#17700)
  website/integrations: zot oci registry integration (#17682)
  website/integrations: sonarr: clarify reverse proxy setup (#17485)
  website/docs: eap add info about custom validation (#17642)
  web: Fix table row click handler. (#17697)
  root: Fix transifex link (#17696)
  translate: add cs_CZ (#17632)
  web: bump @goauthentik/prettier-config from 1.0.5 to 3.1.0 in /web in the goauthentik group across 1 directory (#17684)
  web: Make action field search case insensitive in Event Matcher Policy Form (#17680)
  website/docs: add note about invite link not bound (#17657)
  web:  Abstract Wizard Lifecycle (#17658)
  ...
2025-10-27 10:33:33 -07:00
Ken Sternberg
11f500c670 Merge branch 'main' into dev
* main:
  website: bump the eslint group in /website with 3 updates (#17601)
  web: bump hono from 4.9.12 to 4.10.2 in /web (#17653)
  web: bump @types/node from 24.9.0 to 24.9.1 in /packages/esbuild-plugin-live-reload (#17616)
  core: bump goauthentik.io/api/v3 from 3.2025100.25 to 3.2025120.1 (#17613)
  website: bump @types/node from 24.9.0 to 24.9.1 in /website (#17612)
  web: bump vite from 7.1.10 to 7.1.11 in /web (#17604)
  lib/sync/outgoing: store sync settings in database (#17630)
2025-10-22 10:00:52 -07:00
Ken Sternberg
eaf9185e73 Merge branch 'main' into dev
* main: (213 commits)
  web: bump @types/node from 24.9.0 to 24.9.1 in /packages/prettier-config (#17617)
  web: bump @types/node from 22.15.19 to 24.9.1 in /web (#17618)
  web: bump knip from 5.66.1 to 5.66.2 in /web (#17619)
  translate: Updates for file web/xliff/en.xlf in pt_BR (#17639)
  core, web: update translations (#17643)
  website/docs: rel notes 2025.10: add 3 more integration guides (#17641)
  providers/proxy: drop headers with underscores (#17650)
  core: bump astral-sh/uv from 0.9.4 to 0.9.5 (#17645)
  web: bump style-mod from 4.1.2 to 4.1.3 in /web (#17647)
  core: bump github.com/getsentry/sentry-go from 0.36.0 to 0.36.1 (#17646)
  website/integrations: add terraform cloud (#17610)
  website/integrations: add zendesk (#17541)
  core: bump djangorestframework from 3.16.0 (our fork) to v3.16.1 (official package) (#16594)
  enterprise: add prometheus metrics for license usage and expiry (#17606)
  ci: link to next. for pre-release docs (#17634)
  web: sync web/package-lock.json (#17611)
  website/integrations: random fixes (#17631)
  website/docs: add short-lived certificate recommendation (#17628)
  core, web: update translations (#17605)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR (#17622)
  ...
2025-10-22 08:11:04 -07:00
Ken Sternberg
47ed22b57d Merge branch 'main' into dev
* main: (56 commits)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#17361)
  website/docs: add entra id scim source (#17357)
  outpost: proxyv2: Use Postgres for the Embedded Outpost (#16628)
  tasks: set uid early (#17356)
  tasks: only set tenant on task creation (#17358)
  core: bump golang.org/x/oauth2 from 0.31.0 to 0.32.0 (#17346)
  web: bump eslint-plugin-react-hooks from 6.1.1 to 7.0.0 in /packages/eslint-config in the eslint group across 1 directory (#17347)
  web: bump chromedriver from 141.0.0 to 141.0.1 in /web (#17348)
  web: bump knip from 5.64.1 to 5.64.2 in /web (#17349)
  web: bump @formatjs/intl-listformat from 7.7.11 to 7.7.12 in /web (#17350)
  web: bump pino from 9.13.0 to 10.0.0 in /web (#17351)
  core: bump axllent/mailpit from v1.27.9 to v1.27.10 in /tests/e2e (#17352)
  enterprise/providers/gws+entra: fix group integrity error during discovery (#17355)
  core, web: update translations (#17342)
  ci: bump snok/container-retention-policy from 2.2.1 to 3.0.1 (#17344)
  core: bump goauthentik.io/api/v3 from 3.2025100.18 to 3.2025100.20 (#17345)
  packages/django-dramatiq-postgres: broker: task retrieval fixes and improvements (#17335)
  enterprise/providers/gws+entra: fix integrity error during discovery (#17341)
  web: bump API Client version (#17340)
  api: Clean schema up more (#17055)
  ...
2025-10-09 10:50:39 -07:00
Ken Sternberg
542a605f9a Merge branch 'main' into dev
* main: (118 commits)
  tasks: add preprocess, running and postprocess statuses (#17297)
  web: Fix behavior for modals configured with closeAfterSuccessfulSubmit (#17277)
  web: Responsive toolbar flow (#17278)
  website/integrations: update dokuwiki (#17292)
  core, web: update translations (#17275)
  core: bump astral-sh/uv from 0.8.23 to 0.8.24 (#17281)
  website: bump @types/node from 24.6.2 to 24.7.0 in /website (#17283)
  web: bump the eslint group across 2 directories with 3 updates (#17285)
  web: bump @types/node from 24.6.2 to 24.7.0 in /packages/esbuild-plugin-live-reload (#17287)
  web: bump @types/node from 24.6.2 to 24.7.0 in /packages/prettier-config (#17288)
  web: bump @types/node from 22.15.19 to 24.7.0 in /web (#17289)
  website/integrations: sssd: Updating config template to include default shell (#17274)
  web/a11y: Flow Stages (#17273)
  web/a11y: Flow inspector. (#17271)
  packages/django-channels-postgres/layer: fix connection deadlock (#17270)
  core: bump django to 5.2.7 (#16324)
  core: fix absolute and relative path file uploads (#17269)
  web/a11y: Accessible scrollbars. (#17253)
  web: Fix table column updates, template parsing (#17254)
  website/integrations: add launch url info to dokuwiki (#17268)
  ...
2025-10-07 07:41:29 -07:00
Ken Sternberg
5b4a921b1a Merge branch 'main' into dev
* main: (29 commits)
  web/a11y: Notifications drawer (#17031)
  web: Clean up render interfaces. (#16031)
  web/a11y: Status label (#17148)
  web: Additional text field properties, ARIA fixes (#17115)
  web/e2e: User creation (#17149)
  web/a11y: Tree view (#17147)
  web/a11y: Fix dark theme color contrast (#17144)
  web: Table refresh timestamp. (#17145)
  providers/oauth2: add ui_locales support for OIDC (#17140)
  website/integrations: convert all note boxes to info boxes (#17139)
  website/docs: replaces all note boxes with info boxes (#17138)
  website/docs: developer docs: adjust sentence for writing docs (#17137)
  core: Add input validation for service account creation (#16964)
  website: bump @types/node from 24.5.2 to 24.6.0 in /website (#17126)
  ci: bump actions/setup-node from 4 to 5 (#17123)
  website: bump the build group in /website with 6 updates (#17124)
  website: bump the eslint group in /website with 3 updates (#17125)
  web: bump @sentry/browser from 10.15.0 to 10.16.0 in /web in the sentry group across 1 directory (#17127)
  web: bump the eslint group across 2 directories with 3 updates (#17128)
  lifecycle/aws: bump cross-env from 10.0.0 to 10.1.0 in /lifecycle/aws (#17130)
  ...
2025-09-30 14:26:21 -07:00
Ken Sternberg
08218dcd1a Merge branch 'main' into dev
* main: (38 commits)
  web: Apply consistent background color when input is disabled or readonly. (#17105)
  website/docs: 2025.8.4 release notes (#17119)
  web: revert bump the swc group across 1 directory with 11 updates (#17113)
  ci: fix node version in docker image build (#17110)
  translate: Updates for file web/xliff/en.xlf in pt_BR (#17111)
  tasks: reduce default number of retries and max backoff (#17107)
  packages/django-dramatiq-postgres: broker: fix new messages not being picked up when too many messages are waiting (#17106)
  website/docs: additional documentation for ak_user_by (#17098)
  stages/identification: fix mismatched error messages (#17090)
  providers/oauth2: fix authentication error with identical app passwords (#17100)
  translate: Updates for file web/xliff/en.xlf in de (#17099)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#17096)
  core: bump goauthentik.io/api/v3 from 3.2025100.11 to 3.2025100.14 (#17071)
  website: bump @types/react from 19.1.13 to 19.1.15 in /website (#17075)
  website/integrations: add cloudflare access redirect (#17094)
  cmd/server/healthcheck: info log success instead of debug (#17093)
  website/integrations: cloudflare (#17039)
  rbac: optimize rbac assigned by users query (#17015)
  web: Fix layout class for 'row' in LibraryPage (#16752)
  *: Auto compress images (#16733)
  ...
2025-09-29 15:33:06 -07:00
Ken Sternberg
2c1fd70808 Merge branch 'main' into dev
* main: (70 commits)
  core, web: update translations (#17036)
  web: bump API Client version (#17048)
  tests/e2e: less hardcoded names (#17047)
  core/api: Better naming for partial user/group serializer, optimise bindings (#17022)
  core: bump goauthentik.io/api/v3 from 3.2025100.10 to 3.2025100.11 (#17040)
  website: bump the build group in /website with 6 updates (#17042)
  web: bump the swc group across 1 directory with 11 updates (#17043)
  website/integrations: Move Cloudflare Access Documentation. (#17038)
  web: Fix skip-to-content element target, order. (#17030)
  web: Add disabled radio styles. (#17026)
  web: Report unregistered elements. (#17025)
  website/docs: Update Github expression to handle non-OAuth sources gracefully (#17014)
  tests/e2e: fix ldap tests following #17010 (#17021)
  web: bump @sentry/browser from 10.13.0 to 10.14.0 in /web in the sentry group across 1 directory (#16966)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR (#17001)
  lib/config: fix listen settings (#17005)
  core: bump goauthentik.io/api/v3 from 3.2025100.8 to 3.2025100.10 (#17019)
  core: add index on Group.is_superuser (#17011)
  lib: match exception_to_dict locals behaviour (#17006)
  outposts/ldap: add pwdChangeTime attribute (#17010)
  ...
2025-09-26 08:24:17 -07:00
Ken Sternberg
5603fe193e Merge branch 'main' into dev
* main: (24 commits)
  root: add mypy (#16904)
  website: Remove duplicate sidebar entries. (#16922)
  web: Remove CSS constructor polyfill. (#16920)
  web: Replace Github Slugger package with change-case. (#16921)
  website: Fix broken schema links v2 (#16919)
  website: bump the build group in /website with 3 updates (#16908)
  core: bump astral-sh/uv from 0.8.18 to 0.8.19 (#16906)
  core: bump goauthentik.io/api/v3 from 3.2025100.6 to 3.2025100.8 (#16907)
  website: bump the eslint group in /website with 2 updates (#16909)
  web: bump the eslint group across 2 directories with 2 updates (#16911)
  web: bump the rollup group across 1 directory with 4 updates (#16912)
  web: bump typedoc-plugin-markdown from 4.8.1 to 4.9.0 in /packages/esbuild-plugin-live-reload (#16913)
  web: bump pino from 9.10.0 to 9.11.0 in /packages/esbuild-plugin-live-reload (#16914)
  web: bump pino from 9.10.0 to 9.11.0 in /web (#16915)
  website: add hierarchy line to sidebar (#16565)
  events: remove deprecated models (#15823)
  core: update_attributes: only update the model if attributes changed (#16322)
  Revert "website: Fix broken schema links, non-relative paths, unapplied redirect aliases" (#16902)
  website: Fix broken schema links, non-relative paths, unapplied redirect aliases (#16900)
  website/integrations: adds termix (#16889)
  ...
2025-09-22 11:15:33 -07:00
Ken Sternberg
6a882f22fa Merge branch 'main' into dev
* main:
  core, web: update translations (#16885)
  web: bump the storybook group across 1 directory with 5 updates (#16886)
  api: optimise schemas' common query parameters (#16884)
2025-09-19 08:19:10 -07:00
Ken Sternberg
442d42f850 Merge branch 'main' into dev
* main: (58 commits)
  web: bump the esbuild group across 2 directories with 4 updates (#16868)
  core, web: update translations (#16864)
  core: bump astral-sh/uv from 0.8.17 to 0.8.18 (#16866)
  website: bump @types/node from 24.5.1 to 24.5.2 in /website (#16867)
  web: bump @types/node from 24.5.1 to 24.5.2 in /packages/esbuild-plugin-live-reload (#16869)
  web: bump pino from 9.9.5 to 9.10.0 in /packages/esbuild-plugin-live-reload (#16870)
  web: bump @types/node from 24.5.1 to 24.5.2 in /packages/prettier-config (#16871)
  web: bump @types/node from 22.15.19 to 24.5.2 in /web (#16872)
  web: bump dompurify from 3.2.6 to 3.2.7 in /web (#16873)
  web: bump pino from 9.9.5 to 9.10.0 in /web (#16874)
  web: bump vite from 7.1.5 to 7.1.6 in /web (#16875)
  web: bump chromedriver from 140.0.2 to 140.0.3 in /web (#16876)
  lifecycle/aws: bump aws-cdk from 2.1029.1 to 2.1029.2 in /lifecycle/aws (#16877)
  web: Fix docs links, a11y input descriptors (#16671)
  website: bump the eslint group in /website with 3 updates (#16788)
  website: bump the build group in /website with 3 updates (#16787)
  web: bump the eslint group across 2 directories with 3 updates (#16790)
  website/docs: extends the example to include `jwt_config` for matrix/synapse (#16860)
  web/a11y: Flow Search (#15876)
  web: bump API Client version, remove Webdriver dependencies (#16836)
  ...
2025-09-18 16:39:55 -07:00
Ken Sternberg
d0daec4aa1 Merge branch 'main' into dev
* main: (81 commits)
  translate: Updates for file web/xliff/en.xlf in de (#16808)
  stages: update friendly_name model from null to blank (#16672)
  sources/saml: add default error messages to exceptions (#15562)
  website/docs: 2025.8.3 release notes (#16809)
  core, web: update translations (#16783)
  stages/email_authenticator: Fix email mfa loop (#16579)
  website/docs: updated Frontend development environment contributor docs (#16731)
  webiste/integrations: update roundcube doc (#16753)
  website/docs: update create oauth provider page (#16617)
  website: bump @types/node from 24.4.0 to 24.5.0 in /website (#16789)
  web: bump the rollup group across 1 directory with 4 updates (#16792)
  core: bump github.com/getsentry/sentry-go from 0.35.2 to 0.35.3 (#16786)
  web: bump the storybook group across 1 directory with 5 updates (#16791)
  web: bump @types/node from 24.4.0 to 24.5.0 in /packages/esbuild-plugin-live-reload (#16794)
  web: bump @goauthentik/prettier-config from 1.0.5 to 3.1.0 in /web in the goauthentik group across 1 directory (#16793)
  web: bump @types/node from 24.4.0 to 24.5.0 in /packages/prettier-config (#16795)
  web: bump @types/node from 22.15.19 to 24.5.0 in /web (#16796)
  web: Use curated dictionary for e2e fixtures. (#16750)
  website/integrations: fix wekan redirect URL (#16801)
  website/docs: fix docker tabs not rendering properly (#16799)
  ...
2025-09-16 12:10:58 -07:00
Ken Sternberg
951da48f81 Merge branch 'main' into dev
* main: (121 commits)
  website: bump the eslint group in /website with 3 updates (#16674)
  web: bump the eslint group across 2 directories with 3 updates (#16675)
  web: bump vite from 7.1.4 to 7.1.5 in /web (#16676)
  website/docs: fix typo (#16681)
  core: Include region comments in VSCode Minimap. (#16667)
  tasks: fix status and healthcheck breaking with connection issues (#16504)
  website/docs: add period on very last sentence. (#16669)
  core: bump golang.org/x/sync from 0.16.0 to 0.17.0 (#16657)
  web: bump the eslint group across 3 directories with 2 updates (#16661)
  web: bump the storybook group across 1 directory with 5 updates (#16662)
  core: bump golang.org/x/oauth2 from 0.30.0 to 0.31.0 (#16658)
  core: bump github.com/prometheus/client_golang from 1.23.1 to 1.23.2 (#16659)
  website: bump the eslint group in /website with 2 updates (#16660)
  web: bump the rollup group across 1 directory with 4 updates (#16663)
  web: bump pino from 9.9.2 to 9.9.4 in /web (#16664)
  lifecycle/aws: bump aws-cdk from 2.1028.0 to 2.1029.0 in /lifecycle/aws (#16665)
  core: bump selenium/standalone-chrome from 139.0 to 140.0 in /tests/e2e (#16666)
  website/integrations: fix missing space after comma (#16650)
  website/integrations: add missing comma paperless-ngx (#16651)
  root: bump to debian trixie (#16626)
  ...
2025-09-09 08:12:24 -07:00
Ken Sternberg
7f353ac1b8 Merge branch 'main' into dev
* main: (71 commits)
  website: Redirect Azure to Entra. Add tags for search indexing. (#16474)
  website: Page redirect guide, documentation (#16466)
  root: bump openapi-generator-cli to v7.15.0 (#16440)
  ci: bump actions/attest-build-provenance from 2 to 3 (#16462)
  core: bump astral-sh/uv from 0.8.13 to 0.8.14 (#16461)
  ci: remove Python client API publication (#16468)
  website: Unify Netlify redirects with Docusaurus's client-side router. (#16430)
  core: fix client-side only validation allowing admin to set blank user password (#16467)
  website/integrations: Update Issuer URL for Immich (#16460)
  providers/oauth2: include scope in JWT (#16454)
  lib/sync/outgoing: fix single object sync timeout (#16447)
  website/docs: capitalized proper name of stages, removed old version references. (#16414)
  web: bump pino-pretty from 13.0.0 to 13.1.1 in /web (#16411)
  core: bump h2 from 4.2.0 to 4.3.0 (#16446)
  web: bump @playwright/test from 1.54.1 to 1.55.0 in /web (#16413)
  web: bump the react group across 2 directories with 1 update (#16448)
  web: bump bootstrap from 5.3.7 to 5.3.8 in /web (#16416)
  web: bump @sentry/browser from 10.6.0 to 10.7.0 in /web in the sentry group across 1 directory (#16433)
  root: check for brew install of libxml2 before updating path (#16422)
  core: bump github.com/stretchr/testify from 1.11.0 to 1.11.1 (#16434)
  ...
2025-08-29 08:38:11 -07:00
Ken Sternberg
7080053510 Merge branch 'main' into dev
* main:
  web: Automatic reload during server start up. (#16030)
  website/docs: Add steps for fixing xml python errors, clean up (#16223)
2025-08-26 08:21:54 -07:00
Ken Sternberg
f55207b6ef Merge branch 'main' into dev
* main:
  providers/oauth2: avoid deadlock during session migration (#16361)
  lifecycle/aws: bump aws-cdk from 2.1025.0 to 2.1026.0 in /lifecycle/aws (#16352)
  core: bump github.com/stretchr/testify from 1.10.0 to 1.11.0 (#16357)
  core: bump axllent/mailpit from v1.27.5 to v1.27.6 in /tests/e2e (#16358)
  website/docs: fix missing trailing slash in vaultwarden documentation (#16348)
  root: fix security.md (#16345)
  root: update security.md with github reporting link (#16332)
  website/docs: 2025.8.1 release notes (#16343)
  packages/django-dramatiq-postgres: broker: fix various timing issues (#16340)
  website/docs: adds details to certificates doc (#16335)
  outposts: allow ingress path type configuration (#16339)
  core, web: update translations (#16321)
  outposts: fix service connection update task arguments (#16312)
  core: use email backend for test_email management command (#16311)
  core: bump astral-sh/uv from 0.8.12 to 0.8.13 (#16325)
  website: Move docs netlify.toml (#16320)
  website/docs: add link in 2025.8 rel notes to back-channel logout docs (#16306)
  packages/django-dramatiq-postgres: middleware: fix listening on hosts where ipv6 is not supported (#16308)
  website: Fix version origin detection, build-time URLs  (#15774)
  web/a11y: Associating labels with inputs (#16119)
2025-08-25 14:09:52 -07:00
Ken Sternberg
7347577436 Merge branch 'main' into dev
* main: (210 commits)
  web: Username truncation, field alignment. (#16283)
  website/docs: adds a webhook header mapping example (#16301)
  web: Fix issue where form group uses unknown slot. (#16276)
  lifecycle: set PROMETHEUS_MULTIPROC_DIR as early as possible (#16298)
  providers/oauth2: fix logout token missing sid, fix wrong sub mode used (#16295)
  web: bump core-js from 3.45.0 to 3.45.1 in /web (#16290)
  root: Remove CODEOWNERS entries from docs/ directory (#16287)
  *: Fix dead doc link (#16288)
  web: saml provider view: fix state refresh issues (#14474)
  web: fix "Explore integrations" link in Quick actions (#16274)
  website/integrations: fix dead links to external docs (#16273)
  tasks: add rel_obj to system task exception event (#16270)
  website/docs: update 2025.8 release notes (#16269)
  web: bump @patternfly/elements from 4.1.0 to 4.2.0 in /web (#16265)
  web: bump mermaid from 11.9.0 to 11.10.0 in /web (#16263)
  web: bump @types/guacamole-common-js from 1.5.3 to 1.5.4 in /web (#16262)
  security: Bump supported versions (#16261)
  core: bump channels from 4.3.0 to v4.3.1 (#16260)
  translate: Updates for file web/xliff/en.xlf in cs_CZ (#16264)
  website: bump the eslint group in /website with 3 updates (#16248)
  ...
2025-08-21 09:50:14 -07:00
Ken Sternberg
4963dde699 Merge branch 'main' into dev
* main: (32 commits)
  core: bump goauthentik.io/api/v3 from 3.2025064.6 to 3.2025064.7 (#16024)
  core, web: update translations (#16021)
  ci: move images from beryju/* to authentik/* (#15321)
  core, web: update translations (#15985)
  core: bump cattrs from 24.1.3 to v25.1.1 (#15981)
  web: bump API Client version (#16002)
  ci: bump actions/download-artifact from 4 to 5 (#15995)
  core: bump certifi from 2025.7.14 to v2025.8.3 (#15982)
  core: bump anyio from 4.9.0 to v4.10.0 (#15979)
  core: bump boto3 from 1.40.1 to v1.40.2 (#15980)
  core: bump astral-sh/uv from 0.8.4 to 0.8.5 (#15998)
  core: bump goauthentik.io/api/v3 from 3.2025064.5 to 3.2025064.6 (#15997)
  stages/email: implement rate limiting for account verification (#15531)
  web: Fix stale application slug, missing error state. (#15941)
  website/docs: change azure ad to entra id (#15691)
  website/docs: add tips for image optimization (#15978)
  web: bump API Client version (#15976)
  providers/oauth2: backchannel logout (#15401)
  web: bump API Client version (#15953)
  translate: Updates for file web/xliff/en.xlf in fr (#15974)
  ...
2025-08-07 08:31:56 -07:00
Ken Sternberg
b60bfadaaf Merge branch 'main' into dev
* main: (77 commits)
  website/integrations: add hass-openid instructions (#14672)
  core: add updated_at field to user (#15571)
  root: Add more opencontainer labels to Dockerfiles (#15923)
  core: bump goauthentik.io/api/v3 from 3.2025064.2 to 3.2025064.3 (#15949)
  core, providers/ldap: add parent/child groups to api and ldap results (#14974)
  web: Make Webdriver optional during install. (#15952)
  core, web: update translations (#15945)
  packages/django-dramatiq-postgres: fix typo (#15932)
  web: bump API Client version (#15942)
  core: fix flow planner checking against wrong user when creating recovery link (#15390)
  providers/saml: configuration for default NameID Policy (#15109)
  core: bump boto3 from 1.39.15 to v1.40.1 (#15926)
  core: bump jsii from 1.112.0 to v1.113.0 (#15927)
  core: bump argon2-cffi-bindings from 21.2.0 to v25.1.0 (#15925)
  core: bump aiohttp from 3.12.14 to v3.12.15 (#15924)
  core: bump opentelemetry-api from 1.35.0 to v1.36.0 (#15928)
  web/admin: fix variable name (#15934)
  policies: fix typo (#15933)
  web: bump @sentry/browser from 9.43.0 to 10.0.0 in /web in the sentry group across 1 directory (#15911)
  core: bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0 (#15908)
  ...
2025-08-04 10:42:32 -07:00
Ken Sternberg
0fc0783e7e Merge branch 'main' into dev
* main: (91 commits)
  *: replace Celery with Dramatiq (#13492)
  website/docs: stages/mtls: Clean up stage configuration section (#15753)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in es (#15818)
  website: bump the eslint group in /website with 2 updates (#15805)
  web: bump typedoc from 0.28.7 to 0.28.8 in /packages/esbuild-plugin-live-reload (#15809)
  core: bump axllent/mailpit from v1.27.1 to v1.27.2 in /tests/e2e (#15813)
  web: bump the rollup group across 1 directory with 4 updates (#15806)
  web: bump the eslint group across 3 directories with 2 updates (#15808)
  lifecycle/aws: bump cross-env from 7.0.3 to 10.0.0 in /lifecycle/aws (#15807)
  web: bump ts-pattern from 5.7.1 to 5.8.0 in /web (#15810)
  web: bump @sentry/browser from 9.41.0 to 9.42.0 in /web in the sentry group across 1 directory (#15811)
  web: Add support for placeholder in <ak-text-input> (#15795)
  providers/rac: fix incorrect caching (#15779)
  root: support for custom postgresql connection options (#15577)
  website: bump the build group in /website with 3 updates (#15784)
  web: bump @sentry/browser from 9.40.0 to 9.41.0 in /web in the sentry group across 1 directory (#15785)
  core: bump astral-sh/uv from 0.8.2 to 0.8.3 (#15786)
  lifecycle/aws: bump aws-cdk from 2.1021.0 to 2.1022.0 in /lifecycle/aws (#15787)
  core: bump twilio from 9.6.5 to 9.7.0 (#15788)
  revert: web: Font fixes (#15581) (#15789)
  ...
2025-07-28 08:06:15 -07:00
Ken Sternberg
aa73014f6a Merge branch 'main' into dev
* main: (131 commits)
  website/docs: add notification rule expression policy examples (#15333)
  website/docs: add force password reset guide (#15654)
  website: bump prettier-plugin-packagejson from 2.5.18 to 2.5.19 in /website (#15672)
  website: Flesh out Makefile commands, usage. (#15576)
  website/integrations: fix duplicate guacamole section (#15684)
  core: bump goauthentik.io/api/v3 from 3.2025063.5 to 3.2025063.6 (#15671)
  web: bump typedoc-plugin-markdown from 4.7.0 to 4.7.1 in /packages/esbuild-plugin-live-reload (#15681)
  web: bump the esbuild group across 2 directories with 4 updates (#15674)
  web: bump @types/node from 24.0.14 to 24.0.15 in /packages/prettier-config (#15676)
  website: bump @types/node from 24.0.14 to 24.0.15 in /website (#15675)
  web: bump @types/node from 24.0.14 to 24.0.15 in /packages/esbuild-plugin-live-reload (#15677)
  web: bump prettier-plugin-packagejson from 2.5.18 to 2.5.19 in /packages/prettier-config (#15678)
  web: bump chart.js and @types/chart.js in /web (#15679)
  web: bump the swc group across 1 directory with 11 updates (#15680)
  web: bump prettier-plugin-packagejson from 2.5.18 to 2.5.19 in /packages/esbuild-plugin-live-reload (#15682)
  web: bump @types/node from 22.15.19 to 24.0.15 in /web (#15683)
  website/dev docs: FDE e2e: fix useless markdown lini (#15658)
  providers/radius: set message authenticator (#15635)
  web: bump @eslint/plugin-kit from 0.3.1 to 0.3.3 in /packages/eslint-config (#15661)
  website/docs: add e2e testing steps (#15656)
  ...
2025-07-21 09:29:57 -07:00
Ken Sternberg
a95d3abe83 Merge branch 'main' into dev
* main: (280 commits)
  providers/proxy: fix ingress-nginx proxy buffer size annotations (#15506)
  website/docs: troubleshooting: Fix variable for postgres database in k8s (#15503)
  web: bump @sentry/browser from 9.35.0 to 9.36.0 in /web in the sentry group across 1 directory (#15492)
  core: bump golang.org/x/sync from 0.15.0 to 0.16.0 (#15493)
  core: bump maxmind/geoipupdate from v7.1.0 to v7.1.1 (#15495)
  core: bump astral-sh/uv from 0.7.19 to 0.7.20 (#15496)
  Docusaurus 3.8 prep integrations (#15483)
  web: Fix dangling div. (#15478)
  core: bump google-api-python-client from 2.175.0 to 2.176.0 (#15471)
  core, web: update translations (#15468)
  website: bump the build group in /website with 3 updates (#15469)
  website: bump @types/node from 24.0.10 to 24.0.12 in /website (#15470)
  core: bump msgraph-sdk from 1.36.0 to 1.37.0 (#15472)
  web/flows: more padding fixes (#15467)
  events: fix ak_client_ip not set in notification rule policy context (#15464)
  website/docs: edits to latest Events docs (#15457)
  website: bump the eslint group in /website with 3 updates (#15452)
  website/docs: fix small typos (#15403)
  root: monitoring: force db connection reload before healthcheck (#9970)
  core: bump microsoft-kiota-serialization-form from 1.9.3 to v1.9.4 (#15441)
  ...
2025-07-10 10:59:25 -07:00
Ken Sternberg
6948146faa Merge branch 'main' into dev
* main: (39 commits)
  website/docs: Add steps to troubleshoot /initial-setup/ (#15011)
  core, web: update translations (#15084)
  website: bump the eslint group in /website with 3 updates (#15085)
  website: bump @types/node from 24.0.1 to 24.0.3 in /website (#15086)
  website: bump postcss from 8.5.5 to 8.5.6 in /website (#15087)
  core: bump webauthn from 2.5.2 to 2.6.0 (#15089)
  core: bump goauthentik.io/api/v3 from 3.2025061.2 to 3.2025062.1 (#15090)
  web: bump the eslint group across 2 directories with 3 updates (#15091)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#15074)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#15075)
  ci: fix post-release e2e builds failing (#15082)
  web: bump API Client version (#15079)
  web/common: fix uiConfig not merged correctly (#15080)
  root: backport version bump `2025.6.2` (#15078)
  website/integrations: add note to nextcloud OIDC config (#15073)
  web/admin: remove all special cases of slug handling, replace with a "smart slug" component (#14983)
  Web/cleanup/empty state better slot handling (#14289)
  website/docs: release notes for `2025.6.2` (#15065)
  website/docs: remove commented out config options (#15064)
  website/docs: postgres troubleshooting: get PGPASSWORD from POSTGRES_PASSWORD_FILE (#15039)
  ...
2025-06-17 08:00:48 -07:00
Ken Sternberg
0ea5f10e5a Merge branch 'main' into dev
* main:
  website/docs: also hide the postgres pool_options setting (#15023)
  blueprints: sort schema items (#15022)
  website: bump the build group in /website with 6 updates (#15027)
  core: bump astral-sh/uv from 0.7.12 to 0.7.13 (#15028)
  core: bump twilio from 9.6.2 to 9.6.3 (#15029)
  core: bump sentry-sdk from 2.29.1 to 2.30.0 (#15030)
  core: bump kubernetes from 32.0.1 to 33.1.0 (#15031)
  core, web: update translations (#15026)
  web: bump the sentry group across 1 directory with 2 updates (#15025)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#15018)
  lifecycle/aws: bump aws-cdk from 2.1018.0 to 2.1018.1 in /lifecycle/aws (#15016)
  website: bump postcss from 8.5.4 to 8.5.5 in /website (#15013)
  website: bump @types/node from 24.0.0 to 24.0.1 in /website (#15014)
  core: fix transaction test case (#15021)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#15019)
  website/docs: correct minor version in release notes (#15012)
  root: test label handling and error reporting in PytestTestRunner (#14000)
  outposts/ldap: Handle comma-separated attributes in LDAP search requests (#15000)
  website/integrations: standardize application slug placeholder in docs (#15007)
  core: bump django from 5.1.10 to 5.1.11 (#14997)
2025-06-13 08:33:02 -07:00
Ken Sternberg
d78e459dcb Merge branch 'main' into dev
* main: (30 commits)
  web/elements: Add light mode custom css handling (#14944)
  website/docs: add host header dynamic property mapping (#15006)
  core, web: update translations (#14999)
  website/docs: fixes misplaced sentence (#14998)
  website/docs: note usage of `is_restored` by source stage (#13422)
  website: bump the build group in /website with 6 updates (#15001)
  web: bump @sentry/browser from 9.27.0 to 9.28.0 in /web in the sentry group across 1 directory (#15002)
  core: bump msgraph-sdk from 1.32.0 to 1.33.0 (#15003)
  core: bump google-api-python-client from 2.171.0 to 2.172.0 (#15004)
  web/admin: fix language in certificate import  (#14953)
  website/integrations: add new categories and update sidebar info (#14995)
  brands: fix custom_css being escaped (#14994)
  web/admin: show selected policy engine mode on bindings pages, allow setting it on sources (#12963)
  website/integrations: add bitwarden (#14922)
  core: bump goauthentik.io/api/v3 from 3.2025061.1 to 3.2025061.2 (#14986)
  website: bump @types/node from 22.15.30 to 24.0.0 in /website (#14988)
  website: bump the eslint group in /website with 3 updates (#14987)
  web: bump the eslint group across 2 directories with 3 updates (#14991)
  website/integrations: fix typos, update language and styling (#14978)
  website/integrations: add 1password (#14815)
  ...
2025-06-11 08:14:02 -07:00
Ken Sternberg
f4393b7b3c Merge branch 'main' into dev
* main: (38 commits)
  website/docs: added a link in our Upgrade docs to the Outpost upgrade docs, slight reformatting  (#14931)
  website: fix search across multiple subdomains (#14976)
  core: bump goauthentik.io/api/v3 from 3.2025060.1 to 3.2025061.1 (#14972)
  web: bump API Client version (#14971)
  root: backport 2025.6.1 bump (#14970)
  stages/email: Only attach logo to email if used (#14835)
  web: bump @codemirror/lang-python from 6.1.6 to 6.2.1 in /web (#14713)
  website: bump prettier-plugin-packagejson from 2.5.14 to 2.5.15 in /website (#14829)
  core: bump selenium/standalone-chrome from 136.0 to 137.0 in /tests/e2e (#14963)
  core: bump axllent/mailpit from v1.25.1 to v1.26.0 in /tests/e2e (#14964)
  core: bump astral-sh/uv from 0.7.11 to 0.7.12 (#14965)
  core: bump github.com/redis/go-redis/v9 from 9.9.0 to 9.10.0 (#14966)
  web: bump @types/mocha from 10.0.8 to 10.0.10 in /web (#14684)
  web: bump ts-pattern from 5.4.0 to 5.7.1 in /web (#14686)
  website: bump @types/node from 22.15.29 to 22.15.30 in /website (#14968)
  web: bump mermaid from 11.4.1 to 11.6.0 in /web (#14688)
  web: bump @fortawesome/fontawesome-free from 6.6.0 to 6.7.2 in /web (#14716)
  web: bump the eslint group across 2 directories with 3 updates (#14833)
  website: bump the eslint group in /website with 4 updates (#14967)
  website: bump @typescript-eslint/parser from 8.32.1 to 8.33.1 in /website (#14828)
  ...
2025-06-09 08:51:20 -07:00
Ken Sternberg
0457b59792 Merge branch 'main' into dev
* main: (54 commits)
  web/user: fix user settings flow not loading (#14911)
  website/docs: fix outdated and incorrect example kubernetes deployment (#14928)
  docusaurus-config: Update deps, colors. (#14796)
  admin: only run update checks in the default tenant (#14874)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14923)
  core: bump astral-sh/uv from 0.7.10 to 0.7.11 (#14918)
  providers/proxy: set_oauth_defaults in reconcile instead of task (#14875)
  *: use ManagedAppConfig everywhere (#14839)
  tenants: fix tenant aware celery scheduler (#14921)
  core, web: update translations (#14910)
  core: bump goauthentik.io/api/v3 from 3.2025041.4 to 3.2025060.1 (#14919)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14915)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14916)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14914)
  website/integrations: improve komodo config verification (#14849)
  website/integrations: fix komodo provider url (#14912)
  website/docs: fix note at end of rac credentials prompt (#14909)
  website/docs: add credentials prompt for rac doc (#14840)
  core: bump redis from 6.0.0 to v6.2.0 (#14895)
  core: bump protobuf from 6.30.2 to v6.31.1 (#14894)
  ...
2025-06-05 15:20:24 -07:00
Ken Sternberg
79d5bc02e9 Merge branch 'main' into dev
* main: (97 commits)
  website/docs: update style guide (#14373)
  website/docs: finalize release notes for `2025.6` (#14854)
  providers/rac: apply ConnectionToken scoped-settings last (#14838)
  lib/sync: fix static incorrect label of pages (#14851)
  website/docs: Add FIDO2 references to the documentation (#14826)
  website/docs: add LDAP docs for forward deletion and `memberUid` (#14814)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#14801)
  core: bump structlog from 25.3.0 to 25.4.0 (#14834)
  web: bump tar-fs from 3.0.8 to 3.0.9 in /web (#14836)
  website/integrations: Update Zammad SAML Instructions (#14774)
  website/integrations: remove trailing slash from budibase redirect (#14823)
  remove fluff from release notes 2025.6 (#14819)
  web: bump @sentry/browser from 9.22.0 to 9.23.0 in /web in the sentry group across 1 directory (#14776)
  website: bump postcss from 8.5.3 to 8.5.4 in /website (#14787)
  web: bump the esbuild group across 2 directories with 4 updates (#14711)
  core: bump github.com/redis/go-redis/v9 from 9.8.0 to 9.9.0 (#14733)
  core: bump twilio from 9.6.1 to 9.6.2 (#14789)
  website: bump @types/node from 22.15.21 to 22.15.29 in /website (#14808)
  core: bump astral-sh/uv from 0.7.8 to 0.7.9 (#14806)
  core: bump uvicorn[standard] from 0.34.2 to 0.34.3 (#14811)
  ...
2025-06-03 13:46:57 -07:00
Ken Sternberg
f0e742c3ae Merge branch 'main' into dev
* main: (27 commits)
  lib/sync/outgoing: sync in parallel (#14697)
  core, web: update translations (#14707)
  tests/e2e: fix flaky SAML Source test (#14708)
  web: fix lock (#14705)
  Update packages-npm-publish.yml (#14702)
  website/integrations: coder: fix typo (#14514)
  ci: Update packages-npm-publish.yml (#14701)
  web: bump the swc group across 2 directories with 12 updates (#14623)
  web: Use engine available on Github Actions. (#14699)
  web: bump the rollup group across 1 directory with 4 updates (#14682)
  ci: test with postgres 17 (#13967)
  web: bump knip from 5.33.0 to 5.58.0 in /web (#14685)
  web: bump fuse.js from 7.0.0 to 7.1.0 in /web (#14687)
  web: bump @formatjs/intl-listformat from 7.5.7 to 7.7.11 in /web (#14689)
  root: do not use /bin/bash directly (#14698)
  website/integrations: minio: notice about sso deprecation on CE (#14679)
  core: bump cryptography from 44.0.3 to 45.0.3 (#14690)
  core: bump django-tenants from 3.7.0 to 3.8.0 (#14691)
  core: bump astral-sh/uv from 0.7.7 to 0.7.8 (#14681)
  core: bump axllent/mailpit from v1.25.0 to v1.25.1 in /tests/e2e (#14693)
  ...
2025-05-27 08:33:10 -07:00
Ken Sternberg
8a389b4b46 Merge branch 'main' into dev
* main: (24 commits)
  web: Type Tidy (#14647)
  core: bump pydantic from 2.11.4 to 2.11.5 (#14652)
  core: bump google-api-python-client from 2.169.0 to 2.170.0 (#14653)
  sources/scim: fix all users being added to group when no members are given (#14645)
  web: bump @codemirror/lang-javascript from 6.2.2 to 6.2.4 in /web (#14657)
  web: bump @types/node from 22.15.19 to 22.15.21 in /web (#14660)
  core: bump astral-sh/uv from 0.7.6 to 0.7.7 (#14651)
  web: bump wireit from 0.14.9 to 0.14.12 in /web (#14656)
  web: bump country-flag-icons from 1.5.13 to 1.5.19 in /web (#14659)
  web: bump @trivago/prettier-plugin-sort-imports from 4.3.0 to 5.2.2 in /web (#14661)
  web: bump chart.js from 4.4.4 to 4.4.9 in /web (#14655)
  website: bump the goauthentik group in /website with 3 updates (#14654)
  web: bump dompurify from 3.2.4 to 3.2.6 in /web (#14658)
  web: fix lint (#14665)
  website/docs: improve-rac-documents (#14414)
  web: bump the rollup group across 2 directories with 3 updates (#14622)
  web: bump the sentry group across 1 directory with 2 updates (#14587)
  lifecycle/aws: bump aws-cdk from 2.1016.0 to 2.1016.1 in /lifecycle/aws (#14631)
  web: bump @patternfly/elements from 4.0.2 to 4.1.0 in /web (#14634)
  web: bump @lit/task from 1.0.1 to 1.0.2 in /web (#14635)
  ...
2025-05-23 14:46:54 -07:00
Ken Sternberg
e3402682e6 Merge branch 'main' into dev
* main: (55 commits)
  web: Fix missing Enterprise sidebar entries. (#14615)
  core, web: update translations (#14626)
  esbuild-plugin-live-reload: Publish. (#14624)
  web/NPM Workspaces: Prep ESBuild plugin for publish. (#14552)
  lifecycle: fix arguments not being passed to worker command (#14574)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14611)
  providers/proxy: kubernetes outpost: fix reconcile when ingress class name changed (#14612)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14608)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14607)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#14609)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14606)
  root: move forked dependencies to goauthentik org (#14590)
  core: bump library/node from 22 to 24 (#14410)
  core: bump django-guardian from 2.4.0 to v3.0.0 (#14453)
  enterprise/stages/mtls: improve certificate validation (#14582)
  translate: Updates for file web/xliff/en.xlf in it (#14575)
  core, web: update translations (#14578)
  core: bump sentry-sdk from 2.28.0 to 2.29.1 (#14579)
  core: bump astral-sh/uv from 0.7.5 to 0.7.6 (#14580)
  web/NPM Workspaces: ESbuild version cleanup (#14541)
  ...
2025-05-22 08:15:00 -07:00
Ken Sternberg
38c4701e63 Merge branch 'main' into dev
* main: (60 commits)
  website: bump the build group in /website with 6 updates (#14502)
  core: remove `OldAuthenticatedSession` content type (#14507)
  core: bump msgraph-sdk from 1.29.0 to 1.30.0 (#14503)
  core: bump twilio from 9.6.0 to 9.6.1 (#14505)
  core: bump psycopg[c,pool] from 3.2.8 to 3.2.9 (#14504)
  enterprise: fix expired license's users being counted (#14451)
  website/integrations: fix missing closing brace for semaphore (#14467)
  tests/e2e: Add E2E tests for Flow SFE (#14484)
  website: bump semver from 7.7.1 to 7.7.2 in /website (#14491)
  core: bump django from 5.1.8 to 5.1.9 (#14483)
  core: bump psycopg[c,pool] from 3.2.7 to 3.2.8 (#14481)
  core: bump sentry-sdk from 2.27.0 to 2.28.0 (#14482)
  root: pin package version in pyproject for dependabot (#14469)
  core: fix session migration when old session can't be loaded (#14466)
  root: temporarily deactivate database pool option (#14443)
  website: bump the build group in /website with 3 updates (#14475)
  website/docs: stages: fix-typo (#14477)
  website/docs: Update Kubernetes Bootstrap Instructions (#14471)
  root: improve sentry distributed tracing (#14468)
  Revert "web/admin: fix enterprise menu display" (#14458)
  ...
2025-05-14 08:17:09 -07:00
Ken Sternberg
cddc13fcf7 Merge branch 'main' into dev
* main: (45 commits)
  web, website: update browserslist (#14386)
  core, web: update translations (#14383)
  website/integrations: add atlassian (#14209)
  core: bump github.com/pires/go-proxyproto from 0.8.0 to 0.8.1 (#14388)
  ci: bump golangci/golangci-lint-action from 7 to 8 (#14389)
  core: bump axllent/mailpit from v1.24.1 to v1.24.2 in /tests/e2e (#14390)
  translate: Updates for file web/xliff/en.xlf in it (#14372)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14374)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#14375)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pt (#14379)
  website/integrations: Fix outpost link for Home Assistant configuration (#14382)
  website/docs: fix leftover placeholder in release notes (#14377)
  website/integrations: minio: fix typo (#14376)
  core: bump goauthentik/fips-python from 3.12.10-slim-bookworm-fips to 3.13.3-slim-bookworm-fips (#12763)
  core: bump axllent/mailpit from v1.6.5 to v1.24.1 in /tests/e2e (#14341)
  core: bump selenium/standalone-chrome from 122.0 to 135.0 in /tests/e2e (#14342)
  core: bump lxml from 5.3.2 to v5.4.0 (#14355)
  core: bump azure-core from 1.33.0 to v1.34.0 (#14345)
  core: bump boto3 from 1.37.35 to v1.38.7 (#14346)
  core: bump celery from 5.5.1 to v5.5.2 (#14347)
  ...
2025-05-05 08:42:37 -07:00
Ken Sternberg
136e59cfba Merge branch 'main' into dev
* main: (54 commits)
  ci: use dependabot for compose correctly? (#14340)
  website/docs: use Universal Device Trust for GDTC instead of Okta (#14335)
  ci: use dependabot for docker-compose files (#14336)
  website/docs: fix dry-run release highlight (#14337)
  rbac: fix RoleObjectPermissionTable not showing `add_user_to_group` (#14312)
  core, web: update translations (#14326)
  core: bump github.com/sethvargo/go-envconfig from 1.2.0 to 1.3.0 (#14327)
  web: bump vite from 5.4.16 to 5.4.19 in /web (#14324)
  core: bump setuptools from 78.1.0 to v79.0.0 (#14173)
  core: bump ruff from 0.11.5 to v0.11.6 (#14171)
  core: bump s3transfer from 0.11.4 to v0.11.5 (#14172)
  core: bump packaging from 24.2 to v25.0 (#14169)
  core: bump aiohttp from 3.11.16 to v3.11.18 (#14166)
  core: bump boto3 from 1.37.35 to v1.37.38 (#14167)
  core: bump frozenlist from 1.5.0 to v1.6.0 (#14168)
  core: bump pdoc from 15.0.1 to v15.0.3 (#14170)
  core: bump trio from 0.29.0 to v0.30.0 (#14174)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in it (#14271)
  website: bump the build group across 1 directory with 9 updates (#14293)
  core, web: update translations (#14309)
  ...
2025-05-02 10:42:07 -07:00
Ken Sternberg
5da349342f Merge branch 'main' into dev
* main: (33 commits)
  website/integrations: adds missing trailing slash in homarr doc (#14249)
  lifecycle: fix test-all in docker (#14244)
  core, web: update translations (#14243)
  web/admin: prevent default logo flashing in admin interface (#13960)
  website/docs: Update release notes for 2025.4 (#14158)
  core, web: update translations (#14241)
  Updates for file web/xliff/en.xlf in zh_TW [Manual Sync] (#14225)
  translate: Updates for file web/xliff/en.xlf in nl [Manual Sync] (#14217)
  translate: Updates for file web/xliff/en.xlf in fi [Manual Sync] (#14219)
  translate: Updates for file web/xliff/en.xlf in de [Manual Sync] (#14220)
  translate: Updates for file web/xliff/en.xlf in fr [Manual Sync] (#14221)
  translate: Updates for file web/xliff/en.xlf in pl [Manual Sync] (#14222)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in es [Manual Sync] (#14223)
  translate: Updates for file web/xliff/en.xlf in zh-Hans [Manual Sync] (#14224)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de [Manual Sync] (#14226)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fi [Manual Sync] (#14227)
  translate: Updates for file web/xliff/en.xlf in tr [Manual Sync] (#14228)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pl [Manual Sync] (#14229)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in ko [Manual Sync] (#14230)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in it [Manual Sync] (#14231)
  ...
2025-04-25 10:46:52 -07:00
Ken Sternberg
518e9e1554 Merge branch 'main' into dev
* main:
  web: Safari fixes merge branch (#14181)
  website: bump the build group in /website with 9 updates (#14204)
  website: bump typescript from 5.8.2 to 5.8.3 in /website (#13786)
  lifecycle/migrate: fix migration failing if killed during first startup (#14207)
  core, web: update translations (#14203)
  lifecycle/aws: bump aws-cdk from 2.1010.0 to 2.1012.0 in /lifecycle/aws (#14205)
  website/integrations: improves netbird documentation (#14191)
  website/docs: updated user count info (#14186)
  website/docs: rearranged brands docs (#14116)
  website: integrations: apache guacamole: remove redirect URI comments (#14113)
2025-04-24 10:01:18 -07:00
Ken Sternberg
baa64bc1b0 Merge branch 'main' into dev
* main:
  packages/docusaurus-theme: Fix header alignment, overscroll, vertical padding. (#14120)
  outposts: add support for gateway API (#13272)
  translate: Updates for file web/xliff/en.xlf in fr (#14200)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14199)
  website/docs: adds code examples for getting user objects from a group object (#14101)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#14198)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14195)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14197)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14196)
  website/integrations: mealie add integration (#14188)
  core, web: update translations (#14187)
  core: bump goauthentik.io/api/v3 from 3.2025024.8 to 3.2025024.9 (#14189)
  website/docs: update user object doc (#14132)
  website/docs: dev-docs: style guide: no longer using italic for vars (#14185)
  website/docs: dev docs: style guide: update style conventions for urls (#14184)
  website/integrations: paperless: use <slug>. instead of hardcoded slug value (#14183)
  website/docs: updates style guide code block section (#14088)
  website: components: delete multilinecodeblock src (#14094)
  Revert "policies: buffered policy access view for concurrent authorization attempts when unauthenticated (#13629)" (#14180)
2025-04-23 10:59:38 -07:00
Ken Sternberg
8b958408c2 Merge branch 'main' into dev
* main: (49 commits)
  core: bump uvicorn from 0.34.1 to v0.34.2 (#14175)
  website/integrations: add xcreds (#14163)
  core, web: update translations (#14179)
  web: update default flow background (#14115)
  web: bump API Client version (#14176)
  enterprise/policies: Add Password Uniqueness History Policy (#13453)
  web/xliff: fix duplicated translations (#14164)
  website/docs: fix postgres pool recommended settings (#14149)
  core: bump astral-sh/uv from 0.6.14 to 0.6.16 (#14161)
  web: fix scrollbar styling (#12600)
  website: integrations: gravity: fix issuer URL (#14155)
  web: Packagify live reload plugin. (#14134)
  web: bump API Client version (#14062)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14146)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14145)
  core: bump goauthentik.io/api/v3 from 3.2025024.7 to 3.2025024.8 (#14143)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14144)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#14139)
  core, web: update translations (#14142)
  core: bump yarl from 1.19.0 to v1.20.0 (#14128)
  ...
2025-04-22 09:25:10 -07:00
Ken Sternberg
9a6ca4fba2 Merge branch 'main' into dev
* main: (93 commits)
  core: bump google-auth from 2.38.0 to v2.39.0 (#14076)
  core: bump sentry-sdk from 2.25.1 to v2.26.1 (#14079)
  core: bump prompt-toolkit from 3.0.50 to v3.0.51 (#14078)
  core: bump boto3 from 1.37.33 to v1.37.34 (#14074)
  core: bump msgraph-sdk from 1.27.0 to v1.28.0 (#14077)
  website/docs: fix minor typo in working_with_policies.md (#14071)
  core, web: update translations (#14064)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#14065)
  core: bump goauthentik.io/api/v3 from 3.2025024.4 to 3.2025024.6 (#14069)
  Small fix for Actual-Budget wiki guide (#14066)
  root: support db pool (#13534)
  rbac: add `InitialPermissions` (#13795)
  web: bump API Client version (#14058)
  core: Bump django from 5.0.14 to 5.1.8 (#14059)
  core: bump django-rest-framework from 3.14.0 to 3.16.0 (#14057)
  policies/reputation: limit reputation score (#14008)
  ci: fix api-py-publish by disabling poetry cache (#14010)
  core: bump goauthentik/fips-python from 3.12.9-slim-bookworm-fips to 3.12.10-slim-bookworm-fips (#14044)
  ci: add NPM packages publish (#13974)
  root: add packages/ to codeowners (#13975)
  ...
2025-04-15 08:23:44 -07:00
Ken Sternberg
9cf551b1d6 Merge branch 'main' into dev
* main: (204 commits)
  core: bump protobuf from 5.29.4 to v6.30.2 (#13950)
  core: bump pyasn1-modules from 0.4.1 to v0.4.2 (#13951)
  core: bump microsoft-kiota-authentication-azure from 1.9.2 to v1.9.3 (#13948)
  core: bump microsoft-kiota-http from 1.9.2 to v1.9.3 (#13949)
  core: bump trio-websocket from 0.11.1 to v0.12.2 (#13934)
  core: bump msgraph-core from 1.3.1 to v1.3.3 (#13900)
  core: bump jsii from 1.109.0 to v1.111.0 (#13886)
  core: bump setuptools from 72.1.0 to v78.1.0 (#13928)
  core: bump kombu from 5.3.7 to v5.5.2 (#13888)
  core: bump msgpack from 1.0.8 to v1.1.0 (#13899)
  core: bump msgraph-sdk from 1.24.0 to v1.26.0 (#13901)
  core: bump proto-plus from 1.24.0 to v1.26.1 (#13910)
  core: bump protobuf from 5.27.2 to v5.29.4 (#13911)
  core: bump pydantic from 2.10.6 to v2.11.3 (#13914)
  core: bump rich from 13.7.1 to v14.0.0 (#13922)
  core: bump twisted from 24.7.0 to v24.11.0 (#13936)
  core: bump watchfiles from 0.22.0 to v1.0.5 (#13941)
  core: bump typing-extensions from 4.12.2 to v4.13.1 (#13937)
  core: bump multidict from 6.0.5 to v6.2.0 (#13902)
  core: bump sentry-sdk from 2.22.0 to v2.25.1 (#13927)
  ...
2025-04-09 11:13:44 -07:00
Ken Sternberg
f63b3c2bbb Merge branch 'main' into dev
* main:
  ci: stop publishing latest tag (#13245)
  root: fix dependency install due to description-file (#13655)
2025-03-24 13:30:39 -07:00
Ken Sternberg
61dbc932da Merge branch 'main' into dev
* main: (76 commits)
  admin: fix system API when using bearer token (#13651)
  website: bump the build group in /website with 6 updates (#13645)
  core: bump goauthentik.io/api/v3 from 3.2025022.5 to 3.2025022.6 (#13646)
  translate: Updates for file web/xliff/en.xlf in fr (#13653)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13652)
  website/integrations: add tandoor (#13560)
  core, web: update translations (#13642)
  providers/scim: fix group membership check failing (#13644)
  ci: add semgrep (#13643)
  flows: fix API not returning configured background (#13641)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13631)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13633)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13632)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13634)
  brands: fix migration 0008 by removing incorrect context manager usage (#13635)
  web: Fix prop. (#13630)
  core, web: update translations (#13628)
  web/admin: reworked sync status card (#13625)
  core: bump github.com/golang-jwt/jwt/v5 from 5.2.1 to 5.2.2 (#13626)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13622)
  ...
2025-03-24 09:15:11 -07:00
Ken Sternberg
fa994ae318 Merge branch 'main' into dev
* main:
  website/docs: dev docs: bump node/postgres requirements  (#13516)
  sources: prevent deletion of built-in source (#12914)
  core: bump django-tenants (#13536)
  website/docs: dev docs: full: remove note on installing shell plugin (#13515)
  sources/oauth: fix duplicate authentication (#13322)
  web/admin: fix comment being rendered (#13530)
  core: Bump aws-cdk-lib from 2.183.0 to 2.184.0 (#13522)
  core, web: update translations (#13520)
  lifecycle/aws: Bump aws-cdk from 2.1003.0 to 2.1004.0 in /lifecycle/aws (#13524)
  core: Bump github.com/coreos/go-oidc/v3 from 3.12.0 to 3.13.0 (#13525)
2025-03-17 07:21:18 -07:00
Ken Sternberg
cd78fc01f2 Merge branch 'main' into dev
* main: (44 commits)
  providers/rac: fix signals and Endpoint caching (#13529)
  web/flows: fix missing padding on authenticator_validate card (#13420)
  web/user: show admin interface button on mobile (#13421)
  website: Bump the build group in /website with 6 updates (#13501)
  core: Bump goauthentik.io/api/v3 from 3.2025021.3 to 3.2025021.4 (#13495)
  core: Bump importlib-metadata from 8.5.0 to 8.6.1 (#13499)
  core: Bump msgraph-sdk from 1.23.0 to 1.24.0 (#13500)
  core: Bump google-api-python-client from 2.163.0 to 2.164.0 (#13498)
  core: Bump aws-cdk-lib from 2.182.0 to 2.183.0 (#13496)
  core: Bump psycopg from 3.2.5 to 3.2.6 (#13497)
  translate: Updates for file web/xliff/en.xlf in fr (#13514)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13513)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13510)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13511)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13509)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13508)
  core, web: update translations (#13494)
  website: remove the last updated option from footer (#13493)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13487)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13488)
  ...
2025-03-14 07:11:45 -07:00
Ken Sternberg
9251e608fa Merge branch 'main' into dev
* main:
  stages/email: token_expiry format (#13394)
  core, web: update translations (#13438)
  website/docs: in developer docs replace deprecated poetry shell command (#13460)
2025-03-11 14:58:45 -07:00
Ken Sternberg
0055882212 Merge branch 'main' into dev
* main:
  web: Ignore Storybook when running codespell. (#13454)
  core: bump ruff from 0.9.9 to 0.9.10 (#13448)
  core: bump webauthn from 2.5.1 to 2.5.2 (#13449)
  website/docs: backup and restore: remove extra period (#13440)
  website: bump prismjs from 1.29.0 to 1.30.0 in /website (#13456)
  web: bump prismjs from 1.29.0 to 1.30.0 in /web (#13455)
2025-03-11 07:01:31 -07:00
Ken Sternberg
68387362c2 Merge branch 'main' into dev
* main:
  web: admin interface: faster card load (#13331)
  web/admin: fix display bug for assigned users in application bindings in the wizard (#13435)
  website: bump the build group across 1 directory with 9 updates (#13442)
  core: bump django from 5.0.12 to 5.0.13 (#13425)
  providers/SCIM: fix object exists error for users, attempt to look up user ID in remote system (#13437)
  website/docs: sys mgmt: document authentik backups/restoration (#12943)
  website: fix build in docker (#13430)
  website/integrations: zipline: add (#13257)
2025-03-11 07:01:23 -07:00
Ken Sternberg
5fe344fb12 Merge branch 'main' into dev
* main:
  translate: Updates for file web/xliff/en.xlf in fr (#13431)
  lifecycle/aws: bump aws-cdk from 2.1002.0 to 2.1003.0 in /lifecycle/aws (#13426)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13428)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13429)
  core, web: update translations (#13423)
2025-03-07 08:14:04 -08:00
Ken Sternberg
aa20df5cca Merge branch 'main' into dev
* main:
  website: add a better edit this page element (#13391)
  web/admin: allow user lists to show active only (#13403)
  core: Tidy contributor onboarding, fix typos. (#12700)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13418)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13417)
  lib/config: fix conn_max_age parsing (#13370)
  core: bump golang.org/x/sync from 0.11.0 to 0.12.0 (#13407)
  stages/authenticator_email: Fix Enroll dropdown in the MFA Devices page (#13404)
  core: bump golang.org/x/oauth2 from 0.27.0 to 0.28.0 (#13408)
  core: bump aws-cdk-lib from 2.181.1 to 2.182.0 (#13409)
  core: bump google-api-python-client from 2.162.0 to 2.163.0 (#13410)
  core: bump msgraph-sdk from 1.22.0 to 1.23.0 (#13411)
  core: bump jinja2 from 3.1.5 to 3.1.6 (#13412)
  web/user: ensure modal container on user-settings page is min-height: 100% (#13402)
  core, web: update translations (#13405)
  web/admin: add button to clear application cache (#13399)
  blueprints: Adjust title for MFA set up (#13400)
2025-03-06 14:56:10 -08:00
Ken Sternberg
75c61afd18 Merge branch 'main' into dev
* main:
  web/admin: fix markdown being completely whited out in dark mode on proxy provider pages (#13387)
  web/admin: decorative display in user’s page breaks in other locales (#13393)
  website: bump the build group in /website with 6 updates (#13396)
  core: bump github.com/prometheus/client_golang from 1.21.0 to 1.21.1 (#13397)
  core: bump debugpy from 1.8.12 to 1.8.13 (#13395)
  website/docs: Update Open Web UI integration  (#13392)
  website/integrations: gravity: add (#13258)
  website/integrations: Pocketbase (#12906)
  ci: cache helper docker images (#13390)
2025-03-05 10:18:55 -08:00
Ken Sternberg
811e7946f7 Merge branch 'main' into dev
* main: (135 commits)
  providers/proxy: kubernetes outpost: fix reconcile when only annotations changed (#13372)
  website: bump the build group in /website with 3 updates (#13381)
  core, web: update translations (#13378)
  web/admin: prefer using datefns over moment.js (#13143)
  website/docs: fix typo (#13377)
  stages/authenticator_email: remove flaky assertions (#13371)
  translate: Updates for file web/xliff/en.xlf in fr (#13374)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13373)
  website: bump typescript from 5.7.3 to 5.8.2 in /website (#13368)
  lifecycle/aws: bump aws-cdk from 2.1001.0 to 2.1002.0 in /lifecycle/aws (#13365)
  website: bump the build group in /website with 11 updates (#13367)
  ci: bump getsentry/action-release from 1 to 3 (#13366)
  website: bump @rspack/binding-darwin-arm64 from 1.1.6 to 1.2.6 in /website (#13354)
  core, web: update translations (#13346)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13348)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13347)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13349)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13350)
  ci: update versions for daily full testing (#13303)
  website: bump prettier from 3.5.2 to 3.5.3 in /website (#13355)
  ...
2025-03-04 08:29:59 -08:00
Ken Sternberg
19f25d5aa7 Merge branch 'main' into dev
* main:
  web/user: fix opening application with Enter not respecting new tab setting (#13115)
  web: bump API Client version (#13113)
  providers/rac: move to open source (#13015)
  website/docs: add 2025.2 release notes (#13002)
  core: clear expired database sessions (#13105)
  core: bump sentry-sdk from 2.21.0 to 2.22.0 (#13098)
  core: bump bandit from 1.8.2 to 1.8.3 (#13097)
  core: bump aws-cdk-lib from 2.178.2 to 2.179.0 (#13099)
  core: bump goauthentik.io/api/v3 from 3.2024123.4 to 3.2024123.6 (#13100)
  lifecycle/aws: bump aws-cdk from 2.178.2 to 2.179.0 in /lifecycle/aws (#13101)
  website/docs: Add AdventureLog Community Integration Documentation (#12928)
  website/docs: minor fixes (#13095)
  website/integrations: Update to Wizard and Styling Guide (#12919)
  web: bump API Client version (#13093)
  policies/geoip: distance + impossible travel (#12541)
  root: fix generated API docs not being excluded from codespell (#13091)
2025-02-19 08:32:55 -08:00
Ken Sternberg
ffbe8fb598 Merge branch 'main' into dev
* main: (24 commits)
  core: add additional RBAC permission to restrict setting the superuser status on groups (#12900)
  web: bump API Client version (#13089)
  core: bump github.com/spf13/cobra from 1.8.1 to 1.9.1 (#13085)
  stages/authenticator_email: Email OTP (#12630)
  website: bump dompurify and mermaid in /website (#13077)
  web: bump dompurify and mermaid in /web (#13078)
  core: bump django-filter from 24.3 to 25.1 (#13086)
  enterprise/audit: fix diff being created when not enabled (#13084)
  core, web: update translations (#13088)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13080)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13081)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13082)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13083)
  core: bump django-storages from 1.14.4 to 1.14.5 (#13087)
  web/user: fix redirects back to user settings (#13076)
  ci: parallelize unit tests (#13036)
  core, web: update translations (#13072)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#13073)
  root: Improve debugging experience (#12961)
  core, web: update translations (#13071)
  ...
2025-02-17 08:48:25 -08:00
Ken Sternberg
2279768e6f Merge branch 'main' into dev
* main: (35 commits)
  translate: Updates for file web/xliff/en.xlf in ko [Manual Sync] (#13045)
  translate: Updates for file web/xliff/en.xlf in pl [Manual Sync] (#13043)
  translate: Updates for file web/xliff/en.xlf in ru [Manual Sync] (#13055)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pl [Manual Sync] (#13062)
  translate: Updates for file web/xliff/en.xlf in zh_TW [Manual Sync] (#13056)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in nl [Manual Sync] (#13058)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in ru [Manual Sync] (#13063)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_TW [Manual Sync] (#13064)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in ko [Manual Sync] (#13060)
  translate: Updates for file web/xliff/en.xlf in nl [Manual Sync] (#13044)
  web: Silence ESBuild warning. (#13025)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans [Manual Sync] (#13066)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in tr [Manual Sync] (#13061)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN [Manual Sync] (#13065)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in it [Manual Sync] (#13057)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR [Manual Sync] (#13059)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de [Manual Sync] (#13051)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fi [Manual Sync] (#13052)
  translate: Updates for file web/xliff/en.xlf in zh-Hans [Manual Sync] (#13050)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in es [Manual Sync] (#13054)
  ...
2025-02-14 09:36:35 -08:00
Ken Sternberg
675e60b816 Merge branch 'main' into dev
* main:
  core: revert bump oss/go/microsoft/golang from 1.23-fips-bookworm to 1.24-fips-bookworm (#13012) (#13022)
2025-02-13 10:00:23 -08:00
Ken Sternberg
e338bef104 Merge branch 'main' into dev
* main: (111 commits)
  root: correctly use correct schema for install_id (#13018)
  website: bump docusaurus-plugin-openapi-docs from 4.3.3 to 4.3.4 in /website (#13011)
  web: bump API Client version (#13017)
  core: bump aws-cdk-lib from 2.178.1 to 2.178.2 (#13013)
  core: bump oss/go/microsoft/golang from 1.23-fips-bookworm to 1.24-fips-bookworm (#13012)
  website: bump docusaurus-theme-openapi-docs from 4.3.3 to 4.3.4 in /website (#13010)
  lifecycle/aws: bump aws-cdk from 2.178.1 to 2.178.2 in /lifecycle/aws (#13009)
  core: bump github.com/sethvargo/go-envconfig from 1.1.0 to 1.1.1 (#13008)
  web/admin: fix source selection for identification stage (#13007)
  core: bump sentry-sdk from 2.20.0 to 2.21.0 (#13014)
  website/integrations: Open WebUI (#12939)
  root: use correct default schema for install_id (#13006)
  website/docs: fix a minor typo (#13004)
  enterprise/providers/ssf: fixes v2 (#13003)
  root: make default postgres schema configurable (#12949)
  providers/oauth2: cleanup tokens when user is deactivated (#12859)
  website/docs: fix Nginx redirection example (#12920)
  core: bump twilio from 9.4.4 to 9.4.5 (#12993)
  core: bump coverage from 7.6.11 to 7.6.12 (#12994)
  core: bump cryptography from 44.0.0 to 44.0.1 (#12992)
  ...
2025-02-13 08:06:21 -08:00
Ken Sternberg
457b61c5b4 Merge branch 'main' into dev
* main:
  web: update gen-client-ts to OpenAPI 7.11.0 (#12756)
  website/integrations: rustdesk-server-pro (#12706)
  core: bump codespell from 2.3.0 to 2.4.0 (#12762)
  root: docker: ensure apt packages are up-to-date (#12683)
  ci: fix missing build args for dev and release (#12760)
  web: bump vite from 5.4.11 to 5.4.14 in /web (#12757)
  web: bump undici from 6.21.0 to 6.21.1 in /web (#12755)
  lifecycle: fix cryptography's OpenSSL path (#12753)
2025-01-22 10:09:24 -08:00
Ken Sternberg
25eefb7d55 Merge branch 'main' into dev
* main: (65 commits)
  stages/redirect: fix query parameter when redirecting to flow (#12750)
  website/integrations: cloudflare-access: refactor (#12663)
  sources/kerberos: handle principal expire time (#12748)
  lifecycle: build binary dependencies which link against SSL directly (#12724)
  website/docs: style guide: document styling preferences for URLs (#12715)
  website/integrations: nextcloud: fix broken link (#12744)
  core: bump selenium from 4.27.1 to 4.28.0 (#12745)
  lifecycle: move AWS CFN generation to lifecycle and fix CI (#12743)
  core: search users' attributes (#12740)
  web/components: ak-number-input: add support for min (#12703)
  website/integrations: nextcloud: fix url for "disable username changes" (#12725)
  core: bump pytest-github-actions-annotate-failures from 0.2.0 to 0.3.0 (#12735)
  website: bump katex from 0.16.11 to 0.16.21 in /website (#12731)
  web: bump katex from 0.16.11 to 0.16.21 in /web (#12730)
  website/integrations: Fix URL for authentik installation instead of mobilizon installation (#12729)
  core: bump debugpy from 1.8.11 to 1.8.12 (#12718)
  core: bump ruff from 0.9.1 to 0.9.2 (#12717)
  core: bump webauthn from 2.4.0 to 2.5.0 (#12719)
  core: bump structlog from 24.4.0 to 25.1.0 (#12720)
  website/integrations: all: install -> installation (#12676)
  ...
2025-01-21 09:56:23 -08:00
Ken Sternberg
50d2f69332 Merge branch 'main' into dev
* main:
  website: revise full development environment instructions (#12638)
  website: bump typescript from 5.7.2 to 5.7.3 in /website (#12620)
  website: bump aws-cdk from 2.174.1 to 2.175.0 in /website (#12621)
  ci: bump docker/setup-qemu-action from 3.2.0 to 3.3.0 (#12622)
  core: bump twilio from 9.4.1 to 9.4.2 (#12623)
  core: bump python-kadmin-rs from 0.5.2 to 0.5.3 (#12624)
  core: bump ruff from 0.8.6 to 0.9.0 (#12625)
  core: bump pydantic from 2.10.4 to 2.10.5 (#12626)
  core: bump google-api-python-client from 2.157.0 to 2.158.0 (#12628)
  core: bump goauthentik.io/api/v3 from 3.2024121.3 to 3.2024122.1 (#12629)
  web: bump API Client version (#12617)
  release: 2024.12.2 (#12615)
  website/docs: prepare 2024.12.2 release notes (#12614)
  providers/saml: fix invalid SAML Response when assertion and response are signed (#12611)
  core: fix error when creating new user with default path (#12609)
  rbac: permissions endpoint: allow authenticated users (#12608)
  website/docs: update customer portal (#12603)
  website/docs: policy for email whitelist: modernize (#12558)
2025-01-10 16:26:36 -08:00
Ken Sternberg
7d972ec711 Merge branch 'main' into dev
* main:
  lib: add expression helper ak_create_jwt to create JWTs (#12599)
  api: cleanup owner permissions (#12598)
  website: bump aws-cdk from 2.174.0 to 2.174.1 in /website (#12593)
  core: bump aws-cdk-lib from 2.174.0 to 2.174.1 (#12594)
  website/integrations: portainer: group config steps (#12548)
  translate: Updates for file web/xliff/en.xlf in fi (#12586)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fi (#12584)
  website/docs: fix Nginx redirection example (#12561)
2025-01-08 10:13:59 -08:00
Ken Sternberg
854427e463 Merge branch 'main' into dev
* main:
  core: bump golang.org/x/oauth2 from 0.24.0 to 0.25.0 (#12571)
  website: bump the docusaurus group in /website with 9 updates (#12569)
  core: bump github.com/coreos/go-oidc/v3 from 3.11.0 to 3.12.0 (#12572)
  core: bump ruff from 0.8.5 to 0.8.6 (#12573)
  ci: release: fix AWS cfn template permissions (#12576)
  translate: Updates for file web/xliff/en.xlf in fr (#12578)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#12577)
  sources/kerberos: authenticate with the user's username instead of the first username in authentik (#12497)
  website/integrations: Fix deprecated terraform ressource authentik_scope_mapping in docs (#12554)
  website/user-sources Fix Free IPA docs page (#12549)
  core: bump aws-cdk-lib from 2.173.4 to 2.174.0 (#12574)
  website/integrations: semaphore: fix formatting (#12567)
  website: bump aws-cdk from 2.173.4 to 2.174.0 in /website (#12570)
  website/integrations: Update Frappe Application index.md (#12527)
  website: add api reference docs to redirect file (#12551)
2025-01-06 08:32:50 -08:00
Ken Sternberg
be349e2e14 Merge branch 'main' into dev
* main:
  core: bump github.com/getsentry/sentry-go from 0.30.0 to 0.31.1 (#12543)
  core: bump google-api-python-client from 2.156.0 to 2.157.0 (#12544)
  core: bump ruff from 0.8.4 to 0.8.5 (#12545)
  core: bump msgraph-sdk from 1.15.0 to 1.16.0 (#12546)
  Update index.mdx (#12542)
  web: fix source selection and outpost integration health (#12530)
  Ading a step to paperless guide (#12539)
  website/integrations: Semaphore (#12515)
  website/integrations: komga: document (#12476)
  website/integrations: fix missing quote in paperless-ngx (#12537)
  website/integrations: cloudflare access: upd placeholder for saas (#12536)
  website/integrations: veeam-enterprise-manager: don't hardcode helpcenter doc version (#12538)
2025-01-03 08:09:25 -08:00
Ken Sternberg
bd0e81b8ad Merge branch 'main' into dev
* main:
  website/integrations: meshcentral: document (#12509)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#12524)
  core: bump goauthentik.io/api/v3 from 3.2024121.2 to 3.2024121.3 (#12522)
  web: bump API Client version (#12520)
  website/integrations: chronograf: document (#12474)
  website/integrations: update preparation placeholder (#12507)
  providers/saml: fix handle Accept: application/xml for SAML Metadata endpoint (#12483) (#12518)
  core: bump aws-cdk-lib from 2.173.3 to 2.173.4 (#12513)
  website: bump aws-cdk from 2.173.3 to 2.173.4 in /website (#12514)
  core: bump coverage from 7.6.9 to 7.6.10 (#12499)
  core: bump aws-cdk-lib from 2.173.2 to 2.173.3 (#12500)
  website: bump aws-cdk from 2.173.2 to 2.173.3 in /website (#12501)
  core: bump github.com/go-ldap/ldap/v3 from 3.4.9 to 3.4.10 (#12502)
  website/docs: New "Whats Up Docker" URL (#12488)
2025-01-02 10:01:26 -08:00
Ken Sternberg
f6afb59515 Revert "This (temporary) change is needed to prevent the unit tests from failing."
This reverts commit dddde09be5.
2024-12-26 13:59:53 -08:00
Ken Sternberg
dddde09be5 This (temporary) change is needed to prevent the unit tests from failing.
\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes
2024-12-26 13:59:00 -08:00
Ken Sternberg
6d7fc94698 Merge branch 'main' into dev
* main: (118 commits)
  outposts: fix version label (#12486)
  web: only load version context when authenticated (#12482)
  core: bump goauthentik.io/api/v3 from 3.2024120.2 to 3.2024121.2 (#12478)
  ci: bump helm/kind-action from 1.11.0 to 1.12.0 (#12479)
  web: fix build dev build (#12473)
  root: fix dev build version being invalid semver (#12472)
  internal: fix missing trailing slash in outpost websocket (#12470)
  web: bump API Client version (#12469)
  admin: monitor worker version (#12463)
  core: bump jinja2 from 3.1.4 to 3.1.5 (#12467)
  web: bump API Client version (#12468)
  release: 2024.12.1 (#12466)
  web: misc fixes for admin and flow inspector (#12461)
  website/docs: 2024.12.1 release notes (#12462)
  core: bump goauthentik.io/api/v3 from 3.2024120.1 to 3.2024120.2 (#12456)
  core: bump urllib3 from 2.2.3 to 2.3.0 (#12457)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12454)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12453)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12455)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12458)
  ...
2024-12-26 08:49:23 -08:00
Ken Sternberg
1dcf9108ad Merge branch 'main' into dev
* main:
  flows: better test stage's challenge responses (#12316)
  enterprise/stages/authenticator_endpoint_gdtc: don't set frame options globally (#12311)
  stages/identification: fix invalid challenge warning when no captcha stage is set (#12312)
  website/docs: prepare 2024.10.5 release notes (#12309)
  website: bump nanoid from 3.3.7 to 3.3.8 in /website (#12307)
  flows: silent authz flow (#12213)
  root:  use healthcheck in depends_on for postgres and redis (#12301)
  ci: ensure mark jobs always run and reflect correct status (#12288)
  enterprise: allow deletion/modification of users when in read-only mode (#12289)
  web/flows: resize captcha iframes (#12260)
2024-12-10 09:07:45 -08:00
Ken Sternberg
7bb6a3dfe6 Merge branch 'main' into dev
* main:
  website/docs: add page about the Cobalt pentest (#12249)
  core: bump aws-cdk-lib from 2.171.1 to 2.172.0 (#12296)
  website: bump aws-cdk from 2.171.1 to 2.172.0 in /website (#12295)
  core: bump sentry-sdk from 2.19.1 to 2.19.2 (#12297)
  core: bump coverage from 7.6.8 to 7.6.9 (#12299)
  core, web: update translations (#12290)
  root: fix override locale only if it is not empty (#12283)
  translate: Updates for file web/xliff/en.xlf in fr (#12276)
  core: bump twilio from 9.3.7 to 9.3.8 (#12282)
  website: bump path-to-regexp and express in /website (#12279)
  core: bump sentry-sdk from 2.19.0 to 2.19.1 (#12280)
  core: bump ruff from 0.8.1 to 0.8.2 (#12281)
  website/docs: fix lint (#12287)
  website/integrations: netbird: fix redirect URI regex (#12284)
2024-12-09 08:28:52 -08:00
Ken Sternberg
9cc440eee1 Merge branch 'main' into dev
* main:
  web: simplify `?inline` handler for Storybook (#12246)
  website/docs: Update Traefik middleware example to reflect latest version of Traefik (#12267)
  website/docs: add . in https://netbird.company* (#12166)
  core: bump goauthentik.io/api/v3 from 3.2024104.1 to 3.2024104.2 (#12263)
  core: bump pydantic from 2.10.2 to 2.10.3 (#12262)
  core: bump github.com/getsentry/sentry-go from 0.29.1 to 0.30.0 (#12264)
  core, web: update translations (#12268)
  website: bump @types/react from 18.3.12 to 18.3.13 in /website (#12269)
  website: bump prettier from 3.4.1 to 3.4.2 in /website (#12270)
  ci: bump actions/attest-build-provenance from 1 to 2 (#12271)
  core: bump golang.org/x/sync from 0.9.0 to 0.10.0 (#12272)
  core: bump django from 5.0.9 to 5.0.10 (#12273)
  core: bump webauthn from 2.3.0 to 2.4.0 (#12274)
  website/integrations: add The Lounge (#11971)
  core: bump python-kadmin-rs from 0.3.0 to 0.4.0 (#12257)
  root: fix health status code (#12255)
  ci: fix should_push always being false (#12252)
  web: bump API Client version (#12251)
  providers/oauth2: Add provider federation between OAuth2 Providers (#12083)
  website/integrations: mastodon: set correct uid field (#11945)
2024-12-05 10:47:00 -08:00
Ken Sternberg
fe9e4526ac Merge branch 'main' into dev
* main: (31 commits)
  web/admin: bugfix: dual select initialization revision (#12051)
  web: update tests for Chromedriver 131 (#12199)
  website/integrations: add Aruba Orchestrator (#12220)
  core: bump aws-cdk-lib from 2.167.1 to 2.171.1 (#12237)
  website: bump aws-cdk from 2.167.1 to 2.171.1 in /website (#12241)
  core, web: update translations (#12236)
  core: bump python-kadmin-rs from 0.2.0 to 0.3.0 (#12238)
  core: bump pytest from 8.3.3 to 8.3.4 (#12239)
  core: bump drf-spectacular from 0.27.2 to 0.28.0 (#12240)
  core, web: update translations (#12222)
  core: Bump ruff from 0.8.0 to 0.8.1 (#12224)
  core: Bump ua-parser from 0.18.0 to 1.0.0 (#12225)
  core: Bump msgraph-sdk from 1.13.0 to 1.14.0 (#12226)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#12234)
  website/docs: install: add aws (#12082)
  core: Bump pyjwt from 2.10.0 to 2.10.1 (#12217)
  core: Bump fido2 from 1.1.3 to 1.2.0 (#12218)
  core: Bump cryptography from 43.0.3 to 44.0.0 (#12219)
  providers/oauth2: allow m2m for JWKS without alg in keys (#12196)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#12210)
  ...
2024-12-02 09:10:36 -08:00
Ken Sternberg
20b66f850c Merge branch 'main' into dev
* main:
  website/docs: Add note about single group per role (#12169)
  website/docs: Fix documentation about attribute merging for indirect membership (#12168)
  root: support running authentik in subpath (#8675)
  docs: fix contribution link (#12189)
  core, web: update translations (#12190)
  core: Bump msgraph-sdk from 1.12.0 to 1.13.0 (#12191)
  core: Bump selenium from 4.26.1 to 4.27.0 (#12192)
2024-11-26 09:27:51 -08:00
Ken Sternberg
67b327414b Merge branch 'main' into dev
* main:
  website/docs: Fix CSP syntax (#12124)
2024-11-25 13:11:45 -08:00
Ken Sternberg
5b8d86b5a9 Merge branch 'main' into dev
* main:
  ci: only mirror if secret is available (#12181)
  root: fix database ssl options not set correctly (#12180)
  core, web: update translations (#12145)
  core: bump tornado from 6.4.1 to 6.4.2 (#12165)
  website: bump the docusaurus group in /website with 9 updates (#12172)
  website: bump typescript from 5.6.3 to 5.7.2 in /website (#12173)
  ci: bump actions/checkout from 3 to 4 (#12174)
  core: bump github.com/stretchr/testify from 1.9.0 to 1.10.0 (#12175)
  core: bump coverage from 7.6.7 to 7.6.8 (#12176)
  core: bump ruff from 0.7.4 to 0.8.0 (#12177)
2024-11-25 09:21:19 -08:00
Ken Sternberg
67aed3e318 Merge branch 'main' into dev
* main: (33 commits)
  ci: mirror repo to internal repo (#12160)
  core: bump goauthentik.io/api/v3 from 3.2024102.2 to 3.2024104.1 (#12149)
  core: bump debugpy from 1.8.8 to 1.8.9 (#12150)
  core: bump webauthn from 2.2.0 to 2.3.0 (#12151)
  core: bump pydantic from 2.10.0 to 2.10.1 (#12152)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12156)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12157)
  core: bump sentry-sdk from 2.18.0 to 2.19.0 (#12153)
  web: bump API Client version (#12147)
  root: Backport version change (#12146)
  website/docs: update info about footer links to match new UI (#12120)
  website/docs: prepare release notes (#12142)
  providers/oauth2: fix migration (#12138)
  providers/oauth2: fix migration dependencies (#12123)
  web: bump API Client version (#12129)
  providers/oauth2: fix redirect uri input (#12122)
  providers/proxy: fix redirect_uri (#12121)
  website/docs: prepare release notes (#12119)
  web: bump API Client version (#12118)
  security: fix CVE 2024 52289 (#12113)
  ...
2024-11-22 13:56:13 -08:00
Ken Sternberg
9809b94030 Merge branch 'main' into dev
* main: (28 commits)
  providers/scim: accept string and int for SCIM IDs (#12093)
  website: bump the docusaurus group in /website with 9 updates (#12086)
  core: fix source_flow_manager throwing error when authenticated user attempts to re-authenticate with existing link (#12080)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#12079)
  scripts: remove read_replicas from generated dev config (#12078)
  core: bump geoip2 from 4.8.0 to 4.8.1 (#12071)
  core: bump goauthentik.io/api/v3 from 3.2024100.2 to 3.2024102.2 (#12072)
  core: bump maxmind/geoipupdate from v7.0.1 to v7.1.0 (#12073)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12074)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12075)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12076)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12077)
  web/admin: auto-prefill user path for new users based on selected path (#12070)
  core: bump aiohttp from 3.10.2 to 3.10.11 (#12069)
  web/admin: fix brand title not respected in application list (#12068)
  core: bump pyjwt from 2.9.0 to 2.10.0 (#12063)
  web: add italian locale (#11958)
  web/admin: better footer links (#12004)
  core, web: update translations (#12052)
  core: bump twilio from 9.3.6 to 9.3.7 (#12061)
  ...
2024-11-20 10:23:54 -08:00
Ken Sternberg
e7527c551b Merge branch 'main' into dev
* main:
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12045)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12047)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12044)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12046)
  web/flows: fix invisible captcha call (#12048)
  rbac: fix incorrect object_description for object-level permissions (#12029)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#12036)
  core: bump coverage from 7.6.4 to 7.6.5 (#12037)
  ci: bump codecov/codecov-action from 4 to 5 (#12038)
  release: 2024.10.2 (#12031)
2024-11-15 12:47:17 -08:00
Ken Sternberg
36b10b434a :wqge branch 'main' into dev
* main:
  providers/ldap: fix global search_full_directory permission not being sufficient (#12028)
  website/docs: 2024.10.2 release notes (#12025)
  lifecycle: fix ak exit status not being passed (#12024)
  core: use versioned_script for path only (#12003)
  core, web: update translations (#12020)
  core: bump google-api-python-client from 2.152.0 to 2.153.0 (#12021)
  providers/oauth2: fix manual device code entry (#12017)
  crypto: validate that generated certificate's name is unique (#12015)
  core, web: update translations (#12006)
  core: bump google-api-python-client from 2.151.0 to 2.152.0 (#12007)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12011)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12010)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12012)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12013)
  providers/proxy: fix Issuer when AUTHENTIK_HOST_BROWSER is set (#11968)
  website/docs: move S3 ad GeoIP to System Management/Operations (#11998)
  website/integrations: nextcloud: add SSE warning (#11976)
2024-11-14 11:29:13 -08:00
Ken Sternberg
831797b871 Merge branch 'main' into dev
* main: (21 commits)
  web: bump API Client version (#11997)
  sources/kerberos: use new python-kadmin implementation (#11932)
  core: add ability to provide reason for impersonation (#11951)
  website/integrations:  update vcenter integration docs (#11768)
  core, web: update translations (#11995)
  website: bump postcss from 8.4.48 to 8.4.49 in /website (#11996)
  web: bump API Client version (#11992)
  blueprints: add default Password policy (#11793)
  stages/captcha: Run interactive captcha in Frame (#11857)
  core, web: update translations (#11979)
  core: bump packaging from 24.1 to 24.2 (#11985)
  core: bump ruff from 0.7.2 to 0.7.3 (#11986)
  core: bump msgraph-sdk from 1.11.0 to 1.12.0 (#11987)
  website: bump the docusaurus group in /website with 9 updates (#11988)
  website: bump postcss from 8.4.47 to 8.4.48 in /website (#11989)
  stages/password: use recovery flow from brand (#11953)
  core: bump golang.org/x/sync from 0.8.0 to 0.9.0 (#11962)
  web: bump cookie, swagger-client and express in /web (#11966)
  core, web: update translations (#11959)
  core: bump debugpy from 1.8.7 to 1.8.8 (#11961)
  ...
2024-11-12 10:08:48 -08:00
Ken Sternberg
5cc2c0f45f Merge branch 'main' into dev
* main:
  ci: fix dockerfile warning (#11956)
2024-11-07 12:58:15 -08:00
Ken Sternberg
32442766f4 Merge branch 'main' into dev
* main:
  website/docs: fix slug matching redirect URI causing broken refresh (#11950)
  website/integrations: jellyfin: update plugin catalog location (#11948)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#11942)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#11946)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#11947)
  website/docs: clarify traefik ingress setup (#11938)
  core: bump importlib-metadata from 8.4.0 to 8.5.0 (#11934)
  web: bump API Client version (#11930)
  root: backport version bump `2024.10.1` (#11929)
  website/docs: `2024.10.1` Release Notes (#11926)
  website: bump path-to-regexp from 1.8.0 to 1.9.0 in /website (#11924)
  core: bump sentry-sdk from 2.17.0 to 2.18.0 (#11918)
  website: bump the docusaurus group in /website with 9 updates (#11917)
  core: bump goauthentik.io/api/v3 from 3.2024100.1 to 3.2024100.2 (#11915)
  core, web: update translations (#11914)
2024-11-07 08:08:46 -08:00
Ken Sternberg
75790909a8 Merge branch 'main' into dev
* main:
  web: bump API Client version (#11909)
  enterprise/rac: fix API Schema for invalidation_flow (#11907)
2024-11-04 13:20:15 -08:00
Ken Sternberg
e0d5df89ca Merge branch 'main' into dev
* main:
  core: add `None` check to a device's `extra_description` (#11904)
  providers/oauth2: fix size limited index for tokens (#11879)
  web: fix missing status code on failed build (#11903)
  website: bump docusaurus-theme-openapi-docs from 4.1.0 to 4.2.0 in /website (#11897)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#11891)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#11884)
  translate: Updates for file web/xliff/en.xlf in tr (#11878)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in tr (#11866)
  core: bump google-api-python-client from 2.149.0 to 2.151.0 (#11885)
  core: bump selenium from 4.26.0 to 4.26.1 (#11886)
  core, web: update translations (#11896)
  website: bump docusaurus-plugin-openapi-docs from 4.1.0 to 4.2.0 in /website (#11898)
  core: bump watchdog from 5.0.3 to 6.0.0 (#11899)
  core: bump ruff from 0.7.1 to 0.7.2 (#11900)
  core: bump django-pglock from 1.6.2 to 1.7.0 (#11901)
  website/docs: fix release notes to say Federation (#11889)
2024-11-04 10:25:52 -08:00
Ken Sternberg
f25a9c624e Merge branch 'main' into dev
* main:
  website: bump elliptic from 6.5.7 to 6.6.0 in /website (#11869)
  core: bump selenium from 4.25.0 to 4.26.0 (#11875)
  core: bump goauthentik.io/api/v3 from 3.2024083.14 to 3.2024100.1 (#11876)
  website/docs: add info about invalidation flow, default flows in general (#11800)
  website: fix docs redirect (#11873)
  website: remove RC disclaimer for version 2024.10 (#11871)
  website: update supported versions (#11841)
  web: bump API Client version (#11870)
  root: backport version bump 2024.10.0 (#11868)
  website/docs: 2024.8.4 release notes (#11862)
  web/admin: provide default invalidation flows for LDAP and Radius (#11861)
2024-11-04 10:25:45 -08:00
Ken Sternberg
914993a788 Merge branch 'main' into dev
* main: (43 commits)
  core, web: update translations (#11858)
  web/admin: fix code-based MFA toggle not working in wizard (#11854)
  sources/kerberos: add kiprop to ignored system principals (#11852)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#11846)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in it (#11845)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#11847)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#11848)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#11849)
  translate: Updates for file web/xliff/en.xlf in it (#11850)
  website: 2024.10 Release Notes (#11839)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#11814)
  core, web: update translations (#11821)
  core: bump goauthentik.io/api/v3 from 3.2024083.13 to 3.2024083.14 (#11830)
  core: bump service-identity from 24.1.0 to 24.2.0 (#11831)
  core: bump twilio from 9.3.5 to 9.3.6 (#11832)
  core: bump pytest-randomly from 3.15.0 to 3.16.0 (#11833)
  website/docs: Update social-logins github (#11822)
  website/docs: remove � (#11823)
  lifecycle: fix kdc5-config missing (#11826)
  website/docs: update preview status of different features (#11817)
  ...
2024-10-30 10:04:59 -07:00
Ken Sternberg
89dad07a66 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.
2024-10-23 14:17:30 -07:00
1687 changed files with 41403 additions and 92897 deletions

View File

@@ -215,9 +215,6 @@ runs:
--head "$CHERRY_PICK_BRANCH" \
--label "cherry-pick")
# Assign the PR to the original author
gh pr edit "$NEW_PR" --add-assignee "$PR_AUTHOR" || true
echo "✅ Created cherry-pick PR $NEW_PR for $TARGET_BRANCH"
# Comment on original PR
@@ -257,9 +254,6 @@ runs:
--head "$CHERRY_PICK_BRANCH" \
--label "cherry-pick")
# Assign the PR to the original author
gh pr edit "$NEW_PR" --add-assignee "$PR_AUTHOR" || true
echo "⚠️ Created conflict resolution PR $NEW_PR for $TARGET_BRANCH"
# Comment on original PR

View File

@@ -18,45 +18,33 @@ runs:
run: |
sudo apt-get remove --purge man-db
sudo apt-get update
sudo apt-get install --no-install-recommends -y libpq-dev openssl libxmlsec1-dev pkg-config gettext krb5-multidev libkrb5-dev heimdal-multidev libclang-dev krb5-kdc krb5-user krb5-admin-server
sudo apt-get install --no-install-recommends -y libpq-dev openssl libxmlsec1-dev pkg-config gettext libkrb5-dev krb5-kdc krb5-user krb5-admin-server
sudo rm -rf /usr/local/lib/android
- name: Install uv
if: ${{ contains(inputs.dependencies, 'python') }}
uses: astral-sh/setup-uv@6ee6290f1cbc4156c0bdd66691b2c144ef8df19a # v5
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v5
with:
enable-cache: true
- name: Setup python
if: ${{ contains(inputs.dependencies, 'python') }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v5
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v5
with:
python-version-file: "pyproject.toml"
- name: Install Python deps
if: ${{ contains(inputs.dependencies, 'python') }}
shell: bash
run: uv sync --all-extras --dev --frozen
- name: Setup node (web)
- name: Setup node
if: ${{ contains(inputs.dependencies, 'node') }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v4
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v4
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
registry-url: "https://registry.npmjs.org"
- name: Setup node (root)
if: ${{ contains(inputs.dependencies, 'node') }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v4
with:
node-version-file: package.json
cache: "npm"
cache-dependency-path: package-lock.json
registry-url: "https://registry.npmjs.org"
- name: Install Node deps
if: ${{ contains(inputs.dependencies, 'node') }}
shell: bash
run: npm ci
registry-url: 'https://registry.npmjs.org'
- name: Setup go
if: ${{ contains(inputs.dependencies, 'go') }}
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v5
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v5
with:
go-version-file: "go.mod"
- name: Setup docker cache
@@ -70,7 +58,7 @@ runs:
run: |
export PSQL_TAG=${{ inputs.postgresql_version }}
docker compose -f .github/actions/setup/compose.yml up -d
cd web && npm ci
cd web && npm i
- name: Generate config
if: ${{ contains(inputs.dependencies, 'python') }}
shell: uv run python {0}

View File

@@ -11,13 +11,6 @@ services:
ports:
- 5432:5432
restart: always
pgdog:
image: ghcr.io/pgdogdev/pgdog:latest
volumes:
- ./pgdog.toml:/pgdog/pgdog.toml:ro
ports:
- 127.0.0.1:6432:6432
restart: always
s3:
container_name: s3
image: docker.io/zenko/cloudserver
@@ -29,7 +22,7 @@ services:
- 8020:8000
volumes:
- s3-data:/usr/src/app/localData
- s3-metadata:/usr/src/app/localMetadata
- s3-metadata:/usr/scr/app/localMetadata
restart: always
volumes:

View File

@@ -1,18 +0,0 @@
[general]
host = "[::]"
port = 6432
passthrough_auth = "enabled_plain"
prepared_statements = "extended_anonymous"
pub_sub_channel_size = 8192
[admin]
password = "admin"
[[databases]]
host = "postgresql"
name = "postgres"
[[databases]]
host = "postgresql"
name = "authentik"
[[databases]]
host = "postgresql"
name = "test_authentik"

1
.github/codespell-dictionary.txt vendored Normal file
View File

@@ -0,0 +1 @@
authentic->authentik

32
.github/codespell-words.txt vendored Normal file
View File

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

View File

@@ -38,21 +38,6 @@ updates:
#endregion
#region Rust
- package-ecosystem: rust-toolchain
directory: "/"
schedule:
interval: daily
time: "04:00"
open-pull-requests-limit: 10
commit-message:
prefix: "core:"
labels:
- dependencies
#endregion
#region Web
- package-ecosystem: npm
@@ -249,7 +234,7 @@ updates:
- package-ecosystem: docker
directories:
- /lifecycle/container
- /
- /website
schedule:
interval: daily

View File

@@ -42,9 +42,9 @@ jobs:
# Needed for checkout
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -56,31 +56,32 @@ jobs:
release: ${{ inputs.release }}
- name: Login to Docker Hub
if: ${{ inputs.registry_dockerhub }}
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
username: ${{ secrets.DOCKER_CORP_USERNAME }}
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
- name: Login to GitHub Container Registry
if: ${{ inputs.registry_ghcr }}
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- name: make empty clients
if: ${{ inputs.release }}
run: |
mkdir -p ./gen-ts-api
mkdir -p ./gen-go-api
- name: Setup node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
with:
go-version-file: "go.mod"
- name: Generate API Clients
run: |
make gen-client-ts
make gen-client-go
- name: generate ts client
run: make gen-client-ts
- name: Build Docker Image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
id: push
with:
context: .
@@ -95,7 +96,7 @@ jobs:
platforms: linux/${{ inputs.image_arch }}
cache-from: type=registry,ref=${{ steps.ev.outputs.attestImageNames }}:buildcache-${{ inputs.image_arch }}
cache-to: ${{ steps.ev.outputs.cacheTo }}
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:

View File

@@ -49,7 +49,7 @@ jobs:
tags: ${{ steps.ev.outputs.imageTagsJSON }}
shouldPush: ${{ steps.ev.outputs.shouldPush }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -69,7 +69,7 @@ jobs:
matrix:
tag: ${{ fromJson(needs.get-tags.outputs.tags) }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -79,25 +79,25 @@ jobs:
image-name: ${{ inputs.image_name }}
- name: Login to Docker Hub
if: ${{ inputs.registry_dockerhub }}
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
username: ${{ secrets.DOCKER_CORP_USERNAME }}
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
- name: Login to GitHub Container Registry
if: ${{ inputs.registry_ghcr }}
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: int128/docker-manifest-create-action@8aac06098a12365ccdf99372dcfb453ccce8a0b0 # v2
- uses: int128/docker-manifest-create-action@b60433fd4312d7a64a56d769b76ebe3f45cf36b4 # v2
id: build
with:
tags: ${{ matrix.tag }}
sources: |
${{ steps.ev.outputs.attestImageNames }}@${{ needs.build-server-amd64.outputs.image-digest }}
${{ steps.ev.outputs.attestImageNames }}@${{ needs.build-server-arm64.outputs.image-digest }}
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
with:
subject-name: ${{ steps.ev.outputs.attestImageNames }}

View File

@@ -22,10 +22,10 @@ jobs:
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
token: ${{ steps.generate_token.outputs.token }}
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: web/package.json
registry-url: "https://registry.npmjs.org"
@@ -46,7 +46,7 @@ jobs:
run: |
export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'`
npm i @goauthentik/api@$VERSION
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
- uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v7
id: cpr
with:
token: ${{ steps.generate_token.outputs.token }}

View File

@@ -21,7 +21,7 @@ jobs:
command:
- prettier-check
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Install Dependencies
working-directory: website/
run: npm ci
@@ -32,8 +32,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: website/package.json
cache: "npm"
@@ -41,7 +41,7 @@ jobs:
- working-directory: website/
name: Install Dependencies
run: npm ci
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4
- uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v4
with:
path: |
${{ github.workspace }}/website/api/.docusaurus
@@ -55,7 +55,7 @@ jobs:
env:
NODE_ENV: production
run: npm run build -w api
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v4
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v4
with:
name: api-docs
path: website/api/build
@@ -66,12 +66,12 @@ jobs:
- lint
- build
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v5
with:
name: api-docs
path: website/api/build
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: website/package.json
cache: "npm"

View File

@@ -21,10 +21,10 @@ jobs:
check-changes-applied:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: lifecycle/aws/package.json
cache: "npm"

View File

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

View File

@@ -15,15 +15,13 @@ on:
jobs:
lint:
runs-on: ubuntu-latest
env:
NODE_ENV: production
strategy:
fail-fast: false
matrix:
command:
- prettier-check
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Install dependencies
working-directory: website/
run: npm ci
@@ -32,11 +30,10 @@ jobs:
run: npm run ${{ matrix.command }}
build-docs:
runs-on: ubuntu-latest
env:
NODE_ENV: production
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: website/package.json
cache: "npm"
@@ -49,11 +46,10 @@ jobs:
run: npm run build
build-integrations:
runs-on: ubuntu-latest
env:
NODE_ENV: production
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: website/package.json
cache: "npm"
@@ -73,13 +69,13 @@ jobs:
id-token: write
attestations: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -89,14 +85,14 @@ jobs:
image-name: ghcr.io/goauthentik/dev-docs
- name: Login to Container Registry
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
id: push
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
tags: ${{ steps.ev.outputs.imageTags }}
file: website/Dockerfile
@@ -105,7 +101,7 @@ jobs:
context: .
cache-from: type=registry,ref=ghcr.io/goauthentik/dev-docs:buildcache
cache-to: ${{ steps.ev.outputs.shouldPush == 'true' && 'type=registry,ref=ghcr.io/goauthentik/dev-docs:buildcache,mode=max' || '' }}
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:

View File

@@ -6,10 +6,6 @@ on:
schedule:
# Every night at 3am
- cron: "0 3 * * *"
pull_request:
paths:
# Needs to refer to itself
- .github/workflows/ci-main-daily.yml
jobs:
test-container:
@@ -19,14 +15,14 @@ jobs:
matrix:
version:
- docs
- version-2025-12
- version-2025-10
- version-2025-4
- version-2025-2
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- run: |
current="$(pwd)"
dir="/tmp/authentik/${{ matrix.version }}"
mkdir -p "${dir}/lifecycle/container"
cd "${dir}"
wget "https://${{ matrix.version }}.goauthentik.io/docker-compose.yml" -O "${dir}/lifecycle/container/compose.yml"
"${current}/scripts/test_docker.sh"
mkdir -p $dir
cd $dir
wget https://${{ matrix.version }}.goauthentik.io/compose.yml
${current}/scripts/test_docker.sh

View File

@@ -31,31 +31,21 @@ jobs:
job:
- bandit
- black
- spellcheck
- codespell
- pending-migrations
- ruff
- mypy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: run job
run: uv run make ci-${{ matrix.job }}
test-gen-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: generate schema
run: make migrate gen-build
- name: ensure schema is up-to-date
run: git diff --exit-code -- schema.yml blueprints/schema.json
test-migrations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: run migrations
@@ -81,7 +71,7 @@ jobs:
- 18-alpine
run_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
fetch-depth: 0
- name: checkout stable
@@ -94,7 +84,7 @@ jobs:
# Current version family based on
current_version_family=$(cat internal/constants/VERSION | grep -vE -- 'rc[0-9]+$' || true)
if [[ -n $current_version_family ]]; then
prev_stable="version/${current_version_family}"
prev_stable=$current_version_family
fi
echo "::notice::Checking out ${prev_stable} as stable version..."
git checkout ${prev_stable}
@@ -128,7 +118,7 @@ jobs:
CI_RUN_ID: ${{ matrix.run_id }}
CI_TOTAL_RUNS: "5"
run: |
make ci-test glob="authentik"
uv run make ci-test
- uses: ./.github/actions/test-results
if: ${{ always() }}
with:
@@ -146,7 +136,7 @@ jobs:
- 18-alpine
run_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Setup authentik env
uses: ./.github/actions/setup
with:
@@ -157,7 +147,7 @@ jobs:
CI_RUN_ID: ${{ matrix.run_id }}
CI_TOTAL_RUNS: "5"
run: |
make ci-test glob="authentik"
uv run make ci-test
- uses: ./.github/actions/test-results
if: ${{ always() }}
with:
@@ -166,14 +156,15 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Create k8s Kind Cluster
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab # v1.13.0
- name: run integration
run: |
make ci-test glob="tests/integration"
uv run coverage run manage.py test tests/integration
uv run coverage xml
- uses: ./.github/actions/test-results
if: ${{ always() }}
with:
@@ -196,8 +187,6 @@ jobs:
glob: tests/e2e/test_provider_saml* tests/e2e/test_source_saml*
- name: ldap
glob: tests/e2e/test_provider_ldap* tests/e2e/test_source_ldap*
- name: ws-fed
glob: tests/e2e/test_provider_ws_fed*
- name: radius
glob: tests/e2e/test_provider_radius*
- name: scim
@@ -207,14 +196,14 @@ jobs:
- name: endpoints
glob: tests/e2e/test_endpoints_*
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Setup e2e env (chrome, etc)
run: |
docker compose -f tests/e2e/compose.yml up -d --quiet-pull
- id: cache-web
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v4
with:
path: web/dist
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
@@ -228,7 +217,8 @@ jobs:
npm run build:sfe
- name: run e2e
run: |
make ci-test glob="${{ matrix.job.glob }}"
uv run coverage run manage.py test ${{ matrix.job.glob }}
uv run coverage xml
- uses: ./.github/actions/test-results
if: ${{ always() }}
with:
@@ -246,7 +236,7 @@ jobs:
- name: implicit
glob: tests/openid_conformance/test_implicit.py
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Setup e2e env (chrome, etc)
@@ -256,7 +246,7 @@ jobs:
run: |
docker compose -f tests/openid_conformance/compose.yml up -d --quiet-pull
- id: cache-web
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v4
with:
path: web/dist
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
@@ -270,13 +260,14 @@ jobs:
npm run build:sfe
- name: run conformance
run: |
make ci-test glob="${{ matrix.job.glob }}"
uv run coverage run manage.py test ${{ matrix.job.glob }}
uv run coverage xml
- uses: ./.github/actions/test-results
if: ${{ always() }}
with:
flags: conformance
- if: ${{ !cancelled() }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: conformance-certification-${{ matrix.job.name }}
path: tests/openid_conformance/exports/
@@ -284,7 +275,6 @@ jobs:
if: always()
needs:
- lint
- test-gen-build
- test-migrations
- test-migrations-from-stable
- test-unittest
@@ -320,7 +310,7 @@ jobs:
pull-requests: write
timeout-minutes: 120
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: prepare variables

View File

@@ -21,8 +21,8 @@ jobs:
lint-golint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
with:
go-version-file: "go.mod"
- name: Prepare and generate API
@@ -42,8 +42,8 @@ jobs:
test-unittest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
with:
go-version-file: "go.mod"
- name: Setup authentik env
@@ -86,13 +86,13 @@ jobs:
id-token: write
attestations: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -102,7 +102,7 @@ jobs:
image-name: ghcr.io/goauthentik/dev-${{ matrix.type }}
- name: Login to Container Registry
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
@@ -111,7 +111,7 @@ jobs:
run: make gen-client-go
- name: Build Docker Image
id: push
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
tags: ${{ steps.ev.outputs.imageTags }}
file: lifecycle/container/${{ matrix.type }}.Dockerfile
@@ -122,7 +122,7 @@ jobs:
context: .
cache-from: type=registry,ref=ghcr.io/goauthentik/dev-${{ matrix.type }}:buildcache
cache-to: ${{ steps.ev.outputs.shouldPush == 'true' && format('type=registry,ref=ghcr.io/goauthentik/dev-{0}:buildcache,mode=max', matrix.type) || '' }}
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:
@@ -145,13 +145,13 @@ jobs:
goos: [linux]
goarch: [amd64, arm64]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
with:
go-version-file: "go.mod"
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: web/package.json
cache: "npm"

View File

@@ -31,8 +31,8 @@ jobs:
- command: lit-analyse
project: web
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: ${{ matrix.project }}/package.json
cache: "npm"
@@ -48,8 +48,8 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: web/package.json
cache: "npm"
@@ -76,8 +76,8 @@ jobs:
- ci-web-mark
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: web/package.json
cache: "npm"

View File

@@ -33,16 +33,16 @@ jobs:
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
token: ${{ steps.generate_token.outputs.token }}
- name: Compress images
id: compress
uses: calibreapp/image-actions@d9c8ee5c3dc52ae4622c82ead88d658f4b16b65f # main
uses: calibreapp/image-actions@420075c115b26f8785e293c5bd5bef0911c506e5 # main
with:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
compressOnly: ${{ github.event_name != 'pull_request' }}
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
- uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v7
if: "${{ github.event_name != 'pull_request' && steps.compress.outputs.markdown != '' }}"
id: cpr
with:

View File

@@ -20,13 +20,13 @@ jobs:
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
token: ${{ steps.generate_token.outputs.token }}
- name: Setup authentik env
uses: ./.github/actions/setup
- run: uv run ak update_webauthn_mds
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
- uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v7
id: cpr
with:
token: ${{ steps.generate_token.outputs.token }}

View File

@@ -17,7 +17,7 @@ jobs:
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
env:
GH_APP_ID: ${{ secrets.GH_APP_ID }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
if: ${{ steps.app-token.outcome != 'skipped' }}
with:
fetch-depth: 0

View File

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

View File

@@ -29,19 +29,18 @@ jobs:
- packages/eslint-config
- packages/prettier-config
- packages/docusaurus-config
- packages/logger-js
- packages/esbuild-plugin-live-reload
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
fetch-depth: 2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: ${{ matrix.package }}/package.json
registry-url: "https://registry.npmjs.org"
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # 24d32ffd492484c1d75e0c0b894501ddb9d30d62
uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # 24d32ffd492484c1d75e0c0b894501ddb9d30d62
with:
files: |
${{ matrix.package }}/package.json

View File

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

View File

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

View File

@@ -34,7 +34,7 @@ jobs:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Checkout main
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: main
token: "${{ steps.app-token.outputs.token }}"
@@ -62,7 +62,7 @@ jobs:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Checkout main
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: main
token: ${{ steps.generate_token.outputs.token }}
@@ -73,7 +73,7 @@ jobs:
- name: Bump version
run: "make bump version=${{ inputs.next_version }}.0-rc1"
- name: Create pull request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v7
with:
token: ${{ steps.generate_token.outputs.token }}
branch: release-bump-${{ inputs.next_version }}

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
environment: internal-production
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: main
- run: |

View File

@@ -31,11 +31,11 @@ jobs:
id-token: write
attestations: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -44,21 +44,21 @@ jobs:
with:
image-name: ghcr.io/goauthentik/docs
- name: Login to GitHub Container Registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
id: push
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
tags: ${{ steps.ev.outputs.imageTags }}
file: website/Dockerfile
push: true
platforms: linux/amd64,linux/arm64
context: .
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
if: true
with:
@@ -83,19 +83,14 @@ jobs:
- radius
- rac
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
with:
go-version-file: "go.mod"
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -103,23 +98,23 @@ jobs:
DOCKER_USERNAME: ${{ secrets.DOCKER_CORP_USERNAME }}
with:
image-name: ghcr.io/goauthentik/${{ matrix.type }},authentik/${{ matrix.type }}
- name: Generate API Clients
- name: make empty clients
run: |
make gen-client-ts
make gen-client-go
mkdir -p ./gen-ts-api
mkdir -p ./gen-go-api
- name: Docker Login Registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
username: ${{ secrets.DOCKER_CORP_USERNAME }}
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
id: push
with:
push: true
@@ -129,7 +124,7 @@ jobs:
file: lifecycle/container/${{ matrix.type }}.Dockerfile
platforms: linux/amd64,linux/arm64
context: .
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3
id: attest
with:
subject-name: ${{ steps.ev.outputs.attestImageNames }}
@@ -151,26 +146,19 @@ jobs:
goos: [linux, darwin]
goarch: [amd64, arm64]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
with:
go-version-file: "go.mod"
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v5
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v5
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- name: Install web dependencies
working-directory: web/
run: |
npm ci
- name: Generate API Clients
run: |
make gen-client-ts
make gen-client-go
- name: Build web
working-directory: web/
run: |
npm ci
npm run build-proxy
- name: Build outpost
run: |
@@ -180,7 +168,7 @@ jobs:
export CGO_ENABLED=0
go build -tags=outpost_static_embed -v -o ./authentik-outpost-${{ matrix.type }}_${{ matrix.goos }}_${{ matrix.goarch }} ./cmd/${{ matrix.type }}
- name: Upload binaries to release
uses: svenstaro/upload-release-action@b98a3b12e86552593f3e4e577ca8a62aa2f3f22b # v2
uses: svenstaro/upload-release-action@6b7fa9f267e90b50a19fef07b3596790bb941741 # v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./authentik-outpost-${{ matrix.type }}_${{ matrix.goos }}_${{ matrix.goarch }}
@@ -198,8 +186,8 @@ jobs:
AWS_REGION: eu-central-1
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5
with:
role-to-assume: "arn:aws:iam::016170277896:role/github_goauthentik_authentik"
aws-region: ${{ env.AWS_REGION }}
@@ -214,15 +202,15 @@ jobs:
- build-outpost-binary
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: Run test suite in final docker images
run: |
echo "PG_PASS=$(openssl rand 32 | base64 -w 0)" >> lifecycle/container/.env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand 32 | base64 -w 0)" >> lifecycle/container/.env
docker compose -f lifecycle/container/compose.yml pull -q
docker compose -f lifecycle/container/compose.yml up --no-start
docker compose -f lifecycle/container/compose.yml start postgresql
docker compose -f lifecycle/container/compose.yml run -u root server test-all
echo "PG_PASS=$(openssl rand 32 | base64 -w 0)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand 32 | base64 -w 0)" >> .env
docker compose pull -q
docker compose up --no-start
docker compose start postgresql
docker compose run -u root server test-all
sentry-release:
needs:
- build-server
@@ -230,7 +218,7 @@ jobs:
- build-outpost-binary
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -244,7 +232,7 @@ jobs:
container=$(docker container create ${{ steps.ev.outputs.imageMainName }})
docker cp ${container}:web/ .
- name: Create a Sentry.io release
uses: getsentry/action-release@dab6548b3c03c4717878099e43782cf5be654289 # v3
uses: getsentry/action-release@128c5058bbbe93c8e02147fe0a9c713f166259a6 # v3
continue-on-error: true
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

View File

@@ -52,11 +52,9 @@ jobs:
needs:
- check-inputs
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: "version-${{ needs.check-inputs.outputs.major_version }}"
- name: Setup authentik env
uses: ./.github/actions/setup
- run: make test-docker
bump-authentik:
name: Bump authentik version
@@ -76,7 +74,7 @@ jobs:
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: "${{ steps.app-token.outputs.token }}"
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
ref: "version-${{ needs.check-inputs.outputs.major_version }}"
token: "${{ steps.app-token.outputs.token }}"
@@ -91,7 +89,6 @@ jobs:
# ID from https://api.github.com/users/authentik-automation[bot]
git config --global user.name '${{ steps.app-token.outputs.app-slug }}[bot]'
git config --global user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com'
git pull
git commit -a -m "release: ${{ inputs.version }}" --allow-empty
git tag "version/${{ inputs.version }}" HEAD -m "version/${{ inputs.version }}"
git push --follow-tags
@@ -125,7 +122,7 @@ jobs:
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: "${{ steps.app-token.outputs.token }}"
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
repository: "${{ github.repository_owner }}/helm"
token: "${{ steps.app-token.outputs.token }}"
@@ -137,7 +134,7 @@ jobs:
sed -E -i 's/[0-9]{4}\.[0-9]{1,2}\.[0-9]+$/${{ inputs.version }}/' charts/authentik/Chart.yaml
./scripts/helm-docs.sh
- name: Create pull request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v7
with:
token: "${{ steps.app-token.outputs.token }}"
branch: bump-${{ inputs.version }}
@@ -167,7 +164,7 @@ jobs:
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: "${{ steps.app-token.outputs.token }}"
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
with:
repository: "${{ github.repository_owner }}/version"
token: "${{ steps.app-token.outputs.token }}"
@@ -175,28 +172,24 @@ jobs:
if: "${{ inputs.release_reason == 'feature' }}"
run: |
changelog_url="https://docs.goauthentik.io/docs/releases/${{ needs.check-inputs.outputs.major_version }}"
reason="${{ inputs.release_reason }}"
jq \
--arg version "${{ inputs.version }}" \
--arg changelog "See ${changelog_url}" \
--arg changelog_url "${changelog_url}" \
--arg reason "${reason}" \
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url | .stable.reason = $reason' version.json > version.new.json
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url' version.json > version.new.json
mv version.new.json version.json
- name: Bump version
if: "${{ inputs.release_reason != 'feature' }}"
run: |
changelog_url="https://docs.goauthentik.io/docs/releases/${{ needs.check-inputs.outputs.major_version }}#fixed-in-$(echo -n ${{ inputs.version}} | sed 's/\.//g')"
reason="${{ inputs.release_reason }}"
jq \
--arg version "${{ inputs.version }}" \
--arg changelog "See ${changelog_url}" \
--arg changelog_url "${changelog_url}" \
--arg reason "${reason}" \
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url | .stable.reason = $reason' version.json > version.new.json
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url' version.json > version.new.json
mv version.new.json version.json
- name: Create pull request
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v7
with:
token: "${{ steps.app-token.outputs.token }}"
branch: bump-${{ inputs.version }}

View File

@@ -19,7 +19,7 @@ jobs:
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10
with:
repo-token: ${{ steps.generate_token.outputs.token }}
days-before-stale: 60

View File

@@ -25,11 +25,11 @@ jobs:
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
if: ${{ github.event_name != 'pull_request' }}
with:
token: ${{ steps.generate_token.outputs.token }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
if: ${{ github.event_name == 'pull_request' }}
- name: Setup authentik env
uses: ./.github/actions/setup
@@ -44,7 +44,7 @@ jobs:
make web-check-compile
- name: Create Pull Request
if: ${{ github.event_name != 'pull_request' }}
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v7
with:
token: ${{ steps.generate_token.outputs.token }}
branch: extract-compile-backend-translation

3
.gitignore vendored
View File

@@ -15,9 +15,6 @@ media
node_modules
.cspellcache
cspell-report.*
# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
# in your Git repository. Update and uncomment the following line accordingly.
# <django-project-name>/staticfiles/

12
.vscode/settings.json vendored
View File

@@ -14,10 +14,6 @@
"[xml]": {
"editor.minimap.markSectionHeaderRegex": "<!--\\s*#\\bregion\\s*(?<separator>-?)\\s*(?<label>.*)\\s*-->"
},
"files.associations": {
// The built-in "ignore" language gives us enough syntax highlighting to make these files readable.
"**/dictionaries/*.txt": "ignore"
},
"todo-tree.tree.showCountsInTree": true,
"todo-tree.tree.showBadges": true,
"yaml.customTags": [
@@ -53,9 +49,13 @@
"ignoreCase": false
}
],
"go.testFlags": ["-count=1"],
"go.testFlags": [
"-count=1"
],
"go.testEnvVars": {
"WORKSPACE_DIR": "${workspaceFolder}"
},
"github-actions.workflows.pinned.workflows": [".github/workflows/ci-main.yml"]
"github-actions.workflows.pinned.workflows": [
".github/workflows/ci-main.yml"
]
}

View File

@@ -34,12 +34,11 @@ packages/docusaurus-config @goauthentik/frontend
packages/esbuild-plugin-live-reload @goauthentik/frontend
packages/eslint-config @goauthentik/frontend
packages/prettier-config @goauthentik/frontend
packages/logger-js @goauthentik/frontend
packages/tsconfig @goauthentik/frontend
# Web
web/ @goauthentik/frontend
# Locale
/locale/ @goauthentik/backend @goauthentik/frontend
locale/ @goauthentik/backend @goauthentik/frontend
web/xliff/ @goauthentik/backend @goauthentik/frontend
# Docs
website/ @goauthentik/docs

172
Makefile
View File

@@ -5,6 +5,7 @@ SHELL := /usr/bin/env bash
PWD = $(shell pwd)
UID = $(shell id -u)
GID = $(shell id -g)
NPM_VERSION = $(shell python -m scripts.generate_semver)
PY_SOURCES = authentik packages tests scripts lifecycle .github
DOCKER_IMAGE ?= "authentik:test"
@@ -19,42 +20,24 @@ GEN_API_TS = gen-ts-api
GEN_API_PY = gen-py-api
GEN_API_GO = gen-go-api
BREW_LDFLAGS :=
BREW_CPPFLAGS :=
BREW_PKG_CONFIG_PATH :=
UV := uv
pg_user := $(shell uv run python -m authentik.lib.config postgresql.user 2>/dev/null)
pg_host := $(shell uv run python -m authentik.lib.config postgresql.host 2>/dev/null)
pg_name := $(shell uv run python -m authentik.lib.config postgresql.name 2>/dev/null)
# For macOS users, add the libxml2 installed from brew libxmlsec1 to the build path
# to prevent SAML-related tests from failing and ensure correct pip dependency compilation
ifeq ($(UNAME_S),Darwin)
# Only add for brew users who installed libxmlsec1
BREW_EXISTS := $(shell command -v brew 2> /dev/null)
ifdef BREW_EXISTS
LIBXML2_EXISTS := $(shell brew list libxml2 2> /dev/null)
ifdef LIBXML2_EXISTS
_xml_pref := $(shell brew --prefix libxml2)
BREW_LDFLAGS += -L${_xml_pref}/lib
BREW_CPPFLAGS += -I${_xml_pref}/include
BREW_PKG_CONFIG_PATH = ${_xml_pref}/lib/pkgconfig:$(PKG_CONFIG_PATH)
endif
KRB5_EXISTS := $(shell brew list krb5 2> /dev/null)
ifdef KRB5_EXISTS
_krb5_pref := $(shell brew --prefix krb5)
BREW_LDFLAGS += -L${_krb5_pref}/lib
BREW_CPPFLAGS += -I${_krb5_pref}/include
BREW_PKG_CONFIG_PATH = ${_krb5_pref}/lib/pkgconfig:$(PKG_CONFIG_PATH)
endif
UV := LDFLAGS="$(BREW_LDFLAGS)" CPPFLAGS="$(BREW_CPPFLAGS)" PKG_CONFIG_PATH="$(BREW_PKG_CONFIG_PATH)" uv
endif
endif
# These functions are only evaluated when called in specific targets
LIBXML2_EXISTS = $(shell brew list libxml2 2> /dev/null)
KRB5_EXISTS = $(shell brew list krb5 2> /dev/null)
NPM_VERSION :=
UV_EXISTS := $(shell command -v uv 2> /dev/null)
ifdef UV_EXISTS
NPM_VERSION := $(shell $(UV) run python -m scripts.generate_semver)
else
NPM_VERSION = $(shell python -m scripts.generate_semver)
LIBXML2_LDFLAGS = -L$(shell brew --prefix libxml2)/lib $(LDFLAGS)
LIBXML2_CPPFLAGS = -I$(shell brew --prefix libxml2)/include $(CPPFLAGS)
LIBXML2_PKG_CONFIG = $(shell brew --prefix libxml2)/lib/pkgconfig:$(PKG_CONFIG_PATH)
KRB_PATH =
ifneq ($(KRB5_EXISTS),)
KRB_PATH = PATH="$(shell brew --prefix krb5)/sbin:$(shell brew --prefix krb5)/bin:$$PATH"
endif
all: lint-fix lint gen web test ## Lint, build, and test everything
@@ -73,46 +56,47 @@ go-test:
go test -timeout 0 -v -race -cover ./...
test: ## Run the server tests and produce a coverage report (locally)
$(UV) run coverage run manage.py test --keepdb $(or $(filter-out $@,$(MAKECMDGOALS)),authentik)
$(UV) run coverage html
$(UV) run coverage report
$(KRB_PATH) uv run coverage run manage.py test --keepdb $(or $(filter-out $@,$(MAKECMDGOALS)),authentik)
uv run coverage html
uv run coverage report
lint-fix: lint-spellcheck ## Lint and automatically fix errors in the python source code. Reports spelling errors.
$(UV) run black $(PY_SOURCES)
$(UV) run ruff check --fix $(PY_SOURCES)
lint-fix: lint-codespell ## Lint and automatically fix errors in the python source code. Reports spelling errors.
uv run black $(PY_SOURCES)
uv run ruff check --fix $(PY_SOURCES)
lint-spellcheck: ## Reports spelling errors.
npm run lint:spellcheck
lint-codespell: ## Reports spelling errors.
uv run codespell -w
lint: ci-bandit ci-mypy ## Lint the python and golang sources
lint: ## Lint the python and golang sources
uv run bandit -c pyproject.toml -r $(PY_SOURCES)
golangci-lint run -v
core-install:
ifdef ($(BREW_EXISTS))
ifneq ($(LIBXML2_EXISTS),)
# Clear cache to ensure fresh compilation
$(UV) cache clean
uv cache clean
# Force compilation from source for lxml and xmlsec with correct environment
$(UV) sync --frozen --reinstall-package lxml --reinstall-package xmlsec --no-binary-package lxml --no-binary-package xmlsec
LDFLAGS="$(LIBXML2_LDFLAGS)" CPPFLAGS="$(LIBXML2_CPPFLAGS)" PKG_CONFIG_PATH="$(LIBXML2_PKG_CONFIG)" uv sync --frozen --reinstall-package lxml --reinstall-package xmlsec --no-binary-package lxml --no-binary-package xmlsec
else
$(UV) sync --frozen
uv sync --frozen
endif
migrate: ## Run the Authentik Django server's migrations
$(UV) run python -m lifecycle.migrate
uv run python -m lifecycle.migrate
i18n-extract: core-i18n-extract web-i18n-extract ## Extract strings that require translation into files to send to a translation service
aws-cfn:
cd lifecycle/aws && npm i && $(UV) run npm run aws-cfn
cd lifecycle/aws && npm i && uv run npm run aws-cfn
run-server: ## Run the main authentik server process
$(UV) run ak server
uv run ak server
run-worker: ## Run the main authentik worker process
$(UV) run ak worker
uv run ak worker
core-i18n-extract:
$(UV) run ak makemessages \
uv run ak makemessages \
--add-location file \
--no-obsolete \
--ignore web \
@@ -125,23 +109,12 @@ core-i18n-extract:
install: node-install docs-install core-install ## Install all requires dependencies for `node`, `docs` and `core`
dev-drop-db:
$(eval pg_user := $(shell $(UV) run python -m authentik.lib.config postgresql.user 2>/dev/null))
$(eval pg_pass := $(shell $(UV) run python -m authentik.lib.config postgresql.password 2>/dev/null))
$(eval pg_host := $(shell $(UV) run python -m authentik.lib.config postgresql.host 2>/dev/null))
$(eval pg_name := $(shell $(UV) run python -m authentik.lib.config postgresql.name 2>/dev/null))
PGPASSWORD="${pg_pass}" psql -U ${pg_user} -h ${pg_host} postgres -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '${pg_name}'"
PGPASSWORD="${pg_pass}" dropdb -U ${pg_user} -h ${pg_host} ${pg_name} || true
dropdb -U ${pg_user} -h ${pg_host} ${pg_name} || true
# Also remove the test-db if it exists
PGPASSWORD="${pg_pass}" psql -U ${pg_user} -h ${pg_host} postgres -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'test_${pg_name}'"
PGPASSWORD="${pg_pass}" dropdb -U ${pg_user} -h ${pg_host} test_${pg_name} || true
dropdb -U ${pg_user} -h ${pg_host} test_${pg_name} || true
dev-create-db:
$(eval pg_user := $(shell $(UV) run python -m authentik.lib.config postgresql.user 2>/dev/null))
$(eval pg_pass := $(shell $(UV) run python -m authentik.lib.config postgresql.password 2>/dev/null))
$(eval pg_host := $(shell $(UV) run python -m authentik.lib.config postgresql.host 2>/dev/null))
$(eval pg_name := $(shell $(UV) run python -m authentik.lib.config postgresql.name 2>/dev/null))
PGPASSWORD="${pg_pass}" createdb -U ${pg_user} -h ${pg_host} ${pg_name} || true
PGPASSWORD="${pg_pass}" createdb -U ${pg_user} -h ${pg_host} test_${pg_name} || true
createdb -U ${pg_user} -h ${pg_host} ${pg_name}
dev-reset: dev-drop-db dev-create-db migrate ## Drop and restore the Authentik PostgreSQL instance to a "fresh install" state.
@@ -153,11 +126,11 @@ bump: ## Bump authentik version. Usage: make bump version=20xx.xx.xx
ifndef version
$(error Usage: make bump version=20xx.xx.xx )
endif
$(eval current_version := $(shell cat ${PWD}/internal/constants/VERSION))
$(SED_INPLACE) 's/^version = ".*"/version = "$(version)"/' ${PWD}/pyproject.toml
$(SED_INPLACE) 's/^VERSION = ".*"/VERSION = "$(version)"/' ${PWD}/authentik/__init__.py
$(SED_INPLACE) 's/^version = ".*"/version = "$(version)"/' pyproject.toml
$(SED_INPLACE) 's/^VERSION = ".*"/VERSION = "$(version)"/' authentik/__init__.py
$(MAKE) gen-build gen-compose aws-cfn
$(SED_INPLACE) "s/\"${current_version}\"/\"$(version)\"/" ${PWD}/package.json ${PWD}/package-lock.json ${PWD}/web/package.json ${PWD}/web/package-lock.json
npm version --no-git-tag-version --allow-same-version $(version)
cd ${PWD}/web && npm version --no-git-tag-version --allow-same-version $(version)
echo -n $(version) > ${PWD}/internal/constants/VERSION
#########################
@@ -168,27 +141,17 @@ gen-build: ## Extract the schema from the database
AUTHENTIK_DEBUG=true \
AUTHENTIK_TENANTS__ENABLED=true \
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
$(UV) run ak build_schema
uv run ak build_schema
gen-compose:
$(UV) run scripts/generate_compose.py
uv run scripts/generate_compose.py
gen-changelog: ## (Release) generate the changelog based from the commits since the last version
# These are best-effort guesses based on commit messages
$(eval last_version := $(shell git tag --list 'version/*' --sort 'version:refname' | grep -vE 'rc\d+$$' | tail -1))
$(eval current_commit := $(shell git rev-parse HEAD))
git log --pretty=format:"- %s" $(shell git merge-base ${last_version} ${current_commit})...${current_commit} > merged_to_current
git log --pretty=format:"- %s" $(shell git merge-base ${last_version} ${current_commit})...${last_version} > merged_to_last
grep -Eo 'cherry-pick (#\d+)' merged_to_last | cut -d ' ' -f 2 | sed 's/.*/(&)$$/' > cherry_picked_to_last
grep -vf cherry_picked_to_last merged_to_current | sort > changelog.md
rm merged_to_current
rm merged_to_last
rm cherry_picked_to_last
gen-changelog: ## (Release) generate the changelog based from the commits since the last tag
git log --pretty=format:" - %s" $(shell git describe --tags $(shell git rev-list --tags --max-count=1))...$(shell git branch --show-current) | sort > changelog.md
npx prettier --write changelog.md
gen-diff: ## (Release) generate the changelog diff between the current schema and the last version
$(eval last_version := $(shell git tag --list 'version/*' --sort 'version:refname' | grep -vE 'rc\d+$$' | tail -1))
git show ${last_version}:schema.yml > schema-old.yml
gen-diff: ## (Release) generate the changelog diff between the current schema and the last tag
git show $(shell git describe --tags $(shell git rev-list --tags --max-count=1)):schema.yml > schema-old.yml
docker compose -f scripts/api/compose.yml run --rm --user "${UID}:${GID}" diff \
--markdown \
/local/diff.md \
@@ -228,19 +191,28 @@ gen-client-ts: gen-clean-ts ## Build and install the authentik API for Typescri
gen-client-py: gen-clean-py ## Build and install the authentik API for Python
mkdir -p ${PWD}/${GEN_API_PY}
ifeq ($(wildcard ${PWD}/${GEN_API_PY}/.*),)
git clone --depth 1 https://github.com/goauthentik/client-python.git ${PWD}/${GEN_API_PY}
else
cd ${PWD}/${GEN_API_PY} && git pull
endif
cp ${PWD}/schema.yml ${PWD}/${GEN_API_PY}
make -C ${PWD}/${GEN_API_PY} build version=${NPM_VERSION}
gen-client-go: gen-clean-go ## Build and install the authentik API for Golang
gen-client-go: ## Build and install the authentik API for Golang
mkdir -p ${PWD}/${GEN_API_GO}
ifeq ($(wildcard ${PWD}/${GEN_API_GO}/.*),)
git clone --depth 1 https://github.com/goauthentik/client-go.git ${PWD}/${GEN_API_GO}
else
cd ${PWD}/${GEN_API_GO} && git reset --hard
cd ${PWD}/${GEN_API_GO} && git pull
endif
cp ${PWD}/schema.yml ${PWD}/${GEN_API_GO}
make -C ${PWD}/${GEN_API_GO} build version=${NPM_VERSION}
make -C ${PWD}/${GEN_API_GO} build
go mod edit -replace goauthentik.io/api/v3=./${GEN_API_GO}
gen-dev-config: ## Generate a local development config file
$(UV) run scripts/generate_config.py
uv run scripts/generate_config.py
gen: gen-build gen-client-ts
@@ -291,7 +263,7 @@ docs: docs-lint-fix docs-build ## Automatically fix formatting issues in the Au
docs-install:
npm ci --prefix website
docs-lint-fix: lint-spellcheck
docs-lint-fix: lint-codespell
npm run --prefix website prettier
docs-build:
@@ -336,28 +308,28 @@ test-docker:
# which makes the YAML File a lot smaller
ci--meta-debug:
$(UV) run python -V
python -V
node --version
ci-mypy: ci--meta-debug
$(UV) run mypy --strict $(PY_SOURCES)
uv run mypy --strict $(PY_SOURCES)
ci-black: ci--meta-debug
$(UV) run black --check $(PY_SOURCES)
uv run black --check $(PY_SOURCES)
ci-ruff: ci--meta-debug
$(UV) run ruff check $(PY_SOURCES)
uv run ruff check $(PY_SOURCES)
ci-spellcheck: ci--meta-debug
npm run lint:spellcheck
ci-codespell: ci--meta-debug
uv run codespell -s
ci-bandit: ci--meta-debug
$(UV) run bandit -c pyproject.toml -r $(PY_SOURCES) -iii
uv run bandit -r $(PY_SOURCES)
ci-pending-migrations: ci--meta-debug
$(UV) run ak makemigrations --check
uv run ak makemigrations --check
ci-test: ci--meta-debug dev-create-db
$(UV) run coverage run manage.py test --keepdb $(glob)
$(UV) run coverage report
$(UV) run coverage xml
ci-test: ci--meta-debug
uv run coverage run manage.py test --keepdb authentik
uv run coverage report
uv run coverage xml

View File

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

View File

@@ -3,7 +3,7 @@
from functools import lru_cache
from os import environ
VERSION = "2026.5.0-rc1"
VERSION = "2026.2.0-rc1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@@ -18,6 +18,7 @@ from rest_framework.views import APIView
from authentik import authentik_full_version
from authentik.core.api.utils import PassiveSerializer
from authentik.enterprise.license import LicenseKey
from authentik.lib.config import CONFIG
from authentik.lib.utils.reflection import get_env
from authentik.outposts.apps import MANAGED_OUTPOST
@@ -25,15 +26,6 @@ from authentik.outposts.models import Outpost
from authentik.rbac.permissions import HasPermission
def fips_enabled():
try:
from authentik.enterprise.license import LicenseKey
return backend._fips_enabled if LicenseKey.get_total().status().is_valid else None
except ModuleNotFoundError:
return None
class RuntimeDict(TypedDict):
"""Runtime information"""
@@ -88,7 +80,9 @@ class SystemInfoSerializer(PassiveSerializer):
"architecture": platform.machine(),
"authentik_version": authentik_full_version(),
"environment": get_env(),
"openssl_fips_enabled": fips_enabled(),
"openssl_fips_enabled": (
backend._fips_enabled if LicenseKey.get_total().status().is_valid else None
),
"openssl_version": OPENSSL_VERSION,
"platform": platform.platform(),
"python_version": python_version,

View File

@@ -1,3 +1,5 @@
import mimetypes
from django.db.models import Q
from django.utils.translation import gettext as _
from drf_spectacular.utils import extend_schema
@@ -10,14 +12,13 @@ from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from authentik.admin.files.backends.base import get_content_type
from authentik.admin.files.fields import FileField as AkFileField
from authentik.admin.files.manager import get_file_manager
from authentik.admin.files.usage import FileApiUsage
from authentik.admin.files.validation import validate_upload_file_name
from authentik.api.validation import validate
from authentik.core.api.used_by import DeleteAction, UsedBySerializer
from authentik.core.api.utils import PassiveSerializer, ThemedUrlsSerializer
from authentik.core.api.utils import PassiveSerializer
from authentik.events.models import Event, EventAction
from authentik.lib.utils.reflection import get_apps
from authentik.rbac.permissions import HasPermission
@@ -25,6 +26,11 @@ from authentik.rbac.permissions import HasPermission
MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024 # 25MB
def get_mime_from_filename(filename: str) -> str:
mime_type, _ = mimetypes.guess_type(filename)
return mime_type or "application/octet-stream"
class FileView(APIView):
pagination_class = None
parser_classes = [MultiPartParser]
@@ -47,7 +53,6 @@ class FileView(APIView):
name = CharField()
mime_type = CharField()
url = CharField()
themed_urls = ThemedUrlsSerializer(required=False, allow_null=True)
@extend_schema(
parameters=[FileListParameters],
@@ -75,9 +80,8 @@ class FileView(APIView):
FileView.FileListSerializer(
data={
"name": file,
"url": manager.file_url(file, request),
"mime_type": get_content_type(file),
"themed_urls": manager.themed_urls(file, request),
"url": manager.file_url(file),
"mime_type": get_mime_from_filename(file),
}
)
for file in files
@@ -146,7 +150,7 @@ class FileView(APIView):
"pk": name,
"name": name,
"usage": usage.value,
"mime_type": get_content_type(name),
"mime_type": get_mime_from_filename(name),
},
).from_http(request)

View File

@@ -1,4 +1,3 @@
import mimetypes
from collections.abc import Callable, Generator, Iterator
from typing import cast
@@ -11,32 +10,6 @@ from authentik.admin.files.usage import FileUsage
CACHE_PREFIX = "goauthentik.io/admin/files"
LOGGER = get_logger()
# Theme variable placeholder for theme-specific files like logo-%(theme)s.png
THEME_VARIABLE = "%(theme)s"
def get_content_type(name: str) -> str:
"""Get MIME type for a file based on its extension."""
content_type, _ = mimetypes.guess_type(name)
return content_type or "application/octet-stream"
def get_valid_themes() -> list[str]:
"""Get valid themes that can be substituted for %(theme)s."""
from authentik.brands.api import Themes
return [t.value for t in Themes if t != Themes.AUTOMATIC]
def has_theme_variable(name: str) -> bool:
"""Check if filename contains %(theme)s variable."""
return THEME_VARIABLE in name
def substitute_theme(name: str, theme: str) -> str:
"""Replace %(theme)s with the given theme."""
return name.replace(THEME_VARIABLE, theme)
class Backend:
"""
@@ -94,7 +67,7 @@ class Backend:
Args:
file_path: Relative file path
request: Optional Django HttpRequest for fully qualified URL building
request: Optional Django HttpRequest for fully qualifed URL building
use_cache: whether to retrieve the URL from cache
Returns:
@@ -102,29 +75,6 @@ class Backend:
"""
raise NotImplementedError
def themed_urls(
self,
name: str,
request: HttpRequest | None = None,
) -> dict[str, str] | None:
"""
Get URLs for each theme variant when filename contains %(theme)s.
Args:
name: File path potentially containing %(theme)s
request: Optional Django HttpRequest for URL building
Returns:
Dict mapping theme to URL if %(theme)s present, None otherwise
"""
if not has_theme_variable(name):
return None
return {
theme: self.file_url(substitute_theme(name, theme), request, use_cache=True)
for theme in get_valid_themes()
}
class ManageableBackend(Backend):
"""

View File

@@ -45,13 +45,8 @@ class FileBackend(ManageableBackend):
@property
def manageable(self) -> bool:
# Check _base_dir (the mount point, e.g. /data) rather than base_path
# (which includes usage/schema subdirs, e.g. /data/media/public).
# The subdirectories are created on first file write via mkdir(parents=True)
# in save_file(), so requiring them to exist beforehand would prevent
# file creation on fresh installs.
return (
self._base_dir.exists()
self.base_path.exists()
and (self._base_dir.is_mount() or (self._base_dir / self.usage.value).is_mount())
or (settings.DEBUG or settings.TEST)
)

View File

@@ -46,25 +46,3 @@ class PassthroughBackend(Backend):
) -> str:
"""Return the URL as-is for passthrough files."""
return name
def themed_urls(
self,
name: str,
request: HttpRequest | None = None,
) -> dict[str, str] | None:
"""Support themed URLs for external URLs with %(theme)s placeholder.
If the external URL contains %(theme)s, substitute it for each theme.
We can't verify that themed variants exist at the external location,
but we trust the user to provide valid URLs.
"""
from authentik.admin.files.backends.base import (
get_valid_themes,
has_theme_variable,
substitute_theme,
)
if not has_theme_variable(name):
return None
return {theme: substitute_theme(name, theme) for theme in get_valid_themes()}

View File

@@ -9,7 +9,7 @@ from botocore.exceptions import ClientError
from django.db import connection
from django.http.request import HttpRequest
from authentik.admin.files.backends.base import ManageableBackend, get_content_type
from authentik.admin.files.backends.base import ManageableBackend
from authentik.admin.files.usage import FileUsage
from authentik.lib.config import CONFIG
from authentik.lib.utils.time import timedelta_from_string
@@ -100,25 +100,13 @@ class S3Backend(ManageableBackend):
f"storage.{self.usage.value}.{self.name}.addressing_style",
CONFIG.get(f"storage.{self.name}.addressing_style", "auto"),
)
signature_version = CONFIG.get(
f"storage.{self.usage.value}.{self.name}.signature_version",
CONFIG.get(f"storage.{self.name}.signature_version", "s3v4"),
)
# Keep signature_version pass-through and let boto3/botocore handle it.
# In boto3's S3 configuration docs, `s3v4` (default) and deprecated `s3`
# are the documented values:
# https://github.com/boto/boto3/blob/791a3e8f36d83664a47b4281a0586b3546cef3ec/docs/source/guide/configuration.rst?plain=1#L398-L407
# Botocore also supports additional signer names, so we intentionally do
# not enforce a restricted allowlist here.
return self.session.client(
"s3",
endpoint_url=endpoint_url,
use_ssl=use_ssl,
region_name=region_name,
config=Config(
signature_version=signature_version, s3={"addressing_style": addressing_style}
),
config=Config(signature_version="s3v4", s3={"addressing_style": addressing_style}),
)
@property
@@ -185,22 +173,7 @@ class S3Backend(ManageableBackend):
if custom_domain:
parsed = urlsplit(url)
scheme = "https" if use_https else "http"
path = parsed.path
# When using path-style addressing, the presigned URL contains the bucket
# name in the path (e.g., /bucket-name/key). Since custom_domain must
# include the bucket name (per docs), strip it from the path to avoid
# duplication. See: https://github.com/goauthentik/authentik/issues/19521
# Check with trailing slash to ensure exact bucket name match
if path.startswith(f"/{self.bucket_name}/"):
path = path.removeprefix(f"/{self.bucket_name}")
# Normalize to avoid double slashes
custom_domain = custom_domain.rstrip("/")
if not path.startswith("/"):
path = f"/{path}"
url = f"{scheme}://{custom_domain}{path}?{parsed.query}"
url = f"{scheme}://{custom_domain}{parsed.path}?{parsed.query}"
return url
@@ -216,7 +189,6 @@ class S3Backend(ManageableBackend):
Key=f"{self.base_path}/{name}",
Body=content,
ACL="private",
ContentType=get_content_type(name),
)
@contextmanager
@@ -232,7 +204,6 @@ class S3Backend(ManageableBackend):
Key=f"{self.base_path}/{name}",
ExtraArgs={
"ACL": "private",
"ContentType": get_content_type(name),
},
)

View File

@@ -165,31 +165,3 @@ class TestFileBackend(FileTestFileBackendMixin, TestCase):
def test_file_exists_false(self):
"""Test file_exists returns False for nonexistent file"""
self.assertFalse(self.backend.file_exists("does_not_exist.txt"))
def test_themed_urls_without_theme_variable(self):
"""Test themed_urls returns None when filename has no %(theme)s"""
file_name = "logo.png"
result = self.backend.themed_urls(file_name)
self.assertIsNone(result)
def test_themed_urls_with_theme_variable(self):
"""Test themed_urls returns dict of URLs for each theme"""
file_name = "logo-%(theme)s.png"
result = self.backend.themed_urls(file_name)
self.assertIsInstance(result, dict)
self.assertIn("light", result)
self.assertIn("dark", result)
# Check URLs contain the substituted theme
self.assertIn("logo-light.png", result["light"])
self.assertIn("logo-dark.png", result["dark"])
def test_themed_urls_multiple_theme_variables(self):
"""Test themed_urls with multiple %(theme)s in path"""
file_name = "%(theme)s/logo-%(theme)s.svg"
result = self.backend.themed_urls(file_name)
self.assertIsInstance(result, dict)
self.assertIn("light/logo-light.svg", result["light"])
self.assertIn("dark/logo-dark.svg", result["dark"])

View File

@@ -1,6 +1,5 @@
from unittest import skipUnless
from botocore.exceptions import UnsupportedSignatureVersionError
from django.test import TestCase
from authentik.admin.files.tests.utils import FileTestS3BackendMixin, s3_test_server_available
@@ -82,27 +81,6 @@ class TestS3Backend(FileTestS3BackendMixin, TestCase):
self.assertIn("X-Amz-Signature=", url)
self.assertIn("test.png", url)
def test_client_signature_version_default_v4(self):
"""Test S3 client defaults to v4 signature when not configured."""
self.assertEqual(self.media_s3_backend.client.meta.config.signature_version, "s3v4")
@CONFIG.patch("storage.s3.signature_version", "s3")
def test_client_signature_version_global_override(self):
"""Test S3 client respects globally configured signature version."""
self.assertEqual(self.media_s3_backend.client.meta.config.signature_version, "s3")
@CONFIG.patch("storage.s3.signature_version", "s3v4")
@CONFIG.patch("storage.media.s3.signature_version", "s3")
def test_client_signature_version_media_override(self):
"""Test usage-specific signature version takes precedence over global."""
self.assertEqual(self.media_s3_backend.client.meta.config.signature_version, "s3")
@CONFIG.patch("storage.media.s3.signature_version", "not-a-real-signature")
def test_client_signature_version_unsupported(self):
"""Test unsupported signature version raises botocore error."""
with self.assertRaises(UnsupportedSignatureVersionError):
self.media_s3_backend.file_url("test.png", use_cache=False)
@CONFIG.patch("storage.s3.bucket_name", "test-bucket")
def test_file_exists_true(self):
"""Test file_exists returns True for existing file"""
@@ -132,106 +110,3 @@ class TestS3Backend(FileTestS3BackendMixin, TestCase):
"""Test S3Backend with REPORTS usage"""
self.assertEqual(self.reports_s3_backend.usage, FileUsage.REPORTS)
self.assertEqual(self.reports_s3_backend.base_path, "reports/public")
@CONFIG.patch("storage.s3.secure_urls", True)
@CONFIG.patch("storage.s3.addressing_style", "path")
def test_file_url_custom_domain_with_bucket_no_duplicate(self):
"""Test file_url doesn't duplicate bucket name when custom_domain includes bucket.
Regression test for https://github.com/goauthentik/authentik/issues/19521
When using:
- Path-style addressing (bucket name goes in URL path, not subdomain)
- Custom domain that includes the bucket name (e.g., s3.example.com/bucket-name)
The bucket name should NOT appear twice in the final URL.
Example of the bug:
- custom_domain = "s3.example.com/authentik-media"
- boto3 presigned URL = "http://s3.example.com/authentik-media/media/public/file.png?..."
- Buggy result = "https://s3.example.com/authentik-media/authentik-media/media/public/file.png?..."
"""
bucket_name = self.media_s3_bucket_name
# Custom domain includes the bucket name
custom_domain = f"localhost:8020/{bucket_name}"
with CONFIG.patch("storage.media.s3.custom_domain", custom_domain):
url = self.media_s3_backend.file_url("application-icons/test.svg", use_cache=False)
# The bucket name should appear exactly once in the URL path, not twice
bucket_occurrences = url.count(bucket_name)
self.assertEqual(
bucket_occurrences,
1,
f"Bucket name '{bucket_name}' appears {bucket_occurrences} times in URL, expected 1. "
f"URL: {url}",
)
def test_themed_urls_without_theme_variable(self):
"""Test themed_urls returns None when filename has no %(theme)s"""
result = self.media_s3_backend.themed_urls("logo.png")
self.assertIsNone(result)
def test_themed_urls_with_theme_variable(self):
"""Test themed_urls returns dict of presigned URLs for each theme"""
result = self.media_s3_backend.themed_urls("logo-%(theme)s.png")
self.assertIsInstance(result, dict)
self.assertIn("light", result)
self.assertIn("dark", result)
# Check URLs are valid presigned URLs with correct file paths
self.assertIn("logo-light.png", result["light"])
self.assertIn("logo-dark.png", result["dark"])
self.assertIn("X-Amz-Signature=", result["light"])
self.assertIn("X-Amz-Signature=", result["dark"])
def test_themed_urls_multiple_theme_variables(self):
"""Test themed_urls with multiple %(theme)s in path"""
result = self.media_s3_backend.themed_urls("%(theme)s/logo-%(theme)s.svg")
self.assertIsInstance(result, dict)
self.assertIn("light/logo-light.svg", result["light"])
self.assertIn("dark/logo-dark.svg", result["dark"])
def test_save_file_sets_content_type_svg(self):
"""Test save_file sets correct ContentType for SVG files"""
self.media_s3_backend.save_file("test.svg", b"<svg></svg>")
response = self.media_s3_backend.client.head_object(
Bucket=self.media_s3_bucket_name,
Key="media/public/test.svg",
)
self.assertEqual(response["ContentType"], "image/svg+xml")
def test_save_file_sets_content_type_png(self):
"""Test save_file sets correct ContentType for PNG files"""
self.media_s3_backend.save_file("test.png", b"\x89PNG\r\n\x1a\n")
response = self.media_s3_backend.client.head_object(
Bucket=self.media_s3_bucket_name,
Key="media/public/test.png",
)
self.assertEqual(response["ContentType"], "image/png")
def test_save_file_stream_sets_content_type(self):
"""Test save_file_stream sets correct ContentType"""
with self.media_s3_backend.save_file_stream("test.css") as f:
f.write(b"body { color: red; }")
response = self.media_s3_backend.client.head_object(
Bucket=self.media_s3_bucket_name,
Key="media/public/test.css",
)
self.assertEqual(response["ContentType"], "text/css")
def test_save_file_unknown_extension_octet_stream(self):
"""Test save_file sets octet-stream for unknown extensions"""
self.media_s3_backend.save_file("test.unknownext123", b"data")
response = self.media_s3_backend.client.head_object(
Bucket=self.media_s3_bucket_name,
Key="media/public/test.unknownext123",
)
self.assertEqual(response["ContentType"], "application/octet-stream")

View File

@@ -88,28 +88,6 @@ class FileManager:
LOGGER.warning(f"Could not find file backend for file: {name}")
return ""
def themed_urls(
self,
name: str | None,
request: HttpRequest | Request | None = None,
) -> dict[str, str] | None:
"""
Get URLs for each theme variant when filename contains %(theme)s.
Returns dict mapping theme to URL if %(theme)s present, None otherwise.
"""
if not name:
return None
if isinstance(request, Request):
request = request._request
for backend in self.backends:
if backend.supports_file(name):
return backend.themed_urls(name, request)
return None
def _check_manageable(self) -> None:
if not self.manageable:
raise ImproperlyConfigured("No file management backend configured.")

View File

@@ -5,6 +5,7 @@ from io import BytesIO
from django.test import TestCase
from django.urls import reverse
from authentik.admin.files.api import get_mime_from_filename
from authentik.admin.files.manager import FileManager
from authentik.admin.files.tests.utils import FileTestFileBackendMixin
from authentik.admin.files.usage import FileUsage
@@ -93,9 +94,8 @@ class TestFileAPI(FileTestFileBackendMixin, TestCase):
self.assertIn(
{
"name": "/static/authentik/sources/ldap.png",
"url": "http://testserver/static/authentik/sources/ldap.png",
"url": "/static/authentik/sources/ldap.png",
"mime_type": "image/png",
"themed_urls": None,
},
response.data,
)
@@ -129,9 +129,8 @@ class TestFileAPI(FileTestFileBackendMixin, TestCase):
self.assertIn(
{
"name": "/static/authentik/sources/ldap.png",
"url": "http://testserver/static/authentik/sources/ldap.png",
"url": "/static/authentik/sources/ldap.png",
"mime_type": "image/png",
"themed_urls": None,
},
response.data,
)
@@ -201,64 +200,30 @@ class TestFileAPI(FileTestFileBackendMixin, TestCase):
self.assertEqual(response.status_code, 400)
self.assertIn("field is required", str(response.data))
def test_list_files_includes_themed_urls_none(self):
"""Test listing files includes themed_urls as None for non-themed files"""
manager = FileManager(FileUsage.MEDIA)
file_name = "test-no-theme.png"
manager.save_file(file_name, b"test content")
response = self.client.get(
reverse("authentik_api:files", query={"search": file_name, "manageableOnly": "true"})
)
class TestGetMimeFromFilename(TestCase):
"""Test get_mime_from_filename function"""
self.assertEqual(response.status_code, 200)
file_entry = next((f for f in response.data if f["name"] == file_name), None)
self.assertIsNotNone(file_entry)
self.assertIn("themed_urls", file_entry)
self.assertIsNone(file_entry["themed_urls"])
def test_image_png(self):
"""Test PNG image MIME type"""
self.assertEqual(get_mime_from_filename("test.png"), "image/png")
manager.delete_file(file_name)
def test_image_jpeg(self):
"""Test JPEG image MIME type"""
self.assertEqual(get_mime_from_filename("test.jpg"), "image/jpeg")
def test_list_files_includes_themed_urls_dict(self):
"""Test listing files includes themed_urls as dict for themed files"""
manager = FileManager(FileUsage.MEDIA)
file_name = "logo-%(theme)s.svg"
manager.save_file("logo-light.svg", b"<svg>light</svg>")
manager.save_file("logo-dark.svg", b"<svg>dark</svg>")
manager.save_file(file_name, b"<svg>placeholder</svg>")
def test_image_svg(self):
"""Test SVG image MIME type"""
self.assertEqual(get_mime_from_filename("test.svg"), "image/svg+xml")
response = self.client.get(
reverse("authentik_api:files", query={"search": "%(theme)s", "manageableOnly": "true"})
)
def test_text_plain(self):
"""Test text file MIME type"""
self.assertEqual(get_mime_from_filename("test.txt"), "text/plain")
self.assertEqual(response.status_code, 200)
file_entry = next((f for f in response.data if f["name"] == file_name), None)
self.assertIsNotNone(file_entry)
self.assertIn("themed_urls", file_entry)
self.assertIsInstance(file_entry["themed_urls"], dict)
self.assertIn("light", file_entry["themed_urls"])
self.assertIn("dark", file_entry["themed_urls"])
def test_unknown_extension(self):
"""Test unknown extension returns octet-stream"""
self.assertEqual(get_mime_from_filename("test.unknown"), "application/octet-stream")
manager.delete_file(file_name)
manager.delete_file("logo-light.svg")
manager.delete_file("logo-dark.svg")
def test_upload_file_with_theme_variable(self):
"""Test uploading file with %(theme)s in name"""
manager = FileManager(FileUsage.MEDIA)
file_name = "brand-logo-%(theme)s.svg"
file_content = b"<svg></svg>"
response = self.client.post(
reverse("authentik_api:files"),
{
"file": BytesIO(file_content),
"name": file_name,
"usage": FileUsage.MEDIA.value,
},
format="multipart",
)
self.assertEqual(response.status_code, 200)
self.assertTrue(manager.file_exists(file_name))
manager.delete_file(file_name)
def test_no_extension(self):
"""Test no extension returns octet-stream"""
self.assertEqual(get_mime_from_filename("test"), "application/octet-stream")

View File

@@ -1,7 +1,6 @@
"""Test file service layer"""
from unittest import skipUnless
from urllib.parse import urlparse
from django.http import HttpRequest
from django.test import TestCase
@@ -105,71 +104,3 @@ class TestResolveFileUrlS3Backend(FileTestS3BackendMixin, TestCase):
# S3 URLs should be returned as-is (already absolute)
self.assertTrue(result.startswith("http://s3.test:8080/test"))
class TestThemedUrls(FileTestFileBackendMixin, TestCase):
"""Test FileManager.themed_urls method"""
def test_themed_urls_none_path(self):
"""Test themed_urls returns None for None path"""
manager = FileManager(FileUsage.MEDIA)
result = manager.themed_urls(None)
self.assertIsNone(result)
def test_themed_urls_empty_path(self):
"""Test themed_urls returns None for empty path"""
manager = FileManager(FileUsage.MEDIA)
result = manager.themed_urls("")
self.assertIsNone(result)
def test_themed_urls_no_theme_variable(self):
"""Test themed_urls returns None when no %(theme)s in path"""
manager = FileManager(FileUsage.MEDIA)
result = manager.themed_urls("logo.png")
self.assertIsNone(result)
def test_themed_urls_with_theme_variable(self):
"""Test themed_urls returns dict of URLs for each theme"""
manager = FileManager(FileUsage.MEDIA)
result = manager.themed_urls("logo-%(theme)s.png")
self.assertIsInstance(result, dict)
self.assertIn("light", result)
self.assertIn("dark", result)
self.assertIn("logo-light.png", result["light"])
self.assertIn("logo-dark.png", result["dark"])
def test_themed_urls_with_request(self):
"""Test themed_urls builds absolute URLs with request"""
mock_request = HttpRequest()
mock_request.META = {
"HTTP_HOST": "example.com",
"SERVER_NAME": "example.com",
}
manager = FileManager(FileUsage.MEDIA)
result = manager.themed_urls("logo-%(theme)s.svg", mock_request)
self.assertIsInstance(result, dict)
light_url = urlparse(result["light"])
dark_url = urlparse(result["dark"])
self.assertEqual(light_url.scheme, "http")
self.assertEqual(light_url.netloc, "example.com")
self.assertEqual(dark_url.scheme, "http")
self.assertEqual(dark_url.netloc, "example.com")
def test_themed_urls_passthrough_with_theme_variable(self):
"""Test themed_urls returns dict for passthrough URLs with %(theme)s"""
manager = FileManager(FileUsage.MEDIA)
# External URLs with %(theme)s should return themed URLs
result = manager.themed_urls("https://example.com/logo-%(theme)s.png")
self.assertIsInstance(result, dict)
self.assertEqual(result["light"], "https://example.com/logo-light.png")
self.assertEqual(result["dark"], "https://example.com/logo-dark.png")
def test_themed_urls_passthrough_without_theme_variable(self):
"""Test themed_urls returns None for passthrough URLs without %(theme)s"""
manager = FileManager(FileUsage.MEDIA)
# External URLs without %(theme)s should return None
result = manager.themed_urls("https://example.com/logo.png")
self.assertIsNone(result)

View File

@@ -62,10 +62,10 @@ class TestSanitizeFilePath(TestCase):
"test@file.png", # @
"test#file.png", # #
"test$file.png", # $
"test%file.png", # % (but %(theme)s is allowed)
"test%file.png", # %
"test&file.png", # &
"test*file.png", # *
"test(file).png", # parentheses (but %(theme)s is allowed)
"test(file).png", # parentheses
"test[file].png", # brackets
"test{file}.png", # braces
]
@@ -108,30 +108,3 @@ class TestSanitizeFilePath(TestCase):
with self.assertRaises(ValidationError):
validate_file_name(path)
def test_sanitize_theme_variable_valid(self):
"""Test sanitizing filename with %(theme)s variable"""
# These should all be valid
validate_file_name("logo-%(theme)s.png")
validate_file_name("brand/logo-%(theme)s.svg")
validate_file_name("images/icon-%(theme)s.png")
validate_file_name("%(theme)s/logo.png")
validate_file_name("brand/%(theme)s/logo.png")
def test_sanitize_theme_variable_multiple(self):
"""Test sanitizing filename with multiple %(theme)s variables"""
validate_file_name("%(theme)s/logo-%(theme)s.png")
def test_sanitize_theme_variable_invalid_format(self):
"""Test that partial or malformed theme variables are rejected"""
invalid_paths = [
"test%(theme.png", # missing )s
"test%theme)s.png", # missing (
"test%(themes).png", # wrong variable name
"test%(THEME)s.png", # wrong case
"test%()s.png", # empty variable name
]
for path in invalid_paths:
with self.assertRaises(ValidationError):
validate_file_name(path)

View File

@@ -4,7 +4,6 @@ from pathlib import PurePosixPath
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
from authentik.admin.files.backends.base import THEME_VARIABLE
from authentik.admin.files.backends.passthrough import PassthroughBackend
from authentik.admin.files.backends.static import StaticBackend
from authentik.admin.files.usage import FileUsage
@@ -40,17 +39,12 @@ def validate_upload_file_name(
if not name:
raise ValidationError(_("File name cannot be empty"))
# Allow %(theme)s placeholder for theme-specific files
# Replace with placeholder for validation, then check the result
name_for_validation = name.replace(THEME_VARIABLE, "theme")
# Same regex is used in the frontend as well (with %(theme)s handling)
if not re.match(r"^[a-zA-Z0-9._/-]+$", name_for_validation):
# Same regex is used in the frontend as well
if not re.match(r"^[a-zA-Z0-9._/-]+$", name):
raise ValidationError(
_(
"File name can only contain letters (a-z, A-Z), numbers (0-9), "
"dots (.), hyphens (-), underscores (_), forward slashes (/), "
"and the placeholder %(theme)s for theme-specific files"
"dots (.), hyphens (-), underscores (_), and forward slashes (/)"
)
)

View File

@@ -13,10 +13,10 @@ from rest_framework.exceptions import AuthenticationFailed
from rest_framework.request import Request
from structlog.stdlib import get_logger
from authentik.common.oauth.constants import SCOPE_AUTHENTIK_API
from authentik.core.middleware import CTX_AUTH_VIA
from authentik.core.models import Token, TokenIntents, User, UserTypes
from authentik.outposts.models import Outpost
from authentik.providers.oauth2.constants import SCOPE_AUTHENTIK_API
LOGGER = get_logger()
_tmp = Path(gettempdir())

View File

@@ -71,7 +71,7 @@ def postprocess_schema_responses(
def postprocess_schema_query_params(
result: dict[str, Any], generator: SchemaGenerator, **kwargs
) -> dict[str, Any]:
"""Optimize pagination parameters, instead of redeclaring parameters for each endpoint
"""Optimise pagination parameters, instead of redeclaring parameters for each endpoint
declare them globally and refer to them"""
LOGGER.debug("Deduplicating query parameters")
for path in result["paths"].values():

View File

@@ -11,12 +11,12 @@ from rest_framework.exceptions import AuthenticationFailed
from authentik.api.authentication import IPCUser, TokenAuthentication
from authentik.blueprints.tests import reconcile_app
from authentik.common.oauth.constants import SCOPE_AUTHENTIK_API
from authentik.core.models import Token, TokenIntents, UserTypes
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.lib.generators import generate_id
from authentik.outposts.apps import MANAGED_OUTPOST
from authentik.outposts.models import Outpost
from authentik.providers.oauth2.constants import SCOPE_AUTHENTIK_API
from authentik.providers.oauth2.models import AccessToken, OAuth2Provider

View File

@@ -1,8 +1,6 @@
"""Schema generation tests"""
from pathlib import Path
from tempfile import gettempdir
from uuid import uuid4
from django.core.management import call_command
from django.urls import reverse
@@ -31,14 +29,15 @@ class TestSchemaGeneration(APITestCase):
def test_build_schema(self):
"""Test schema build command"""
tmp = Path(gettempdir())
blueprint_file = tmp / f"{str(uuid4())}.json"
api_file = tmp / f"{str(uuid4())}.yml"
blueprint_file = Path("blueprints/schema.json")
api_file = Path("schema.yml")
blueprint_file.unlink()
api_file.unlink()
with (
CONFIG.patch("debug", True),
CONFIG.patch("tenants.enabled", True),
CONFIG.patch("outposts.disable_embedded_outpost", True),
):
call_command("build_schema", blueprint_file=blueprint_file, api_file=api_file)
call_command("build_schema")
self.assertTrue(blueprint_file.exists())
self.assertTrue(api_file.exists())

View File

@@ -18,7 +18,7 @@ entries:
name: foo
title: foo
permissions:
- permission: authentik_flows.view_flow
- permission: view_flow
user: !KeyOf user
- permission: authentik_flows.view_flow
- permission: view_flow
role: !KeyOf role

View File

@@ -9,7 +9,7 @@ from functools import reduce
from json import JSONDecodeError, loads
from operator import ixor
from os import getenv
from typing import Any, Literal
from typing import Any, Literal, Union
from uuid import UUID
from deepmerge import always_merger
@@ -43,6 +43,8 @@ def get_attrs(obj: SerializerModel) -> dict[str, Any]:
continue
if _field.read_only:
data.pop(field_name, None)
if _field.get_initial() == data.get(field_name, None):
data.pop(field_name, None)
if field_name.endswith("_set"):
data.pop(field_name, None)
return data
@@ -68,17 +70,19 @@ class BlueprintEntryDesiredState(Enum):
class BlueprintEntryPermission:
"""Describe object-level permissions"""
permission: str | YAMLTag
user: int | YAMLTag | None = field(default=None)
role: str | YAMLTag | None = field(default=None)
permission: Union[str, "YAMLTag"]
user: Union[int, "YAMLTag", None] = field(default=None)
role: Union[str, "YAMLTag", None] = field(default=None)
@dataclass
class BlueprintEntry:
"""Single entry of a blueprint"""
model: str | YAMLTag
state: BlueprintEntryDesiredState | YAMLTag = field(default=BlueprintEntryDesiredState.PRESENT)
model: Union[str, "YAMLTag"]
state: Union[BlueprintEntryDesiredState, "YAMLTag"] = field(
default=BlueprintEntryDesiredState.PRESENT
)
conditions: list[Any] = field(default_factory=list)
identifiers: dict[str, Any] = field(default_factory=dict)
attrs: dict[str, Any] | None = field(default_factory=dict)
@@ -92,7 +96,7 @@ class BlueprintEntry:
self.__tag_contexts: list[YAMLTagContext] = []
@staticmethod
def from_model(model: SerializerModel, *extra_identifier_names: str) -> BlueprintEntry:
def from_model(model: SerializerModel, *extra_identifier_names: str) -> "BlueprintEntry":
"""Convert a SerializerModel instance to a blueprint Entry"""
identifiers = {
"pk": model.pk,
@@ -110,8 +114,8 @@ class BlueprintEntry:
def get_tag_context(
self,
depth: int = 0,
context_tag_type: type[YAMLTagContext] | tuple[YAMLTagContext, ...] | None = None,
) -> YAMLTagContext:
context_tag_type: type["YAMLTagContext"] | tuple["YAMLTagContext", ...] | None = None,
) -> "YAMLTagContext":
"""Get a YAMLTagContext object located at a certain depth in the tag tree"""
if depth < 0:
raise ValueError("depth must be a positive number or zero")
@@ -126,7 +130,7 @@ class BlueprintEntry:
except IndexError as exc:
raise ValueError(f"invalid depth: {depth}. Max depth: {len(contexts) - 1}") from exc
def tag_resolver(self, value: Any, blueprint: Blueprint) -> Any:
def tag_resolver(self, value: Any, blueprint: "Blueprint") -> Any:
"""Check if we have any special tags that need handling"""
val = copy(value)
@@ -148,23 +152,23 @@ class BlueprintEntry:
return val
def get_attrs(self, blueprint: Blueprint) -> dict[str, Any]:
def get_attrs(self, blueprint: "Blueprint") -> dict[str, Any]:
"""Get attributes of this entry, with all yaml tags resolved"""
return self.tag_resolver(self.attrs, blueprint)
def get_identifiers(self, blueprint: Blueprint) -> dict[str, Any]:
def get_identifiers(self, blueprint: "Blueprint") -> dict[str, Any]:
"""Get attributes of this entry, with all yaml tags resolved"""
return self.tag_resolver(self.identifiers, blueprint)
def get_state(self, blueprint: Blueprint) -> BlueprintEntryDesiredState:
def get_state(self, blueprint: "Blueprint") -> BlueprintEntryDesiredState:
"""Get the blueprint state, with yaml tags resolved if present"""
return BlueprintEntryDesiredState(self.tag_resolver(self.state, blueprint))
def get_model(self, blueprint: Blueprint) -> str:
def get_model(self, blueprint: "Blueprint") -> str:
"""Get the blueprint model, with yaml tags resolved if present"""
return str(self.tag_resolver(self.model, blueprint))
def get_permissions(self, blueprint: Blueprint) -> Generator[BlueprintEntryPermission]:
def get_permissions(self, blueprint: "Blueprint") -> Generator[BlueprintEntryPermission]:
"""Get permissions of this entry, with all yaml tags resolved"""
for perm in self.permissions:
yield BlueprintEntryPermission(
@@ -173,7 +177,7 @@ class BlueprintEntry:
role=self.tag_resolver(perm.role, blueprint),
)
def check_all_conditions_match(self, blueprint: Blueprint) -> bool:
def check_all_conditions_match(self, blueprint: "Blueprint") -> bool:
"""Check all conditions of this entry match (evaluate to True)"""
return all(self.tag_resolver(self.conditions, blueprint))
@@ -228,7 +232,7 @@ class KeyOf(YAMLTag):
id_from: str
def __init__(self, loader: BlueprintLoader, node: ScalarNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: ScalarNode) -> None:
super().__init__()
self.id_from = node.value
@@ -254,7 +258,7 @@ class Env(YAMLTag):
key: str
default: Any | None
def __init__(self, loader: BlueprintLoader, node: ScalarNode | SequenceNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: ScalarNode | SequenceNode) -> None:
super().__init__()
self.default = None
if isinstance(node, ScalarNode):
@@ -273,7 +277,7 @@ class File(YAMLTag):
path: str
default: Any | None
def __init__(self, loader: BlueprintLoader, node: ScalarNode | SequenceNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: ScalarNode | SequenceNode) -> None:
super().__init__()
self.default = None
if isinstance(node, ScalarNode):
@@ -301,7 +305,7 @@ class Context(YAMLTag):
key: str
default: Any | None
def __init__(self, loader: BlueprintLoader, node: ScalarNode | SequenceNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: ScalarNode | SequenceNode) -> None:
super().__init__()
self.default = None
if isinstance(node, ScalarNode):
@@ -324,7 +328,7 @@ class ParseJSON(YAMLTag):
raw: str
def __init__(self, loader: BlueprintLoader, node: ScalarNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: ScalarNode) -> None:
super().__init__()
self.raw = node.value
@@ -341,7 +345,7 @@ class Format(YAMLTag):
format_string: str
args: list[Any]
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
super().__init__()
self.format_string = loader.construct_object(node.value[0])
self.args = []
@@ -368,7 +372,7 @@ class Find(YAMLTag):
model_name: str | YAMLTag
conditions: list[list]
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
super().__init__()
self.model_name = loader.construct_object(node.value[0])
self.conditions = []
@@ -440,7 +444,7 @@ class Condition(YAMLTag):
"XNOR": lambda args: not (reduce(ixor, args) if len(args) > 1 else args[0]),
}
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
super().__init__()
self.mode = loader.construct_object(node.value[0])
self.args = []
@@ -474,7 +478,7 @@ class If(YAMLTag):
when_true: Any
when_false: Any
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
super().__init__()
self.condition = loader.construct_object(node.value[0])
if len(node.value) == 1:
@@ -514,7 +518,7 @@ class Enumerate(YAMLTag, YAMLTagContext):
),
}
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
super().__init__()
self.iterable = loader.construct_object(node.value[0])
self.output_body = loader.construct_object(node.value[1])
@@ -580,7 +584,7 @@ class EnumeratedItem(YAMLTag):
_SUPPORTED_CONTEXT_TAGS = (Enumerate,)
def __init__(self, _loader: BlueprintLoader, node: ScalarNode) -> None:
def __init__(self, _loader: "BlueprintLoader", node: ScalarNode) -> None:
super().__init__()
self.depth = int(node.value)
@@ -636,7 +640,7 @@ class AtIndex(YAMLTag):
attribute: int | str | YAMLTag
default: Any | UNSET
def __init__(self, loader: BlueprintLoader, node: SequenceNode) -> None:
def __init__(self, loader: "BlueprintLoader", node: SequenceNode) -> None:
super().__init__()
self.obj = loader.construct_object(node.value[0])
self.attribute = loader.construct_object(node.value[1])
@@ -753,7 +757,7 @@ class EntryInvalidError(SentryIgnoredException):
@staticmethod
def from_entry(
msg_or_exc: str | Exception, entry: BlueprintEntry, *args, **kwargs
) -> EntryInvalidError:
) -> "EntryInvalidError":
"""Create EntryInvalidError with the context of an entry"""
error = EntryInvalidError(msg_or_exc, *args, **kwargs)
if isinstance(msg_or_exc, ValidationError):

View File

@@ -15,7 +15,7 @@ from django.db.models import Model
from django.db.models.query_utils import Q
from django.db.transaction import atomic
from django.db.utils import IntegrityError
from guardian.models import RoleObjectPermission
from guardian.models import RoleObjectPermission, UserObjectPermission
from rest_framework.exceptions import ValidationError
from rest_framework.serializers import BaseSerializer, Serializer
from structlog.stdlib import BoundLogger, get_logger
@@ -41,6 +41,7 @@ from authentik.core.models import (
UserSourceConnection,
)
from authentik.endpoints.models import Connector
from authentik.enterprise.license import LicenseKey
from authentik.events.logs import LogEvent, capture_logs
from authentik.events.utils import cleanse_dict
from authentik.flows.models import Stage
@@ -70,6 +71,7 @@ def excluded_models() -> list[type[Model]]:
ContentType,
Permission,
RoleObjectPermission,
UserObjectPermission,
# Base classes
Provider,
Source,
@@ -139,22 +141,13 @@ class Importer:
def default_context(self):
"""Default context"""
context = {
return {
"goauthentik.io/enterprise/licensed": LicenseKey.get_total().status().is_valid,
"goauthentik.io/rbac/models": rbac_models(),
"goauthentik.io/enterprise/licensed": False,
}
try:
from authentik.enterprise.license import LicenseKey
context["goauthentik.io/enterprise/licensed"] = (
LicenseKey.get_total().status().is_valid,
)
except ModuleNotFoundError:
pass
return context
@staticmethod
def from_string(yaml_input: str, context: dict | None = None) -> Importer:
def from_string(yaml_input: str, context: dict | None = None) -> "Importer":
"""Parse YAML string and create blueprint importer from it"""
import_dict = load(yaml_input, BlueprintLoader)
try:
@@ -272,7 +265,7 @@ class Importer:
and entry.state != BlueprintEntryDesiredState.MUST_CREATED
):
self.logger.debug(
"Initialize serializer with instance",
"Initialise serializer with instance",
model=model,
instance=model_instance,
pk=model_instance.pk,
@@ -290,7 +283,7 @@ class Importer:
)
else:
self.logger.debug(
"Initialized new serializer instance",
"Initialised new serializer instance",
model=model,
**cleanse_dict(updated_identifiers),
)

View File

@@ -23,7 +23,7 @@ class ApplyBlueprintMetaSerializer(PassiveSerializer):
# We cannot override `instance` as that will confuse rest_framework
# and make it attempt to update the instance
blueprint_instance: BlueprintInstance
blueprint_instance: "BlueprintInstance"
def validate(self, attrs):
from authentik.blueprints.models import BlueprintInstance

View File

@@ -6,12 +6,7 @@ from django.db import models
from drf_spectacular.utils import extend_schema, extend_schema_field
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.fields import (
CharField,
ChoiceField,
ListField,
SerializerMethodField,
)
from rest_framework.fields import CharField, ChoiceField, ListField, SerializerMethodField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import AllowAny
from rest_framework.request import Request
@@ -21,7 +16,7 @@ from rest_framework.viewsets import ModelViewSet
from authentik.brands.models import Brand
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer, PassiveSerializer, ThemedUrlsSerializer
from authentik.core.api.utils import ModelSerializer, PassiveSerializer
from authentik.rbac.filters import SecretKeyFilter
from authentik.tenants.api.settings import FlagJSONField
from authentik.tenants.flags import Flag
@@ -95,9 +90,7 @@ class CurrentBrandSerializer(PassiveSerializer):
matched_domain = CharField(source="domain")
branding_title = CharField()
branding_logo = CharField(source="branding_logo_url")
branding_logo_themed_urls = ThemedUrlsSerializer(read_only=True, allow_null=True)
branding_favicon = CharField(source="branding_favicon_url")
branding_favicon_themed_urls = ThemedUrlsSerializer(read_only=True, allow_null=True)
branding_custom_css = CharField()
ui_footer_links = ListField(
child=FooterLinkSerializer(),
@@ -124,8 +117,10 @@ class CurrentBrandSerializer(PassiveSerializer):
@extend_schema_field(field=FlagJSONField)
def get_flags(self, _):
values = {}
for flag in Flag.available(visibility="public"):
values[flag().key] = flag.get()
for flag in Flag.available():
_flag = flag()
if _flag.visibility == "public":
values[_flag.key] = _flag.get()
return values

View File

@@ -89,26 +89,14 @@ class Brand(SerializerModel):
"""Get branding_logo URL"""
return get_file_manager(FileUsage.MEDIA).file_url(self.branding_logo)
def branding_logo_themed_urls(self) -> dict[str, str] | None:
"""Get themed URLs for branding_logo if it contains %(theme)s"""
return get_file_manager(FileUsage.MEDIA).themed_urls(self.branding_logo)
def branding_favicon_url(self) -> str:
"""Get branding_favicon URL"""
return get_file_manager(FileUsage.MEDIA).file_url(self.branding_favicon)
def branding_favicon_themed_urls(self) -> dict[str, str] | None:
"""Get themed URLs for branding_favicon if it contains %(theme)s"""
return get_file_manager(FileUsage.MEDIA).themed_urls(self.branding_favicon)
def branding_default_flow_background_url(self) -> str:
"""Get branding_default_flow_background URL"""
return get_file_manager(FileUsage.MEDIA).file_url(self.branding_default_flow_background)
def branding_default_flow_background_themed_urls(self) -> dict[str, str] | None:
"""Get themed URLs for branding_default_flow_background if it contains %(theme)s"""
return get_file_manager(FileUsage.MEDIA).themed_urls(self.branding_default_flow_background)
@property
def serializer(self) -> type[Serializer]:
from authentik.brands.api import BrandSerializer

View File

@@ -6,6 +6,7 @@ from django.urls import reverse
from rest_framework.test import APITestCase
from authentik.blueprints.tests import apply_blueprint
from authentik.brands.api import Themes
from authentik.brands.models import Brand
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_brand
@@ -21,8 +22,10 @@ class TestBrands(APITestCase):
def setUp(self):
super().setUp()
self.default_flags = {}
for flag in Flag.available(visibility="public"):
self.default_flags[flag().key] = flag.get()
for flag in Flag.available():
_flag = flag()
if _flag.visibility == "public":
self.default_flags[_flag.key] = _flag.get()
Brand.objects.all().delete()
def test_current_brand(self):
@@ -32,14 +35,12 @@ class TestBrands(APITestCase):
self.client.get(reverse("authentik_api:brand-current")).content.decode(),
{
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
"branding_logo_themed_urls": None,
"branding_favicon": "/static/dist/assets/icons/icon.png",
"branding_favicon_themed_urls": None,
"branding_title": "authentik",
"branding_custom_css": "",
"matched_domain": brand.domain,
"ui_footer_links": [],
"ui_theme": "automatic",
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
@@ -54,14 +55,12 @@ class TestBrands(APITestCase):
).content.decode(),
{
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
"branding_logo_themed_urls": None,
"branding_favicon": "/static/dist/assets/icons/icon.png",
"branding_favicon_themed_urls": None,
"branding_title": "custom",
"branding_custom_css": "",
"matched_domain": "bar.baz",
"ui_footer_links": [],
"ui_theme": "automatic",
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
@@ -73,14 +72,12 @@ class TestBrands(APITestCase):
self.client.get(reverse("authentik_api:brand-current")).content.decode(),
{
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
"branding_logo_themed_urls": None,
"branding_favicon": "/static/dist/assets/icons/icon.png",
"branding_favicon_themed_urls": None,
"branding_title": "authentik",
"branding_custom_css": "",
"matched_domain": "fallback",
"ui_footer_links": [],
"ui_theme": "automatic",
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
@@ -97,14 +94,12 @@ class TestBrands(APITestCase):
response,
{
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
"branding_logo_themed_urls": None,
"branding_favicon": "/static/dist/assets/icons/icon.png",
"branding_favicon_themed_urls": None,
"branding_title": "authentik",
"branding_custom_css": "",
"matched_domain": "authentik-default",
"ui_footer_links": [],
"ui_theme": "automatic",
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
@@ -122,14 +117,12 @@ class TestBrands(APITestCase):
response,
{
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
"branding_logo_themed_urls": None,
"branding_favicon": "/static/dist/assets/icons/icon.png",
"branding_favicon_themed_urls": None,
"branding_title": "authentik",
"branding_custom_css": "",
"matched_domain": "authentik-default",
"ui_footer_links": [],
"ui_theme": "automatic",
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
@@ -140,14 +133,12 @@ class TestBrands(APITestCase):
).content.decode(),
{
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
"branding_logo_themed_urls": None,
"branding_favicon": "/static/dist/assets/icons/icon.png",
"branding_favicon_themed_urls": None,
"branding_title": "custom",
"branding_custom_css": "",
"matched_domain": "bar.baz",
"ui_footer_links": [],
"ui_theme": "automatic",
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
@@ -163,14 +154,12 @@ class TestBrands(APITestCase):
).content.decode(),
{
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
"branding_logo_themed_urls": None,
"branding_favicon": "/static/dist/assets/icons/icon.png",
"branding_favicon_themed_urls": None,
"branding_title": "custom-strong",
"branding_custom_css": "",
"matched_domain": "foo.bar.baz",
"ui_footer_links": [],
"ui_theme": "automatic",
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
@@ -186,14 +175,12 @@ class TestBrands(APITestCase):
).content.decode(),
{
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
"branding_logo_themed_urls": None,
"branding_favicon": "/static/dist/assets/icons/icon.png",
"branding_favicon_themed_urls": None,
"branding_title": "custom-weak",
"branding_custom_css": "",
"matched_domain": "bar.baz",
"ui_footer_links": [],
"ui_theme": "automatic",
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},
@@ -269,14 +256,12 @@ class TestBrands(APITestCase):
self.client.get(reverse("authentik_api:brand-current")).content.decode(),
{
"branding_logo": "https://goauthentik.io/img/icon.png",
"branding_logo_themed_urls": None,
"branding_favicon": "https://goauthentik.io/img/icon.png",
"branding_favicon_themed_urls": None,
"branding_title": "authentik",
"branding_custom_css": "",
"matched_domain": brand.domain,
"ui_footer_links": [],
"ui_theme": "automatic",
"ui_theme": Themes.AUTOMATIC,
"default_locale": "",
"flags": self.default_flags,
},

View File

@@ -3,7 +3,7 @@
from typing import Any
from django.db.models import Case, F, IntegerField, Q, Value, When
from django.db.models.functions import Concat, Length
from django.db.models.functions import Length
from django.http.request import HttpRequest
from django.utils.html import _json_script_escapes
from django.utils.safestring import mark_safe
@@ -26,8 +26,7 @@ def get_brand_for_request(request: HttpRequest) -> Brand:
domain_length=Length("domain"),
match_priority=Case(
When(
condition=Q(host_domain__iexact=F("domain"))
| Q(host_domain__iendswith=Concat(Value("."), F("domain"))),
condition=Q(host_domain__iendswith=F("domain")),
then=F("domain_length"),
),
default=Value(-1),

View File

@@ -24,7 +24,7 @@ from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.users import UserSerializer
from authentik.core.api.utils import ModelSerializer, ThemedUrlsSerializer
from authentik.core.api.utils import ModelSerializer
from authentik.core.models import Application, User
from authentik.events.logs import LogEventSerializer, capture_logs
from authentik.policies.api.exec import PolicyTestResultSerializer
@@ -53,9 +53,6 @@ class ApplicationSerializer(ModelSerializer):
)
meta_icon_url = ReadOnlyField(source="get_meta_icon")
meta_icon_themed_urls = ThemedUrlsSerializer(
source="get_meta_icon_themed_urls", read_only=True, allow_null=True
)
def get_launch_url(self, app: Application) -> str | None:
"""Allow formatting of launch URL"""
@@ -66,7 +63,7 @@ class ApplicationSerializer(ModelSerializer):
user = self.context["request"].user
# Cache serialized user data to avoid N+1 when formatting launch URLs
# for multiple applications. UserSerializer accesses user.groups which
# for multiple applications. UserSerializer accesses user.ak_groups which
# would otherwise trigger a query for each application.
if user is not None:
if "_cached_user_data" not in self.context:
@@ -105,7 +102,6 @@ class ApplicationSerializer(ModelSerializer):
"meta_launch_url",
"meta_icon",
"meta_icon_url",
"meta_icon_themed_urls",
"meta_description",
"meta_publisher",
"policy_engine_mode",
@@ -154,14 +150,14 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
return queryset
def _get_allowed_applications(
self, paginated_apps: Iterator[Application], user: User | None = None
self, pagined_apps: Iterator[Application], user: User | None = None
) -> list[Application]:
applications = []
request = self.request._request
if user:
request = copy(request)
request.user = user
for application in paginated_apps:
for application in pagined_apps:
engine = PolicyEngine(application, request.user, request)
engine.build()
if engine.passing:

View File

@@ -2,31 +2,18 @@
from typing import TypedDict
from drf_spectacular.utils import (
extend_schema,
inline_serializer,
)
from rest_framework import mixins, serializers
from rest_framework.decorators import action
from rest_framework import mixins
from rest_framework.fields import SerializerMethodField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import (
CharField,
DateTimeField,
IPAddressField,
ListField,
)
from rest_framework.serializers import CharField, DateTimeField, IPAddressField
from rest_framework.viewsets import GenericViewSet
from ua_parser import user_agent_parser
from authentik.api.validation import validate
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer, PassiveSerializer
from authentik.core.api.utils import ModelSerializer
from authentik.core.models import AuthenticatedSession
from authentik.events.context_processors.asn import ASN_CONTEXT_PROCESSOR, ASNDict
from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR, GeoIPDict
from authentik.rbac.decorators import permission_required
class UserAgentDeviceDict(TypedDict):
@@ -65,14 +52,6 @@ class UserAgentDict(TypedDict):
string: str
class BulkDeleteSessionSerializer(PassiveSerializer):
"""Serializer for bulk deleting authenticated sessions by user"""
user_pks = ListField(
child=serializers.IntegerField(), help_text="List of user IDs to revoke all sessions for"
)
class AuthenticatedSessionSerializer(ModelSerializer):
"""AuthenticatedSession Serializer"""
@@ -136,22 +115,3 @@ class AuthenticatedSessionViewSet(
filterset_fields = ["user__username", "session__last_ip", "session__last_user_agent"]
ordering = ["user__username"]
owner_field = "user"
@permission_required("authentik_core.delete_authenticatedsession")
@extend_schema(
parameters=[BulkDeleteSessionSerializer],
responses={
200: inline_serializer(
"BulkDeleteSessionResponse",
{"deleted": serializers.IntegerField()},
),
},
)
@validate(BulkDeleteSessionSerializer, location="query")
@action(detail=False, methods=["DELETE"], pagination_class=None, filter_backends=[])
def bulk_delete(self, request: Request, *, query: BulkDeleteSessionSerializer) -> Response:
"""Bulk revoke all sessions for multiple users"""
user_pks = query.validated_data.get("user_pks", [])
deleted_count, _ = AuthenticatedSession.objects.filter(user_id__in=user_pks).delete()
return Response({"deleted": deleted_count}, status=200)

View File

@@ -16,15 +16,11 @@ from rest_framework.viewsets import ViewSet
from authentik.api.validation import validate
from authentik.core.api.users import ParamUserSerializer
from authentik.core.api.utils import MetaNameSerializer
from authentik.enterprise.stages.authenticator_endpoint_gdtc.models import EndpointDevice
from authentik.stages.authenticator import device_classes, devices_for_user
from authentik.stages.authenticator.models import Device
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
try:
from authentik.enterprise.stages.authenticator_endpoint_gdtc.models import EndpointDevice
except ModuleNotFoundError:
EndpointDevice = None
class DeviceSerializer(MetaNameSerializer):
"""Serializer for authenticator devices"""
@@ -47,7 +43,7 @@ class DeviceSerializer(MetaNameSerializer):
"""Get extra description"""
if isinstance(instance, WebAuthnDevice):
return instance.device_type.description if instance.device_type else None
if EndpointDevice and isinstance(instance, EndpointDevice):
if isinstance(instance, EndpointDevice):
return instance.data.get("deviceSignals", {}).get("deviceModel")
return None
@@ -55,7 +51,7 @@ class DeviceSerializer(MetaNameSerializer):
"""Get external Device ID"""
if isinstance(instance, WebAuthnDevice):
return instance.device_type.aaguid if instance.device_type else None
if EndpointDevice and isinstance(instance, EndpointDevice):
if isinstance(instance, EndpointDevice):
return instance.data.get("deviceSignals", {}).get("deviceModel")
return None

View File

@@ -85,7 +85,6 @@ class GroupSerializer(ModelSerializer):
source="roles",
required=False,
)
inherited_roles_obj = SerializerMethodField(allow_null=True)
num_pk = IntegerField(read_only=True)
@property
@@ -109,13 +108,6 @@ class GroupSerializer(ModelSerializer):
return True
return str(request.query_params.get("include_parents", "false")).lower() == "true"
@property
def _should_include_inherited_roles(self) -> bool:
request: Request = self.context.get("request", None)
if not request:
return True
return str(request.query_params.get("include_inherited_roles", "false")).lower() == "true"
@extend_schema_field(PartialUserSerializer(many=True))
def get_users_obj(self, instance: Group) -> list[PartialUserSerializer] | None:
if not self._should_include_users:
@@ -134,15 +126,6 @@ class GroupSerializer(ModelSerializer):
return None
return RelatedGroupSerializer(instance.parents, many=True).data
@extend_schema_field(RoleSerializer(many=True))
def get_inherited_roles_obj(self, instance: Group) -> list | None:
"""Return only inherited roles from ancestor groups (excludes direct roles)"""
if not self._should_include_inherited_roles:
return None
direct_role_pks = instance.roles.values_list("pk", flat=True)
inherited_roles = instance.all_roles().exclude(pk__in=direct_role_pks)
return RoleSerializer(inherited_roles, many=True).data
def validate_is_superuser(self, superuser: bool):
"""Ensure that the user creating this group has permissions to set the superuser flag"""
request: Request = self.context.get("request", None)
@@ -184,7 +167,6 @@ class GroupSerializer(ModelSerializer):
"attributes",
"roles",
"roles_obj",
"inherited_roles_obj",
"children",
"children_obj",
]
@@ -307,7 +289,6 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
OpenApiParameter("include_users", bool, default=True),
OpenApiParameter("include_children", bool, default=False),
OpenApiParameter("include_parents", bool, default=False),
OpenApiParameter("include_inherited_roles", bool, default=False),
]
)
def list(self, request, *args, **kwargs):
@@ -318,7 +299,6 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
OpenApiParameter("include_users", bool, default=True),
OpenApiParameter("include_children", bool, default=False),
OpenApiParameter("include_parents", bool, default=False),
OpenApiParameter("include_inherited_roles", bool, default=False),
]
)
def retrieve(self, request, *args, **kwargs):

View File

@@ -10,6 +10,7 @@ from rest_framework.request import Request
from rest_framework.response import Response
from authentik.core.api.utils import PassiveSerializer
from authentik.enterprise.apps import EnterpriseConfig
from authentik.lib.models import DeprecatedMixin
from authentik.lib.utils.reflection import all_subclasses
@@ -60,25 +61,19 @@ class TypesMixin:
continue
instance = subclass()
try:
type_signature = {
"name": subclass._meta.verbose_name,
"description": subclass.__doc__,
"component": instance.component,
"model_name": subclass._meta.model_name,
"icon_url": getattr(instance, "icon_url", None),
"requires_enterprise": False,
"deprecated": isinstance(instance, DeprecatedMixin),
}
try:
from authentik.enterprise.apps import EnterpriseConfig
type_signature["requires_enterprise"] = isinstance(
subclass._meta.app_config, EnterpriseConfig
)
except ModuleNotFoundError:
pass
data.append(type_signature)
data.append(
{
"name": subclass._meta.verbose_name,
"description": subclass.__doc__,
"component": instance.component,
"model_name": subclass._meta.model_name,
"icon_url": getattr(instance, "icon_url", None),
"requires_enterprise": isinstance(
subclass._meta.app_config, EnterpriseConfig
),
"deprecated": isinstance(instance, DeprecatedMixin),
}
)
except NotImplementedError:
continue
if additional:

View File

@@ -18,14 +18,10 @@ from authentik.core.models import Provider
class ProviderSerializer(ModelSerializer, MetaNameSerializer):
"""Provider Serializer"""
assigned_application_slug = ReadOnlyField(source="application.slug", allow_null=True)
assigned_application_name = ReadOnlyField(source="application.name", allow_null=True)
assigned_backchannel_application_slug = ReadOnlyField(
source="backchannel_application.slug", allow_null=True
)
assigned_backchannel_application_name = ReadOnlyField(
source="backchannel_application.name", allow_null=True
)
assigned_application_slug = ReadOnlyField(source="application.slug")
assigned_application_name = ReadOnlyField(source="application.name")
assigned_backchannel_application_slug = ReadOnlyField(source="backchannel_application.slug")
assigned_backchannel_application_name = ReadOnlyField(source="backchannel_application.name")
component = SerializerMethodField()

View File

@@ -14,7 +14,7 @@ from structlog.stdlib import get_logger
from authentik.core.api.object_types import TypesMixin
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import MetaNameSerializer, ModelSerializer, ThemedUrlsSerializer
from authentik.core.api.utils import MetaNameSerializer, ModelSerializer
from authentik.core.models import GroupSourceConnection, Source, UserSourceConnection
from authentik.core.types import UserSettingSerializer
from authentik.policies.engine import PolicyEngine
@@ -28,7 +28,6 @@ class SourceSerializer(ModelSerializer, MetaNameSerializer):
managed = ReadOnlyField()
component = SerializerMethodField()
icon_url = ReadOnlyField()
icon_themed_urls = ThemedUrlsSerializer(read_only=True, allow_null=True)
def get_component(self, obj: Source) -> str:
"""Get object component so that we know how to edit the object"""
@@ -58,7 +57,6 @@ class SourceSerializer(ModelSerializer, MetaNameSerializer):
"user_path_template",
"icon",
"icon_url",
"icon_themed_urls",
]

View File

@@ -75,8 +75,7 @@ class TokenSerializer(ManagedSerializer, ModelSerializer):
except ValueError:
pass
expires = attrs.get("expires")
if expires is not None and expires > max_token_lifetime_dt:
if "expires" in attrs and attrs.get("expires") > max_token_lifetime_dt:
raise ValidationError(
{
"expires": (

View File

@@ -30,6 +30,7 @@ from drf_spectacular.utils import (
extend_schema_field,
inline_serializer,
)
from guardian.shortcuts import get_objects_for_user
from rest_framework.authentication import SessionAuthentication
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
@@ -41,7 +42,6 @@ from rest_framework.fields import (
IntegerField,
ListField,
SerializerMethodField,
UUIDField,
)
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
@@ -72,14 +72,12 @@ from authentik.core.middleware import (
from authentik.core.models import (
USER_ATTRIBUTE_TOKEN_EXPIRING,
USER_PATH_SERVICE_ACCOUNT,
USERNAME_MAX_LENGTH,
Group,
Session,
Token,
TokenIntents,
User,
UserTypes,
default_token_duration,
)
from authentik.endpoints.connectors.agent.auth import AgentAuth
from authentik.events.models import Event, EventAction
@@ -89,7 +87,6 @@ from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner
from authentik.flows.views.executor import QS_KEY_TOKEN
from authentik.lib.avatars import get_avatar
from authentik.lib.utils.reflection import ConditionalInheritance
from authentik.lib.utils.time import timedelta_from_string, timedelta_string_validator
from authentik.rbac.api.roles import RoleSerializer
from authentik.rbac.decorators import permission_required
from authentik.rbac.models import Role, get_permission_choices
@@ -132,6 +129,7 @@ class UserSerializer(ModelSerializer):
groups = PrimaryKeyRelatedField(
allow_empty=True,
many=True,
source="ak_groups",
queryset=Group.objects.all().order_by("name"),
default=list,
)
@@ -145,7 +143,7 @@ class UserSerializer(ModelSerializer):
roles_obj = SerializerMethodField(allow_null=True)
uid = CharField(read_only=True)
username = CharField(
max_length=USERNAME_MAX_LENGTH,
max_length=150,
validators=[UniqueValidator(queryset=User.objects.all().order_by("username"))],
)
@@ -167,7 +165,7 @@ class UserSerializer(ModelSerializer):
def get_groups_obj(self, instance: User) -> list[PartialGroupSerializer] | None:
if not self._should_include_groups:
return None
return PartialGroupSerializer(instance.groups, many=True).data
return PartialGroupSerializer(instance.ak_groups, many=True).data
@extend_schema_field(RoleSerializer(many=True))
def get_roles_obj(self, instance: User) -> list[RoleSerializer] | None:
@@ -241,14 +239,14 @@ class UserSerializer(ModelSerializer):
and self.instance.type == UserTypes.INTERNAL_SERVICE_ACCOUNT
and user_type != UserTypes.INTERNAL_SERVICE_ACCOUNT.value
):
raise ValidationError(_("Can't change internal service account to other user type."))
raise ValidationError("Can't change internal service account to other user type.")
if not self.instance and user_type == UserTypes.INTERNAL_SERVICE_ACCOUNT.value:
raise ValidationError(_("Setting a user to internal service account is not allowed."))
raise ValidationError("Setting a user to internal service account is not allowed.")
return user_type
def validate(self, attrs: dict) -> dict:
if self.instance and self.instance.type == UserTypes.INTERNAL_SERVICE_ACCOUNT:
raise ValidationError(_("Can't modify internal service account users"))
raise ValidationError("Can't modify internal service account users")
return super().validate(attrs)
class Meta:
@@ -400,18 +398,6 @@ class UserServiceAccountSerializer(PassiveSerializer):
)
class UserRecoveryLinkSerializer(PassiveSerializer):
"""Payload to create a recovery link"""
token_duration = CharField(required=False)
class UserRecoveryEmailSerializer(UserRecoveryLinkSerializer):
"""Payload to create and email a recovery link"""
email_stage = UUIDField()
class UsersFilter(FilterSet):
"""Filter for users"""
@@ -430,12 +416,7 @@ class UsersFilter(FilterSet):
last_updated = IsoDateTimeFilter(field_name="last_updated")
last_updated__gt = IsoDateTimeFilter(field_name="last_updated", lookup_expr="gt")
last_login__lt = IsoDateTimeFilter(field_name="last_login", lookup_expr="lt")
last_login = IsoDateTimeFilter(field_name="last_login")
last_login__gt = IsoDateTimeFilter(field_name="last_login", lookup_expr="gt")
last_login__isnull = BooleanFilter(field_name="last_login", lookup_expr="isnull")
is_superuser = BooleanFilter(field_name="groups", method="filter_is_superuser")
is_superuser = BooleanFilter(field_name="ak_groups", method="filter_is_superuser")
uuid = UUIDFilter(field_name="uuid")
path = CharFilter(field_name="path")
@@ -444,12 +425,12 @@ class UsersFilter(FilterSet):
type = MultipleChoiceFilter(choices=UserTypes.choices, field_name="type")
groups_by_name = ModelMultipleChoiceFilter(
field_name="groups__name",
field_name="ak_groups__name",
to_field_name="name",
queryset=Group.objects.all().order_by("name"),
)
groups_by_pk = ModelMultipleChoiceFilter(
field_name="groups",
field_name="ak_groups",
queryset=Group.objects.all().order_by("name"),
)
@@ -465,22 +446,22 @@ class UsersFilter(FilterSet):
def filter_is_superuser(self, queryset, name, value):
if value:
return queryset.filter(groups__is_superuser=True).distinct()
return queryset.exclude(groups__is_superuser=True).distinct()
return queryset.filter(ak_groups__is_superuser=True).distinct()
return queryset.exclude(ak_groups__is_superuser=True).distinct()
def filter_attributes(self, queryset, name, value):
"""Filter attributes by query args"""
try:
value = loads(value)
except ValueError:
raise ValidationError(_("filter: failed to parse JSON")) from None
raise ValidationError(detail="filter: failed to parse JSON") from None
if not isinstance(value, dict):
raise ValidationError(_("filter: value must be key:value mapping"))
raise ValidationError(detail="filter: value must be key:value mapping")
qs = {}
for key, _value in value.items():
qs[f"attributes__{key}"] = _value
try:
__ = len(queryset.filter(**qs))
_ = len(queryset.filter(**qs))
return queryset.filter(**qs)
except ValueError:
return queryset
@@ -492,7 +473,6 @@ class UsersFilter(FilterSet):
"email",
"date_joined",
"last_updated",
"last_login",
"name",
"is_active",
"is_superuser",
@@ -513,7 +493,7 @@ class UserViewSet(
"""User Viewset"""
queryset = User.objects.none()
ordering = ["username", "date_joined", "last_updated", "last_login"]
ordering = ["username", "date_joined", "last_updated"]
serializer_class = UserSerializer
filterset_class = UsersFilter
search_fields = ["email", "name", "uuid", "username"]
@@ -544,7 +524,7 @@ class UserViewSet(
def get_queryset(self):
base_qs = User.objects.all().exclude_anonymous()
if self.serializer_class(context={"request": self.request})._should_include_groups:
base_qs = base_qs.prefetch_related("groups")
base_qs = base_qs.prefetch_related("ak_groups")
if self.serializer_class(context={"request": self.request})._should_include_roles:
base_qs = base_qs.prefetch_related("roles")
return base_qs
@@ -558,16 +538,14 @@ class UserViewSet(
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
def _create_recovery_link(
self, token_duration: str | None, for_email=False
) -> tuple[str, Token]:
def _create_recovery_link(self, for_email=False) -> tuple[str, Token]:
"""Create a recovery link (when the current brand has a recovery flow set),
that can either be shown to an admin or sent to the user directly"""
brand: Brand = self.request.brand
brand: Brand = self.request._request.brand
# Check that there is a recovery flow, if not return an error
flow = brand.flow_recovery
if not flow:
raise ValidationError({"non_field_errors": _("No recovery flow set.")})
raise ValidationError({"non_field_errors": "No recovery flow set."})
user: User = self.get_object()
planner = FlowPlanner(flow)
planner.allow_empty_flows = True
@@ -581,15 +559,11 @@ class UserViewSet(
)
except FlowNonApplicableException:
raise ValidationError(
{"non_field_errors": _("Recovery flow not applicable to user")}
{"non_field_errors": "Recovery flow not applicable to user"}
) from None
_plan = FlowToken.pickle(plan)
if for_email:
_plan = pickle_flow_token_for_email(plan)
expires = default_token_duration()
if token_duration:
timedelta_string_validator(token_duration)
expires = now() + timedelta_from_string(token_duration)
token, __ = FlowToken.objects.update_or_create(
identifier=f"{user.uid}-password-reset",
defaults={
@@ -597,7 +571,6 @@ class UserViewSet(
"flow": flow,
"_plan": _plan,
"revoke_on_execution": not for_email,
"expires": expires,
},
)
querystring = urlencode({QS_KEY_TOKEN: token.key})
@@ -745,60 +718,60 @@ class UserViewSet(
@permission_required("authentik_core.reset_user_password")
@extend_schema(
request=UserRecoveryLinkSerializer,
responses={
"200": LinkSerializer(many=False),
},
request=None,
)
@action(detail=True, pagination_class=None, filter_backends=[], methods=["POST"])
@validate(UserRecoveryLinkSerializer)
def recovery(self, request: Request, pk: int, body: UserRecoveryLinkSerializer) -> Response:
def recovery(self, request: Request, pk: int) -> Response:
"""Create a temporary link that a user can use to recover their account"""
link, _ = self._create_recovery_link(
token_duration=body.validated_data.get("token_duration")
)
link, _ = self._create_recovery_link()
return Response({"link": link})
@permission_required("authentik_core.reset_user_password")
@extend_schema(
request=UserRecoveryEmailSerializer,
parameters=[
OpenApiParameter(
name="email_stage",
location=OpenApiParameter.QUERY,
type=OpenApiTypes.STR,
required=True,
)
],
responses={
"204": OpenApiResponse(description="Successfully sent recover email"),
},
request=None,
)
@action(detail=True, pagination_class=None, filter_backends=[], methods=["POST"])
@validate(UserRecoveryEmailSerializer)
def recovery_email(
self, request: Request, pk: int, body: UserRecoveryEmailSerializer
) -> Response:
def recovery_email(self, request: Request, pk: int) -> Response:
"""Send an email with a temporary link that a user can use to recover their account"""
email_error_message = _("User does not have an email address set.")
stage_error_message = _("Email stage not found.")
user: User = self.get_object()
if not user.email:
for_user: User = self.get_object()
if for_user.email == "":
LOGGER.debug("User doesn't have an email address")
raise ValidationError({"non_field_errors": email_error_message})
if not (stage := EmailStage.objects.filter(pk=body.validated_data["email_stage"]).first()):
LOGGER.debug("Email stage does not exist")
raise ValidationError({"non_field_errors": stage_error_message})
if not request.user.has_perm("authentik_stages_email.view_emailstage", stage):
LOGGER.debug("User has no view access to email stage")
raise ValidationError({"non_field_errors": stage_error_message})
link, token = self._create_recovery_link(
token_duration=body.validated_data.get("token_duration"), for_email=True
)
raise ValidationError({"non_field_errors": "User does not have an email address set."})
link, token = self._create_recovery_link(for_email=True)
# Lookup the email stage to assure the current user can access it
stages = get_objects_for_user(
request.user, "authentik_stages_email.view_emailstage"
).filter(pk=request.query_params.get("email_stage"))
if not stages.exists():
LOGGER.debug("Email stage does not exist/user has no permissions")
raise ValidationError({"non_field_errors": "Email stage does not exist."})
email_stage: EmailStage = stages.first()
message = TemplateEmailMessage(
subject=_(stage.subject),
to=[(user.name, user.email)],
template_name=stage.template,
language=user.locale(request),
subject=_(email_stage.subject),
to=[(for_user.name, for_user.email)],
template_name=email_stage.template,
language=for_user.locale(request),
template_context={
"url": link,
"user": user,
"user": for_user,
"expires": token.expires,
},
)
send_mails(stage, message)
send_mails(email_stage, message)
return Response(status=204)
@permission_required("authentik_core.impersonate")

View File

@@ -127,10 +127,3 @@ class LinkSerializer(PassiveSerializer):
"""Returns a single link"""
link = CharField()
class ThemedUrlsSerializer(PassiveSerializer):
"""Themed URLs - maps theme names to URLs for light and dark themes"""
light = CharField(required=False, allow_null=True)
dark = CharField(required=False, allow_null=True)

View File

@@ -8,7 +8,7 @@ from uuid import uuid4
from django.contrib.auth import logout
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest
from django.http import HttpRequest, HttpResponse
from django.utils.deprecation import MiddlewareMixin
from django.utils.functional import SimpleLazyObject
from django.utils.translation import override
@@ -47,7 +47,7 @@ async def aget_user(request):
class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request: HttpRequest) -> HttpResponseBadRequest | None:
def process_request(self, request):
if not hasattr(request, "session"):
raise ImproperlyConfigured(
"The Django authentication middleware requires session "
@@ -62,8 +62,7 @@ class AuthenticationMiddleware(MiddlewareMixin):
user = request.user
if user and user.is_authenticated and not user.is_active:
logout(request)
return HttpResponseBadRequest()
return None
raise AssertionError()
class ImpersonateMiddleware:

View File

@@ -16,7 +16,7 @@ def backport_is_backchannel(apps: Apps, schema_editor: BaseDatabaseSchemaEditor)
for obj in model.objects.using(db_alias).only("is_backchannel"):
obj.is_backchannel = True
obj.save()
except DatabaseError, InternalError, ProgrammingError:
except (DatabaseError, InternalError, ProgrammingError):
# The model might not have been migrated yet/doesn't exist yet
# so we don't need to worry about backporting the data
pass

View File

@@ -1,9 +1,101 @@
# Generated by Django 5.0.11 on 2025-01-27 12:58
import uuid
import pickle # nosec
from django.core import signing
from django.contrib.auth import BACKEND_SESSION_KEY, HASH_SESSION_KEY, SESSION_KEY
from django.db import migrations, models
import django.db.models.deletion
from django.conf import settings
from authentik.lib.migrations import progress_bar
from authentik.root.middleware import ClientIPMiddleware
class PickleSerializer:
"""
Simple wrapper around pickle to be used in signing.dumps()/loads() and
cache backends.
"""
def __init__(self, protocol=None):
self.protocol = pickle.HIGHEST_PROTOCOL if protocol is None else protocol
def dumps(self, obj):
"""Pickle data to be stored in redis"""
return pickle.dumps(obj, self.protocol)
def loads(self, data):
"""Unpickle data to be loaded from redis"""
try:
return pickle.loads(data) # nosec
except Exception:
return {}
def _migrate_session(
apps,
db_alias,
session_key,
session_data,
expires,
):
Session = apps.get_model("authentik_core", "Session")
OldAuthenticatedSession = apps.get_model("authentik_core", "OldAuthenticatedSession")
AuthenticatedSession = apps.get_model("authentik_core", "AuthenticatedSession")
old_auth_session = (
OldAuthenticatedSession.objects.using(db_alias).filter(session_key=session_key).first()
)
args = {
"session_key": session_key,
"expires": expires,
"last_ip": ClientIPMiddleware.default_ip,
"last_user_agent": "",
"session_data": {},
}
for k, v in session_data.items():
if k == "authentik/stages/user_login/last_ip":
args["last_ip"] = v
elif k in ["last_user_agent", "last_used"]:
args[k] = v
elif args in [SESSION_KEY, BACKEND_SESSION_KEY, HASH_SESSION_KEY]:
pass
else:
args["session_data"][k] = v
if old_auth_session:
args["last_user_agent"] = old_auth_session.last_user_agent
args["last_used"] = old_auth_session.last_used
args["session_data"] = pickle.dumps(args["session_data"])
session = Session.objects.using(db_alias).create(**args)
if old_auth_session:
AuthenticatedSession.objects.using(db_alias).create(
session=session,
user=old_auth_session.user,
uuid=old_auth_session.uuid,
)
def migrate_database_sessions(apps, schema_editor):
DjangoSession = apps.get_model("sessions", "Session")
db_alias = schema_editor.connection.alias
print("\nMigration database sessions, this might take a couple of minutes...")
for django_session in progress_bar(DjangoSession.objects.using(db_alias).all()):
session_data = signing.loads(
django_session.session_data,
salt="django.contrib.sessions.SessionStore",
serializer=PickleSerializer,
)
_migrate_session(
apps=apps,
db_alias=db_alias,
session_key=django_session.session_key,
session_data=session_data,
expires=django_session.expire_date,
)
class Migration(migrations.Migration):
@@ -113,4 +205,8 @@ class Migration(migrations.Migration):
"verbose_name_plural": "Authenticated Sessions",
},
),
migrations.RunPython(
code=migrate_database_sessions,
reverse_code=migrations.RunPython.noop,
),
]

View File

@@ -1,47 +0,0 @@
# Generated by Django 5.2.10 on 2026-01-19 21:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0056_user_roles"),
("authentik_rbac", "0010_remove_role_group_alter_role_name"),
]
operations = [
migrations.RemoveField(
model_name="user",
name="user_permissions",
),
migrations.AlterField(
model_name="group",
name="roles",
field=models.ManyToManyField(
blank=True, related_name="groups", to="authentik_rbac.role"
),
),
migrations.RemoveField(
model_name="user",
name="groups",
),
migrations.RenameField(
model_name="user",
old_name="ak_groups",
new_name="groups",
),
migrations.AlterModelOptions(
name="user",
options={
"permissions": [
("reset_user_password", "Reset Password"),
("impersonate", "Can impersonate other users"),
("preview_user", "Can preview user data sent to providers"),
("view_user_applications", "View applications the user has access to"),
],
"verbose_name": "User",
"verbose_name_plural": "Users",
},
),
]

View File

@@ -1,11 +1,9 @@
"""authentik core models"""
import re
import traceback
from datetime import datetime, timedelta
from datetime import datetime
from enum import StrEnum
from hashlib import sha256
from typing import Any, Self
from typing import Any, Optional, Self
from uuid import uuid4
import pgtrigger
@@ -17,6 +15,7 @@ from django.contrib.sessions.base_session import AbstractBaseSession
from django.core.validators import validate_slug
from django.db import models
from django.db.models import Q, QuerySet, options
from django.db.models.constants import LOOKUP_SEP
from django.http import HttpRequest
from django.utils.functional import cached_property
from django.utils.timezone import now
@@ -44,7 +43,6 @@ from authentik.lib.models import (
DomainlessFormattedURLValidator,
SerializerModel,
)
from authentik.lib.utils.inheritance import get_deepest_child
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.models import PolicyBindingModel
from authentik.rbac.models import Role
@@ -52,7 +50,6 @@ from authentik.tenants.models import DEFAULT_TOKEN_DURATION, DEFAULT_TOKEN_LENGT
from authentik.tenants.utils import get_current_tenant, get_unique_identifier
LOGGER = get_logger()
USERNAME_MAX_LENGTH = 150
USER_PATH_SYSTEM_PREFIX = "goauthentik.io"
_USER_ATTR_PREFIX = f"{USER_PATH_SYSTEM_PREFIX}/user"
USER_ATTRIBUTE_DEBUG = f"{_USER_ATTR_PREFIX}/debug"
@@ -186,7 +183,7 @@ class Group(SerializerModel, AttributesMixin):
default=False, help_text=_("Users added to this group will be superusers.")
)
roles = models.ManyToManyField("authentik_rbac.Role", related_name="groups", blank=True)
roles = models.ManyToManyField("authentik_rbac.Role", related_name="ak_groups", blank=True)
parents = models.ManyToManyField(
"Group",
@@ -228,14 +225,14 @@ class Group(SerializerModel, AttributesMixin):
# in the LDAP Outpost we use the last 5 chars so match here
return int(str(self.pk.int)[:5])
def is_member(self, user: User) -> bool:
def is_member(self, user: "User") -> bool:
"""Recursively check if `user` is member of us, or any parent."""
return user.all_groups().filter(group_uuid=self.group_uuid).exists()
def all_roles(self) -> QuerySet[Role]:
"""Get all roles of this group and all of its ancestors."""
return Role.objects.filter(
groups__in=Group.objects.filter(pk=self.pk).with_ancestors()
ak_groups__in=Group.objects.filter(pk=self.pk).with_ancestors()
).distinct()
def get_managed_role(self, create=False):
@@ -243,7 +240,7 @@ class Group(SerializerModel, AttributesMixin):
name = managed_role_name(self)
role, created = Role.objects.get_or_create(name=name, managed=name)
if created:
role.groups.add(self)
role.ak_groups.add(self)
return role
else:
return Role.objects.filter(name=managed_role_name(self)).first()
@@ -358,17 +355,13 @@ class UserManager(DjangoUserManager):
class User(SerializerModel, AttributesMixin, AbstractUser):
"""authentik User model, based on django's contrib auth user model."""
# Overwriting PermissionsMixin: permissions are handled by roles.
# (This knowingly violates the Liskov substitution principle. It is better to fail loudly.)
user_permissions = None
uuid = models.UUIDField(default=uuid4, editable=False, unique=True)
name = models.TextField(help_text=_("User's display name."))
path = models.TextField(default="users")
type = models.TextField(choices=UserTypes.choices, default=UserTypes.INTERNAL)
sources = models.ManyToManyField("Source", through="UserSourceConnection")
groups = models.ManyToManyField("Group", related_name="users")
ak_groups = models.ManyToManyField("Group", related_name="users")
roles = models.ManyToManyField("authentik_rbac.Role", related_name="users", blank=True)
password_change_date = models.DateTimeField(auto_now_add=True)
@@ -382,6 +375,8 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
permissions = [
("reset_user_password", _("Reset Password")),
("impersonate", _("Can impersonate other users")),
("assign_user_permissions", _("Can assign permissions to users")),
("unassign_user_permissions", _("Can unassign permissions from users")),
("preview_user", _("Can preview user data sent to providers")),
("view_user_applications", _("View applications the user has access to")),
]
@@ -405,11 +400,11 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
def all_groups(self) -> QuerySet[Group]:
"""Recursively get all groups this user is a member of."""
return self.groups.all().with_ancestors()
return self.ak_groups.all().with_ancestors()
def all_roles(self) -> QuerySet[Role]:
"""Get all roles of this user and all of its groups (recursively)."""
return Role.objects.filter(Q(users=self) | Q(groups__in=self.all_groups())).distinct()
return Role.objects.filter(Q(users=self) | Q(ak_groups__in=self.all_groups())).distinct()
def get_managed_role(self, create=False):
if create:
@@ -471,7 +466,7 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
always_merger.merge(final_attributes, self.attributes)
return final_attributes
def app_entitlements(self, app: Application | None) -> QuerySet[ApplicationEntitlement]:
def app_entitlements(self, app: "Application | None") -> QuerySet["ApplicationEntitlement"]:
"""Get all entitlements this user has for `app`."""
if not app:
return []
@@ -490,7 +485,7 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
).order_by("name")
return qs
def app_entitlements_attributes(self, app: Application | None) -> dict:
def app_entitlements_attributes(self, app: "Application | None") -> dict:
"""Get a dictionary containing all merged attributes from app entitlements for `app`."""
final_attributes = {}
for attrs in self.app_entitlements(app).values_list("attributes", flat=True):
@@ -513,54 +508,6 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
"""superuser == staff user"""
return self.is_superuser # type: ignore
# TODO: remove this after 2026.
@property
def ak_groups(self):
"""This is a proxy for a renamed, deprecated field."""
from authentik.events.models import Event, EventAction
deprecation = "authentik.core.models.User.ak_groups"
replacement = "authentik.core.models.User.groups"
message_logger = (
f"{deprecation} is deprecated and will be removed in a future version of "
f"authentik. Please use {replacement} instead."
)
message_event = (
f"{message_logger} This event will not be repeated until it expires (by "
"default: in 30 days). See authentik logs for every will invocation of this "
"deprecation."
)
stacktrace = traceback.format_stack()
# The last line is this function, the next-to-last line is its caller
cause = stacktrace[-2] if len(stacktrace) > 1 else "Unknown, see stacktrace in logs"
if search := re.search(r'"(.*?)"', cause):
cause = f"Property mapping or Expression policy named {search.group(1)}"
LOGGER.warning(
"deprecation used",
message=message_logger,
deprecation=deprecation,
replacement=replacement,
cause=cause,
stacktrace=stacktrace,
)
if not Event.filter_not_expired(
action=EventAction.CONFIGURATION_WARNING,
context__deprecation=deprecation,
context__cause=cause,
).exists():
event = Event.new(
EventAction.CONFIGURATION_WARNING,
deprecation=deprecation,
replacement=replacement,
message=message_event,
cause=cause,
)
event.expires = datetime.now() + timedelta(days=30)
event.save()
return self.groups
def set_password(self, raw_password, signal=True, sender=None, request=None):
if self.pk and signal:
from authentik.core.signals import password_changed
@@ -707,7 +654,7 @@ class BackchannelProvider(Provider):
class ApplicationQuerySet(QuerySet):
def with_provider(self) -> QuerySet[Application]:
def with_provider(self) -> "QuerySet[Application]":
qs = self.select_related("provider")
for subclass in Provider.objects.get_queryset()._get_subclasses_recurse(Provider):
qs = qs.select_related(f"provider__{subclass}")
@@ -766,15 +713,9 @@ class Application(SerializerModel, PolicyBindingModel):
return get_file_manager(FileUsage.MEDIA).file_url(self.meta_icon)
@property
def get_meta_icon_themed_urls(self) -> dict[str, str] | None:
"""Get themed URLs for meta_icon if it contains %(theme)s"""
if not self.meta_icon:
return None
return get_file_manager(FileUsage.MEDIA).themed_urls(self.meta_icon)
def get_launch_url(self, user: User | None = None, user_data: dict | None = None) -> str | None:
def get_launch_url(
self, user: Optional["User"] = None, user_data: dict | None = None
) -> str | None:
"""Get launch URL if set, otherwise attempt to get launch URL based on provider.
Args:
@@ -803,7 +744,25 @@ class Application(SerializerModel, PolicyBindingModel):
"""Get casted provider instance. Needs Application queryset with_provider"""
if not self.provider:
return None
return get_deepest_child(self.provider)
candidates = []
base_class = Provider
for subclass in base_class.objects.get_queryset()._get_subclasses_recurse(base_class):
parent = self.provider
for level in subclass.split(LOOKUP_SEP):
try:
parent = getattr(parent, level)
except AttributeError:
break
if parent in candidates:
continue
idx = subclass.count(LOOKUP_SEP)
if type(parent) is not base_class:
idx += 1
candidates.insert(idx, parent)
if not candidates:
return None
return candidates[-1]
def backchannel_provider_for[T: Provider](self, provider_type: type[T], **kwargs) -> T | None:
"""Get Backchannel provider for a specific type"""
@@ -970,14 +929,6 @@ class Source(ManagedModel, SerializerModel, PolicyBindingModel):
return get_file_manager(FileUsage.MEDIA).file_url(self.icon)
@property
def icon_themed_urls(self) -> dict[str, str] | None:
"""Get themed URLs for icon if it contains %(theme)s"""
if not self.icon:
return None
return get_file_manager(FileUsage.MEDIA).themed_urls(self.icon)
def get_user_path(self) -> str:
"""Get user path, fallback to default for formatting errors"""
try:
@@ -997,7 +948,7 @@ class Source(ManagedModel, SerializerModel, PolicyBindingModel):
raise NotImplementedError
@property
def property_mapping_type(self) -> type[PropertyMapping]:
def property_mapping_type(self) -> "type[PropertyMapping]":
"""Return property mapping type used by this object"""
if self.managed == self.MANAGED_INBUILT:
from authentik.core.models import PropertyMapping
@@ -1118,7 +1069,7 @@ class ExpiringModel(models.Model):
return self.delete(*args, **kwargs)
@classmethod
def filter_not_expired(cls, **kwargs) -> QuerySet[Self]:
def filter_not_expired(cls, **kwargs) -> QuerySet["Self"]:
"""Filer for tokens which are not expired yet or are not expiring,
and match filters in `kwargs`"""
for obj in cls.objects.filter(**kwargs).filter(Q(expires__lt=now(), expiring=True)):
@@ -1314,7 +1265,7 @@ class AuthenticatedSession(SerializerModel):
return f"Authenticated Session {str(self.pk)[:10]}"
@staticmethod
def from_request(request: HttpRequest, user: User) -> AuthenticatedSession | None:
def from_request(request: HttpRequest, user: User) -> Optional["AuthenticatedSession"]:
"""Create a new session from a http request"""
if not hasattr(request, "session") or not request.session.exists(
request.session.session_key

View File

@@ -66,12 +66,9 @@ class SessionStore(SessionBase):
def decode(self, session_data):
try:
return pickle.loads(session_data) # nosec
except pickle.PickleError, AttributeError, TypeError:
# PickleError, ValueError - unpickling exceptions
# AttributeError - can happen when Django model fields (e.g., FileField) are unpickled
# and their descriptors fail to initialize (e.g., missing storage)
# TypeError - can happen with incompatible pickled objects
# If any of these happen, just return an empty dictionary (an empty session)
except pickle.PickleError:
# ValueError, unpickling exceptions. If any of these happen, just return an empty
# dictionary (an empty session)
pass
return {}

View File

@@ -51,7 +51,7 @@ def user_logged_in_session(sender, request: HttpRequest, user: User, **_):
if session:
session.save()
if not RefreshOtherFlowsAfterAuthentication.get():
if not RefreshOtherFlowsAfterAuthentication().get():
return
layer = get_channel_layer()
device_cookie = request.COOKIES.get("authentik_device")
@@ -63,7 +63,7 @@ def user_logged_in_session(sender, request: HttpRequest, user: User, **_):
@receiver(post_delete, sender=AuthenticatedSession)
def authenticated_session_delete(sender: type[Model], instance: AuthenticatedSession, **_):
def authenticated_session_delete(sender: type[Model], instance: "AuthenticatedSession", **_):
"""Delete session when authenticated session is deleted"""
Session.objects.filter(session_key=instance.pk).delete()

View File

@@ -392,10 +392,10 @@ class GroupUpdateStage(StageView):
groups.append(group)
with transaction.atomic():
self.user.groups.remove(
*self.user.groups.filter(groupsourceconnection__source=self.source)
self.user.ak_groups.remove(
*self.user.ak_groups.filter(groupsourceconnection__source=self.source)
)
self.user.groups.add(*groups)
self.user.ak_groups.add(*groups)
return True

View File

@@ -49,7 +49,7 @@ class SourceMapper:
def build_object_properties(
self,
object_type: type[User | Group],
manager: PropertyMappingManager | None = None,
manager: "PropertyMappingManager | None" = None,
user: User | None = None,
request: HttpRequest | None = None,
**kwargs,

View File

@@ -21,10 +21,6 @@
{% block head_before %}
{% endblock %}
{% block interface_stylesheet %}
<link rel="stylesheet" type="text/css" href="{% versioned_script 'dist/styles/interface-%v.css' %}" />
{% endblock %}
{% include "base/theme.html" %}
<style data-id="brand-css">{{ brand_css }}</style>

View File

@@ -1,6 +1,8 @@
{% load static %}
{% load authentik_core %}
<link rel="stylesheet" type="text/css" href="{% versioned_script 'dist/styles/interface-%v.css' %}" />
{% if ui_theme == "dark" %}
<meta name="color-scheme" content="dark" />
<meta name="theme-color" content="#18191a">
@@ -8,23 +10,15 @@
{% elif ui_theme == "light" %}
<meta name="color-scheme" content="light" />
<meta name="theme-color" content="#ffffff">
{% else %}
{% else %}
<script data-id="theme-script">
"use strict";
(function () {
try {
/* Ignore older theme names */
let locallyStoredTheme = window.localStorage?.getItem("theme") || null;
if (typeof locallyStoredTheme === "string") {
locallyStoredTheme = locallyStoredTheme.trim();
}
if (!(["auto", "light", "dark"].includes(locallyStoredTheme))) {
locallyStoredTheme = null;
}
const initialThemeChoice =
new URLSearchParams(window.location.search).get("theme") || locallyStoredTheme;
new URLSearchParams(window.location.search).get("theme") ||
window.localStorage?.getItem("theme");
const themeChoice =
initialThemeChoice || document.documentElement.dataset.themeChoice || "auto";

View File

@@ -44,24 +44,19 @@
{% endblock %}
</div>
</main>
<footer
name="site-footer"
aria-label="{% trans 'Site footer' %}"
class="pf-c-login__footer pf-m-dark">
<div name="flow-links" aria-label="{% trans 'Flow links' %}">
<ul class="pf-c-list pf-m-inline" part="list">
{% for link in footer_links %}
<li part="list-item">
<a part="list-item-link" href="{{ link.href }}">{{ link.name }}</a>
</li>
{% endfor %}
<li part="list-item">
<span>
{% trans 'Powered by authentik' %}
</span>
</li>
</ul>
</div>
<footer aria-label="Site footer" class="pf-c-login__footer pf-m-dark">
<ul class="pf-c-list pf-m-inline">
{% for link in footer_links %}
<li>
<a href="{{ link.href }}">{{ link.name }}</a>
</li>
{% endfor %}
<li>
<span>
{% trans 'Powered by authentik' %}
</span>
</li>
</ul>
</footer>
</div>
</div>

View File

@@ -38,7 +38,7 @@ class TestApplicationEntitlements(APITestCase):
def test_group(self):
"""Test direct group"""
group = Group.objects.create(name=generate_id())
self.user.groups.add(group)
self.user.ak_groups.add(group)
ent = ApplicationEntitlement.objects.create(app=self.app, name=generate_id())
PolicyBinding.objects.create(target=ent, group=group, order=0)
ents = self.user.app_entitlements(self.app)
@@ -50,7 +50,7 @@ class TestApplicationEntitlements(APITestCase):
parent = Group.objects.create(name=generate_id())
group = Group.objects.create(name=generate_id())
group.parents.add(parent)
self.user.groups.add(group)
self.user.ak_groups.add(group)
ent = ApplicationEntitlement.objects.create(app=self.app, name=generate_id())
PolicyBinding.objects.create(target=ent, group=parent, order=0)
ents = self.user.app_entitlements(self.app)

View File

@@ -107,8 +107,6 @@ class TestApplicationsAPI(APITestCase):
"provider_obj": {
"assigned_application_name": "allowed",
"assigned_application_slug": "allowed",
"assigned_backchannel_application_name": None,
"assigned_backchannel_application_slug": None,
"authentication_flow": None,
"invalidation_flow": None,
"authorization_flow": str(self.provider.authorization_flow.pk),
@@ -127,7 +125,6 @@ class TestApplicationsAPI(APITestCase):
"open_in_new_tab": True,
"meta_icon": "",
"meta_icon_url": None,
"meta_icon_themed_urls": None,
"meta_description": "",
"meta_publisher": "",
"policy_engine_mode": "any",
@@ -165,8 +162,6 @@ class TestApplicationsAPI(APITestCase):
"provider_obj": {
"assigned_application_name": "allowed",
"assigned_application_slug": "allowed",
"assigned_backchannel_application_name": None,
"assigned_backchannel_application_slug": None,
"authentication_flow": None,
"invalidation_flow": None,
"authorization_flow": str(self.provider.authorization_flow.pk),
@@ -185,7 +180,6 @@ class TestApplicationsAPI(APITestCase):
"open_in_new_tab": True,
"meta_icon": "",
"meta_icon_url": None,
"meta_icon_themed_urls": None,
"meta_description": "",
"meta_publisher": "",
"policy_engine_mode": "any",
@@ -195,7 +189,6 @@ class TestApplicationsAPI(APITestCase):
"meta_description": "",
"meta_icon": "",
"meta_icon_url": None,
"meta_icon_themed_urls": None,
"meta_launch_url": "",
"open_in_new_tab": False,
"meta_publisher": "",

View File

@@ -122,8 +122,8 @@ class TestGroupsAPI(APITestCase):
def test_superuser_update_no_perm(self):
"""Test updating a superuser group without permission"""
group = Group.objects.create(name=generate_id(), is_superuser=True)
self.login_user.assign_perms_to_managed_role("authentik_core.view_group", group)
self.login_user.assign_perms_to_managed_role("authentik_core.change_group", group)
self.login_user.assign_perms_to_managed_role("view_group", group)
self.login_user.assign_perms_to_managed_role("change_group", group)
self.client.force_login(self.login_user)
res = self.client.patch(
reverse("authentik_api:group-detail", kwargs={"pk": group.pk}),
@@ -139,8 +139,8 @@ class TestGroupsAPI(APITestCase):
"""Test updating a superuser group without permission
and without changing the superuser status"""
group = Group.objects.create(name=generate_id(), is_superuser=True)
self.login_user.assign_perms_to_managed_role("authentik_core.view_group", group)
self.login_user.assign_perms_to_managed_role("authentik_core.change_group", group)
self.login_user.assign_perms_to_managed_role("view_group", group)
self.login_user.assign_perms_to_managed_role("change_group", group)
self.client.force_login(self.login_user)
res = self.client.patch(
reverse("authentik_api:group-detail", kwargs={"pk": group.pk}),

View File

@@ -63,7 +63,7 @@ class TestPropertyMappingAPI(APITestCase):
PropertyMappingSerializer().validate_expression("/")
def test_types(self):
"""Test PropertyMapping's types endpoint"""
"""Test PropertyMappigns's types endpoint"""
response = self.client.get(
reverse("authentik_api:propertymapping-types"),
)

View File

@@ -54,7 +54,7 @@ class TestSourceFlowManager(FlowTestCase):
)
self.assertTrue(stage.handle_groups())
self.assertTrue(Group.objects.filter(name="group 1").exists())
self.assertTrue(self.user.groups.filter(name="group 1").exists())
self.assertTrue(self.user.ak_groups.filter(name="group 1").exists())
self.assertTrue(
GroupOAuthSourceConnection.objects.filter(
group=Group.objects.get(name="group 1"), source=self.source
@@ -88,7 +88,7 @@ class TestSourceFlowManager(FlowTestCase):
)
self.assertTrue(stage.handle_groups())
self.assertTrue(Group.objects.filter(name="group 1").exists())
self.assertTrue(self.user.groups.filter(name="group 1").exists())
self.assertTrue(self.user.ak_groups.filter(name="group 1").exists())
self.assertTrue(
GroupOAuthSourceConnection.objects.filter(
group=Group.objects.get(name="group 1"), source=self.source
@@ -123,7 +123,7 @@ class TestSourceFlowManager(FlowTestCase):
)
self.assertTrue(stage.handle_groups())
self.assertTrue(Group.objects.filter(name="group 1").exists())
self.assertTrue(self.user.groups.filter(name="group 1").exists())
self.assertTrue(self.user.ak_groups.filter(name="group 1").exists())
self.assertTrue(
GroupOAuthSourceConnection.objects.filter(group=group, source=self.source).exists()
)
@@ -155,7 +155,7 @@ class TestSourceFlowManager(FlowTestCase):
)
self.assertTrue(stage.handle_groups())
self.assertTrue(Group.objects.filter(name="group 1").exists())
self.assertTrue(self.user.groups.filter(name="group 1").exists())
self.assertTrue(self.user.ak_groups.filter(name="group 1").exists())
self.assertTrue(
GroupOAuthSourceConnection.objects.filter(
group=Group.objects.get(name="group 1"), source=self.source
@@ -189,7 +189,7 @@ class TestSourceFlowManager(FlowTestCase):
request=request,
)
self.assertFalse(stage.handle_groups())
self.assertFalse(self.user.groups.filter(name="group 1").exists())
self.assertFalse(self.user.ak_groups.filter(name="group 1").exists())
self.assertFalse(
GroupOAuthSourceConnection.objects.filter(group=group, source=self.source).exists()
)
@@ -201,7 +201,7 @@ class TestSourceFlowManager(FlowTestCase):
other_group = Group.objects.create(name="other group")
old_group = Group.objects.create(name="old group")
new_group = Group.objects.create(name="new group")
self.user.groups.set([other_group, old_group])
self.user.ak_groups.set([other_group, old_group])
GroupOAuthSourceConnection.objects.create(
group=old_group, source=self.source, identifier=old_group.name
)
@@ -231,7 +231,7 @@ class TestSourceFlowManager(FlowTestCase):
request=request,
)
self.assertTrue(stage.handle_groups())
self.assertFalse(self.user.groups.filter(name="old group").exists())
self.assertTrue(self.user.groups.filter(name="other group").exists())
self.assertTrue(self.user.groups.filter(name="new group").exists())
self.assertEqual(self.user.groups.count(), 2)
self.assertFalse(self.user.ak_groups.filter(name="old group").exists())
self.assertTrue(self.user.ak_groups.filter(name="other group").exists())
self.assertTrue(self.user.ak_groups.filter(name="new group").exists())
self.assertEqual(self.user.ak_groups.count(), 2)

View File

@@ -3,7 +3,6 @@
from django.test.testcases import TestCase
from authentik.core.models import User
from authentik.events.models import Event
from authentik.lib.generators import generate_id
@@ -19,17 +18,3 @@ class TestUsers(TestCase):
self.assertTrue(user.has_perm(perm))
user.remove_perms_from_managed_role(perm)
self.assertFalse(user.has_perm(perm))
def test_user_ak_groups(self):
"""Test user.ak_groups is a proxy for user.groups"""
user = User.objects.create(username=generate_id())
self.assertEqual(user.ak_groups, user.groups)
def test_user_ak_groups_event(self):
"""Test user.ak_groups creates exactly one event"""
user = User.objects.create(username=generate_id())
self.assertEqual(Event.objects.count(), 0)
user.ak_groups.all()
self.assertEqual(Event.objects.count(), 1)
user.ak_groups.all()
self.assertEqual(Event.objects.count(), 1)

View File

@@ -1,10 +1,9 @@
"""Test Users API"""
from datetime import datetime, timedelta
from datetime import datetime
from json import loads
from django.urls.base import reverse
from django.utils.timezone import now
from rest_framework.test import APITestCase
from authentik.brands.models import Brand
@@ -128,62 +127,13 @@ class TestUsersAPI(APITestCase):
)
self.assertEqual(response.status_code, 200)
def test_recovery_duration(self):
"""Test user recovery token duration"""
Token.objects.all().delete()
flow = create_test_flow(
FlowDesignation.RECOVERY,
authentication=FlowAuthenticationRequirement.REQUIRE_UNAUTHENTICATED,
)
brand: Brand = create_test_brand()
brand.flow_recovery = flow
brand.save()
self.client.force_login(self.admin)
response = self.client.post(
reverse("authentik_api:user-recovery", kwargs={"pk": self.user.pk}),
data={"token_duration": "days=33"},
)
self.assertEqual(response.status_code, 200)
expires = Token.objects.first().expires
expected_expires = now() + timedelta(days=33)
self.assertTrue(timedelta(minutes=-1) < expected_expires - expires < timedelta(minutes=1))
def test_recovery_duration_update(self):
"""Test user recovery token duration update"""
Token.objects.all().delete()
flow = create_test_flow(
FlowDesignation.RECOVERY,
authentication=FlowAuthenticationRequirement.REQUIRE_UNAUTHENTICATED,
)
brand: Brand = create_test_brand()
brand.flow_recovery = flow
brand.save()
self.client.force_login(self.admin)
response = self.client.post(
reverse("authentik_api:user-recovery", kwargs={"pk": self.user.pk}),
data={"token_duration": "days=33"},
)
self.assertEqual(response.status_code, 200)
expires = Token.objects.first().expires
expected_expires = now() + timedelta(days=33)
self.assertTrue(timedelta(minutes=-1) < expected_expires - expires < timedelta(minutes=1))
response = self.client.post(
reverse("authentik_api:user-recovery", kwargs={"pk": self.user.pk}),
data={"token_duration": "days=66"},
)
expires = Token.objects.first().expires
expected_expires = now() + timedelta(days=66)
self.assertTrue(timedelta(minutes=-1) < expected_expires - expires < timedelta(minutes=1))
def test_recovery_email_no_flow(self):
"""Test user recovery link (no recovery flow set)"""
self.client.force_login(self.admin)
self.user.email = ""
self.user.save()
stage = EmailStage.objects.create(name="email")
response = self.client.post(
reverse("authentik_api:user-recovery-email", kwargs={"pk": self.user.pk}),
data={"email_stage": stage.pk},
reverse("authentik_api:user-recovery-email", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 400)
self.assertJSONEqual(
@@ -192,8 +142,7 @@ class TestUsersAPI(APITestCase):
self.user.email = "foo@bar.baz"
self.user.save()
response = self.client.post(
reverse("authentik_api:user-recovery-email", kwargs={"pk": self.user.pk}),
data={"email_stage": stage.pk},
reverse("authentik_api:user-recovery-email", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 400)
self.assertJSONEqual(response.content, {"non_field_errors": "No recovery flow set."})
@@ -211,7 +160,7 @@ class TestUsersAPI(APITestCase):
reverse("authentik_api:user-recovery-email", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 400)
self.assertJSONEqual(response.content, {"email_stage": ["This field is required."]})
self.assertJSONEqual(response.content, {"non_field_errors": "Email stage does not exist."})
def test_recovery_email(self):
"""Test user recovery link"""
@@ -229,8 +178,8 @@ class TestUsersAPI(APITestCase):
reverse(
"authentik_api:user-recovery-email",
kwargs={"pk": self.user.pk},
),
data={"email_stage": stage.pk},
)
+ f"?email_stage={stage.pk}"
)
self.assertEqual(response.status_code, 204)
@@ -791,90 +740,3 @@ class TestUsersAPI(APITestCase):
response.content,
{"name": ["This field must be unique."]},
)
def test_filter_last_login(self):
"""Test API filtering by last_login"""
from datetime import timedelta
from django.utils import timezone
User.objects.all().delete()
admin = create_test_admin_user()
self.client.force_login(admin)
# Create users with different last_login values
user_recent = create_test_user()
user_recent.last_login = timezone.now()
user_recent.save()
user_old = create_test_user()
user_old.last_login = timezone.now() - timedelta(days=400) # Over 1 year ago
user_old.save()
user_never = create_test_user()
user_never.last_login = None # Never logged in
user_never.save()
# Filter users who logged in before 1 year ago
one_year_ago = (timezone.now() - timedelta(days=365)).isoformat()
response = self.client.get(
reverse("authentik_api:user-list"),
data={"last_login__lt": one_year_ago},
)
self.assertEqual(response.status_code, 200)
body = loads(response.content)
self.assertEqual(len(body["results"]), 1)
self.assertEqual(body["results"][0]["pk"], user_old.pk)
# Filter users who have never logged in
response = self.client.get(
reverse("authentik_api:user-list"),
data={"last_login__isnull": True},
)
self.assertEqual(response.status_code, 200)
body = loads(response.content)
# Should include user_never and admin (who hasn't logged in via the app)
pks = [r["pk"] for r in body["results"]]
self.assertIn(user_never.pk, pks)
def test_sort_by_last_login(self):
"""Test API sorting by last_login"""
from datetime import timedelta
from django.utils import timezone
User.objects.all().delete()
admin = create_test_admin_user()
self.client.force_login(admin)
user1 = create_test_user()
user1.last_login = timezone.now() - timedelta(days=10)
user1.save()
user2 = create_test_user()
user2.last_login = timezone.now() - timedelta(days=5)
user2.save()
# Ascending order (oldest first)
response = self.client.get(
reverse("authentik_api:user-list"),
data={"ordering": "last_login"},
)
self.assertEqual(response.status_code, 200)
body = loads(response.content)
# Users with null last_login come first, then user1 (older), then user2 (newer)
self.assertEqual(len(body["results"]), 3)
# Descending order (newest first)
response = self.client.get(
reverse("authentik_api:user-list"),
data={"ordering": "-last_login"},
)
self.assertEqual(response.status_code, 200)
body = loads(response.content)
# user2 should come before user1 (more recent login)
pks = [r["pk"] for r in body["results"]]
self.assertIn(user1.pk, pks)
self.assertIn(user2.pk, pks)
# Verify user2 comes before user1 in descending order
self.assertLess(pks.index(user2.pk), pks.index(user1.pk))

View File

@@ -7,8 +7,6 @@ from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec, rsa
from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PrivateKey
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes
from cryptography.x509.oid import NameOID
from django.db import models
@@ -23,8 +21,6 @@ class PrivateKeyAlg(models.TextChoices):
RSA = "rsa", _("rsa")
ECDSA = "ecdsa", _("ecdsa")
ED25519 = "ed25519", _("Ed25519")
ED448 = "ed448", _("Ed448")
class CertificateBuilder:
@@ -60,10 +56,6 @@ class CertificateBuilder:
return rsa.generate_private_key(
public_exponent=65537, key_size=4096, backend=default_backend()
)
if self.alg == PrivateKeyAlg.ED25519:
return Ed25519PrivateKey.generate()
if self.alg == PrivateKeyAlg.ED448:
return Ed448PrivateKey.generate()
raise ValueError(f"Invalid alg: {self.alg}")
def build(
@@ -106,25 +98,18 @@ class CertificateBuilder:
self.__builder = self.__builder.add_extension(
x509.SubjectAlternativeName(alt_names), critical=True
)
algo = hashes.SHA256()
# EdDSA doesn't take a hash algorithm
if isinstance(self.__private_key, (Ed25519PrivateKey | Ed448PrivateKey)):
algo = None
self.__certificate = self.__builder.sign(
private_key=self.__private_key,
algorithm=algo,
algorithm=hashes.SHA256(),
backend=default_backend(),
)
@property
def private_key(self):
"""Return private key in PEM format"""
format = serialization.PrivateFormat.TraditionalOpenSSL
if isinstance(self.__private_key, (Ed25519PrivateKey | Ed448PrivateKey)):
format = serialization.PrivateFormat.PKCS8
return self.__private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=format,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
).decode("utf-8")

View File

@@ -41,7 +41,7 @@ def backfill_certificate_metadata(apps, schema_editor): # noqa: ARG001
"fingerprint_sha1",
]
)
except ValueError, TypeError, AttributeError:
except (ValueError, TypeError, AttributeError):
pass
# Backfill kid with MD5 for backwards compatibility

View File

@@ -78,7 +78,7 @@ def generate_key_id_legacy(key_data: str) -> str:
"""Generate Key ID using MD5 (legacy format for backwards compatibility)."""
if not key_data:
return ""
return md5(key_data.encode("utf-8"), usedforsecurity=False).hexdigest() # nosec
return md5(key_data.encode("utf-8")).hexdigest() # nosec
class CertificateKeyPair(SerializerModel, ManagedModel, CreatedUpdatedModel):

View File

@@ -196,10 +196,8 @@ class TestCrypto(APITestCase):
"""Test certificate export (download)"""
keypair = create_test_cert()
user = create_test_user()
user.assign_perms_to_managed_role("authentik_crypto.view_certificatekeypair", keypair)
user.assign_perms_to_managed_role(
"authentik_crypto.view_certificatekeypair_certificate", keypair
)
user.assign_perms_to_managed_role("view_certificatekeypair", keypair)
user.assign_perms_to_managed_role("view_certificatekeypair_certificate", keypair)
self.client.force_login(user)
response = self.client.get(
reverse(
@@ -222,8 +220,8 @@ class TestCrypto(APITestCase):
"""Test private_key export (download)"""
keypair = create_test_cert()
user = create_test_user()
user.assign_perms_to_managed_role("authentik_crypto.view_certificatekeypair", keypair)
user.assign_perms_to_managed_role("authentik_crypto.view_certificatekeypair_key", keypair)
user.assign_perms_to_managed_role("view_certificatekeypair", keypair)
user.assign_perms_to_managed_role("view_certificatekeypair_key", keypair)
self.client.force_login(user)
response = self.client.get(
reverse(

View File

@@ -12,7 +12,6 @@ class DeviceAccessGroupSerializer(ModelSerializer):
fields = [
"pbm_uuid",
"name",
"attributes",
]

View File

@@ -3,7 +3,7 @@ from rest_framework.fields import SerializerMethodField
from authentik.core.api.utils import ModelSerializer
from authentik.endpoints.api.connectors import ConnectorSerializer
from authentik.endpoints.api.device_fact_snapshots import DeviceFactSnapshotSerializer
from authentik.endpoints.models import Connector, DeviceConnection, DeviceFactSnapshot
from authentik.endpoints.models import DeviceConnection
class DeviceConnectionSerializer(ModelSerializer):
@@ -12,19 +12,10 @@ class DeviceConnectionSerializer(ModelSerializer):
latest_snapshot = SerializerMethodField(allow_null=True)
def get_latest_snapshot(self, instance: DeviceConnection) -> DeviceFactSnapshotSerializer:
snapshot: DeviceFactSnapshot | None = instance.devicefactsnapshot_set.order_by(
"-created"
).first()
snapshot = instance.devicefactsnapshot_set.order_by("-created").first()
if not snapshot:
return None
connector: Connector = Connector.objects.get_subclass(pk=snapshot.connection.connector_id)
vendor = connector.controller.vendor_identifier()
return DeviceFactSnapshotSerializer(
snapshot,
context={
"vendor": vendor,
},
).data
return DeviceFactSnapshotSerializer(snapshot).data
class Meta:
model = DeviceConnection

View File

@@ -1,32 +1,11 @@
from enum import StrEnum
from rest_framework.fields import SerializerMethodField
from authentik.core.api.utils import ModelSerializer
from authentik.endpoints.controller import MERGED_VENDOR
from authentik.endpoints.facts import DeviceFacts
from authentik.endpoints.models import Connector, DeviceFactSnapshot
from authentik.lib.utils.reflection import all_subclasses
def get_vendor_choices():
choices = [(MERGED_VENDOR, MERGED_VENDOR)]
for connector_type in all_subclasses(Connector):
ident = connector_type().controller.vendor_identifier()
choices.append((ident, ident))
return choices
vendors = StrEnum("DeviceConnectorVendors", get_vendor_choices())
from authentik.endpoints.models import DeviceFactSnapshot
class DeviceFactSnapshotSerializer(ModelSerializer):
data = DeviceFacts()
vendor = SerializerMethodField()
def get_vendor(self, instance: DeviceFactSnapshot) -> vendors:
return self.context.get("vendor", MERGED_VENDOR)
class Meta:
model = DeviceFactSnapshot
@@ -35,7 +14,6 @@ class DeviceFactSnapshotSerializer(ModelSerializer):
"connection",
"created",
"expires",
"vendor",
]
extra_kwargs = {
"created": {"read_only": True},

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