Compare commits

...

212 Commits

Author SHA1 Message Date
5c1db432f0 release: 2023.4.1 2023-04-18 10:50:44 +03:00
07fd4daa3e Merge branch 'main' into version-2023.4 2023-04-17 22:46:09 +03:00
9faad8a055 web: bump @sentry/browser from 7.47.0 to 7.48.0 in /web (#5268)
Bumps [@sentry/browser](https://github.com/getsentry/sentry-javascript) from 7.47.0 to 7.48.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.47.0...7.48.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 10:16:44 +02:00
a94392808f core: bump goauthentik.io/api/v3 from 3.2023031.17 to 3.2023040.1 (#5269)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023031.17 to 3.2023040.1.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2023031.17...v3.2023040.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 10:13:37 +02:00
c4998e7dd4 web: bump @sentry/tracing from 7.47.0 to 7.48.0 in /web (#5266)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 7.47.0 to 7.48.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.47.0...7.48.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 10:12:32 +02:00
1ab587d80e website: bump react-before-after-slider-component from 1.1.6 to 1.1.8 in /website (#5267)
website: bump react-before-after-slider-component in /website

Bumps [react-before-after-slider-component](https://github.com/smeleshkin/react-before-after-slider-component) from 1.1.6 to 1.1.8.
- [Release notes](https://github.com/smeleshkin/react-before-after-slider-component/releases)
- [Commits](https://github.com/smeleshkin/react-before-after-slider-component/compare/v.1.1.6...v.1.1.8)

---
updated-dependencies:
- dependency-name: react-before-after-slider-component
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 10:12:11 +02:00
5715ffd845 website: bump postcss from 8.4.21 to 8.4.22 in /website (#5265)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.21 to 8.4.22.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.21...8.4.22)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 10:11:53 +02:00
8c3834e6b2 core: bump pytest from 7.3.0 to 7.3.1 (#5270)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.3.0 to 7.3.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.3.0...7.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 10:11:29 +02:00
f841586153 core: bump importlib-metadata from 6.3.0 to 6.4.1 (#5271)
Bumps [importlib-metadata](https://github.com/python/importlib_metadata) from 6.3.0 to 6.4.1.
- [Release notes](https://github.com/python/importlib_metadata/releases)
- [Changelog](https://github.com/python/importlib_metadata/blob/main/CHANGES.rst)
- [Commits](https://github.com/python/importlib_metadata/compare/v6.3.0...v6.4.1)

---
updated-dependencies:
- dependency-name: importlib-metadata
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 10:11:11 +02:00
b8b681250f core: bump drf-spectacular from 0.26.1 to 0.26.2 (#5272)
Bumps [drf-spectacular](https://github.com/tfranzel/drf-spectacular) from 0.26.1 to 0.26.2.
- [Release notes](https://github.com/tfranzel/drf-spectacular/releases)
- [Changelog](https://github.com/tfranzel/drf-spectacular/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tfranzel/drf-spectacular/compare/0.26.1...0.26.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 10:09:08 +02:00
3ab9ee5acc website/docs: separate docker steps (#5246)
* separated steps for macs

* fixed formatting

* fixed formatting harder

* two passwords

* tweaks

* separated error logging step

* comments in wrong place

---------

Co-authored-by: Tana Berry <tana@goauthentik.io>
2023-04-14 17:04:09 -05:00
1a4c640835 lifecycle: fix worker healthcheck (#5259)
closes #5258

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-14 14:39:31 +02:00
38bf0ee740 lifecycle: re-add exec to ak wrapper (#5253)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-14 13:52:11 +02:00
520fb2fac1 ci: fix tag lookup for previous stable version (#5257)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-14 13:51:57 +02:00
95adc38ff4 web: bump API Client version (#5256)
Signed-off-by: GitHub <noreply@github.com>
2023-04-14 11:34:14 +00:00
55ad2d7eab website/docs: add helm RBAC notice (#5255)
website/docs: add helm notice

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-14 13:21:05 +02:00
8160663214 release: 2023.4.0 (#5254) 2023-04-14 13:20:22 +02:00
aa80babfff release: 2023.4.0 2023-04-14 13:28:57 +03:00
6a700cb376 core: fix user metrics for users which can't access events (#5252)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-14 11:20:26 +02:00
e123afd9ee web/admin: fix impersonate button layout (#5251)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-14 11:20:07 +02:00
96e732e45b web: bump @codemirror/lang-javascript from 6.1.5 to 6.1.6 in /web (#5247)
Bumps [@codemirror/lang-javascript](https://github.com/codemirror/lang-javascript) from 6.1.5 to 6.1.6.
- [Release notes](https://github.com/codemirror/lang-javascript/releases)
- [Changelog](https://github.com/codemirror/lang-javascript/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/lang-javascript/compare/6.1.5...6.1.6)

---
updated-dependencies:
- dependency-name: "@codemirror/lang-javascript"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-14 10:35:25 +02:00
6349ab60e7 web: bump core-js from 3.30.0 to 3.30.1 in /web (#5248)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.30.0 to 3.30.1.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.30.1/packages/core-js)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-14 10:35:12 +02:00
2b0749af6b core: bump github.com/prometheus/client_golang from 1.14.0 to 1.15.0 (#5249)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.14.0...v1.15.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-14 10:34:56 +02:00
a5098364eb events: unpack wrapped query from FlowExecutor (#5244)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-14 00:07:41 +02:00
71820191a3 root: fix contributing List points (#5245) 2023-04-13 22:48:13 +02:00
c08c849fec website: fix doc build (#5242)
* ci: run both builds

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

* fix build

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-13 17:20:44 +02:00
6a74fa11c6 providers/oauth2: inconsistent client secret generation (#5241)
* use simpler char set for client secret

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

* also adjust radius

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

* use similar logic in web to generate ids and secrets

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

* dont use math.random

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-13 15:06:28 +02:00
7841720acf core: bump gitpython from 3.1.29 to 3.1.30 (#5239)
Bumps [gitpython](https://github.com/gitpython-developers/GitPython) from 3.1.29 to 3.1.30.
- [Release notes](https://github.com/gitpython-developers/GitPython/releases)
- [Changelog](https://github.com/gitpython-developers/GitPython/blob/main/CHANGES)
- [Commits](https://github.com/gitpython-developers/GitPython/compare/3.1.29...3.1.30)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-13 14:15:00 +02:00
67644ace87 website/docs: prepare 2023.4 release notes (#5223)
* website/docs: prepare 2023.4 release notes

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

* add prompt preview

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

* Apply suggestions from code review

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

* Update website/docs/releases/2023/v2023.4.md

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

* add new release to sidebar

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2023-04-13 14:11:46 +02:00
f84a10b59b core: revert django update (#5236)
* Revert "core: bump django from 4.1.7 to 4.2 (#5151)"

This reverts commit 18a4eac527.

* run unittests with postgres 11 and 12

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-13 14:10:12 +02:00
200d6d6adf website: bump docusaurus (#5235)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-13 13:45:51 +02:00
d0f1ebfad3 core: bump packaging from 23.0 to 23.1 (#5234)
Bumps [packaging](https://github.com/pypa/packaging) from 23.0 to 23.1.
- [Release notes](https://github.com/pypa/packaging/releases)
- [Changelog](https://github.com/pypa/packaging/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pypa/packaging/compare/23.0...23.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-13 11:31:19 +02:00
7d849d7bd7 core: bump maxmindinc/geoipupdate from v4.11 to v5.0 (#5233)
Bumps maxmindinc/geoipupdate from v4.11 to v5.0.

---
updated-dependencies:
- dependency-name: maxmindinc/geoipupdate
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-13 11:30:57 +02:00
f1dfe04786 website/integrations: Addition of phpIPAM SAML integration documentation (#5221)
* website/integrations: Addition of phpIPAM SAML integration documentation

* website/integrations: Addition of phpIPAM SAML integration documentation

* website/integrations: Fix formatting to pass npm prettier checks of new phpIPAM documentation

* website/integrations: Fix typo in certificate for codespell linting.

* website/integrations: Change => to ->. Fix indentation on python expressions. Fix copy/paste error on modules SAML attribute.

---------

Co-authored-by: Aaron Naden <aaron@DESKTOP-H5LSEU8>
2023-04-12 17:28:58 -05:00
4d7d2b8d3a web: bump pyright from 1.1.302 to 1.1.303 in /web (#5229)
Bumps [pyright](https://github.com/Microsoft/pyright/tree/HEAD/packages/pyright) from 1.1.302 to 1.1.303.
- [Release notes](https://github.com/Microsoft/pyright/releases)
- [Commits](https://github.com/Microsoft/pyright/commits/1.1.303/packages/pyright)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-12 11:21:39 +02:00
a6cc0f189c web: bump @rollup/plugin-commonjs from 24.0.1 to 24.1.0 in /web (#5230)
Bumps [@rollup/plugin-commonjs](https://github.com/rollup/plugins/tree/HEAD/packages/commonjs) from 24.0.1 to 24.1.0.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/commonjs/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/commonjs-v24.1.0/packages/commonjs)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-commonjs"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-12 11:20:55 +02:00
18a4eac527 core: bump django from 4.1.7 to 4.2 (#5151)
* core: bump django from 4.1.7 to 4.2

Bumps [django](https://github.com/django/django) from 4.1.7 to 4.2.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/4.1.7...4.2)

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

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

* upgrade to psycopg3, use custom engine for prometheus metrics

See https://github.com/korfuri/django-prometheus/issues/350

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

* make scripts use pscopg3

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-04-11 15:00:27 +02:00
6dd2e2b85f web: bump @typescript-eslint/eslint-plugin from 5.57.1 to 5.58.0 in /web (#5225)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.57.1 to 5.58.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.58.0/packages/eslint-plugin)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-11 14:30:15 +02:00
7bfea87864 web: bump @typescript-eslint/parser from 5.57.1 to 5.58.0 in /web (#5226)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.57.1 to 5.58.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.58.0/packages/parser)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-11 14:02:10 +02:00
1ca8feb5fc sources/ldap: make schema optional (#5213)
* sources/ldap: make schema optional

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

* create one connection and re-use it

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

* use magicmock

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-10 21:55:56 +02:00
c1615d044b web/flows: update flow background (#5222) 2023-04-10 19:33:29 +02:00
edc9d60e22 web: bump eslint-plugin-custom-elements from 0.0.7 to 0.0.8 in /web (#5215)
Bumps [eslint-plugin-custom-elements](https://github.com/github/eslint-plugin-custom-elements) from 0.0.7 to 0.0.8.
- [Release notes](https://github.com/github/eslint-plugin-custom-elements/releases)
- [Commits](https://github.com/github/eslint-plugin-custom-elements/compare/v0.0.7...v0.0.8)

---
updated-dependencies:
- dependency-name: eslint-plugin-custom-elements
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-10 18:57:11 +02:00
e6b135d535 core: bump pytest from 7.2.2 to 7.3.0 (#5218)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.2 to 7.3.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.2.2...7.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-10 18:56:32 +02:00
8cfad9a854 core: bump golang.org/x/oauth2 from 0.6.0 to 0.7.0 (#5219)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/oauth2/releases)
- [Commits](https://github.com/golang/oauth2/compare/v0.6.0...v0.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-10 18:55:48 +02:00
2237358633 web: bump eslint from 8.37.0 to 8.38.0 in /web (#5217)
Bumps [eslint](https://github.com/eslint/eslint) from 8.37.0 to 8.38.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.37.0...v8.38.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-10 18:55:29 +02:00
d15cd9ce5f core: bump importlib-metadata from 6.1.0 to 6.3.0 (#5220)
Bumps [importlib-metadata](https://github.com/python/importlib_metadata) from 6.1.0 to 6.3.0.
- [Release notes](https://github.com/python/importlib_metadata/releases)
- [Changelog](https://github.com/python/importlib_metadata/blob/main/CHANGES.rst)
- [Commits](https://github.com/python/importlib_metadata/compare/v6.1.0...v6.3.0)

---
updated-dependencies:
- dependency-name: importlib-metadata
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-10 18:54:48 +02:00
62abe22673 website/blog: blog re supply chain attacks (#5204)
* blog re supply chain attacks

* fixed title and slug

* tweaks

* fix formatting

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

* fix weird links from notion

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

* add truncate

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

* fix email

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Tana Berry <tanaberry@Tanas-MacBook-Pro-authentik.local>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-04-09 22:14:40 +02:00
8b78570597 outposts: run containers as non root (#5212)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-09 21:39:07 +02:00
549e4dcb94 core: bump twilio from 7.17.0 to 8.0.0 (#5194)
Bumps [twilio](https://github.com/twilio/twilio-python) from 7.17.0 to 8.0.0.
- [Release notes](https://github.com/twilio/twilio-python/releases)
- [Changelog](https://github.com/twilio/twilio-python/blob/main/CHANGES.md)
- [Upgrade guide](https://github.com/twilio/twilio-python/blob/main/UPGRADE.md)
- [Commits](https://github.com/twilio/twilio-python/compare/7.17.0...8.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-08 22:14:10 +02:00
1480ff6732 core: bump structlog from 22.3.0 to 23.1.0 (#5202)
Bumps [structlog](https://github.com/hynek/structlog) from 22.3.0 to 23.1.0.
- [Release notes](https://github.com/hynek/structlog/releases)
- [Changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hynek/structlog/compare/22.3.0...23.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-08 21:53:25 +02:00
0e1000764d core: bump coverage from 7.2.2 to 7.2.3 (#5203)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.2.2 to 7.2.3.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.2.2...7.2.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-08 21:53:14 +02:00
8dc9b43bb5 core: bump sentry-sdk from 1.19.0 to 1.19.1 (#5195) 2023-04-06 21:56:39 +02:00
3ce0aa54c7 web: bump @sentry/browser from 7.46.0 to 7.47.0 in /web (#5190) 2023-04-06 18:04:43 +02:00
b5888e79f5 web: bump lit from 2.7.1 to 2.7.2 in /web (#5192) 2023-04-06 18:04:27 +02:00
25d779e879 core: bump python from 3.11.2-slim-bullseye to 3.11.3-slim-bullseye (#5191) 2023-04-06 18:03:28 +02:00
d1fbb85821 web: bump @sentry/tracing from 7.46.0 to 7.47.0 in /web (#5193) 2023-04-06 18:03:02 +02:00
ea307689d4 Update README.md (#5188)
* Update README.md

Revise authentik feature statement for grammar and clarity

Signed-off-by: Yash Gupta <97800656+yash-gupta167@users.noreply.github.com>

* Update README.md

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

---------

Signed-off-by: Yash Gupta <97800656+yash-gupta167@users.noreply.github.com>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2023-04-06 08:07:48 -05:00
7a06c1685b core: bump duo-client from 4.7.0 to 4.7.1 (#5196) 2023-04-06 10:30:32 +02:00
977757f561 policies: provider raw result for better policy reusability (#5189)
* policies: include raw_result in PolicyResult

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

* move ak_call_policy to base evaluator

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-06 09:42:29 +02:00
c117d98e27 README: added link to Contributor file, small edits (#5172)
added link to Contributor file, small edits

Co-authored-by: Tana Berry <tanaberry@Tanas-MacBook-Pro-authentik.local>
2023-04-05 12:41:38 -05:00
711e98d049 stages/identification: revert is_active check (#5183) 2023-04-05 15:49:35 +02:00
f84c176bd0 web/admin: fix sidebar avatar not loaded (#5184) 2023-04-05 15:49:18 +02:00
c4b11ca861 CONTRIBUTING: added a section about contributing to docs (#5173)
added a section about contributing to docs

Co-authored-by: Tana Berry <tanaberry@Tanas-MacBook-Pro-authentik.local>
2023-04-05 07:29:35 -05:00
132a353b92 outposts: set k8s deployment security context (#5163)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-05 13:36:46 +02:00
bb464aad50 web: bump @codemirror/lang-javascript from 6.1.4 to 6.1.5 in /web (#5176)
Bumps [@codemirror/lang-javascript](https://github.com/codemirror/lang-javascript) from 6.1.4 to 6.1.5.
- [Release notes](https://github.com/codemirror/lang-javascript/releases)
- [Changelog](https://github.com/codemirror/lang-javascript/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/lang-javascript/compare/6.1.4...6.1.5)

---
updated-dependencies:
- dependency-name: "@codemirror/lang-javascript"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 11:32:14 +02:00
ab27cd0a9a core: bump goauthentik.io/api/v3 from 3.2023031.14 to 3.2023031.17 (#5181)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023031.14 to 3.2023031.17.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2023031.14...v3.2023031.17)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 11:32:02 +02:00
241280f2b5 core: bump golang from 1.20.2-bullseye to 1.20.3-bullseye (#5175)
Bumps golang from 1.20.2-bullseye to 1.20.3-bullseye.

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 11:31:47 +02:00
d110b5b661 ci: bump peter-evans/create-pull-request from 4 to 5 (#5179)
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4 to 5.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v4...v5)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 11:31:25 +02:00
8871a4acb2 web: bump @rollup/plugin-node-resolve from 15.0.1 to 15.0.2 in /web (#5178)
Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 15.0.1 to 15.0.2.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/node-resolve/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/node-resolve-v15.0.2/packages/node-resolve)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-node-resolve"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 11:31:05 +02:00
a1ad357abd web: bump pyright from 1.1.301 to 1.1.302 in /web (#5177)
Bumps [pyright](https://github.com/Microsoft/pyright/tree/HEAD/packages/pyright) from 1.1.301 to 1.1.302.
- [Release notes](https://github.com/Microsoft/pyright/releases)
- [Commits](https://github.com/Microsoft/pyright/commits/1.1.302/packages/pyright)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 11:30:45 +02:00
81f9842797 web: bump mermaid from 10.0.2 to 10.1.0 in /web (#5182)
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 10.0.2 to 10.1.0.
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Changelog](https://github.com/mermaid-js/mermaid/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/mermaid-js/mermaid/compare/v10.0.2...v10.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 11:30:24 +02:00
712256cdfe web: bump @rollup/plugin-typescript from 11.0.0 to 11.1.0 in /web (#5180)
Bumps [@rollup/plugin-typescript](https://github.com/rollup/plugins/tree/HEAD/packages/typescript) from 11.0.0 to 11.1.0.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/typescript/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/commonjs-v11.1.0/packages/typescript)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-typescript"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 11:29:33 +02:00
fb4808418c core: bump sentry-sdk from 1.18.0 to 1.19.0 (#5169)
* core: bump sentry-sdk from 1.18.0 to 1.19.0

Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 1.18.0 to 1.19.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/1.18.0...1.19.0)

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

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

* use new features

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-04-04 15:29:09 +02:00
7c7bb9dc2e web/admin: fix ldap form when editing scim provider from view page (#5164) 2023-04-04 12:42:18 +02:00
9a3809135e web: bump @typescript-eslint/eslint-plugin from 5.57.0 to 5.57.1 in /web (#5156)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.57.0 to 5.57.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.57.1/packages/eslint-plugin)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-04 10:30:16 +02:00
de13265997 web: bump @typescript-eslint/parser from 5.57.0 to 5.57.1 in /web (#5158)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.57.0 to 5.57.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.57.1/packages/parser)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-04 10:28:24 +02:00
0228ea9a4c web: bump core-js from 3.29.1 to 3.30.0 in /web (#5157)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.29.1 to 3.30.0.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.30.0/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-04 10:28:11 +02:00
faf986c231 web: bump lit from 2.7.0 to 2.7.1 in /web (#5159)
Bumps [lit](https://github.com/lit/lit/tree/HEAD/packages/lit) from 2.7.0 to 2.7.1.
- [Release notes](https://github.com/lit/lit/releases)
- [Changelog](https://github.com/lit/lit/blob/main/packages/lit/CHANGELOG.md)
- [Commits](https://github.com/lit/lit/commits/lit@2.7.1/packages/lit)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-04 10:27:56 +02:00
315eae009f core: bump pylint from 2.17.1 to 2.17.2 (#5160)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.17.1 to 2.17.2.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.17.1...v2.17.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-04 10:27:41 +02:00
02f75a92ce lifecycle: don't use celery ping for worker healthcheck (#5153)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-03 18:15:31 +02:00
a92786e153 core: bump psycopg2-binary from 2.9.5 to 2.9.6 (#5150)
Bumps [psycopg2-binary](https://github.com/psycopg/psycopg2) from 2.9.5 to 2.9.6.
- [Release notes](https://github.com/psycopg/psycopg2/releases)
- [Changelog](https://github.com/psycopg/psycopg2/blob/master/NEWS)
- [Commits](https://github.com/psycopg/psycopg2/commits/2.9.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-03 17:28:30 +02:00
157c23946e web: bump @babel/preset-env from 7.20.2 to 7.21.4 in /web (#5145)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.20.2 to 7.21.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.4/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-03 14:09:05 +02:00
f6b33d65af web: bump @babel/preset-typescript from 7.21.0 to 7.21.4 in /web (#5143) 2023-04-03 13:39:31 +02:00
ce461631b5 web: bump @babel/core from 7.21.3 to 7.21.4 in /web (#5142) 2023-04-03 13:38:35 +02:00
2f106a9049 core: bump github.com/getsentry/sentry-go from 0.19.0 to 0.20.0 (#5146) 2023-04-03 13:38:10 +02:00
7038431e19 web: bump @babel/plugin-transform-runtime from 7.21.0 to 7.21.4 in /web (#5144) 2023-04-03 13:37:52 +02:00
3fd9b53fe6 core: bump goauthentik.io/api/v3 from 3.2023031.11 to 3.2023031.14 (#5147) 2023-04-03 13:36:52 +02:00
e542783fec web: bump API Client version (#5141)
Signed-off-by: GitHub <noreply@github.com>
2023-04-02 17:39:51 +02:00
adcd11b1f8 core: extend postgres configuration (#5138)
Add postgres configuration options to control
TLS verification and client certificates.
2023-04-02 17:39:36 +02:00
6192d01b7e stages: Add ability to set user friendly names for MFA stages (#5005)
* Added ability to name MFA stage

* Schema

* Changed Charfield to Textfield

* Regenerated schema

* Add explicit required

* set null instead of blank so title check works

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

* add help text and adjust wording

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-04-02 16:52:44 +02:00
fd2677af1f root: bump api generator (#5139)
* root: bump api generator

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

* bump api diff too

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

* bump go api client

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

* simplify go api generation

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-04-01 18:10:52 +02:00
5947c7b97e stages/user_write: improve error handling (#5136)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-31 23:59:37 +02:00
986d7bf714 root: set codecov after_n_builds and threshold (#5137)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-31 23:59:23 +02:00
6282e923d6 core: bump redis from 4.5.3 to 4.5.4 (#5135)
Bumps [redis](https://github.com/redis/redis-py) from 4.5.3 to 4.5.4.
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](https://github.com/redis/redis-py/compare/v4.5.3...v4.5.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-31 16:48:30 +02:00
88b4125a6a web: bump @sentry/browser from 7.45.0 to 7.46.0 in /web (#5130)
Bumps [@sentry/browser](https://github.com/getsentry/sentry-javascript) from 7.45.0 to 7.46.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.45.0...7.46.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-31 10:58:03 +02:00
208c2d1913 web: bump @sentry/tracing from 7.45.0 to 7.46.0 in /web (#5132) 2023-03-31 10:53:15 +02:00
54dc0a46b4 web: bump @webcomponents/webcomponentsjs from 2.7.0 to 2.8.0 in /web (#5131) 2023-03-31 10:53:06 +02:00
fc807744bf website/blog: JWT blog final draft for review (#5128)
* final draft for review

* fix some formatting stuff

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

* add image and table

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

* update tags

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

* image for table because markdown

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

* Update website/blog/2023-03-30-JWTs-a-token-that-changed-how-we-see-identity/item.md

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

* Update website/blog/2023-03-30-JWTs-a-token-that-changed-how-we-see-identity/item.md

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

* fix formatting

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

* Update website/blog/2023-03-30-JWTs-a-token-that-changed-how-we-see-identity/item.md

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana Berry <tanaberry@Tanas-MacBook-Pro-authentik.local>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-03-30 14:27:14 -05:00
9666d407b4 lifecycle: also migrate before starting worker, trap exit to cleanup mode (#5123)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-30 14:04:38 +02:00
75510ead84 core: fix app launch URL flow selection (#5113) 2023-03-30 02:10:25 +02:00
73bf6fd530 core: bump channels-redis from 4.0.0 to 4.1.0 (#5115)
* core: bump channels-redis from 4.0.0 to 4.1.0

Bumps [channels-redis](https://github.com/django/channels_redis) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/django/channels_redis/releases)
- [Changelog](https://github.com/django/channels_redis/blob/main/CHANGELOG.txt)
- [Commits](https://github.com/django/channels_redis/compare/4.0.0...4.1.0)

---
updated-dependencies:
- dependency-name: channels-redis
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

* remove channels <4.1 workaround

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-03-30 00:08:07 +02:00
2e5a33f0c2 web: bump pyright from 1.1.300 to 1.1.301 in /web (#5117) 2023-03-29 14:51:22 +02:00
8c33d13dff web: bump eslint from 8.36.0 to 8.37.0 in /web (#5116) 2023-03-29 12:29:12 +02:00
a70de69228 core: bump sentry-sdk from 1.17.0 to 1.18.0 (#5118)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 1.17.0 to 1.18.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/1.17.0...1.18.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-29 11:33:02 +02:00
ab2d39dd2a core: bump black from 23.1.0 to 23.3.0 (#5114)
Bumps [black](https://github.com/psf/black) from 23.1.0 to 23.3.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/23.1.0...23.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-29 11:32:42 +02:00
2084156f1d web: only show debug locale if debug mode is enabled (#5111)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-28 20:49:40 +02:00
1d2725825c providers/scim: add missing default fields (#5108)
* providers/scim: add missing default fields

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

#4554

* update tests

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-28 14:42:52 +02:00
b9754f9c13 web/user: rework search (#5107)
closes #5106

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-28 14:09:55 +02:00
bb2e5b4861 web: bump @typescript-eslint/parser from 5.56.0 to 5.57.0 in /web (#5102)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.56.0 to 5.57.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.57.0/packages/parser)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-28 12:06:07 +02:00
89abc99dc0 website/docs: prepare 2023.4 release notes (#5083)
* website/docs: prepare 2023.4 release notes

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

* Update website/docs/releases/_template.md

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2023-03-28 12:05:44 +02:00
f92c661d09 core: bump github.com/go-openapi/strfmt from 0.21.5 to 0.21.7 (#5103)
Bumps [github.com/go-openapi/strfmt](https://github.com/go-openapi/strfmt) from 0.21.5 to 0.21.7.
- [Release notes](https://github.com/go-openapi/strfmt/releases)
- [Commits](https://github.com/go-openapi/strfmt/compare/v0.21.5...v0.21.7)

---
updated-dependencies:
- dependency-name: github.com/go-openapi/strfmt
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-28 12:01:19 +02:00
3468afc399 web: bump @codemirror/lang-html from 6.4.2 to 6.4.3 in /web (#5101)
Bumps [@codemirror/lang-html](https://github.com/codemirror/lang-html) from 6.4.2 to 6.4.3.
- [Release notes](https://github.com/codemirror/lang-html/releases)
- [Changelog](https://github.com/codemirror/lang-html/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/lang-html/compare/6.4.2...6.4.3)

---
updated-dependencies:
- dependency-name: "@codemirror/lang-html"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-28 12:01:03 +02:00
a286ae276b web: bump @fortawesome/fontawesome-free from 6.3.0 to 6.4.0 in /web (#5099)
Bumps [@fortawesome/fontawesome-free](https://github.com/FortAwesome/Font-Awesome) from 6.3.0 to 6.4.0.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.3.0...6.4.0)

---
updated-dependencies:
- dependency-name: "@fortawesome/fontawesome-free"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-28 12:00:51 +02:00
4fdd978b57 core: bump goauthentik.io/api/v3 from 3.2023031.5 to 3.2023031.10 (#5104)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023031.5 to 3.2023031.10.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2023031.5...v3.2023031.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-28 12:00:27 +02:00
c52bd8c4b9 core: bump redis from 4.3.4 to 4.5.3 (#5098)
Bumps [redis](https://github.com/redis/redis-py) from 4.3.4 to 4.5.3.
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](https://github.com/redis/redis-py/compare/v4.3.4...v4.5.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-28 11:59:37 +02:00
ca5ae5f914 web: bump @typescript-eslint/eslint-plugin from 5.56.0 to 5.57.0 in /web (#5100)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.56.0 to 5.57.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.57.0/packages/eslint-plugin)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-28 11:57:55 +02:00
4604c92046 core: bump duo-client from 4.6.1 to 4.7.0 (#5105) 2023-03-28 11:56:50 +02:00
4218ece2a5 stages/authenticator_validate: fix stage not working without pending user (#5096)
closes #5094

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-27 23:08:55 +02:00
0d6481c4d5 website/developer-docs: add note to create version subdomain and conf… (#5093)
website/developer-docs: add note to create version subdomain and configure

closes #5092

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-27 18:01:56 +02:00
a7fc579202 web/admin: show warning when adding user to superuser group (#5091)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-27 16:27:34 +02:00
5600261852 core: bump goauthentik.io/api/v3 from 3.2023031.3 to 3.2023031.5 (#5089)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023031.3 to 3.2023031.5.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2023031.3...v3.2023031.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-27 10:44:55 +02:00
824737965d web: bump @sentry/browser from 7.44.2 to 7.45.0 in /web (#5085)
Bumps [@sentry/browser](https://github.com/getsentry/sentry-javascript) from 7.44.2 to 7.45.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.44.2...7.45.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-27 09:21:11 +02:00
5476f517da website: bump prettier from 2.8.6 to 2.8.7 in /website (#5084) 2023-03-27 09:17:09 +02:00
d38043fe72 web: bump prettier from 2.8.6 to 2.8.7 in /web (#5086) 2023-03-27 09:17:00 +02:00
102570c61a web: bump @sentry/tracing from 7.44.2 to 7.45.0 in /web (#5087) 2023-03-27 09:16:50 +02:00
238e6e3f24 core: bump django-filter from 22.1 to 23.1 (#5088) 2023-03-27 09:16:28 +02:00
89c7e61769 core: bump selenium from 4.8.2 to 4.8.3 (#5090) 2023-03-27 09:15:45 +02:00
b097cf4d7e providers/scim: fix error when user-group m2m is updated forward (#5082)
* providers/scim: fix error when user-group m2m is updated forward

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

* fix

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-26 22:34:53 +02:00
5c0d7f9a58 web/admin: fix error when creating bindings due to hidden inputs (#5081)
* web/admin: fix error when creating bindings due to hidden inputs

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

* fix flaky test

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-26 18:58:02 +02:00
95b99e3e55 web: bump API Client version (#5079)
Signed-off-by: GitHub <noreply@github.com>
2023-03-25 22:39:03 +01:00
6437fbc814 web/admin: prompt preview (#5078)
* add initial prompt preview

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

* improve error handling

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

* don't flood api with requests when fields are changeed

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

* add tests

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-25 22:31:48 +01:00
d6fa19a97f web: bump API Client version (#5072) 2023-03-24 13:34:24 +01:00
1957717160 providers: Add ability to choose a default authentication flow (#5070)
* core: add ability to choose a default authentication flow for a provider

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

* update web to use correct ak-search-select

I don't think this element existed when the PR was initially created, lol

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

* only use provider authentication flow for authentication designation

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

* add tests

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

* fix tests

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

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-03-24 13:26:00 +01:00
94a93adb4b ci: bump peter-evans/enable-pull-request-automerge from 2 to 3 (#5067)
Bumps [peter-evans/enable-pull-request-automerge](https://github.com/peter-evans/enable-pull-request-automerge) from 2 to 3.
- [Release notes](https://github.com/peter-evans/enable-pull-request-automerge/releases)
- [Commits](https://github.com/peter-evans/enable-pull-request-automerge/compare/v2...v3)

---
updated-dependencies:
- dependency-name: peter-evans/enable-pull-request-automerge
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-24 11:01:13 +01:00
5d84f2a079 website: codespell with custom dictionary and CI (#5062) 2023-03-24 00:24:55 +01:00
5b9f35a4a1 website/blog: removed strikethrough text and formatted feature list (#5061)
removed srtikethrough text and formatted feature list

Co-authored-by: Tana Berry <tanaberry@Tanas-MacBook-Pro-authentik.local>
2023-03-23 17:44:30 -05:00
b3dd87bbab web: remove more until (#5057)
* more cleanup

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

* don't dynamically import duo form

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

* migrate more

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

* fix import

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

* properly send evens when tab isn't switched

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

* fix loop on tabs

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

* migrate more

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

* don't bubble tab events

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

* remove most other uses of until()

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

* cleanup user settings

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

* only use stale for issues

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-23 23:16:26 +01:00
af7189953c website: fix build (#5060)
* ci: build website

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

* fix build

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-23 21:40:36 +01:00
35d2e9cd5f website: add pricing waitlist and blog post (#5058)
* pricing

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

* update

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

* website: add pricing waitlist and blog post

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

* Apply suggestions from code review

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

* fix lint

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2023-03-23 21:34:34 +01:00
9a52d8db83 website/stages/prompt: Update new prompt fields docs (#5055)
* Update docs

Signed-off-by: sdimovv <36302090+sdimovv@users.noreply.github.com>

* Update index.md

Signed-off-by: sdimovv <36302090+sdimovv@users.noreply.github.com>

---------

Signed-off-by: sdimovv <36302090+sdimovv@users.noreply.github.com>
2023-03-23 16:59:01 +01:00
14f0034a0a web/elements: only render form once instance is loaded (#5049)
* web/elements: only render form once instance is loaded

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

* use radio for transport

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

* only wait for instance to be loaded if set

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

* add hook to load additional data in form

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

* make send an abstract function instead of attribute

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

* ensure form is updated after data is loaded

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

* remove until for select and multi-selects in forms

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

* don't use until for file uploads

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

* remove last until from form

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

* remove deprecated import

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

* prevent form double load, add error handling for PreventFormSubmit

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

* fix double creation of inner element in proxy form

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

* make PreventFormSubmit work correctly

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-23 14:05:14 +01:00
20522558fe web: bump country-flag-icons from 1.5.6 to 1.5.7 in /web (#5051)
Bumps [country-flag-icons](https://gitlab.com/catamphetamine/country-flag-icons) from 1.5.6 to 1.5.7.
- [Release notes](https://gitlab.com/catamphetamine/country-flag-icons/tags)
- [Changelog](https://gitlab.com/catamphetamine/country-flag-icons/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/catamphetamine/country-flag-icons/compare/v1.5.6...v1.5.7)

---
updated-dependencies:
- dependency-name: country-flag-icons
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 11:09:58 +01:00
f00ee5c174 core: bump pylint from 2.17.0 to 2.17.1 (#5053)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.17.0 to 2.17.1.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.17.0...v2.17.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 11:09:46 +01:00
95e24c9ec2 core: bump twilio from 7.16.5 to 7.17.0 (#5052)
Bumps [twilio](https://github.com/twilio/twilio-python) from 7.16.5 to 7.17.0.
- [Release notes](https://github.com/twilio/twilio-python/releases)
- [Changelog](https://github.com/twilio/twilio-python/blob/main/CHANGES.md)
- [Commits](https://github.com/twilio/twilio-python/compare/7.16.5...7.17.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 11:05:36 +01:00
6b42e404bf stages/prompt: Fix dropdown invalid choice (#5046) 2023-03-22 21:25:13 +01:00
9abd4b3e14 web/admin: fix error listing blueprints with missing metadata (#5041)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-22 10:21:27 +01:00
865138e7e7 web: bump @sentry/tracing from 7.44.1 to 7.44.2 in /web (#5037)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 7.44.1 to 7.44.2.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.44.1...7.44.2)

---
updated-dependencies:
- dependency-name: "@sentry/tracing"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-22 10:17:01 +01:00
7524413b22 web: bump prettier from 2.8.5 to 2.8.6 in /web (#5039)
Bumps [prettier](https://github.com/prettier/prettier) from 2.8.5 to 2.8.6.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/2.8.5...2.8.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-22 10:16:43 +01:00
70bdbfd5ef web: bump pyright from 1.1.299 to 1.1.300 in /web (#5038)
Bumps [pyright](https://github.com/Microsoft/pyright/tree/HEAD/packages/pyright) from 1.1.299 to 1.1.300.
- [Release notes](https://github.com/Microsoft/pyright/releases)
- [Commits](https://github.com/Microsoft/pyright/commits/1.1.300/packages/pyright)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-22 10:11:50 +01:00
73a7c0c559 web: bump lit from 2.6.1 to 2.7.0 in /web (#5040)
Bumps [lit](https://github.com/lit/lit/tree/HEAD/packages/lit) from 2.6.1 to 2.7.0.
- [Release notes](https://github.com/lit/lit/releases)
- [Changelog](https://github.com/lit/lit/blob/main/packages/lit/CHANGELOG.md)
- [Commits](https://github.com/lit/lit/commits/lit@2.7.0/packages/lit)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-22 10:08:41 +01:00
cafff808ab website/docs: "productive" to "production" term change and version info (#5010)
* production site change and version info

* changed future tense to present tense

* fixed section about .env file

* removed code block with port info

---------

Co-authored-by: Tana Berry <tanaberry@Tanas-MacBook-Pro-authentik.local>
2023-03-21 09:04:50 -05:00
bbbbc2a718 website/integrations: add detail to MinIO docs (#5000)
* website/integrations: add detail to MinIO docs

Add more information and reference links for the Scope Mapping, to clarify how it's used.

Also update to reflect that MinIO seems to require a Confidential client type now.

Signed-off-by: Braxton Schafer <braxton@cmdcentral.xyz>

* fix lint and move

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

---------

Signed-off-by: Braxton Schafer <braxton@cmdcentral.xyz>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-03-21 13:26:25 +01:00
1452f2680a Translate 'locale/en/LC_MESSAGES/django.po' in 'zh_CN' [manual sync] (#5031)
Translate locale/en/LC_MESSAGES/django.po in zh_CN [Manual Sync]

100% translated for the source file 'locale/en/LC_MESSAGES/django.po'
on the 'zh_CN' language.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-03-21 13:04:31 +01:00
dd39aab1fb Translate 'locale/en/LC_MESSAGES/django.po' in 'zh-Hans' [manual sync] (#5032)
Apply translations in zh-Hans [Manual Sync]

100% translated for the source file 'locale/en/LC_MESSAGES/django.po'
on the 'zh-Hans' language.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-03-21 13:04:19 +01:00
524fbd5838 Translate 'web/src/locales/en.po' in 'zh-Hans' [manual sync] (#5033)
Translate web/src/locales/en.po in zh-Hans [Manual Sync]

100% translated for the source file 'web/src/locales/en.po'
on the 'zh-Hans' language.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-03-21 13:04:02 +01:00
bb7c3456fa Translate 'web/src/locales/en.po' in 'zh_CN' [manual sync] (#5034)
Translate web/src/locales/en.po in zh_CN [Manual Sync]

100% translated for the source file 'web/src/locales/en.po'
on the 'zh_CN' language.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2023-03-21 13:03:54 +01:00
b611fd10a2 web: bump @codemirror/legacy-modes from 6.3.1 to 6.3.2 in /web (#5023)
Bumps [@codemirror/legacy-modes](https://github.com/codemirror/legacy-modes) from 6.3.1 to 6.3.2.
- [Release notes](https://github.com/codemirror/legacy-modes/releases)
- [Changelog](https://github.com/codemirror/legacy-modes/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/legacy-modes/compare/6.3.1...6.3.2)

---
updated-dependencies:
- dependency-name: "@codemirror/legacy-modes"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-21 12:12:55 +01:00
65b1cbc010 web: bump @sentry/browser from 7.43.0 to 7.44.2 in /web (#5030)
Bumps [@sentry/browser](https://github.com/getsentry/sentry-javascript) from 7.43.0 to 7.44.2.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/7.44.2/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.43.0...7.44.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-21 12:10:11 +01:00
119f64159b website: bump prettier from 2.8.4 to 2.8.6 in /website (#5029)
Bumps [prettier](https://github.com/prettier/prettier) from 2.8.4 to 2.8.6.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/2.8.4...2.8.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-21 12:09:55 +01:00
1352ed7e44 web: bump @sentry/tracing from 7.43.0 to 7.44.1 in /web (#5022) 2023-03-21 12:00:18 +01:00
34ce85fcd1 web: bump prettier from 2.8.4 to 2.8.5 in /web (#5024) 2023-03-21 12:00:08 +01:00
977ae4f225 core: bump watchdog from 2.3.1 to 3.0.0 (#5028) 2023-03-21 11:59:47 +01:00
a464ffe846 web: bump @typescript-eslint/eslint-plugin from 5.55.0 to 5.56.0 in /web (#5025) 2023-03-21 11:58:50 +01:00
6757d43d33 web: bump @typescript-eslint/parser from 5.55.0 to 5.56.0 in /web (#5026) 2023-03-21 11:53:46 +01:00
da3222df07 core: fix websocket url path (#5019)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-21 00:20:48 +01:00
54cacd784c *: load websocket paths similarly to URLs (#5018)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-20 23:39:25 +01:00
32840d3909 web/admin: fix error adding users to groups (#5016)
* web/admin: fix error adding users to groups

and vice versa

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

* remove seed

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-20 18:15:36 +01:00
eb78632853 root: bump go api client (#5014)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-20 17:09:11 +01:00
4868d4a14d web: bump API Client version (#5013)
Signed-off-by: GitHub <noreply@github.com>
2023-03-20 16:57:25 +01:00
3f5effb1bc providers/radius: simple radius outpost (#1796)
* initial implementation

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

* cleanup

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

* add migrations

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

* fix web

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

* minor fixes

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

* use search-select

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

* update locale

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

* fixup

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

* fix ip with port being sent to delegated ip

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

* add radius tests

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

* update docs

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

---------

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-20 16:54:35 +01:00
84c2da8a6e core: bump goauthentik.io/api/v3 from 3.2023031.1 to 3.2023031.2 (#5008)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023031.1 to 3.2023031.2.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2023031.1...v3.2023031.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-20 11:03:38 +01:00
56744659e4 core: bump importlib-metadata from 6.0.0 to 6.1.0 (#5009)
Bumps [importlib-metadata](https://github.com/python/importlib_metadata) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/python/importlib_metadata/releases)
- [Changelog](https://github.com/python/importlib_metadata/blob/main/CHANGES.rst)
- [Commits](https://github.com/python/importlib_metadata/compare/v6.0.0...v6.1.0)

---
updated-dependencies:
- dependency-name: importlib-metadata
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-20 11:03:26 +01:00
bad7deb52a web: bump country-flag-icons from 1.5.5 to 1.5.6 in /web (#5006)
Bumps [country-flag-icons](https://gitlab.com/catamphetamine/country-flag-icons) from 1.5.5 to 1.5.6.
- [Release notes](https://gitlab.com/catamphetamine/country-flag-icons/tags)
- [Changelog](https://gitlab.com/catamphetamine/country-flag-icons/blob/master/CHANGELOG.md)
- [Commits](https://gitlab.com/catamphetamine/country-flag-icons/compare/v1.5.5...v1.5.6)

---
updated-dependencies:
- dependency-name: country-flag-icons
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-20 11:02:44 +01:00
5748e19845 core: bump drf-spectacular from 0.26.0 to 0.26.1 (#5007)
Bumps [drf-spectacular](https://github.com/tfranzel/drf-spectacular) from 0.26.0 to 0.26.1.
- [Release notes](https://github.com/tfranzel/drf-spectacular/releases)
- [Changelog](https://github.com/tfranzel/drf-spectacular/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tfranzel/drf-spectacular/compare/0.26.0...0.26.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-20 11:02:25 +01:00
16a03160d0 core: Add unique constraint to user UUID (#5004) 2023-03-20 00:33:08 +01:00
a566856b65 web: bump API Client version (#5003)
Signed-off-by: GitHub <noreply@github.com>
2023-03-19 19:05:33 +01:00
8b52d711e8 stages/prompt: Add Radio Button Group, Dropdown and Text Area prompt fields (#4822)
* Added radio-button prompt type in model

* Add radio-button prompt

* Refactored radio-button prompt; Added dropdown prompt

* Added tests

* Fixed unrelated to choice fields bug causing validation errors; Added more tests

* Added description for new prompts

* Added docs

* Fix lint

* Add forgotten file changes

* Fix lint

* Small fix

* Add text-area prompts

* Update authentik/stages/prompt/models.py

Co-authored-by: Jens L. <jens@beryju.org>
Signed-off-by: sdimovv <36302090+sdimovv@users.noreply.github.com>

* Update authentik/stages/prompt/models.py

Co-authored-by: Jens L. <jens@beryju.org>
Signed-off-by: sdimovv <36302090+sdimovv@users.noreply.github.com>

* Fix inline css

* remove AKGlobal, update schema

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

---------

Signed-off-by: sdimovv <36302090+sdimovv@users.noreply.github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@beryju.org>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-03-19 18:56:17 +01:00
4da18b5f0c website/docs: improve docs for configuring event retention (#5002)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>

#2723
2023-03-19 18:56:03 +01:00
63e3f6545b website/integrations: Writefreely instructions (#4787)
* Add writefreely

Signed-off-by: Tealk <tealk@rollenspiel.monster>

* fix lint

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

---------

Signed-off-by: Tealk <tealk@rollenspiel.monster>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-03-18 19:32:07 +01:00
e35c3d19bc website/integrations: Automatic sign-in to HedgeDoc (#4843)
* Automatic sign-in to HedgeDoc

Following the HedgeDoc guides, if you clicks on a HedgeDoc application,
you then still have to click “Sign-in” and “Sign in via authentik” to
actually get signed in.

This patch suggests adding a launch URL to the application which will
cause users to automatically get signed in.

* fix lint

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2023-03-18 19:29:51 +01:00
ef028af7d1 providers/proxy: rework endpoints logic (#4993)
* providers/proxy: rework endpoints logic

again...this time with tests and better logic

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

* fix tests

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-18 18:51:20 +01:00
b69c26d485 website: use slider on docs, add flow images (#4997)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-18 16:21:30 +01:00
e13cfec84f website/docs: added content to Welcome page (#4996)
* added content to Welcome page

* minor tweak

* typos

* Update website/docs/index.md

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

* Update website/docs/index.md

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

* Update website/docs/index.md

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

* Update website/docs/index.md

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

* Update website/docs/index.md

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

* fix lint

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

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Tana Berry <tanaberry@Tanas-MacBook-Pro-authentik.local>
Co-authored-by: Jens L. <jens@goauthentik.io>
2023-03-18 16:12:46 +01:00
97df7848a5 blueprints: allow setting of token key in blueprint context (#4995)
closes #4717

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-18 00:10:12 +01:00
e2d3a95c80 web: full web components part 1 (#4964)
* migrate loading

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

* migrate api browser

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

* migrate base css

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

* move tenant fetching to base interface

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

* import pre-loaded stages in flow interface and not executor to strip down executor size

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

* fix redirect and such

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-17 23:10:19 +01:00
bebf18f257 web/admin: fix prompt field display (#4990)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-17 16:05:27 +01:00
53e68b8540 website/docs: Capitalized company name in copyright (#4991)
Capitalized company name in copyright

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
2023-03-17 10:00:28 -05:00
9dbd54690c web/elements: fix search select inconsistency (#4989)
* web/elements: fix search-select inconsistency

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

* web/common: fix config having to be json converted everywhere

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

* web/elements: refactor form without iron-form

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

* web/admin: fix misc

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-17 13:48:34 +01:00
9e41b7d208 core: bump coverage from 7.2.1 to 7.2.2 (#4984)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.2.1 to 7.2.2.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.2.1...7.2.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-17 11:18:24 +01:00
1c66d420c4 core: bump sentry-sdk from 1.16.0 to 1.17.0 (#4983)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/1.16.0...1.17.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-17 11:17:56 +01:00
0ca913f8d4 core: bump uvicorn from 0.21.0 to 0.21.1 (#4985)
Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.21.0 to 0.21.1.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.21.0...0.21.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-17 11:17:46 +01:00
b97274058c core: bump goauthentik.io/api/v3 from 3.2023030.7 to 3.2023031.1 (#4986)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023030.7 to 3.2023031.1.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2023030.7...v3.2023031.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-17 11:17:36 +01:00
aef0333695 core: bump github.com/go-openapi/strfmt from 0.21.3 to 0.21.5 (#4987)
Bumps [github.com/go-openapi/strfmt](https://github.com/go-openapi/strfmt) from 0.21.3 to 0.21.5.
- [Release notes](https://github.com/go-openapi/strfmt/releases)
- [Commits](https://github.com/go-openapi/strfmt/compare/v0.21.3...v0.21.5)

---
updated-dependencies:
- dependency-name: github.com/go-openapi/strfmt
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-17 11:17:24 +01:00
c847b16b3e website/intergrations: update sentry to reflect name change (#4988)
Docs: update sentry to reflect name change

Sentry/onpremise is now sentry/self-hosted!

Signed-off-by: Zakaria aourzag <github@zakariao.nl>
2023-03-17 11:17:09 +01:00
e2e83f5631 web: bump API Client version (#4981)
Signed-off-by: GitHub <noreply@github.com>
2023-03-16 22:46:01 +01:00
8363016982 version: 2023.3 (#4980)
* release: 2023.3.0

* providers/ldap: fix duplicate attributes (#4972)

closes #4971

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

* providers/oauth2: fix response for response_type code and response_mode fragment (#4975)

* web/flows: fix authenticator selector in dark mode (#4974)

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

* release: 2023.3.1

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-16 22:43:57 +01:00
397b9845ec web/admin: fix inconsistent display of flows in selections (#4977)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-16 22:39:26 +01:00
b9da24c952 website/blog: fix wrong language (#4979)
fix wrong language

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-16 20:50:14 +01:00
1053962bec website/blog: authentik on Django: 500% slower to run but 200% faster to build (#4978)
authentik on Django: 500% slower to run but 200% faster to build

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-16 19:51:27 +01:00
19ff8129e5 website/docs: prepare 2023.3.1 release notes (#4976)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-16 18:09:30 +01:00
40cdf6877d web/flows: fix authenticator selector in dark mode (#4974)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-16 15:59:21 +01:00
2a399cf8e8 providers/oauth2: fix response for response_type code and response_mode fragment (#4975) 2023-03-16 15:58:38 +01:00
345fa1bed6 providers/ldap: fix duplicate attributes (#4972)
closes #4971

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-16 12:14:17 +01:00
70ffb6d49e core: bump maxmindinc/geoipupdate from v4.10 to v4.11 (#4965)
Bumps maxmindinc/geoipupdate from v4.10 to v4.11.

---
updated-dependencies:
- dependency-name: maxmindinc/geoipupdate
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 10:45:06 +01:00
3ecdcebd35 ci: bump actions/setup-go from 3 to 4 (#4966)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3...v4)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 10:44:18 +01:00
4f02c8ab98 core: bump goauthentik.io/api/v3 from 3.2023030.4 to 3.2023030.7 (#4968)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023030.4 to 3.2023030.7.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2023030.4...v3.2023030.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 10:44:00 +01:00
41974c3f82 core: bump webauthn from 1.7.2 to 1.8.0 (#4969)
Bumps [webauthn](https://github.com/duo-labs/py_webauthn) from 1.7.2 to 1.8.0.
- [Release notes](https://github.com/duo-labs/py_webauthn/releases)
- [Changelog](https://github.com/duo-labs/py_webauthn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/duo-labs/py_webauthn/compare/v1.7.2...v1.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 10:43:47 +01:00
808f697423 web: bump pyright from 1.1.298 to 1.1.299 in /web (#4967)
Bumps [pyright](https://github.com/Microsoft/pyright/tree/HEAD/packages/pyright) from 1.1.298 to 1.1.299.
- [Release notes](https://github.com/Microsoft/pyright/releases)
- [Commits](https://github.com/Microsoft/pyright/commits/1.1.299/packages/pyright)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-16 10:43:02 +01:00
a9dc3ff0d8 core: bump github.com/pires/go-proxyproto from 0.6.2 to 0.7.0 (#4962)
Bumps [github.com/pires/go-proxyproto](https://github.com/pires/go-proxyproto) from 0.6.2 to 0.7.0.
- [Release notes](https://github.com/pires/go-proxyproto/releases)
- [Commits](https://github.com/pires/go-proxyproto/compare/v0.6.2...v0.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-15 20:25:39 +01:00
acde584cbd web: bump API Client version (#4961)
Signed-off-by: GitHub <noreply@github.com>
2023-03-15 20:25:28 +01:00
df52116135 core: bump goauthentik.io/api/v3 from 3.2023030.3 to 3.2023030.4 (#4963)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023030.3 to 3.2023030.4.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2023030.3...v3.2023030.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-15 20:25:16 +01:00
eaf56f4f3f stages/user_login: stay logged in (#4958)
* add initial remember me offset

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

* add to go executor

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

* add ui for user login stage

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

* add tests

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

* update docs

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-15 20:21:05 +01:00
364 changed files with 25163 additions and 19431 deletions

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 2023.3.0 current_version = 2023.4.1
tag = True tag = True
commit = True commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+) parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)

View File

@ -12,3 +12,9 @@ indent_size = 2
[*.{yaml,yml}] [*.{yaml,yml}]
indent_size = 2 indent_size = 2
[*.go]
indent_style = tab
[Makefile]
indent_style = tab

View File

@ -1,6 +1,11 @@
name: 'Setup authentik testing environment' name: 'Setup authentik testing environment'
description: 'Setup authentik testing environment' description: 'Setup authentik testing environment'
inputs:
postgresql_tag:
description: "Optional postgresql image tag"
default: "12"
runs: runs:
using: "composite" using: "composite"
steps: steps:
@ -24,6 +29,7 @@ runs:
- name: Setup dependencies - name: Setup dependencies
shell: bash shell: bash
run: | run: |
export PSQL_TAG=${{ inputs.postgresql_tag }}
docker-compose -f .github/actions/setup/docker-compose.yml up -d docker-compose -f .github/actions/setup/docker-compose.yml up -d
poetry env use python3.11 poetry env use python3.11
poetry install poetry install

View File

@ -3,7 +3,7 @@ version: '3.7'
services: services:
postgresql: postgresql:
container_name: postgres container_name: postgres
image: library/postgres:12 image: library/postgres:${PSQL_TAG:-12}
volumes: volumes:
- db-data:/var/lib/postgresql/data - db-data:/var/lib/postgresql/data
environment: environment:

11
.github/codecov.yml vendored
View File

@ -1,3 +1,10 @@
coverage: coverage:
precision: 2 status:
round: up project:
default:
target: auto
# adjust accordingly based on how flaky your tests are
# this allows a 1% drop from the previous base commit coverage
threshold: 1%
notify:
after_n_builds: 3

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

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

1
.github/stale.yml vendored
View File

@ -16,3 +16,4 @@ markComment: >
This issue has been automatically marked as stale because it has not had This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you recent activity. It will be closed if no further activity occurs. Thank you
for your contributions. for your contributions.
only: issues

View File

@ -29,6 +29,7 @@ jobs:
- bandit - bandit
- pyright - pyright
- pending-migrations - pending-migrations
- codespell
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -59,7 +60,7 @@ jobs:
cp authentik/lib/default.yml local.env.yml cp authentik/lib/default.yml local.env.yml
cp -R .github .. cp -R .github ..
cp -R scripts .. cp -R scripts ..
git checkout $(git describe --abbrev=0 --match 'version/*') git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
rm -rf .github/ scripts/ rm -rf .github/ scripts/
mv ../.github ../scripts . mv ../.github ../scripts .
- name: Setup authentik env (ensure stable deps are installed) - name: Setup authentik env (ensure stable deps are installed)
@ -79,12 +80,21 @@ jobs:
- name: migrate to latest - name: migrate to latest
run: poetry run python -m lifecycle.migrate run: poetry run python -m lifecycle.migrate
test-unittest: test-unittest:
name: test-unittest - PostgreSQL ${{ matrix.psql }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 30 timeout-minutes: 30
strategy:
fail-fast: false
matrix:
psql:
- 11-alpine
- 12-alpine
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup authentik env - name: Setup authentik env
uses: ./.github/actions/setup uses: ./.github/actions/setup
with:
postgresql_tag: ${{ matrix.psql }}
- name: run unittest - name: run unittest
run: | run: |
poetry run make test poetry run make test
@ -128,6 +138,8 @@ jobs:
glob: tests/e2e/test_provider_saml* tests/e2e/test_source_saml* glob: tests/e2e/test_provider_saml* tests/e2e/test_source_saml*
- name: ldap - name: ldap
glob: tests/e2e/test_provider_ldap* tests/e2e/test_source_ldap* glob: tests/e2e/test_provider_ldap* tests/e2e/test_source_ldap*
- name: radius
glob: tests/e2e/test_provider_radius*
- name: flows - name: flows
glob: tests/e2e/test_flows* glob: tests/e2e/test_flows*
steps: steps:

View File

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-go@v3 - uses: actions/setup-go@v4
with: with:
go-version: "^1.17" go-version: "^1.17"
- name: Prepare and generate API - name: Prepare and generate API
@ -34,7 +34,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-go@v3 - uses: actions/setup-go@v4
with: with:
go-version: "^1.17" go-version: "^1.17"
- name: Generate API - name: Generate API
@ -59,8 +59,9 @@ jobs:
type: type:
- proxy - proxy
- ldap - ldap
- radius
arch: arch:
- 'linux/amd64' - "linux/amd64"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -106,17 +107,18 @@ jobs:
type: type:
- proxy - proxy
- ldap - ldap
- radius
goos: [linux] goos: [linux]
goarch: [amd64, arm64] goarch: [amd64, arm64]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-go@v3 - uses: actions/setup-go@v4
with: with:
go-version: "^1.17" go-version: "^1.17"
- uses: actions/setup-node@v3.6.0 - uses: actions/setup-node@v3.6.0
with: with:
node-version: '18' node-version: "18"
cache: 'npm' cache: "npm"
cache-dependency-path: web/package-lock.json cache-dependency-path: web/package-lock.json
- name: Generate API - name: Generate API
run: make gen-client-go run: make gen-client-go

View File

@ -39,10 +39,32 @@ jobs:
- name: test - name: test
working-directory: website/ working-directory: website/
run: npm test run: npm test
build:
runs-on: ubuntu-latest
name: ${{ matrix.job }}
strategy:
fail-fast: false
matrix:
job:
- build
- build-docs-only
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3.6.0
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: website/package-lock.json
- working-directory: website/
run: npm ci
- name: build
working-directory: website/
run: npm run ${{ matrix.job }}
ci-website-mark: ci-website-mark:
needs: needs:
- lint-prettier - lint-prettier
- test - test
- build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: echo mark - run: echo mark

View File

@ -52,9 +52,10 @@ jobs:
type: type:
- proxy - proxy
- ldap - ldap
- radius
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-go@v3 - uses: actions/setup-go@v4
with: with:
go-version: "^1.17" go-version: "^1.17"
- name: Set up QEMU - name: Set up QEMU
@ -99,11 +100,12 @@ jobs:
type: type:
- proxy - proxy
- ldap - ldap
- radius
goos: [linux, darwin] goos: [linux, darwin]
goarch: [amd64, arm64] goarch: [amd64, arm64]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-go@v3 - uses: actions/setup-go@v4
with: with:
go-version: "^1.17" go-version: "^1.17"
- uses: actions/setup-node@v3.6.0 - uses: actions/setup-node@v3.6.0

View File

@ -26,7 +26,7 @@ jobs:
- name: run compile - name: run compile
run: poetry run ./manage.py compilemessages run: poetry run ./manage.py compilemessages
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@v4 uses: peter-evans/create-pull-request@v5
id: cpr id: cpr
with: with:
token: ${{ secrets.BOT_GITHUB_TOKEN }} token: ${{ secrets.BOT_GITHUB_TOKEN }}

View File

@ -30,7 +30,7 @@ jobs:
run: | run: |
export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'` export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'`
npm i @goauthentik/api@$VERSION npm i @goauthentik/api@$VERSION
- uses: peter-evans/create-pull-request@v4 - uses: peter-evans/create-pull-request@v5
id: cpr id: cpr
with: with:
token: ${{ secrets.BOT_GITHUB_TOKEN }} token: ${{ secrets.BOT_GITHUB_TOKEN }}
@ -42,7 +42,7 @@ jobs:
signoff: true signoff: true
team-reviewers: "@goauthentik/core" team-reviewers: "@goauthentik/core"
author: authentik bot <github-bot@goauthentik.io> author: authentik bot <github-bot@goauthentik.io>
- uses: peter-evans/enable-pull-request-automerge@v2 - uses: peter-evans/enable-pull-request-automerge@v3
with: with:
token: ${{ secrets.BOT_GITHUB_TOKEN }} token: ${{ secrets.BOT_GITHUB_TOKEN }}
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }} pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}

View File

@ -20,6 +20,7 @@ The following is a set of guidelines for contributing to authentik and its compo
- [Reporting Bugs](#reporting-bugs) - [Reporting Bugs](#reporting-bugs)
- [Suggesting Enhancements](#suggesting-enhancements) - [Suggesting Enhancements](#suggesting-enhancements)
- [Your First Code Contribution](#your-first-code-contribution) - [Your First Code Contribution](#your-first-code-contribution)
- [Help with the Docs](#help-with-the-docs)
- [Pull Requests](#pull-requests) - [Pull Requests](#pull-requests)
[Styleguides](#styleguides) [Styleguides](#styleguides)
@ -135,6 +136,9 @@ authentik can be run locally, all though depending on which part you want to wor
This is documented in the [developer docs](https://goauthentik.io/developer-docs/?utm_source=github) This is documented in the [developer docs](https://goauthentik.io/developer-docs/?utm_source=github)
### Help with the Docs
Contributions to the technical documentation are greatly appreciated. Open a PR if you have improvements to make or new content to add. If you have questions or suggestions about the documentation, open an Issue. No contribution is too small.
### Pull Requests ### Pull Requests
The process described here has several goals: The process described here has several goals:

View File

@ -20,7 +20,7 @@ WORKDIR /work/web
RUN npm ci && npm run build RUN npm ci && npm run build
# Stage 3: Poetry to requirements.txt export # Stage 3: Poetry to requirements.txt export
FROM docker.io/python:3.11.2-slim-bullseye AS poetry-locker FROM docker.io/python:3.11.3-slim-bullseye AS poetry-locker
WORKDIR /work WORKDIR /work
COPY ./pyproject.toml /work COPY ./pyproject.toml /work
@ -31,7 +31,7 @@ RUN pip install --no-cache-dir poetry && \
poetry export -f requirements.txt --dev --output requirements-dev.txt poetry export -f requirements.txt --dev --output requirements-dev.txt
# Stage 4: Build go proxy # Stage 4: Build go proxy
FROM docker.io/golang:1.20.2-bullseye AS go-builder FROM docker.io/golang:1.20.3-bullseye AS go-builder
WORKDIR /work WORKDIR /work
@ -47,7 +47,7 @@ COPY ./go.sum /work/go.sum
RUN go build -o /work/authentik ./cmd/server/ RUN go build -o /work/authentik ./cmd/server/
# Stage 5: MaxMind GeoIP # Stage 5: MaxMind GeoIP
FROM docker.io/maxmindinc/geoipupdate:v4.10 as geoip FROM docker.io/maxmindinc/geoipupdate:v5.0 as geoip
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City" ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City"
ENV GEOIPUPDATE_VERBOSE="true" ENV GEOIPUPDATE_VERBOSE="true"
@ -62,7 +62,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
" "
# Stage 6: Run # Stage 6: Run
FROM docker.io/python:3.11.2-slim-bullseye AS final-image FROM docker.io/python:3.11.3-slim-bullseye AS final-image
LABEL org.opencontainers.image.url https://goauthentik.io LABEL org.opencontainers.image.url https://goauthentik.io
LABEL org.opencontainers.image.description goauthentik.io Main server image, see https://goauthentik.io for more info. LABEL org.opencontainers.image.description goauthentik.io Main server image, see https://goauthentik.io for more info.
@ -102,7 +102,7 @@ COPY ./tests /tests
COPY ./manage.py / COPY ./manage.py /
COPY ./blueprints /blueprints COPY ./blueprints /blueprints
COPY ./lifecycle/ /lifecycle COPY ./lifecycle/ /lifecycle
COPY --from=go-builder /work/authentik /authentik-proxy COPY --from=go-builder /work/authentik /bin/authentik
COPY --from=web-builder /work/web/dist/ /web/dist/ COPY --from=web-builder /work/web/dist/ /web/dist/
COPY --from=web-builder /work/web/authentik/ /web/authentik/ COPY --from=web-builder /work/web/authentik/ /web/authentik/
COPY --from=website-builder /work/website/help/ /website/help/ COPY --from=website-builder /work/website/help/ /website/help/

View File

@ -4,6 +4,20 @@ UID = $(shell id -u)
GID = $(shell id -g) GID = $(shell id -g)
NPM_VERSION = $(shell python -m scripts.npm_version) NPM_VERSION = $(shell python -m scripts.npm_version)
CODESPELL_ARGS = -D - -D .github/codespell-dictionary.txt \
-I .github/codespell-words.txt \
-S 'web/src/locales/**' \
authentik \
internal \
cmd \
web/src \
website/src \
website/blog \
website/developer-docs \
website/docs \
website/integrations \
website/src
all: lint-fix lint test gen web all: lint-fix lint test gen web
test-go: test-go:
@ -26,14 +40,7 @@ test:
lint-fix: lint-fix:
isort authentik tests scripts lifecycle isort authentik tests scripts lifecycle
black authentik tests scripts lifecycle black authentik tests scripts lifecycle
codespell -I .github/codespell-words.txt -S 'web/src/locales/**' -w \ codespell -w $(CODESPELL_ARGS)
authentik \
internal \
cmd \
web/src \
website/src \
website/docs \
website/developer-docs
lint: lint:
pylint authentik tests lifecycle pylint authentik tests lifecycle
@ -43,9 +50,6 @@ lint:
migrate: migrate:
python -m lifecycle.migrate python -m lifecycle.migrate
run:
go run -v ./cmd/server/
i18n-extract: i18n-extract-core web-extract i18n-extract: i18n-extract-core web-extract
i18n-extract-core: i18n-extract-core:
@ -59,15 +63,20 @@ gen-build:
AUTHENTIK_DEBUG=true ak make_blueprint_schema > blueprints/schema.json AUTHENTIK_DEBUG=true ak make_blueprint_schema > blueprints/schema.json
AUTHENTIK_DEBUG=true ak spectacular --file schema.yml AUTHENTIK_DEBUG=true ak spectacular --file schema.yml
gen-changelog:
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: gen-diff:
git show $(shell git describe --abbrev=0):schema.yml > old_schema.yml git show $(shell git describe --tags $(shell git rev-list --tags --max-count=1)):schema.yml > old_schema.yml
docker run \ docker run \
--rm -v ${PWD}:/local \ --rm -v ${PWD}:/local \
--user ${UID}:${GID} \ --user ${UID}:${GID} \
docker.io/openapitools/openapi-diff:2.1.0-beta.3 \ docker.io/openapitools/openapi-diff:2.1.0-beta.6 \
--markdown /local/diff.md \ --markdown /local/diff.md \
/local/old_schema.yml /local/schema.yml /local/old_schema.yml /local/schema.yml
rm old_schema.yml rm old_schema.yml
npx prettier --write diff.md
gen-clean: gen-clean:
rm -rf web/api/src/ rm -rf web/api/src/
@ -77,7 +86,7 @@ gen-client-ts:
docker run \ docker run \
--rm -v ${PWD}:/local \ --rm -v ${PWD}:/local \
--user ${UID}:${GID} \ --user ${UID}:${GID} \
docker.io/openapitools/openapi-generator-cli:v6.0.0 generate \ docker.io/openapitools/openapi-generator-cli:v6.5.0 generate \
-i /local/schema.yml \ -i /local/schema.yml \
-g typescript-fetch \ -g typescript-fetch \
-o /local/gen-ts-api \ -o /local/gen-ts-api \
@ -90,20 +99,21 @@ gen-client-ts:
\cp -rfv gen-ts-api/* web/node_modules/@goauthentik/api \cp -rfv gen-ts-api/* web/node_modules/@goauthentik/api
gen-client-go: gen-client-go:
wget https://raw.githubusercontent.com/goauthentik/client-go/main/config.yaml -O config.yaml mkdir -p ./gen-go-api ./gen-go-api/templates
mkdir -p templates wget https://raw.githubusercontent.com/goauthentik/client-go/main/config.yaml -O ./gen-go-api/config.yaml
wget https://raw.githubusercontent.com/goauthentik/client-go/main/templates/README.mustache -O templates/README.mustache wget https://raw.githubusercontent.com/goauthentik/client-go/main/templates/README.mustache -O ./gen-go-api/templates/README.mustache
wget https://raw.githubusercontent.com/goauthentik/client-go/main/templates/go.mod.mustache -O templates/go.mod.mustache wget https://raw.githubusercontent.com/goauthentik/client-go/main/templates/go.mod.mustache -O ./gen-go-api/templates/go.mod.mustache
cp schema.yml ./gen-go-api/
docker run \ docker run \
--rm -v ${PWD}:/local \ --rm -v ${PWD}/gen-go-api:/local \
--user ${UID}:${GID} \ --user ${UID}:${GID} \
docker.io/openapitools/openapi-generator-cli:v6.0.0 generate \ docker.io/openapitools/openapi-generator-cli:v6.5.0 generate \
-i /local/schema.yml \ -i /local/schema.yml \
-g go \ -g go \
-o /local/gen-go-api \ -o /local/ \
-c /local/config.yaml -c /local/config.yaml
go mod edit -replace goauthentik.io/api/v3=./gen-go-api go mod edit -replace goauthentik.io/api/v3=./gen-go-api
rm -rf config.yaml ./templates/ rm -rf ./gen-go-api/config.yaml ./gen-go-api/templates/
gen-dev-config: gen-dev-config:
python -m scripts.generate_config python -m scripts.generate_config
@ -172,6 +182,9 @@ ci-pylint: ci--meta-debug
ci-black: ci--meta-debug ci-black: ci--meta-debug
black --check $(PY_SOURCES) black --check $(PY_SOURCES)
ci-codespell: ci--meta-debug
codespell $(CODESPELL_ARGS) -s
ci-isort: ci--meta-debug ci-isort: ci--meta-debug
isort --check $(PY_SOURCES) isort --check $(PY_SOURCES)

View File

@ -15,13 +15,13 @@
## What is authentik? ## What is authentik?
authentik is an open-source Identity Provider focused on flexibility and versatility. You can use authentik in an existing environment to add support for new protocols. authentik is also a great solution for implementing signup/recovery/etc in your application, so you don't have to deal with it. Authentik is an open-source Identity Provider that emphasizes flexibility and versatility. It can be seamlessly integrated into existing environments to support new protocols. Authentik is also a great solution for implementing sign-up, recovery, and other similar features in your application, saving you the hassle of dealing with them.
## Installation ## Installation
For small/test setups it is recommended to use docker-compose, see the [documentation](https://goauthentik.io/docs/installation/docker-compose/?utm_source=github) For small/test setups it is recommended to use Docker Compose; refer to the [documentation](https://goauthentik.io/docs/installation/docker-compose/?utm_source=github).
For bigger setups, there is a Helm Chart [here](https://github.com/goauthentik/helm). This is documented [here](https://goauthentik.io/docs/installation/kubernetes/?utm_source=github) For bigger setups, there is a Helm Chart [here](https://github.com/goauthentik/helm). This is documented [here](https://goauthentik.io/docs/installation/kubernetes/?utm_source=github).
## Screenshots ## Screenshots
@ -32,15 +32,15 @@ For bigger setups, there is a Helm Chart [here](https://github.com/goauthentik/h
## Development ## Development
See [Development Documentation](https://goauthentik.io/developer-docs/?utm_source=github) See [Developer Documentation](https://goauthentik.io/developer-docs/?utm_source=github)
## Security ## Security
See [SECURITY.md](SECURITY.md) See [SECURITY.md](SECURITY.md)
## Support ## Adoption and Contributions
Your organization uses authentik? We'd love to add your logo to the readme and our website! Email us @ hello@goauthentik.io or open a GitHub Issue/PR! Your organization uses authentik? We'd love to add your logo to the readme and our website! Email us @ hello@goauthentik.io or open a GitHub Issue/PR! For more information on how to contribute to authentik, please refer to our [CONTRIBUTING.md file](./CONTRIBUTING.md).
## Sponsors ## Sponsors

View File

@ -2,7 +2,7 @@
from os import environ from os import environ
from typing import Optional from typing import Optional
__version__ = "2023.3.0" __version__ = "2023.4.1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -7,82 +7,13 @@ API Browser - {{ tenant.branding_title }}
{% endblock %} {% endblock %}
{% block head %} {% block head %}
<script type="module" src="{% static 'dist/rapidoc-min.js' %}"></script> <script src="{% static 'dist/standalone/api-browser/index.js' %}?version={{ version }}" type="module"></script>
<script> <meta name="theme-color" content="#151515" media="(prefers-color-scheme: light)">
function getCookie(name) { <meta name="theme-color" content="#151515" media="(prefers-color-scheme: dark)">
let cookieValue = ""; <link rel="icon" href="{{ tenant.branding_favicon }}">
if (document.cookie && document.cookie !== "") { <link rel="shortcut icon" href="{{ tenant.branding_favicon }}">
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === name + "=") {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
window.addEventListener('DOMContentLoaded', (event) => {
const rapidocEl = document.querySelector('rapi-doc');
rapidocEl.addEventListener('before-try', (e) => {
e.detail.request.headers.append('X-authentik-CSRF', getCookie("authentik_csrf"));
});
});
</script>
<style>
img.logo {
width: 100%;
padding: 1rem 0.5rem 1.5rem 0.5rem;
min-height: 48px;
}
</style>
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<rapi-doc <ak-api-browser schemaPath="{{ path }}"></ak-api-browser>
spec-url="{{ path }}"
heading-text=""
theme="light"
render-style="read"
default-schema-tab="schema"
primary-color="#fd4b2d"
nav-bg-color="#212427"
bg-color="#000000"
text-color="#000000"
nav-text-color="#ffffff"
nav-hover-bg-color="#3c3f42"
nav-accent-color="#4f5255"
nav-hover-text-color="#ffffff"
use-path-in-nav-bar="true"
nav-item-spacing="relaxed"
allow-server-selection="false"
show-header="false"
allow-spec-url-load="false"
allow-spec-file-load="false">
<div slot="nav-logo">
<img alt="authentik Logo" class="logo" src="{% static 'dist/assets/icons/icon_left_brand.png' %}" />
</div>
</rapi-doc>
<script>
const rapidoc = document.querySelector("rapi-doc");
const matcher = window.matchMedia("(prefers-color-scheme: light)");
const changer = (ev) => {
const style = getComputedStyle(document.documentElement);
let bg, text = "";
if (matcher.matches) {
bg = style.getPropertyValue('--pf-global--BackgroundColor--light-300');
text = style.getPropertyValue('--pf-global--Color--300');
} else {
bg = style.getPropertyValue('--ak-dark-background');
text = style.getPropertyValue('--ak-dark-foreground');
}
rapidoc.attributes.getNamedItem("bg-color").value = bg.trim();
rapidoc.attributes.getNamedItem("text-color").value = text.trim();
rapidoc.requestUpdate();
};
matcher.addEventListener("change", changer);
window.addEventListener("load", changer);
</script>
{% endblock %} {% endblock %}

View File

@ -56,6 +56,7 @@ from authentik.providers.oauth2.api.tokens import (
RefreshTokenViewSet, RefreshTokenViewSet,
) )
from authentik.providers.proxy.api import ProxyOutpostConfigViewSet, ProxyProviderViewSet from authentik.providers.proxy.api import ProxyOutpostConfigViewSet, ProxyProviderViewSet
from authentik.providers.radius.api import RadiusOutpostConfigViewSet, RadiusProviderViewSet
from authentik.providers.saml.api.property_mapping import SAMLPropertyMappingViewSet from authentik.providers.saml.api.property_mapping import SAMLPropertyMappingViewSet
from authentik.providers.saml.api.providers import SAMLProviderViewSet from authentik.providers.saml.api.providers import SAMLProviderViewSet
from authentik.providers.scim.api.property_mapping import SCIMMappingViewSet from authentik.providers.scim.api.property_mapping import SCIMMappingViewSet
@ -128,6 +129,7 @@ router.register("outposts/service_connections/docker", DockerServiceConnectionVi
router.register("outposts/service_connections/kubernetes", KubernetesServiceConnectionViewSet) router.register("outposts/service_connections/kubernetes", KubernetesServiceConnectionViewSet)
router.register("outposts/proxy", ProxyOutpostConfigViewSet) router.register("outposts/proxy", ProxyOutpostConfigViewSet)
router.register("outposts/ldap", LDAPOutpostConfigViewSet) router.register("outposts/ldap", LDAPOutpostConfigViewSet)
router.register("outposts/radius", RadiusOutpostConfigViewSet)
router.register("flows/instances", FlowViewSet) router.register("flows/instances", FlowViewSet)
router.register("flows/bindings", FlowStageBindingViewSet) router.register("flows/bindings", FlowStageBindingViewSet)
@ -166,6 +168,7 @@ router.register("providers/proxy", ProxyProviderViewSet)
router.register("providers/oauth2", OAuth2ProviderViewSet) router.register("providers/oauth2", OAuth2ProviderViewSet)
router.register("providers/saml", SAMLProviderViewSet) router.register("providers/saml", SAMLProviderViewSet)
router.register("providers/scim", SCIMProviderViewSet) router.register("providers/scim", SCIMProviderViewSet)
router.register("providers/radius", RadiusProviderViewSet)
router.register("oauth2/authorization_codes", AuthorizationCodeViewSet) router.register("oauth2/authorization_codes", AuthorizationCodeViewSet)
router.register("oauth2/refresh_tokens", RefreshTokenViewSet) router.register("oauth2/refresh_tokens", RefreshTokenViewSet)

View File

@ -19,10 +19,8 @@ class Command(BaseCommand):
for blueprint_path in options.get("blueprints", []): for blueprint_path in options.get("blueprints", []):
content = BlueprintInstance(path=blueprint_path).retrieve() content = BlueprintInstance(path=blueprint_path).retrieve()
importer = Importer(content) importer = Importer(content)
valid, logs = importer.validate() valid, _ = importer.validate()
if not valid: if not valid:
for log in logs:
getattr(LOGGER, log.pop("log_level"))(**log)
self.stderr.write("blueprint invalid") self.stderr.write("blueprint invalid")
sys_exit(1) sys_exit(1)
importer.apply() importer.apply()

View File

@ -40,6 +40,10 @@ from authentik.lib.models import SerializerModel
from authentik.outposts.models import OutpostServiceConnection from authentik.outposts.models import OutpostServiceConnection
from authentik.policies.models import Policy, PolicyBindingModel from authentik.policies.models import Policy, PolicyBindingModel
# Context set when the serializer is created in a blueprint context
# Update website/developer-docs/blueprints/v1/models.md when used
SERIALIZER_CONTEXT_BLUEPRINT = "blueprint_entry"
def is_model_allowed(model: type[Model]) -> bool: def is_model_allowed(model: type[Model]) -> bool:
"""Check if model is allowed""" """Check if model is allowed"""
@ -158,7 +162,12 @@ class Importer:
raise EntryInvalidError(f"Model {model} not allowed") raise EntryInvalidError(f"Model {model} not allowed")
if issubclass(model, BaseMetaModel): if issubclass(model, BaseMetaModel):
serializer_class: type[Serializer] = model.serializer() serializer_class: type[Serializer] = model.serializer()
serializer = serializer_class(data=entry.get_attrs(self.__import)) serializer = serializer_class(
data=entry.get_attrs(self.__import),
context={
SERIALIZER_CONTEXT_BLUEPRINT: entry,
},
)
try: try:
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
except ValidationError as exc: except ValidationError as exc:
@ -217,7 +226,12 @@ class Importer:
always_merger.merge(full_data, updated_identifiers) always_merger.merge(full_data, updated_identifiers)
serializer_kwargs["data"] = full_data serializer_kwargs["data"] = full_data
serializer: Serializer = model().serializer(**serializer_kwargs) serializer: Serializer = model().serializer(
context={
SERIALIZER_CONTEXT_BLUEPRINT: entry,
},
**serializer_kwargs,
)
try: try:
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
except ValidationError as exc: except ValidationError as exc:

View File

@ -122,7 +122,7 @@ def blueprints_find():
) )
blueprint.meta = from_dict(BlueprintMetadata, metadata) if metadata else None blueprint.meta = from_dict(BlueprintMetadata, metadata) if metadata else None
blueprints.append(blueprint) blueprints.append(blueprint)
LOGGER.info( LOGGER.debug(
"parsed & loaded blueprint", "parsed & loaded blueprint",
hash=file_hash, hash=file_hash,
path=str(path), path=str(path),

View File

@ -35,6 +35,7 @@ class ProviderSerializer(ModelSerializer, MetaNameSerializer):
fields = [ fields = [
"pk", "pk",
"name", "name",
"authentication_flow",
"authorization_flow", "authorization_flow",
"property_mappings", "property_mappings",
"component", "component",

View File

@ -16,6 +16,7 @@ from rest_framework.viewsets import ModelViewSet
from authentik.api.authorization import OwnerSuperuserPermissions from authentik.api.authorization import OwnerSuperuserPermissions
from authentik.api.decorators import permission_required from authentik.api.decorators import permission_required
from authentik.blueprints.api import ManagedSerializer from authentik.blueprints.api import ManagedSerializer
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.users import UserSerializer from authentik.core.api.users import UserSerializer
from authentik.core.api.utils import PassiveSerializer from authentik.core.api.utils import PassiveSerializer
@ -29,6 +30,11 @@ class TokenSerializer(ManagedSerializer, ModelSerializer):
user_obj = UserSerializer(required=False, source="user", read_only=True) user_obj = UserSerializer(required=False, source="user", read_only=True)
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
if SERIALIZER_CONTEXT_BLUEPRINT in self.context:
self.fields["key"] = CharField()
def validate(self, attrs: dict[Any, str]) -> dict[Any, str]: def validate(self, attrs: dict[Any, str]) -> dict[Any, str]:
"""Ensure only API or App password tokens are created.""" """Ensure only API or App password tokens are created."""
request: Request = self.context.get("request") request: Request = self.context.get("request")

View File

@ -211,8 +211,9 @@ class UserMetricsSerializer(PassiveSerializer):
def get_logins(self, _): def get_logins(self, _):
"""Get successful logins per 8 hours for the last 7 days""" """Get successful logins per 8 hours for the last 7 days"""
user = self.context["user"] user = self.context["user"]
request = self.context["request"]
return ( return (
get_objects_for_user(user, "authentik_events.view_event").filter( get_objects_for_user(request.user, "authentik_events.view_event").filter(
action=EventAction.LOGIN, user__pk=user.pk action=EventAction.LOGIN, user__pk=user.pk
) )
# 3 data points per day, so 8 hour spans # 3 data points per day, so 8 hour spans
@ -223,8 +224,9 @@ class UserMetricsSerializer(PassiveSerializer):
def get_logins_failed(self, _): def get_logins_failed(self, _):
"""Get failed logins per 8 hours for the last 7 days""" """Get failed logins per 8 hours for the last 7 days"""
user = self.context["user"] user = self.context["user"]
request = self.context["request"]
return ( return (
get_objects_for_user(user, "authentik_events.view_event").filter( get_objects_for_user(request.user, "authentik_events.view_event").filter(
action=EventAction.LOGIN_FAILED, context__username=user.username action=EventAction.LOGIN_FAILED, context__username=user.username
) )
# 3 data points per day, so 8 hour spans # 3 data points per day, so 8 hour spans
@ -235,8 +237,9 @@ class UserMetricsSerializer(PassiveSerializer):
def get_authorizations(self, _): def get_authorizations(self, _):
"""Get failed logins per 8 hours for the last 7 days""" """Get failed logins per 8 hours for the last 7 days"""
user = self.context["user"] user = self.context["user"]
request = self.context["request"]
return ( return (
get_objects_for_user(user, "authentik_events.view_event").filter( get_objects_for_user(request.user, "authentik_events.view_event").filter(
action=EventAction.AUTHORIZE_APPLICATION, user__pk=user.pk action=EventAction.AUTHORIZE_APPLICATION, user__pk=user.pk
) )
# 3 data points per day, so 8 hour spans # 3 data points per day, so 8 hour spans
@ -471,8 +474,9 @@ class UserViewSet(UsedByMixin, ModelViewSet):
def metrics(self, request: Request, pk: int) -> Response: def metrics(self, request: Request, pk: int) -> Response:
"""User metrics per 1h""" """User metrics per 1h"""
user: User = self.get_object() user: User = self.get_object()
serializer = UserMetricsSerializer(True) serializer = UserMetricsSerializer(instance={})
serializer.context["user"] = user serializer.context["user"] = user
serializer.context["request"] = request
return Response(serializer.data) return Response(serializer.data)
@permission_required("authentik_core.reset_user_password") @permission_required("authentik_core.reset_user_password")

View File

@ -11,6 +11,7 @@ class AuthentikCoreConfig(ManagedAppConfig):
label = "authentik_core" label = "authentik_core"
verbose_name = "authentik Core" verbose_name = "authentik Core"
mountpoint = "" mountpoint = ""
ws_mountpoint = "authentik.core.urls"
default = True default = True
def reconcile_load_core_signals(self): def reconcile_load_core_signals(self):

View File

@ -21,11 +21,14 @@ PROPERTY_MAPPING_TIME = Histogram(
class PropertyMappingEvaluator(BaseEvaluator): class PropertyMappingEvaluator(BaseEvaluator):
"""Custom Evaluator that adds some different context variables.""" """Custom Evaluator that adds some different context variables."""
dry_run: bool
def __init__( def __init__(
self, self,
model: Model, model: Model,
user: Optional[User] = None, user: Optional[User] = None,
request: Optional[HttpRequest] = None, request: Optional[HttpRequest] = None,
dry_run: Optional[bool] = False,
**kwargs, **kwargs,
): ):
if hasattr(model, "name"): if hasattr(model, "name"):
@ -42,9 +45,13 @@ class PropertyMappingEvaluator(BaseEvaluator):
req.http_request = request req.http_request = request
self._context["request"] = req self._context["request"] = req
self._context.update(**kwargs) self._context.update(**kwargs)
self.dry_run = dry_run
def handle_error(self, exc: Exception, expression_source: str): def handle_error(self, exc: Exception, expression_source: str):
"""Exception Handler""" """Exception Handler"""
# For dry-run requests we don't save exceptions
if self.dry_run:
return
error_string = exception_to_string(exc) error_string = exception_to_string(exc)
event = Event.new( event = Event.new(
EventAction.PROPERTY_MAPPING_EXCEPTION, EventAction.PROPERTY_MAPPING_EXCEPTION,

View File

@ -0,0 +1,19 @@
# Generated by Django 4.1.7 on 2023-03-19 21:57
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0026_alter_propertymapping_name_alter_provider_name"),
]
operations = [
migrations.AlterField(
model_name="user",
name="uuid",
field=models.UUIDField(default=uuid.uuid4, editable=False, unique=True),
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 4.1.7 on 2023-03-23 21:44
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_flows", "0025_alter_flowstagebinding_evaluate_on_plan_and_more"),
("authentik_core", "0027_alter_user_uuid"),
]
operations = [
migrations.AddField(
model_name="provider",
name="authentication_flow",
field=models.ForeignKey(
help_text="Flow used for authentication when the associated application is accessed by an un-authenticated user.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="provider_authentication",
to="authentik_flows.flow",
),
),
]

View File

@ -146,7 +146,7 @@ class UserManager(DjangoUserManager):
class User(SerializerModel, GuardianUserMixin, AbstractUser): class User(SerializerModel, GuardianUserMixin, AbstractUser):
"""Custom User model to allow easier adding of user-based settings""" """Custom User model to allow easier adding of user-based settings"""
uuid = models.UUIDField(default=uuid4, editable=False) uuid = models.UUIDField(default=uuid4, editable=False, unique=True)
name = models.TextField(help_text=_("User's display name.")) name = models.TextField(help_text=_("User's display name."))
path = models.TextField(default="users") path = models.TextField(default="users")
@ -249,6 +249,17 @@ class Provider(SerializerModel):
name = models.TextField(unique=True) name = models.TextField(unique=True)
authentication_flow = models.ForeignKey(
"authentik_flows.Flow",
null=True,
on_delete=models.SET_NULL,
help_text=_(
"Flow used for authentication when the associated application is accessed by an "
"un-authenticated user."
),
related_name="provider_authentication",
)
authorization_flow = models.ForeignKey( authorization_flow = models.ForeignKey(
"authentik_flows.Flow", "authentik_flows.Flow",
on_delete=models.CASCADE, on_delete=models.CASCADE,

View File

@ -9,16 +9,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>{% block title %}{% trans title|default:tenant.branding_title %}{% endblock %}</title> <title>{% block title %}{% trans title|default:tenant.branding_title %}{% endblock %}</title>
<link rel="shortcut icon" type="image/png" href="{% static 'dist/assets/icons/icon.png' %}"> <link rel="shortcut icon" type="image/png" href="{% static 'dist/assets/icons/icon.png' %}">
<link rel="stylesheet" type="text/css" href="{% static 'dist/patternfly-base.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'dist/page.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'dist/empty-state.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'dist/spinner.css' %}">
{% block head_before %} {% block head_before %}
{% endblock %} {% endblock %}
<link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}"> <link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'dist/theme-dark.css' %}" media="(prefers-color-scheme: dark)"> <link rel="stylesheet" type="text/css" href="{% static 'dist/theme-dark.css' %}" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" type="text/css" href="{% static 'dist/custom.css' %}" data-inject> <link rel="stylesheet" type="text/css" href="{% static 'dist/custom.css' %}" data-inject>
<script src="{% static 'dist/poly.js' %}" type="module"></script> <script src="{% static 'dist/poly.js' %}?version={{ version }}" type="module"></script>
<script src="{% static 'dist/standalone/loading/index.js' %}?version={{ version }}" type="module"></script>
{% block head %} {% block head %}
{% endblock %} {% endblock %}
<meta name="sentry-trace" content="{{ sentry_trace }}" /> <meta name="sentry-trace" content="{{ sentry_trace }}" />

View File

@ -1,7 +1,6 @@
{% extends "base/skeleton.html" %} {% extends "base/skeleton.html" %}
{% load static %} {% load static %}
{% load i18n %}
{% block head %} {% block head %}
<script src="{% static 'dist/admin/AdminInterface.js' %}?version={{ version }}" type="module"></script> <script src="{% static 'dist/admin/AdminInterface.js' %}?version={{ version }}" type="module"></script>
@ -15,19 +14,6 @@
{% block body %} {% block body %}
<ak-message-container></ak-message-container> <ak-message-container></ak-message-container>
<ak-interface-admin> <ak-interface-admin>
<section class="ak-static-page pf-c-page__main-section pf-m-no-padding-mobile pf-m-xl"> <ak-loading></ak-loading>
<div class="pf-c-empty-state" style="height: 100vh;">
<div class="pf-c-empty-state__content">
<span class="pf-c-spinner pf-m-xl pf-c-empty-state__icon" role="progressbar" aria-valuetext="{% trans 'Loading...' %}">
<span class="pf-c-spinner__clipper"></span>
<span class="pf-c-spinner__lead-ball"></span>
<span class="pf-c-spinner__tail-ball"></span>
</span>
<h1 class="pf-c-title pf-m-lg">
{% trans "Loading..." %}
</h1>
</div>
</div>
</section>
</ak-interface-admin> </ak-interface-admin>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,6 @@
{% extends "base/skeleton.html" %} {% extends "base/skeleton.html" %}
{% load static %} {% load static %}
{% load i18n %}
{% block head_before %} {% block head_before %}
{{ block.super }} {{ block.super }}
@ -31,19 +30,6 @@ window.authentik.flow = {
{% block body %} {% block body %}
<ak-message-container></ak-message-container> <ak-message-container></ak-message-container>
<ak-flow-executor> <ak-flow-executor>
<section class="ak-static-page pf-c-page__main-section pf-m-no-padding-mobile pf-m-xl"> <ak-loading></ak-loading>
<div class="pf-c-empty-state" style="height: 100vh;">
<div class="pf-c-empty-state__content">
<span class="pf-c-spinner pf-m-xl pf-c-empty-state__icon" role="progressbar" aria-valuetext="{% trans 'Loading...' %}">
<span class="pf-c-spinner__clipper"></span>
<span class="pf-c-spinner__lead-ball"></span>
<span class="pf-c-spinner__tail-ball"></span>
</span>
<h1 class="pf-c-title pf-m-lg">
{% trans "Loading..." %}
</h1>
</div>
</div>
</section>
</ak-flow-executor> </ak-flow-executor>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,6 @@
{% extends "base/skeleton.html" %} {% extends "base/skeleton.html" %}
{% load static %} {% load static %}
{% load i18n %}
{% block head %} {% block head %}
<script src="{% static 'dist/user/UserInterface.js' %}?version={{ version }}" type="module"></script> <script src="{% static 'dist/user/UserInterface.js' %}?version={{ version }}" type="module"></script>
@ -15,19 +14,6 @@
{% block body %} {% block body %}
<ak-message-container></ak-message-container> <ak-message-container></ak-message-container>
<ak-interface-user> <ak-interface-user>
<section class="ak-static-page pf-c-page__main-section pf-m-no-padding-mobile pf-m-xl"> <ak-loading></ak-loading>
<div class="pf-c-empty-state" style="height: 100vh;">
<div class="pf-c-empty-state__content">
<span class="pf-c-spinner pf-m-xl pf-c-empty-state__icon" role="progressbar" aria-valuetext="{% trans 'Loading...' %}">
<span class="pf-c-spinner__clipper"></span>
<span class="pf-c-spinner__lead-ball"></span>
<span class="pf-c-spinner__tail-ball"></span>
</span>
<h1 class="pf-c-title pf-m-lg">
{% trans "Loading..." %}
</h1>
</div>
</div>
</section>
</ak-interface-user> </ak-interface-user>
{% endblock %} {% endblock %}

View File

@ -129,6 +129,7 @@ class TestApplicationsAPI(APITestCase):
"provider_obj": { "provider_obj": {
"assigned_application_name": "allowed", "assigned_application_name": "allowed",
"assigned_application_slug": "allowed", "assigned_application_slug": "allowed",
"authentication_flow": None,
"authorization_flow": str(self.provider.authorization_flow.pk), "authorization_flow": str(self.provider.authorization_flow.pk),
"component": "ak-provider-oauth2-form", "component": "ak-provider-oauth2-form",
"meta_model_name": "authentik_providers_oauth2.oauth2provider", "meta_model_name": "authentik_providers_oauth2.oauth2provider",
@ -178,6 +179,7 @@ class TestApplicationsAPI(APITestCase):
"provider_obj": { "provider_obj": {
"assigned_application_name": "allowed", "assigned_application_name": "allowed",
"assigned_application_slug": "allowed", "assigned_application_slug": "allowed",
"authentication_flow": None,
"authorization_flow": str(self.provider.authorization_flow.pk), "authorization_flow": str(self.provider.authorization_flow.pk),
"component": "ak-provider-oauth2-form", "component": "ak-provider-oauth2-form",
"meta_model_name": "authentik_providers_oauth2.oauth2provider", "meta_model_name": "authentik_providers_oauth2.oauth2provider",

View File

@ -4,7 +4,10 @@ from guardian.shortcuts import get_anonymous_user
from authentik.core.exceptions import PropertyMappingExpressionException from authentik.core.exceptions import PropertyMappingExpressionException
from authentik.core.models import PropertyMapping from authentik.core.models import PropertyMapping
from authentik.core.tests.utils import create_test_admin_user
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.lib.generators import generate_id
from authentik.policies.expression.models import ExpressionPolicy
class TestPropertyMappings(TestCase): class TestPropertyMappings(TestCase):
@ -12,23 +15,24 @@ class TestPropertyMappings(TestCase):
def setUp(self) -> None: def setUp(self) -> None:
super().setUp() super().setUp()
self.user = create_test_admin_user()
self.factory = RequestFactory() self.factory = RequestFactory()
def test_expression(self): def test_expression(self):
"""Test expression""" """Test expression"""
mapping = PropertyMapping.objects.create(name="test", expression="return 'test'") mapping = PropertyMapping.objects.create(name=generate_id(), expression="return 'test'")
self.assertEqual(mapping.evaluate(None, None), "test") self.assertEqual(mapping.evaluate(None, None), "test")
def test_expression_syntax(self): def test_expression_syntax(self):
"""Test expression syntax error""" """Test expression syntax error"""
mapping = PropertyMapping.objects.create(name="test", expression="-") mapping = PropertyMapping.objects.create(name=generate_id(), expression="-")
with self.assertRaises(PropertyMappingExpressionException): with self.assertRaises(PropertyMappingExpressionException):
mapping.evaluate(None, None) mapping.evaluate(None, None)
def test_expression_error_general(self): def test_expression_error_general(self):
"""Test expression error""" """Test expression error"""
expr = "return aaa" expr = "return aaa"
mapping = PropertyMapping.objects.create(name="test", expression=expr) mapping = PropertyMapping.objects.create(name=generate_id(), expression=expr)
with self.assertRaises(PropertyMappingExpressionException): with self.assertRaises(PropertyMappingExpressionException):
mapping.evaluate(None, None) mapping.evaluate(None, None)
events = Event.objects.filter( events = Event.objects.filter(
@ -41,7 +45,7 @@ class TestPropertyMappings(TestCase):
"""Test expression error (with user and http request""" """Test expression error (with user and http request"""
expr = "return aaa" expr = "return aaa"
request = self.factory.get("/") request = self.factory.get("/")
mapping = PropertyMapping.objects.create(name="test", expression=expr) mapping = PropertyMapping.objects.create(name=generate_id(), expression=expr)
with self.assertRaises(PropertyMappingExpressionException): with self.assertRaises(PropertyMappingExpressionException):
mapping.evaluate(get_anonymous_user(), request) mapping.evaluate(get_anonymous_user(), request)
events = Event.objects.filter( events = Event.objects.filter(
@ -52,3 +56,23 @@ class TestPropertyMappings(TestCase):
event = events.first() event = events.first()
self.assertEqual(event.user["username"], "AnonymousUser") self.assertEqual(event.user["username"], "AnonymousUser")
self.assertEqual(event.client_ip, "127.0.0.1") self.assertEqual(event.client_ip, "127.0.0.1")
def test_call_policy(self):
"""test ak_call_policy"""
expr = ExpressionPolicy.objects.create(
name=generate_id(),
execution_logging=True,
expression="return request.http_request.path",
)
http_request = self.factory.get("/")
tmpl = (
"""
res = ak_call_policy('%s')
result = [request.http_request.path, res.raw_result]
return result
"""
% expr.name
)
evaluator = PropertyMapping(expression=tmpl, name=generate_id())
res = evaluator.evaluate(self.user, http_request)
self.assertEqual(res, ["/", "/"])

View File

@ -27,6 +27,6 @@ class UserSettingSerializer(PassiveSerializer):
object_uid = CharField() object_uid = CharField()
component = CharField() component = CharField()
title = CharField() title = CharField(required=True)
configure_url = CharField(required=False) configure_url = CharField(required=False)
icon_url = CharField(required=False) icon_url = CharField(required=False)

View File

@ -1,4 +1,6 @@
"""authentik URL Configuration""" """authentik URL Configuration"""
from channels.auth import AuthMiddleware
from channels.sessions import CookieMiddleware
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.urls import path from django.urls import path
@ -9,6 +11,8 @@ from authentik.core.views import apps, impersonate
from authentik.core.views.debug import AccessDeniedView from authentik.core.views.debug import AccessDeniedView
from authentik.core.views.interface import FlowInterfaceView, InterfaceView from authentik.core.views.interface import FlowInterfaceView, InterfaceView
from authentik.core.views.session import EndSessionView from authentik.core.views.session import EndSessionView
from authentik.root.asgi_middleware import SessionMiddleware
from authentik.root.messages.consumer import MessageConsumer
urlpatterns = [ urlpatterns = [
path( path(
@ -64,6 +68,12 @@ urlpatterns = [
), ),
] ]
websocket_urlpatterns = [
path(
"ws/client/", CookieMiddleware(SessionMiddleware(AuthMiddleware(MessageConsumer.as_asgi())))
),
]
if settings.DEBUG: if settings.DEBUG:
urlpatterns += [ urlpatterns += [
path("debug/policy/deny/", AccessDeniedView.as_view(), name="debug-policy-deny"), path("debug/policy/deny/", AccessDeniedView.as_view(), name="debug-policy-deny"),

View File

@ -12,16 +12,19 @@ from authentik.flows.challenge import (
RedirectChallenge, RedirectChallenge,
) )
from authentik.flows.exceptions import FlowNonApplicableException from authentik.flows.exceptions import FlowNonApplicableException
from authentik.flows.models import in_memory_stage from authentik.flows.models import FlowDesignation, in_memory_stage
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, FlowPlanner from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, FlowPlanner
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
from authentik.flows.views.executor import SESSION_KEY_PLAN from authentik.flows.views.executor import (
SESSION_KEY_APPLICATION_PRE,
SESSION_KEY_PLAN,
ToDefaultFlow,
)
from authentik.lib.utils.urls import redirect_with_qs from authentik.lib.utils.urls import redirect_with_qs
from authentik.stages.consent.stage import ( from authentik.stages.consent.stage import (
PLAN_CONTEXT_CONSENT_HEADER, PLAN_CONTEXT_CONSENT_HEADER,
PLAN_CONTEXT_CONSENT_PERMISSIONS, PLAN_CONTEXT_CONSENT_PERMISSIONS,
) )
from authentik.tenants.models import Tenant
class RedirectToAppLaunch(View): class RedirectToAppLaunch(View):
@ -36,10 +39,10 @@ class RedirectToAppLaunch(View):
# Check if we're authenticated already, saves us the flow run # Check if we're authenticated already, saves us the flow run
if request.user.is_authenticated: if request.user.is_authenticated:
return HttpResponseRedirect(app.get_launch_url(request.user)) return HttpResponseRedirect(app.get_launch_url(request.user))
self.request.session[SESSION_KEY_APPLICATION_PRE] = app
# otherwise, do a custom flow plan that includes the application that's # otherwise, do a custom flow plan that includes the application that's
# being accessed, to improve usability # being accessed, to improve usability
tenant: Tenant = request.tenant flow = ToDefaultFlow(request=request, designation=FlowDesignation.AUTHENTICATION).get_flow()
flow = tenant.flow_authentication
planner = FlowPlanner(flow) planner = FlowPlanner(flow)
planner.allow_empty_flows = True planner.allow_empty_flows = True
try: try:

View File

@ -214,11 +214,18 @@ class Event(SerializerModel, ExpiringModel):
Events independently from requests. Events independently from requests.
`user` arguments optionally overrides user from requests.""" `user` arguments optionally overrides user from requests."""
if request: if request:
from authentik.flows.views.executor import QS_QUERY
self.context["http_request"] = { self.context["http_request"] = {
"path": request.path, "path": request.path,
"method": request.method, "method": request.method,
"args": QueryDict(request.META.get("QUERY_STRING", "")), "args": QueryDict(request.META.get("QUERY_STRING", "")),
} }
# Special case for events created during flow execution
# since they keep the http query within a wrapped query
if QS_QUERY in self.context["http_request"]["args"]:
wrapped = self.context["http_request"]["args"][QS_QUERY]
self.context["http_request"]["args"] = QueryDict(wrapped)
if hasattr(request, "tenant"): if hasattr(request, "tenant"):
tenant: Tenant = request.tenant tenant: Tenant = request.tenant
# Because self.created only gets set on save, we can't use it's value here # Because self.created only gets set on save, we can't use it's value here

View File

@ -271,6 +271,15 @@ class ConfigurableStage(models.Model):
abstract = True abstract = True
class FriendlyNamedStage(models.Model):
"""Abstract base class for a Stage that can have a user friendly name configured."""
friendly_name = models.TextField(null=True)
class Meta:
abstract = True
class FlowToken(Token): class FlowToken(Token):
"""Subclass of a standard Token, stores the currently active flow plan upon creation. """Subclass of a standard Token, stores the currently active flow plan upon creation.
Can be used to later resume a flow.""" Can be used to later resume a flow."""

View File

@ -2,10 +2,13 @@
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_flow from authentik.core.tests.utils import create_test_flow
from authentik.flows.models import Flow, FlowDesignation from authentik.flows.models import Flow, FlowDesignation
from authentik.flows.planner import FlowPlan from authentik.flows.planner import FlowPlan
from authentik.flows.views.executor import SESSION_KEY_PLAN from authentik.flows.views.executor import SESSION_KEY_APPLICATION_PRE, SESSION_KEY_PLAN
from authentik.lib.generators import generate_id
from authentik.providers.oauth2.models import OAuth2Provider
class TestHelperView(TestCase): class TestHelperView(TestCase):
@ -22,6 +25,41 @@ class TestHelperView(TestCase):
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, expected_url) self.assertEqual(response.url, expected_url)
def test_default_view_app(self):
"""Test that ToDefaultFlow returns the expected URL (when accessing an application)"""
Flow.objects.filter(designation=FlowDesignation.AUTHENTICATION).delete()
flow = create_test_flow(FlowDesignation.AUTHENTICATION)
self.client.session[SESSION_KEY_APPLICATION_PRE] = Application(
name=generate_id(),
slug=generate_id(),
provider=OAuth2Provider(
name=generate_id(),
authentication_flow=flow,
),
)
response = self.client.get(
reverse("authentik_flows:default-authentication"),
)
expected_url = reverse("authentik_core:if-flow", kwargs={"flow_slug": flow.slug})
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, expected_url)
def test_default_view_app_no_provider(self):
"""Test that ToDefaultFlow returns the expected URL
(when accessing an application, without a provider)"""
Flow.objects.filter(designation=FlowDesignation.AUTHENTICATION).delete()
flow = create_test_flow(FlowDesignation.AUTHENTICATION)
self.client.session[SESSION_KEY_APPLICATION_PRE] = Application(
name=generate_id(),
slug=generate_id(),
)
response = self.client.get(
reverse("authentik_flows:default-authentication"),
)
expected_url = reverse("authentik_core:if-flow", kwargs={"flow_slug": flow.slug})
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, expected_url)
def test_default_view_invalid_plan(self): def test_default_view_invalid_plan(self):
"""Test that ToDefaultFlow returns the expected URL (with an invalid plan)""" """Test that ToDefaultFlow returns the expected URL (with an invalid plan)"""
Flow.objects.filter(designation=FlowDesignation.INVALIDATION).delete() Flow.objects.filter(designation=FlowDesignation.INVALIDATION).delete()

View File

@ -22,6 +22,7 @@ from sentry_sdk.api import set_tag
from sentry_sdk.hub import Hub from sentry_sdk.hub import Hub
from structlog.stdlib import BoundLogger, get_logger from structlog.stdlib import BoundLogger, get_logger
from authentik.core.models import Application
from authentik.events.models import Event, EventAction, cleanse_dict from authentik.events.models import Event, EventAction, cleanse_dict
from authentik.flows.challenge import ( from authentik.flows.challenge import (
Challenge, Challenge,
@ -68,6 +69,7 @@ SESSION_KEY_GET = "authentik/flows/get"
SESSION_KEY_POST = "authentik/flows/post" SESSION_KEY_POST = "authentik/flows/post"
SESSION_KEY_HISTORY = "authentik/flows/history" SESSION_KEY_HISTORY = "authentik/flows/history"
QS_KEY_TOKEN = "flow_token" # nosec QS_KEY_TOKEN = "flow_token" # nosec
QS_QUERY = "query"
def challenge_types(): def challenge_types():
@ -172,7 +174,7 @@ class FlowExecutorView(APIView):
op="authentik.flow.executor.dispatch", description=self.flow.slug op="authentik.flow.executor.dispatch", description=self.flow.slug
) as span: ) as span:
span.set_data("authentik Flow", self.flow.slug) span.set_data("authentik Flow", self.flow.slug)
get_params = QueryDict(request.GET.get("query", "")) get_params = QueryDict(request.GET.get(QS_QUERY, ""))
if QS_KEY_TOKEN in get_params: if QS_KEY_TOKEN in get_params:
plan = self._check_flow_token(get_params[QS_KEY_TOKEN]) plan = self._check_flow_token(get_params[QS_KEY_TOKEN])
if plan: if plan:
@ -475,20 +477,32 @@ class ToDefaultFlow(View):
LOGGER.debug("flow_by_policy: no flow found", filters=flow_filter) LOGGER.debug("flow_by_policy: no flow found", filters=flow_filter)
return None return None
def dispatch(self, request: HttpRequest) -> HttpResponse: def get_flow(self) -> Flow:
tenant: Tenant = request.tenant """Get a flow for the selected designation"""
tenant: Tenant = self.request.tenant
flow = None flow = None
# First, attempt to get default flow from tenant # First, attempt to get default flow from tenant
if self.designation == FlowDesignation.AUTHENTICATION: if self.designation == FlowDesignation.AUTHENTICATION:
flow = tenant.flow_authentication flow = tenant.flow_authentication
if self.designation == FlowDesignation.INVALIDATION: # Check if we have a default flow from application
application: Optional[Application] = self.request.session.get(
SESSION_KEY_APPLICATION_PRE
)
if application and application.provider and application.provider.authentication_flow:
flow = application.provider.authentication_flow
elif self.designation == FlowDesignation.INVALIDATION:
flow = tenant.flow_invalidation flow = tenant.flow_invalidation
if flow:
return flow
# If no flow was set, get the first based on slug and policy # If no flow was set, get the first based on slug and policy
if not flow: flow = self.flow_by_policy(self.request, designation=self.designation)
flow = self.flow_by_policy(request, designation=self.designation) if flow:
return flow
# If we still don't have a flow, 404 # If we still don't have a flow, 404
if not flow: raise Http404
raise Http404
def dispatch(self, request: HttpRequest) -> HttpResponse:
flow = self.get_flow()
# If user already has a pending plan, clear it so we don't have to later. # If user already has a pending plan, clear it so we don't have to later.
if SESSION_KEY_PLAN in self.request.session: if SESSION_KEY_PLAN in self.request.session:
plan: FlowPlan = self.request.session[SESSION_KEY_PLAN] plan: FlowPlan = self.request.session[SESSION_KEY_PLAN]

View File

@ -8,6 +8,7 @@ from typing import Any, Iterable, Optional
from cachetools import TLRUCache, cached from cachetools import TLRUCache, cached
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django_otp import devices_for_user from django_otp import devices_for_user
from guardian.shortcuts import get_anonymous_user
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from sentry_sdk.hub import Hub from sentry_sdk.hub import Hub
from sentry_sdk.tracing import Span from sentry_sdk.tracing import Span
@ -16,7 +17,9 @@ from structlog.stdlib import get_logger
from authentik.core.models import User from authentik.core.models import User
from authentik.events.models import Event from authentik.events.models import Event
from authentik.lib.utils.http import get_http_session from authentik.lib.utils.http import get_http_session
from authentik.policies.types import PolicyRequest from authentik.policies.models import Policy, PolicyBinding
from authentik.policies.process import PolicyProcess
from authentik.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger() LOGGER = get_logger()
@ -37,19 +40,20 @@ class BaseEvaluator:
# update website/docs/expressions/_objects.md # update website/docs/expressions/_objects.md
# update website/docs/expressions/_functions.md # update website/docs/expressions/_functions.md
self._globals = { self._globals = {
"regex_match": BaseEvaluator.expr_regex_match, "ak_call_policy": self.expr_func_call_policy,
"regex_replace": BaseEvaluator.expr_regex_replace, "ak_create_event": self.expr_event_create,
"list_flatten": BaseEvaluator.expr_flatten,
"ak_is_group_member": BaseEvaluator.expr_is_group_member, "ak_is_group_member": BaseEvaluator.expr_is_group_member,
"ak_logger": get_logger(self._filename).bind(),
"ak_user_by": BaseEvaluator.expr_user_by, "ak_user_by": BaseEvaluator.expr_user_by,
"ak_user_has_authenticator": BaseEvaluator.expr_func_user_has_authenticator, "ak_user_has_authenticator": BaseEvaluator.expr_func_user_has_authenticator,
"resolve_dns": BaseEvaluator.expr_resolve_dns,
"reverse_dns": BaseEvaluator.expr_reverse_dns,
"ak_create_event": self.expr_event_create,
"ak_logger": get_logger(self._filename).bind(),
"requests": get_http_session(),
"ip_address": ip_address, "ip_address": ip_address,
"ip_network": ip_network, "ip_network": ip_network,
"list_flatten": BaseEvaluator.expr_flatten,
"regex_match": BaseEvaluator.expr_regex_match,
"regex_replace": BaseEvaluator.expr_regex_replace,
"requests": get_http_session(),
"resolve_dns": BaseEvaluator.expr_resolve_dns,
"reverse_dns": BaseEvaluator.expr_reverse_dns,
} }
self._context = {} self._context = {}
@ -152,6 +156,19 @@ class BaseEvaluator:
return return
event.save() event.save()
def expr_func_call_policy(self, name: str, **kwargs) -> PolicyResult:
"""Call policy by name, with current request"""
policy = Policy.objects.filter(name=name).select_subclasses().first()
if not policy:
raise ValueError(f"Policy '{name}' not found.")
user = self._context.get("user", get_anonymous_user())
req = PolicyRequest(user)
if "request" in self._context:
req = self._context["request"]
req.context.update(kwargs)
proc = PolicyProcess(PolicyBinding(policy=policy), request=req, connection=None)
return proc.profiling_wrapper()
def wrap_expression(self, expression: str, params: Iterable[str]) -> str: def wrap_expression(self, expression: str, params: Iterable[str]) -> str:
"""Wrap expression in a function, call it, and save the result as `result`""" """Wrap expression in a function, call it, and save the result as `result`"""
handler_signature = ",".join(params) handler_signature = ",".join(params)

View File

@ -19,9 +19,12 @@ from rest_framework.exceptions import APIException
from sentry_sdk import HttpTransport from sentry_sdk import HttpTransport
from sentry_sdk import init as sentry_sdk_init from sentry_sdk import init as sentry_sdk_init
from sentry_sdk.api import set_tag from sentry_sdk.api import set_tag
from sentry_sdk.integrations.argv import ArgvIntegration
from sentry_sdk.integrations.celery import CeleryIntegration from sentry_sdk.integrations.celery import CeleryIntegration
from sentry_sdk.integrations.django import DjangoIntegration from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.redis import RedisIntegration from sentry_sdk.integrations.redis import RedisIntegration
from sentry_sdk.integrations.socket import SocketIntegration
from sentry_sdk.integrations.stdlib import StdlibIntegration
from sentry_sdk.integrations.threading import ThreadingIntegration from sentry_sdk.integrations.threading import ThreadingIntegration
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from websockets.exceptions import WebSocketException from websockets.exceptions import WebSocketException
@ -61,10 +64,13 @@ def sentry_init(**sentry_init_kwargs):
sentry_sdk_init( sentry_sdk_init(
dsn=CONFIG.y("error_reporting.sentry_dsn"), dsn=CONFIG.y("error_reporting.sentry_dsn"),
integrations=[ integrations=[
ArgvIntegration(),
StdlibIntegration(),
DjangoIntegration(transaction_style="function_name"), DjangoIntegration(transaction_style="function_name"),
CeleryIntegration(), CeleryIntegration(monitor_beat_tasks=True),
RedisIntegration(), RedisIntegration(),
ThreadingIntegration(propagate_hub=True), ThreadingIntegration(propagate_hub=True),
SocketIntegration(),
], ],
before_send=before_send, before_send=before_send,
traces_sampler=traces_sampler, traces_sampler=traces_sampler,

View File

@ -28,6 +28,7 @@ from authentik.outposts.models import (
) )
from authentik.providers.ldap.models import LDAPProvider from authentik.providers.ldap.models import LDAPProvider
from authentik.providers.proxy.models import ProxyProvider from authentik.providers.proxy.models import ProxyProvider
from authentik.providers.radius.models import RadiusProvider
class OutpostSerializer(ModelSerializer): class OutpostSerializer(ModelSerializer):
@ -51,6 +52,7 @@ class OutpostSerializer(ModelSerializer):
type_map = { type_map = {
OutpostType.LDAP: LDAPProvider, OutpostType.LDAP: LDAPProvider,
OutpostType.PROXY: ProxyProvider, OutpostType.PROXY: ProxyProvider,
OutpostType.RADIUS: RadiusProvider,
None: Provider, None: Provider,
} }
for provider in providers: for provider in providers:

View File

@ -24,6 +24,7 @@ class AuthentikOutpostConfig(ManagedAppConfig):
label = "authentik_outposts" label = "authentik_outposts"
verbose_name = "authentik Outpost" verbose_name = "authentik Outpost"
default = True default = True
ws_mountpoint = "authentik.outposts.urls"
def reconcile_load_outposts_signals(self): def reconcile_load_outposts_signals(self):
"""Load outposts signals""" """Load outposts signals"""

View File

@ -4,6 +4,7 @@ from typing import TYPE_CHECKING
from django.utils.text import slugify from django.utils.text import slugify
from kubernetes.client import ( from kubernetes.client import (
AppsV1Api, AppsV1Api,
V1Capabilities,
V1Container, V1Container,
V1ContainerPort, V1ContainerPort,
V1Deployment, V1Deployment,
@ -13,9 +14,12 @@ from kubernetes.client import (
V1LabelSelector, V1LabelSelector,
V1ObjectMeta, V1ObjectMeta,
V1ObjectReference, V1ObjectReference,
V1PodSecurityContext,
V1PodSpec, V1PodSpec,
V1PodTemplateSpec, V1PodTemplateSpec,
V1SeccompProfile,
V1SecretKeySelector, V1SecretKeySelector,
V1SecurityContext,
) )
from authentik import __version__, get_full_version from authentik import __version__, get_full_version
@ -103,6 +107,11 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
image_pull_secrets=[ image_pull_secrets=[
V1ObjectReference(name=secret) for secret in image_pull_secrets V1ObjectReference(name=secret) for secret in image_pull_secrets
], ],
security_context=V1PodSecurityContext(
seccomp_profile=V1SeccompProfile(
type="RuntimeDefault",
),
),
containers=[ containers=[
V1Container( V1Container(
name=str(self.outpost.type), name=str(self.outpost.type),
@ -146,6 +155,13 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
), ),
), ),
], ],
security_context=V1SecurityContext(
run_as_non_root=True,
allow_privilege_escalation=False,
capabilities=V1Capabilities(
drop=["ALL"],
),
),
) )
], ],
), ),

View File

@ -0,0 +1,20 @@
# Generated by Django 4.1.7 on 2023-03-20 10:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_outposts", "0019_alter_outpost_name_and_more"),
]
operations = [
migrations.AlterField(
model_name="outpost",
name="type",
field=models.TextField(
choices=[("proxy", "Proxy"), ("ldap", "Ldap"), ("radius", "Radius")],
default="proxy",
),
),
]

View File

@ -94,6 +94,7 @@ class OutpostType(models.TextChoices):
PROXY = "proxy" PROXY = "proxy"
LDAP = "ldap" LDAP = "ldap"
RADIUS = "radius"
def default_outpost_config(host: Optional[str] = None): def default_outpost_config(host: Optional[str] = None):

View File

@ -7,6 +7,7 @@ from urllib.parse import urlparse
import yaml import yaml
from asgiref.sync import async_to_sync from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.core.cache import cache from django.core.cache import cache
from django.db import DatabaseError, InternalError, ProgrammingError from django.db import DatabaseError, InternalError, ProgrammingError
from django.db.models.base import Model from django.db.models.base import Model
@ -42,7 +43,6 @@ from authentik.providers.ldap.controllers.kubernetes import LDAPKubernetesContro
from authentik.providers.proxy.controllers.docker import ProxyDockerController from authentik.providers.proxy.controllers.docker import ProxyDockerController
from authentik.providers.proxy.controllers.kubernetes import ProxyKubernetesController from authentik.providers.proxy.controllers.kubernetes import ProxyKubernetesController
from authentik.root.celery import CELERY_APP from authentik.root.celery import CELERY_APP
from authentik.root.messages.storage import closing_send
LOGGER = get_logger() LOGGER = get_logger()
CACHE_KEY_OUTPOST_DOWN = "outpost_teardown_%s" CACHE_KEY_OUTPOST_DOWN = "outpost_teardown_%s"
@ -214,26 +214,29 @@ def outpost_post_save(model_class: str, model_pk: Any):
outpost_send_update(reverse) outpost_send_update(reverse)
def outpost_send_update(model_instace: Model): def outpost_send_update(model_instance: Model):
"""Send outpost update to all registered outposts, regardless to which authentik """Send outpost update to all registered outposts, regardless to which authentik
instance they are connected""" instance they are connected"""
if isinstance(model_instace, OutpostModel): channel_layer = get_channel_layer()
for outpost in model_instace.outpost_set.all(): if isinstance(model_instance, OutpostModel):
_outpost_single_update(outpost) for outpost in model_instance.outpost_set.all():
elif isinstance(model_instace, Outpost): _outpost_single_update(outpost, channel_layer)
_outpost_single_update(model_instace) elif isinstance(model_instance, Outpost):
_outpost_single_update(model_instance, channel_layer)
def _outpost_single_update(outpost: Outpost): def _outpost_single_update(outpost: Outpost, layer=None):
"""Update outpost instances connected to a single outpost""" """Update outpost instances connected to a single outpost"""
# Ensure token again, because this function is called when anything related to an # Ensure token again, because this function is called when anything related to an
# OutpostModel is saved, so we can be sure permissions are right # OutpostModel is saved, so we can be sure permissions are right
_ = outpost.token _ = outpost.token
outpost.build_user_permissions(outpost.user) outpost.build_user_permissions(outpost.user)
if not layer: # pragma: no cover
layer = get_channel_layer()
for state in OutpostState.for_outpost(outpost): for state in OutpostState.for_outpost(outpost):
for channel in state.channel_ids: for channel in state.channel_ids:
LOGGER.debug("sending update", channel=channel, instance=state.uid, outpost=outpost) LOGGER.debug("sending update", channel=channel, instance=state.uid, outpost=outpost)
async_to_sync(closing_send)(channel, {"type": "event.update"}) async_to_sync(layer.send)(channel, {"type": "event.update"})
@CELERY_APP.task( @CELERY_APP.task(

View File

@ -0,0 +1,8 @@
"""Outpost Websocket URLS"""
from django.urls import path
from authentik.outposts.channels import OutpostConsumer
websocket_urlpatterns = [
path("ws/outpost/<uuid:pk>/", OutpostConsumer.as_asgi()),
]

View File

@ -9,8 +9,6 @@ from authentik.flows.planner import PLAN_CONTEXT_SSO
from authentik.lib.expression.evaluator import BaseEvaluator from authentik.lib.expression.evaluator import BaseEvaluator
from authentik.lib.utils.http import get_client_ip from authentik.lib.utils.http import get_client_ip
from authentik.policies.exceptions import PolicyException from authentik.policies.exceptions import PolicyException
from authentik.policies.models import Policy, PolicyBinding
from authentik.policies.process import PolicyProcess
from authentik.policies.types import PolicyRequest, PolicyResult from authentik.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger() LOGGER = get_logger()
@ -32,22 +30,11 @@ class PolicyEvaluator(BaseEvaluator):
# update website/docs/expressions/_functions.md # update website/docs/expressions/_functions.md
self._context["ak_message"] = self.expr_func_message self._context["ak_message"] = self.expr_func_message
self._context["ak_user_has_authenticator"] = self.expr_func_user_has_authenticator self._context["ak_user_has_authenticator"] = self.expr_func_user_has_authenticator
self._context["ak_call_policy"] = self.expr_func_call_policy
def expr_func_message(self, message: str): def expr_func_message(self, message: str):
"""Wrapper to append to messages list, which is returned with PolicyResult""" """Wrapper to append to messages list, which is returned with PolicyResult"""
self._messages.append(message) self._messages.append(message)
def expr_func_call_policy(self, name: str, **kwargs) -> PolicyResult:
"""Call policy by name, with current request"""
policy = Policy.objects.filter(name=name).select_subclasses().first()
if not policy:
raise ValueError(f"Policy '{name}' not found.")
req: PolicyRequest = self._context["request"]
req.context.update(kwargs)
proc = PolicyProcess(PolicyBinding(policy=policy), request=req, connection=None)
return proc.profiling_wrapper()
def set_policy_request(self, request: PolicyRequest): def set_policy_request(self, request: PolicyRequest):
"""Update context based on policy request (if http request is given, update that too)""" """Update context based on policy request (if http request is given, update that too)"""
# update website/docs/expressions/_objects.md # update website/docs/expressions/_objects.md
@ -83,6 +70,7 @@ class PolicyEvaluator(BaseEvaluator):
return PolicyResult(False, str(exc)) return PolicyResult(False, str(exc))
else: else:
policy_result = PolicyResult(False, *self._messages) policy_result = PolicyResult(False, *self._messages)
policy_result.raw_result = result
if result is None: if result is None:
LOGGER.warning( LOGGER.warning(
"Expression policy returned None", "Expression policy returned None",

View File

@ -54,6 +54,7 @@ class TestPasswordPolicyFlow(FlowTestCase):
component="ak-stage-prompt", component="ak-stage-prompt",
fields=[ fields=[
{ {
"choices": None,
"field_key": "password", "field_key": "password",
"label": "PASSWORD_LABEL", "label": "PASSWORD_LABEL",
"order": 0, "order": 0,

View File

@ -69,10 +69,11 @@ class PolicyRequest:
@dataclass @dataclass
class PolicyResult: class PolicyResult:
"""Small data-class to hold policy results""" """Result from evaluating a policy."""
passing: bool passing: bool
messages: tuple[str, ...] messages: tuple[str, ...]
raw_result: Any
source_binding: Optional["PolicyBinding"] source_binding: Optional["PolicyBinding"]
source_results: Optional[list["PolicyResult"]] source_results: Optional[list["PolicyResult"]]
@ -83,6 +84,7 @@ class PolicyResult:
super().__init__() super().__init__()
self.passing = passing self.passing = passing
self.messages = messages self.messages = messages
self.raw_result = None
self.source_binding = None self.source_binding = None
self.source_results = [] self.source_results = []
self.log_messages = [] self.log_messages = []

View File

@ -3,6 +3,8 @@
import django.utils.timezone import django.utils.timezone
from django.db import migrations, models from django.db import migrations, models
import authentik.providers.oauth2.models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
@ -37,4 +39,14 @@ class Migration(migrations.Migration):
), ),
preserve_default=False, preserve_default=False,
), ),
migrations.AlterField(
model_name="oauth2provider",
name="client_secret",
field=models.CharField(
blank=True,
default=authentik.providers.oauth2.models.generate_client_secret,
max_length=255,
verbose_name="Client Secret",
),
),
] ]

View File

@ -27,6 +27,11 @@ from authentik.providers.oauth2.id_token import IDToken, SubModes
from authentik.sources.oauth.models import OAuthSource from authentik.sources.oauth.models import OAuthSource
def generate_client_secret() -> str:
"""Generate client secret with adequate length"""
return generate_id(128)
class ClientTypes(models.TextChoices): class ClientTypes(models.TextChoices):
"""Confidential clients are capable of maintaining the confidentiality """Confidential clients are capable of maintaining the confidentiality
of their credentials. Public clients are incapable.""" of their credentials. Public clients are incapable."""
@ -132,7 +137,7 @@ class OAuth2Provider(Provider):
max_length=255, max_length=255,
blank=True, blank=True,
verbose_name=_("Client Secret"), verbose_name=_("Client Secret"),
default=generate_key, default=generate_client_secret,
) )
redirect_uris = models.TextField( redirect_uris = models.TextField(
default="", default="",

View File

@ -7,7 +7,6 @@ from rest_framework.test import APITestCase
from authentik.blueprints.tests import apply_blueprint from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import Application from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.lib.generators import generate_id, generate_key
from authentik.providers.oauth2.models import OAuth2Provider, ScopeMapping from authentik.providers.oauth2.models import OAuth2Provider, ScopeMapping
@ -18,8 +17,6 @@ class TestAPI(APITestCase):
def setUp(self) -> None: def setUp(self) -> None:
self.provider: OAuth2Provider = OAuth2Provider.objects.create( self.provider: OAuth2Provider = OAuth2Provider.objects.create(
name="test", name="test",
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://testserver", redirect_uris="http://testserver",
) )

View File

@ -9,7 +9,7 @@ from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.flows.challenge import ChallengeTypes from authentik.flows.challenge import ChallengeTypes
from authentik.lib.generators import generate_id, generate_key from authentik.lib.generators import generate_id
from authentik.lib.utils.time import timedelta_from_string from authentik.lib.utils.time import timedelta_from_string
from authentik.providers.oauth2.constants import TOKEN_TYPE from authentik.providers.oauth2.constants import TOKEN_TYPE
from authentik.providers.oauth2.errors import AuthorizeError, ClientIdError, RedirectUriError from authentik.providers.oauth2.errors import AuthorizeError, ClientIdError, RedirectUriError
@ -298,7 +298,6 @@ class TestAuthorize(OAuthTestCase):
provider: OAuth2Provider = OAuth2Provider.objects.create( provider: OAuth2Provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id="test", client_id="test",
client_secret=generate_key(),
authorization_flow=flow, authorization_flow=flow,
redirect_uris="http://localhost", redirect_uris="http://localhost",
signing_key=self.keypair, signing_key=self.keypair,
@ -355,13 +354,67 @@ class TestAuthorize(OAuthTestCase):
delta=5, delta=5,
) )
def test_full_fragment_code(self):
"""Test full authorization"""
flow = create_test_flow()
provider: OAuth2Provider = OAuth2Provider.objects.create(
name=generate_id(),
client_id="test",
authorization_flow=flow,
redirect_uris="http://localhost",
signing_key=self.keypair,
)
Application.objects.create(name="app", slug="app", provider=provider)
state = generate_id()
user = create_test_admin_user()
self.client.force_login(user)
with patch(
"authentik.providers.oauth2.id_token.get_login_event",
MagicMock(
return_value=Event(
action=EventAction.LOGIN,
context={PLAN_CONTEXT_METHOD: "password"},
created=now(),
)
),
):
# Step 1, initiate params and get redirect to flow
self.client.get(
reverse("authentik_providers_oauth2:authorize"),
data={
"response_type": "code",
"response_mode": "fragment",
"client_id": "test",
"state": state,
"scope": "openid",
"redirect_uri": "http://localhost",
"nonce": generate_id(),
},
)
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
code: AuthorizationCode = AuthorizationCode.objects.filter(user=user).first()
self.assertJSONEqual(
response.content.decode(),
{
"component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": (f"http://localhost#code={code.code}" f"&state={state}"),
},
)
self.assertAlmostEqual(
code.expires.timestamp() - now().timestamp(),
timedelta_from_string(provider.access_code_validity).total_seconds(),
delta=5,
)
def test_full_form_post_id_token(self): def test_full_form_post_id_token(self):
"""Test full authorization (form_post response)""" """Test full authorization (form_post response)"""
flow = create_test_flow() flow = create_test_flow()
provider = OAuth2Provider.objects.create( provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(), client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=flow, authorization_flow=flow,
redirect_uris="http://localhost", redirect_uris="http://localhost",
signing_key=self.keypair, signing_key=self.keypair,
@ -411,7 +464,6 @@ class TestAuthorize(OAuthTestCase):
provider = OAuth2Provider.objects.create( provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(), client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=flow, authorization_flow=flow,
redirect_uris="http://localhost", redirect_uris="http://localhost",
signing_key=self.keypair, signing_key=self.keypair,

View File

@ -8,7 +8,7 @@ from django.utils import timezone
from authentik.core.models import Application from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
from authentik.lib.generators import generate_id, generate_key from authentik.lib.generators import generate_id
from authentik.providers.oauth2.constants import ACR_AUTHENTIK_DEFAULT from authentik.providers.oauth2.constants import ACR_AUTHENTIK_DEFAULT
from authentik.providers.oauth2.models import AccessToken, IDToken, OAuth2Provider, RefreshToken from authentik.providers.oauth2.models import AccessToken, IDToken, OAuth2Provider, RefreshToken
from authentik.providers.oauth2.tests.utils import OAuthTestCase from authentik.providers.oauth2.tests.utils import OAuthTestCase
@ -21,8 +21,6 @@ class TesOAuth2Introspection(OAuthTestCase):
super().setUp() super().setUp()
self.provider: OAuth2Provider = OAuth2Provider.objects.create( self.provider: OAuth2Provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="", redirect_uris="",
signing_key=create_test_cert(), signing_key=create_test_cert(),

View File

@ -8,7 +8,7 @@ from django.utils import timezone
from authentik.core.models import Application from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
from authentik.lib.generators import generate_id, generate_key from authentik.lib.generators import generate_id
from authentik.providers.oauth2.models import AccessToken, IDToken, OAuth2Provider, RefreshToken from authentik.providers.oauth2.models import AccessToken, IDToken, OAuth2Provider, RefreshToken
from authentik.providers.oauth2.tests.utils import OAuthTestCase from authentik.providers.oauth2.tests.utils import OAuthTestCase
@ -20,8 +20,6 @@ class TesOAuth2Revoke(OAuthTestCase):
super().setUp() super().setUp()
self.provider: OAuth2Provider = OAuth2Provider.objects.create( self.provider: OAuth2Provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="", redirect_uris="",
signing_key=create_test_cert(), signing_key=create_test_cert(),

View File

@ -38,8 +38,6 @@ class TestToken(OAuthTestCase):
"""test request param""" """test request param"""
provider = OAuth2Provider.objects.create( provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://TestServer", redirect_uris="http://TestServer",
signing_key=self.keypair, signing_key=self.keypair,
@ -67,8 +65,6 @@ class TestToken(OAuthTestCase):
"""test request param""" """test request param"""
provider = OAuth2Provider.objects.create( provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://testserver", redirect_uris="http://testserver",
signing_key=self.keypair, signing_key=self.keypair,
@ -90,8 +86,6 @@ class TestToken(OAuthTestCase):
"""test request param""" """test request param"""
provider = OAuth2Provider.objects.create( provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid", redirect_uris="http://local.invalid",
signing_key=self.keypair, signing_key=self.keypair,
@ -120,8 +114,6 @@ class TestToken(OAuthTestCase):
"""test request param""" """test request param"""
provider = OAuth2Provider.objects.create( provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid", redirect_uris="http://local.invalid",
signing_key=self.keypair, signing_key=self.keypair,
@ -163,8 +155,6 @@ class TestToken(OAuthTestCase):
"""test request param""" """test request param"""
provider = OAuth2Provider.objects.create( provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid", redirect_uris="http://local.invalid",
signing_key=self.keypair, signing_key=self.keypair,
@ -215,8 +205,6 @@ class TestToken(OAuthTestCase):
"""test request param""" """test request param"""
provider = OAuth2Provider.objects.create( provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid", redirect_uris="http://local.invalid",
signing_key=self.keypair, signing_key=self.keypair,
@ -263,8 +251,6 @@ class TestToken(OAuthTestCase):
"""test request param""" """test request param"""
provider = OAuth2Provider.objects.create( provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://testserver", redirect_uris="http://testserver",
signing_key=self.keypair, signing_key=self.keypair,

View File

@ -8,7 +8,6 @@ from jwt import decode
from authentik.blueprints.tests import apply_blueprint from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import USER_ATTRIBUTE_SA, Application, Group, Token, TokenIntents from authentik.core.models import USER_ATTRIBUTE_SA, Application, Group, Token, TokenIntents
from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
from authentik.lib.generators import generate_id, generate_key
from authentik.policies.models import PolicyBinding from authentik.policies.models import PolicyBinding
from authentik.providers.oauth2.constants import ( from authentik.providers.oauth2.constants import (
GRANT_TYPE_CLIENT_CREDENTIALS, GRANT_TYPE_CLIENT_CREDENTIALS,
@ -31,8 +30,6 @@ class TestTokenClientCredentials(OAuthTestCase):
self.factory = RequestFactory() self.factory = RequestFactory()
self.provider = OAuth2Provider.objects.create( self.provider = OAuth2Provider.objects.create(
name="test", name="test",
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://testserver", redirect_uris="http://testserver",
signing_key=create_test_cert(), signing_key=create_test_cert(),

View File

@ -9,7 +9,7 @@ from jwt import decode
from authentik.blueprints.tests import apply_blueprint from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import Application, Group from authentik.core.models import Application, Group
from authentik.core.tests.utils import create_test_cert, create_test_flow from authentik.core.tests.utils import create_test_cert, create_test_flow
from authentik.lib.generators import generate_id, generate_key from authentik.lib.generators import generate_id
from authentik.policies.models import PolicyBinding from authentik.policies.models import PolicyBinding
from authentik.providers.oauth2.constants import ( from authentik.providers.oauth2.constants import (
GRANT_TYPE_CLIENT_CREDENTIALS, GRANT_TYPE_CLIENT_CREDENTIALS,
@ -39,7 +39,7 @@ class TestTokenClientCredentialsJWTSource(OAuthTestCase):
slug=generate_id(), slug=generate_id(),
provider_type="openidconnect", provider_type="openidconnect",
consumer_key=generate_id(), consumer_key=generate_id(),
consumer_secret=generate_key(), consumer_secret=generate_id(),
authorization_url="http://foo", authorization_url="http://foo",
access_token_url=f"http://{generate_id()}", access_token_url=f"http://{generate_id()}",
profile_url="http://foo", profile_url="http://foo",
@ -52,8 +52,6 @@ class TestTokenClientCredentialsJWTSource(OAuthTestCase):
self.provider: OAuth2Provider = OAuth2Provider.objects.create( self.provider: OAuth2Provider = OAuth2Provider.objects.create(
name="test", name="test",
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://testserver", redirect_uris="http://testserver",
signing_key=self.cert, signing_key=self.cert,

View File

@ -7,7 +7,7 @@ from django.urls import reverse
from authentik.blueprints.tests import apply_blueprint from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import Application from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
from authentik.lib.generators import generate_code_fixed_length, generate_id, generate_key from authentik.lib.generators import generate_code_fixed_length, generate_id
from authentik.providers.oauth2.constants import GRANT_TYPE_DEVICE_CODE from authentik.providers.oauth2.constants import GRANT_TYPE_DEVICE_CODE
from authentik.providers.oauth2.models import DeviceToken, OAuth2Provider, ScopeMapping from authentik.providers.oauth2.models import DeviceToken, OAuth2Provider, ScopeMapping
from authentik.providers.oauth2.tests.utils import OAuthTestCase from authentik.providers.oauth2.tests.utils import OAuthTestCase
@ -22,8 +22,6 @@ class TestTokenDeviceCode(OAuthTestCase):
self.factory = RequestFactory() self.factory = RequestFactory()
self.provider = OAuth2Provider.objects.create( self.provider = OAuth2Provider.objects.create(
name="test", name="test",
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://testserver", redirect_uris="http://testserver",
signing_key=create_test_cert(), signing_key=create_test_cert(),

View File

@ -9,7 +9,7 @@ from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import Application from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.lib.generators import generate_id, generate_key from authentik.lib.generators import generate_id
from authentik.providers.oauth2.models import AccessToken, IDToken, OAuth2Provider, ScopeMapping from authentik.providers.oauth2.models import AccessToken, IDToken, OAuth2Provider, ScopeMapping
from authentik.providers.oauth2.tests.utils import OAuthTestCase from authentik.providers.oauth2.tests.utils import OAuthTestCase
@ -23,8 +23,6 @@ class TestUserinfo(OAuthTestCase):
self.app = Application.objects.create(name=generate_id(), slug=generate_id()) self.app = Application.objects.create(name=generate_id(), slug=generate_id())
self.provider: OAuth2Provider = OAuth2Provider.objects.create( self.provider: OAuth2Provider = OAuth2Provider.objects.create(
name=generate_id(), name=generate_id(),
client_id=generate_id(),
client_secret=generate_key(),
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="", redirect_uris="",
signing_key=create_test_cert(), signing_key=create_test_cert(),

View File

@ -514,7 +514,12 @@ class OAuthFulfillmentStage(StageView):
return urlunsplit(uri) return urlunsplit(uri)
if self.params.response_mode == ResponseMode.FRAGMENT: if self.params.response_mode == ResponseMode.FRAGMENT:
query_fragment = self.create_implicit_response(code) query_fragment = {}
if self.params.grant_type in [GrantTypes.AUTHORIZATION_CODE]:
query_fragment["code"] = code.code
query_fragment["state"] = [str(self.params.state) if self.params.state else ""]
else:
query_fragment = self.create_implicit_response(code)
uri = uri._replace( uri = uri._replace(
fragment=uri.fragment + urlencode(query_fragment, doseq=True), fragment=uri.fragment + urlencode(query_fragment, doseq=True),

View File

View File

@ -0,0 +1,65 @@
"""RadiusProvider API Views"""
from rest_framework.fields import CharField
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.providers.radius.models import RadiusProvider
class RadiusProviderSerializer(ProviderSerializer):
"""RadiusProvider Serializer"""
class Meta:
model = RadiusProvider
fields = ProviderSerializer.Meta.fields + [
"client_networks",
# Shared secret is not a write-only field, as
# an admin might have to view it
"shared_secret",
]
extra_kwargs = ProviderSerializer.Meta.extra_kwargs
class RadiusProviderViewSet(UsedByMixin, ModelViewSet):
"""RadiusProvider Viewset"""
queryset = RadiusProvider.objects.all()
serializer_class = RadiusProviderSerializer
ordering = ["name"]
search_fields = ["name", "client_networks"]
filterset_fields = {
"application": ["isnull"],
"name": ["iexact"],
"authorization_flow__slug": ["iexact"],
"client_networks": ["iexact"],
}
class RadiusOutpostConfigSerializer(ModelSerializer):
"""RadiusProvider Serializer"""
application_slug = CharField(source="application.slug")
auth_flow_slug = CharField(source="authorization_flow.slug")
class Meta:
model = RadiusProvider
fields = [
"pk",
"name",
"application_slug",
"auth_flow_slug",
"client_networks",
"shared_secret",
]
class RadiusOutpostConfigViewSet(ReadOnlyModelViewSet):
"""RadiusProvider Viewset"""
queryset = RadiusProvider.objects.filter(application__isnull=False)
serializer_class = RadiusOutpostConfigSerializer
ordering = ["name"]
search_fields = ["name"]
filterset_fields = ["name"]

View File

@ -0,0 +1,10 @@
"""authentik radius provider app config"""
from django.apps import AppConfig
class AuthentikProviderRadiusConfig(AppConfig):
"""authentik radius provider app config"""
name = "authentik.providers.radius"
label = "authentik_providers_radius"
verbose_name = "authentik Providers.Radius"

View File

@ -0,0 +1,14 @@
"""Radius Provider Docker Controller"""
from authentik.outposts.controllers.base import DeploymentPort
from authentik.outposts.controllers.docker import DockerController
from authentik.outposts.models import DockerServiceConnection, Outpost
class RadiusDockerController(DockerController):
"""Radius Provider Docker Controller"""
def __init__(self, outpost: Outpost, connection: DockerServiceConnection):
super().__init__(outpost, connection)
self.deployment_ports = [
DeploymentPort(1812, "radius", "udp", 1812),
]

View File

@ -0,0 +1,14 @@
"""Radius Provider Kubernetes Controller"""
from authentik.outposts.controllers.base import DeploymentPort
from authentik.outposts.controllers.kubernetes import KubernetesController
from authentik.outposts.models import KubernetesServiceConnection, Outpost
class RadiusKubernetesController(KubernetesController):
"""Radius Provider Kubernetes Controller"""
def __init__(self, outpost: Outpost, connection: KubernetesServiceConnection):
super().__init__(outpost, connection)
self.deployment_ports = [
DeploymentPort(1812, "radius", "udp", 1812),
]

View File

@ -0,0 +1,52 @@
# Generated by Django 4.1.7 on 2023-03-20 10:58
import django.db.models.deletion
from django.db import migrations, models
import authentik.lib.generators
class Migration(migrations.Migration):
initial = True
dependencies = [
("authentik_core", "0027_alter_user_uuid"),
]
operations = [
migrations.CreateModel(
name="RadiusProvider",
fields=[
(
"provider_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_core.provider",
),
),
(
"shared_secret",
models.TextField(
default=authentik.lib.generators.generate_id,
help_text="Shared secret between clients and server to hash packets.",
),
),
(
"client_networks",
models.TextField(
default="0.0.0.0/0, ::/0",
help_text="List of CIDRs (comma-separated) that clients can connect from. A more specific CIDR will match before a looser one. Clients connecting from a non-specified CIDR will be dropped.",
),
),
],
options={
"verbose_name": "Radius Provider",
"verbose_name_plural": "Radius Providers",
},
bases=("authentik_core.provider", models.Model),
),
]

View File

@ -0,0 +1,50 @@
"""Radius Provider"""
from typing import Optional, Type
from django.db import models
from django.utils.translation import gettext_lazy as _
from rest_framework.serializers import Serializer
from authentik.core.models import Provider
from authentik.lib.generators import generate_id
from authentik.outposts.models import OutpostModel
class RadiusProvider(OutpostModel, Provider):
"""Allow applications to authenticate against authentik's users using Radius."""
shared_secret = models.TextField(
default=generate_id,
help_text=_("Shared secret between clients and server to hash packets."),
)
client_networks = models.TextField(
default="0.0.0.0/0, ::/0",
help_text=_(
"List of CIDRs (comma-separated) that clients can connect from. A more specific "
"CIDR will match before a looser one. Clients connecting from a non-specified CIDR "
"will be dropped."
),
)
@property
def launch_url(self) -> Optional[str]:
"""Radius never has a launch URL"""
return None
@property
def component(self) -> str:
return "ak-provider-radius-form"
@property
def serializer(self) -> Type[Serializer]:
from authentik.providers.radius.api import RadiusProviderSerializer
return RadiusProviderSerializer
def __str__(self):
return f"Radius Provider {self.name}"
class Meta:
verbose_name = _("Radius Provider")
verbose_name_plural = _("Radius Providers")

View File

@ -34,8 +34,16 @@ def pre_delete_scim(sender: type[Model], instance: User | Group, **_):
@receiver(m2m_changed, sender=User.ak_groups.through) @receiver(m2m_changed, sender=User.ak_groups.through)
def m2m_changed_scim(sender: type[Model], instance, action: str, pk_set: set, **kwargs): def m2m_changed_scim(
sender: type[Model], instance, action: str, pk_set: set, reverse: bool, **kwargs
):
"""Sync group membership""" """Sync group membership"""
if action not in ["post_add", "post_remove"]: if action not in ["post_add", "post_remove"]:
return return
scim_signal_m2m.delay(str(instance.pk), action, list(pk_set)) # reverse: instance is a Group, pk_set is a list of user pks
# non-reverse: instance is a User, pk_set is a list of groups
if reverse:
scim_signal_m2m.delay(str(instance.pk), action, list(pk_set))
else:
for group_pk in pk_set:
scim_signal_m2m.delay(group_pk, action, [instance.pk])

View File

@ -151,7 +151,7 @@ def scim_signal_direct(model: str, pk: Any, raw_op: str):
@CELERY_APP.task() @CELERY_APP.task()
def scim_signal_m2m(group_pk: str, action: str, pk_set: set[int]): def scim_signal_m2m(group_pk: str, action: str, pk_set: list[int]):
"""Update m2m (group membership)""" """Update m2m (group membership)"""
group = Group.objects.filter(pk=group_pk).first() group = Group.objects.filter(pk=group_pk).first()
if not group: if not group:

View File

@ -82,9 +82,11 @@ class SCIMMembershipTests(TestCase):
mocker.request_history[3].body, mocker.request_history[3].body,
{ {
"emails": [], "emails": [],
"active": True,
"externalId": user.uid, "externalId": user.uid,
"name": {"familyName": "", "formatted": "", "givenName": ""}, "name": {"familyName": "", "formatted": "", "givenName": ""},
"photos": [], "photos": [],
"displayName": "",
"userName": user.username, "userName": user.username,
}, },
) )
@ -163,6 +165,8 @@ class SCIMMembershipTests(TestCase):
self.assertJSONEqual( self.assertJSONEqual(
mocker.request_history[3].body, mocker.request_history[3].body,
{ {
"active": True,
"displayName": "",
"emails": [], "emails": [],
"externalId": user.uid, "externalId": user.uid,
"name": {"familyName": "", "formatted": "", "givenName": ""}, "name": {"familyName": "", "formatted": "", "givenName": ""},

View File

@ -61,6 +61,7 @@ class SCIMUserTests(TestCase):
self.assertJSONEqual( self.assertJSONEqual(
mock.request_history[1].body, mock.request_history[1].body,
{ {
"active": True,
"emails": [ "emails": [
{ {
"primary": True, "primary": True,
@ -74,6 +75,7 @@ class SCIMUserTests(TestCase):
"formatted": uid, "formatted": uid,
"givenName": uid, "givenName": uid,
}, },
"displayName": uid,
"photos": [], "photos": [],
"userName": uid, "userName": uid,
}, },
@ -115,6 +117,7 @@ class SCIMUserTests(TestCase):
self.assertEqual( self.assertEqual(
body, body,
{ {
"active": True,
"emails": [ "emails": [
{ {
"primary": True, "primary": True,
@ -122,6 +125,7 @@ class SCIMUserTests(TestCase):
"value": f"{uid}@goauthentik.io", "value": f"{uid}@goauthentik.io",
} }
], ],
"displayName": uid,
"externalId": user.uid, "externalId": user.uid,
"name": { "name": {
"familyName": "", "familyName": "",
@ -166,6 +170,7 @@ class SCIMUserTests(TestCase):
self.assertJSONEqual( self.assertJSONEqual(
mock.request_history[1].body, mock.request_history[1].body,
{ {
"active": True,
"emails": [ "emails": [
{ {
"primary": True, "primary": True,
@ -179,6 +184,7 @@ class SCIMUserTests(TestCase):
"formatted": uid, "formatted": uid,
"givenName": uid, "givenName": uid,
}, },
"displayName": uid,
"photos": [], "photos": [],
"userName": uid, "userName": uid,
}, },
@ -232,6 +238,7 @@ class SCIMUserTests(TestCase):
self.assertJSONEqual( self.assertJSONEqual(
mock.request_history[1].body, mock.request_history[1].body,
{ {
"active": True,
"emails": [ "emails": [
{ {
"primary": True, "primary": True,
@ -245,6 +252,7 @@ class SCIMUserTests(TestCase):
"formatted": uid, "formatted": uid,
"givenName": uid, "givenName": uid,
}, },
"displayName": uid,
"photos": [], "photos": [],
"userName": uid, "userName": uid,
}, },

View File

@ -2,9 +2,12 @@
import os import os
from contextvars import ContextVar from contextvars import ContextVar
from logging.config import dictConfig from logging.config import dictConfig
from pathlib import Path
from tempfile import gettempdir
from typing import Callable from typing import Callable
from celery import Celery from celery import Celery, bootsteps
from celery.apps.worker import Worker
from celery.signals import ( from celery.signals import (
after_task_publish, after_task_publish,
setup_logging, setup_logging,
@ -28,6 +31,7 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
LOGGER = get_logger() LOGGER = get_logger()
CELERY_APP = Celery("authentik") CELERY_APP = Celery("authentik")
CTX_TASK_ID = ContextVar(STRUCTLOG_KEY_PREFIX + "task_id", default=Ellipsis) CTX_TASK_ID = ContextVar(STRUCTLOG_KEY_PREFIX + "task_id", default=Ellipsis)
HEARTBEAT_FILE = Path(gettempdir() + "/authentik-worker")
@setup_logging.connect @setup_logging.connect
@ -99,6 +103,33 @@ def worker_ready_hook(*args, **kwargs):
start_blueprint_watcher() start_blueprint_watcher()
class LivenessProbe(bootsteps.StartStopStep):
"""Add a timed task to touch a temporary file for healthchecking reasons"""
requires = {"celery.worker.components:Timer"}
def __init__(self, parent, **kwargs):
super().__init__(parent, **kwargs)
self.requests = []
self.tref = None
def start(self, parent: Worker):
self.tref = parent.timer.call_repeatedly(
10.0,
self.update_heartbeat_file,
(parent,),
priority=10,
)
self.update_heartbeat_file(parent)
def stop(self, parent: Worker):
HEARTBEAT_FILE.unlink(missing_ok=True)
def update_heartbeat_file(self, worker: Worker):
"""Touch heartbeat file"""
HEARTBEAT_FILE.touch()
# Using a string here means the worker doesn't have to serialize # Using a string here means the worker doesn't have to serialize
# the configuration object to child processes. # the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys # - namespace='CELERY' means all celery-related configuration keys
@ -107,3 +138,4 @@ CELERY_APP.config_from_object(settings, namespace="CELERY")
# Load task modules from all registered Django app configs. # Load task modules from all registered Django app configs.
CELERY_APP.autodiscover_tasks() CELERY_APP.autodiscover_tasks()
CELERY_APP.steps["worker"].add(LivenessProbe)

View File

@ -1,7 +1,6 @@
"""Channels Messages storage""" """Channels Messages storage"""
from asgiref.sync import async_to_sync from asgiref.sync import async_to_sync
from channels import DEFAULT_CHANNEL_LAYER from channels.layers import get_channel_layer
from channels.layers import channel_layers
from django.contrib.messages.storage.base import Message from django.contrib.messages.storage.base import Message
from django.contrib.messages.storage.session import SessionStorage from django.contrib.messages.storage.session import SessionStorage
from django.core.cache import cache from django.core.cache import cache
@ -11,21 +10,13 @@ SESSION_KEY = "_messages"
CACHE_PREFIX = "goauthentik.io/root/messages_" CACHE_PREFIX = "goauthentik.io/root/messages_"
async def closing_send(channel, message):
"""Wrapper around layer send that closes the connection"""
# See https://github.com/django/channels_redis/issues/332
# TODO: Remove this after channels_redis 4.1 is released
channel_layer = channel_layers.make_backend(DEFAULT_CHANNEL_LAYER)
await channel_layer.send(channel, message)
await channel_layer.close_pools()
class ChannelsStorage(SessionStorage): class ChannelsStorage(SessionStorage):
"""Send contrib.messages over websocket""" """Send contrib.messages over websocket"""
def __init__(self, request: HttpRequest) -> None: def __init__(self, request: HttpRequest) -> None:
# pyright: reportGeneralTypeIssues=false # pyright: reportGeneralTypeIssues=false
super().__init__(request) super().__init__(request)
self.channel = get_channel_layer()
def _store(self, messages: list[Message], response, *args, **kwargs): def _store(self, messages: list[Message], response, *args, **kwargs):
prefix = f"{CACHE_PREFIX}{self.request.session.session_key}_messages_" prefix = f"{CACHE_PREFIX}{self.request.session.session_key}_messages_"
@ -37,7 +28,7 @@ class ChannelsStorage(SessionStorage):
for key in keys: for key in keys:
uid = key.replace(prefix, "") uid = key.replace(prefix, "")
for message in messages: for message in messages:
async_to_sync(closing_send)( async_to_sync(self.channel.send)(
uid, uid,
{ {
"type": "event.update", "type": "event.update",

View File

@ -79,6 +79,7 @@ INSTALLED_APPS = [
"authentik.providers.ldap", "authentik.providers.ldap",
"authentik.providers.oauth2", "authentik.providers.oauth2",
"authentik.providers.proxy", "authentik.providers.proxy",
"authentik.providers.radius",
"authentik.providers.saml", "authentik.providers.saml",
"authentik.providers.scim", "authentik.providers.scim",
"authentik.recovery", "authentik.recovery",
@ -275,6 +276,10 @@ DATABASES = {
"USER": CONFIG.y("postgresql.user"), "USER": CONFIG.y("postgresql.user"),
"PASSWORD": CONFIG.y("postgresql.password"), "PASSWORD": CONFIG.y("postgresql.password"),
"PORT": int(CONFIG.y("postgresql.port")), "PORT": int(CONFIG.y("postgresql.port")),
"SSLMODE": CONFIG.y("postgresql.sslmode"),
"SSLROOTCERT": CONFIG.y("postgresql.sslrootcert"),
"SSLCERT": CONFIG.y("postgresql.sslcert"),
"SSLKEY": CONFIG.y("postgresql.sslkey"),
} }
} }

View File

@ -16,7 +16,7 @@ class PytestTestRunner: # pragma: no cover
self.failfast = failfast self.failfast = failfast
self.keepdb = keepdb self.keepdb = keepdb
self.args = ["-vv"] self.args = ["-vv", "--full-trace"]
if self.failfast: if self.failfast:
self.args.append("--exitfirst") self.args.append("--exitfirst")
if self.keepdb: if self.keepdb:

View File

@ -1,15 +1,21 @@
"""root Websocket URLS""" """root Websocket URLS"""
from channels.auth import AuthMiddleware from importlib import import_module
from channels.sessions import CookieMiddleware
from django.urls import path
from authentik.outposts.channels import OutpostConsumer from structlog.stdlib import get_logger
from authentik.root.asgi_middleware import SessionMiddleware
from authentik.root.messages.consumer import MessageConsumer
websocket_urlpatterns = [ from authentik.lib.utils.reflection import get_apps
path("ws/outpost/<uuid:pk>/", OutpostConsumer.as_asgi()),
path( LOGGER = get_logger()
"ws/client/", CookieMiddleware(SessionMiddleware(AuthMiddleware(MessageConsumer.as_asgi())))
), websocket_urlpatterns = []
] for _authentik_app in get_apps():
mountpoint = getattr(_authentik_app, "ws_mountpoint", None)
if not mountpoint:
continue
ws_paths = import_module(mountpoint)
websocket_urlpatterns.extend(getattr(ws_paths, "websocket_urlpatterns"))
LOGGER.debug(
"Mounted URLs",
app_name=_authentik_app.name,
app_mountpoint=mountpoint,
)

View File

@ -2,13 +2,12 @@
from typing import Optional from typing import Optional
from django.http import HttpRequest from django.http import HttpRequest
from ldap3 import Connection
from ldap3.core.exceptions import LDAPException, LDAPInvalidCredentialsResult from ldap3.core.exceptions import LDAPException, LDAPInvalidCredentialsResult
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.auth import InbuiltBackend from authentik.core.auth import InbuiltBackend
from authentik.core.models import User from authentik.core.models import User
from authentik.sources.ldap.models import LDAP_TIMEOUT, LDAPSource from authentik.sources.ldap.models import LDAPSource
LOGGER = get_logger() LOGGER = get_logger()
LDAP_DISTINGUISHED_NAME = "distinguishedName" LDAP_DISTINGUISHED_NAME = "distinguishedName"
@ -58,12 +57,11 @@ class LDAPBackend(InbuiltBackend):
# Try to bind as new user # Try to bind as new user
LOGGER.debug("Attempting Binding as user", user=user) LOGGER.debug("Attempting Binding as user", user=user)
try: try:
temp_connection = Connection( temp_connection = source.connection(
source.server, connection_kwargs={
user=user.attributes.get(LDAP_DISTINGUISHED_NAME), "user": user.attributes.get(LDAP_DISTINGUISHED_NAME),
password=password, "password": password,
raise_exceptions=True, }
receive_timeout=LDAP_TIMEOUT,
) )
temp_connection.bind() temp_connection.bind()
return user return user

View File

@ -1,9 +1,11 @@
"""authentik LDAP Models""" """authentik LDAP Models"""
from ssl import CERT_REQUIRED from ssl import CERT_REQUIRED
from typing import Optional
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from ldap3 import ALL, RANDOM, Connection, Server, ServerPool, Tls from ldap3 import ALL, NONE, RANDOM, Connection, Server, ServerPool, Tls
from ldap3.core.exceptions import LDAPSchemaError
from rest_framework.serializers import Serializer from rest_framework.serializers import Serializer
from authentik.core.models import Group, PropertyMapping, Source from authentik.core.models import Group, PropertyMapping, Source
@ -103,8 +105,7 @@ class LDAPSource(Source):
return LDAPSourceSerializer return LDAPSourceSerializer
@property def server(self, **kwargs) -> Server:
def server(self) -> Server:
"""Get LDAP Server/ServerPool""" """Get LDAP Server/ServerPool"""
servers = [] servers = []
tls_kwargs = {} tls_kwargs = {}
@ -113,32 +114,45 @@ class LDAPSource(Source):
tls_kwargs["validate"] = CERT_REQUIRED tls_kwargs["validate"] = CERT_REQUIRED
if ciphers := CONFIG.y("ldap.tls.ciphers", None): if ciphers := CONFIG.y("ldap.tls.ciphers", None):
tls_kwargs["ciphers"] = ciphers.strip() tls_kwargs["ciphers"] = ciphers.strip()
kwargs = { server_kwargs = {
"get_info": ALL, "get_info": ALL,
"connect_timeout": LDAP_TIMEOUT, "connect_timeout": LDAP_TIMEOUT,
"tls": Tls(**tls_kwargs), "tls": Tls(**tls_kwargs),
} }
server_kwargs.update(kwargs)
if "," in self.server_uri: if "," in self.server_uri:
for server in self.server_uri.split(","): for server in self.server_uri.split(","):
servers.append(Server(server, **kwargs)) servers.append(Server(server, **server_kwargs))
else: else:
servers = [Server(self.server_uri, **kwargs)] servers = [Server(self.server_uri, **server_kwargs)]
return ServerPool(servers, RANDOM, active=True, exhaust=True) return ServerPool(servers, RANDOM, active=True, exhaust=True)
@property def connection(
def connection(self) -> Connection: self, server_kwargs: Optional[dict] = None, connection_kwargs: Optional[dict] = None
) -> Connection:
"""Get a fully connected and bound LDAP Connection""" """Get a fully connected and bound LDAP Connection"""
server_kwargs = server_kwargs or {}
connection_kwargs = connection_kwargs or {}
connection_kwargs.setdefault("user", self.bind_cn)
connection_kwargs.setdefault("password", self.bind_password)
connection = Connection( connection = Connection(
self.server, self.server(**server_kwargs),
raise_exceptions=True, raise_exceptions=True,
user=self.bind_cn,
password=self.bind_password,
receive_timeout=LDAP_TIMEOUT, receive_timeout=LDAP_TIMEOUT,
**connection_kwargs,
) )
if self.start_tls: if self.start_tls:
connection.start_tls(read_server_info=False) connection.start_tls(read_server_info=False)
connection.bind() try:
connection.bind()
except LDAPSchemaError as exc:
# Schema error, so try connecting without schema info
# See https://github.com/goauthentik/authentik/issues/4590
if server_kwargs.get("get_info", ALL) == NONE:
raise exc
server_kwargs["get_info"] = NONE
return self.connection(server_kwargs, connection_kwargs)
return connection return connection
class Meta: class Meta:

View File

@ -47,10 +47,11 @@ class LDAPPasswordChanger:
def __init__(self, source: LDAPSource) -> None: def __init__(self, source: LDAPSource) -> None:
self._source = source self._source = source
self._connection = source.connection()
def get_domain_root_dn(self) -> str: def get_domain_root_dn(self) -> str:
"""Attempt to get root DN via MS specific fields or generic LDAP fields""" """Attempt to get root DN via MS specific fields or generic LDAP fields"""
info = self._source.connection.server.info info = self._connection.server.info
if "rootDomainNamingContext" in info.other: if "rootDomainNamingContext" in info.other:
return info.other["rootDomainNamingContext"][0] return info.other["rootDomainNamingContext"][0]
naming_contexts = info.naming_contexts naming_contexts = info.naming_contexts
@ -61,7 +62,7 @@ class LDAPPasswordChanger:
"""Check if DOMAIN_PASSWORD_COMPLEX is enabled""" """Check if DOMAIN_PASSWORD_COMPLEX is enabled"""
root_dn = self.get_domain_root_dn() root_dn = self.get_domain_root_dn()
try: try:
root_attrs = self._source.connection.extend.standard.paged_search( root_attrs = self._connection.extend.standard.paged_search(
search_base=root_dn, search_base=root_dn,
search_filter="(objectClass=*)", search_filter="(objectClass=*)",
search_scope=BASE, search_scope=BASE,
@ -90,14 +91,14 @@ class LDAPPasswordChanger:
LOGGER.info(f"User has no {LDAP_DISTINGUISHED_NAME} set.") LOGGER.info(f"User has no {LDAP_DISTINGUISHED_NAME} set.")
return return
try: try:
self._source.connection.extend.microsoft.modify_password(user_dn, password) self._connection.extend.microsoft.modify_password(user_dn, password)
except LDAPAttributeError: except LDAPAttributeError:
self._source.connection.extend.standard.modify_password(user_dn, new_password=password) self._connection.extend.standard.modify_password(user_dn, new_password=password)
def _ad_check_password_existing(self, password: str, user_dn: str) -> bool: def _ad_check_password_existing(self, password: str, user_dn: str) -> bool:
"""Check if a password contains sAMAccount or displayName""" """Check if a password contains sAMAccount or displayName"""
users = list( users = list(
self._source.connection.extend.standard.paged_search( self._connection.extend.standard.paged_search(
search_base=user_dn, search_base=user_dn,
search_filter=self._source.user_object_filter, search_filter=self._source.user_object_filter,
search_scope=BASE, search_scope=BASE,

View File

@ -3,6 +3,7 @@ from typing import Any, Generator
from django.db.models.base import Model from django.db.models.base import Model
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from ldap3 import Connection
from structlog.stdlib import BoundLogger, get_logger from structlog.stdlib import BoundLogger, get_logger
from authentik.core.exceptions import PropertyMappingExpressionException from authentik.core.exceptions import PropertyMappingExpressionException
@ -19,10 +20,12 @@ class BaseLDAPSynchronizer:
_source: LDAPSource _source: LDAPSource
_logger: BoundLogger _logger: BoundLogger
_connection: Connection
_messages: list[str] _messages: list[str]
def __init__(self, source: LDAPSource): def __init__(self, source: LDAPSource):
self._source = source self._source = source
self._connection = source.connection()
self._messages = [] self._messages = []
self._logger = get_logger().bind(source=source, syncer=self.__class__.__name__) self._logger = get_logger().bind(source=source, syncer=self.__class__.__name__)

View File

@ -14,7 +14,7 @@ class GroupLDAPSynchronizer(BaseLDAPSynchronizer):
"""Sync LDAP Users and groups into authentik""" """Sync LDAP Users and groups into authentik"""
def get_objects(self, **kwargs) -> Generator: def get_objects(self, **kwargs) -> Generator:
return self._source.connection.extend.standard.paged_search( return self._connection.extend.standard.paged_search(
search_base=self.base_dn_groups, search_base=self.base_dn_groups,
search_filter=self._source.group_object_filter, search_filter=self._source.group_object_filter,
search_scope=SUBTREE, search_scope=SUBTREE,

View File

@ -20,7 +20,7 @@ class MembershipLDAPSynchronizer(BaseLDAPSynchronizer):
self.group_cache: dict[str, Group] = {} self.group_cache: dict[str, Group] = {}
def get_objects(self, **kwargs) -> Generator: def get_objects(self, **kwargs) -> Generator:
return self._source.connection.extend.standard.paged_search( return self._connection.extend.standard.paged_search(
search_base=self.base_dn_groups, search_base=self.base_dn_groups,
search_filter=self._source.group_object_filter, search_filter=self._source.group_object_filter,
search_scope=SUBTREE, search_scope=SUBTREE,

View File

@ -16,7 +16,7 @@ class UserLDAPSynchronizer(BaseLDAPSynchronizer):
"""Sync LDAP Users into authentik""" """Sync LDAP Users into authentik"""
def get_objects(self, **kwargs) -> Generator: def get_objects(self, **kwargs) -> Generator:
return self._source.connection.extend.standard.paged_search( return self._connection.extend.standard.paged_search(
search_base=self.base_dn_users, search_base=self.base_dn_users,
search_filter=self._source.user_object_filter, search_filter=self._source.user_object_filter,
search_scope=SUBTREE, search_scope=SUBTREE,

View File

@ -1,5 +1,5 @@
"""LDAP Source tests""" """LDAP Source tests"""
from unittest.mock import Mock, PropertyMock, patch from unittest.mock import MagicMock, Mock, patch
from django.db.models import Q from django.db.models import Q
from django.test import TestCase from django.test import TestCase
@ -37,7 +37,7 @@ class LDAPSyncTests(TestCase):
| Q(managed__startswith="goauthentik.io/sources/ldap/ms-") | Q(managed__startswith="goauthentik.io/sources/ldap/ms-")
) )
) )
connection = PropertyMock(return_value=mock_ad_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
user_sync = UserLDAPSynchronizer(self.source) user_sync = UserLDAPSynchronizer(self.source)
user_sync.sync() user_sync.sync()
@ -64,7 +64,7 @@ class LDAPSyncTests(TestCase):
) )
) )
self.source.save() self.source.save()
connection = PropertyMock(return_value=mock_slapd_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
user_sync = UserLDAPSynchronizer(self.source) user_sync = UserLDAPSynchronizer(self.source)
user_sync.sync() user_sync.sync()

View File

@ -1,5 +1,5 @@
"""LDAP Source tests""" """LDAP Source tests"""
from unittest.mock import PropertyMock, patch from unittest.mock import MagicMock, patch
from django.test import TestCase from django.test import TestCase
@ -10,7 +10,7 @@ from authentik.sources.ldap.password import LDAPPasswordChanger
from authentik.sources.ldap.tests.mock_ad import mock_ad_connection from authentik.sources.ldap.tests.mock_ad import mock_ad_connection
LDAP_PASSWORD = generate_key() LDAP_PASSWORD = generate_key()
LDAP_CONNECTION_PATCH = PropertyMock(return_value=mock_ad_connection(LDAP_PASSWORD)) LDAP_CONNECTION_PATCH = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
class LDAPPasswordTests(TestCase): class LDAPPasswordTests(TestCase):

View File

@ -1,5 +1,5 @@
"""LDAP Source tests""" """LDAP Source tests"""
from unittest.mock import PropertyMock, patch from unittest.mock import MagicMock, patch
from django.db.models import Q from django.db.models import Q
from django.test import TestCase from django.test import TestCase
@ -48,7 +48,7 @@ class LDAPSyncTests(TestCase):
) )
self.source.property_mappings.set([mapping]) self.source.property_mappings.set([mapping])
self.source.save() self.source.save()
connection = PropertyMock(return_value=mock_ad_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
user_sync = UserLDAPSynchronizer(self.source) user_sync = UserLDAPSynchronizer(self.source)
user_sync.sync() user_sync.sync()
@ -69,7 +69,7 @@ class LDAPSyncTests(TestCase):
) )
) )
self.source.save() self.source.save()
connection = PropertyMock(return_value=mock_ad_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
# Create the user beforehand so we can set attributes and check they aren't removed # Create the user beforehand so we can set attributes and check they aren't removed
user = User.objects.create( user = User.objects.create(
@ -103,7 +103,7 @@ class LDAPSyncTests(TestCase):
) )
) )
self.source.save() self.source.save()
connection = PropertyMock(return_value=mock_slapd_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
user_sync = UserLDAPSynchronizer(self.source) user_sync = UserLDAPSynchronizer(self.source)
user_sync.sync() user_sync.sync()
@ -121,11 +121,11 @@ class LDAPSyncTests(TestCase):
self.source.property_mappings_group.set( self.source.property_mappings_group.set(
LDAPPropertyMapping.objects.filter(managed="goauthentik.io/sources/ldap/default-name") LDAPPropertyMapping.objects.filter(managed="goauthentik.io/sources/ldap/default-name")
) )
_user = create_test_admin_user() connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
parent_group = Group.objects.get(name=_user.username)
self.source.sync_parent_group = parent_group
connection = PropertyMock(return_value=mock_ad_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
_user = create_test_admin_user()
parent_group = Group.objects.get(name=_user.username)
self.source.sync_parent_group = parent_group
self.source.save() self.source.save()
group_sync = GroupLDAPSynchronizer(self.source) group_sync = GroupLDAPSynchronizer(self.source)
group_sync.sync() group_sync.sync()
@ -148,7 +148,7 @@ class LDAPSyncTests(TestCase):
self.source.property_mappings_group.set( self.source.property_mappings_group.set(
LDAPPropertyMapping.objects.filter(managed="goauthentik.io/sources/ldap/openldap-cn") LDAPPropertyMapping.objects.filter(managed="goauthentik.io/sources/ldap/openldap-cn")
) )
connection = PropertyMock(return_value=mock_slapd_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
self.source.save() self.source.save()
group_sync = GroupLDAPSynchronizer(self.source) group_sync = GroupLDAPSynchronizer(self.source)
@ -173,7 +173,7 @@ class LDAPSyncTests(TestCase):
self.source.property_mappings_group.set( self.source.property_mappings_group.set(
LDAPPropertyMapping.objects.filter(managed="goauthentik.io/sources/ldap/openldap-cn") LDAPPropertyMapping.objects.filter(managed="goauthentik.io/sources/ldap/openldap-cn")
) )
connection = PropertyMock(return_value=mock_slapd_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
self.source.save() self.source.save()
user_sync = UserLDAPSynchronizer(self.source) user_sync = UserLDAPSynchronizer(self.source)
@ -195,7 +195,7 @@ class LDAPSyncTests(TestCase):
) )
) )
self.source.save() self.source.save()
connection = PropertyMock(return_value=mock_ad_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get() ldap_sync_all.delay().get()
@ -210,6 +210,6 @@ class LDAPSyncTests(TestCase):
) )
) )
self.source.save() self.source.save()
connection = PropertyMock(return_value=mock_slapd_connection(LDAP_PASSWORD)) connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
ldap_sync_all.delay().get() ldap_sync_all.delay().get()

View File

@ -33,6 +33,7 @@ class AuthenticatorDuoStageSerializer(StageSerializer):
model = AuthenticatorDuoStage model = AuthenticatorDuoStage
fields = StageSerializer.Meta.fields + [ fields = StageSerializer.Meta.fields + [
"configure_flow", "configure_flow",
"friendly_name",
"client_id", "client_id",
"client_secret", "client_secret",
"api_hostname", "api_hostname",

View File

@ -0,0 +1,20 @@
# Generated by Django 4.1.7 on 2023-04-02 14:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
(
"authentik_stages_authenticator_duo",
"0004_authenticatorduostage_admin_integration_key_and_more",
),
]
operations = [
migrations.AddField(
model_name="authenticatorduostage",
name="friendly_name",
field=models.TextField(null=True),
),
]

View File

@ -12,12 +12,12 @@ from rest_framework.serializers import BaseSerializer, Serializer
from authentik import __version__ from authentik import __version__
from authentik.core.types import UserSettingSerializer from authentik.core.types import UserSettingSerializer
from authentik.flows.models import ConfigurableStage, Stage from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
from authentik.lib.models import SerializerModel from authentik.lib.models import SerializerModel
from authentik.lib.utils.http import authentik_user_agent from authentik.lib.utils.http import authentik_user_agent
class AuthenticatorDuoStage(ConfigurableStage, Stage): class AuthenticatorDuoStage(ConfigurableStage, FriendlyNamedStage, Stage):
"""Setup Duo authenticator devices""" """Setup Duo authenticator devices"""
api_hostname = models.TextField() api_hostname = models.TextField()
@ -68,7 +68,7 @@ class AuthenticatorDuoStage(ConfigurableStage, Stage):
def ui_user_settings(self) -> Optional[UserSettingSerializer]: def ui_user_settings(self) -> Optional[UserSettingSerializer]:
return UserSettingSerializer( return UserSettingSerializer(
data={ data={
"title": str(self._meta.verbose_name), "title": self.friendly_name or str(self._meta.verbose_name),
"component": "ak-user-settings-authenticator-duo", "component": "ak-user-settings-authenticator-duo",
} }
) )

View File

@ -19,6 +19,7 @@ class AuthenticatorSMSStageSerializer(StageSerializer):
model = AuthenticatorSMSStage model = AuthenticatorSMSStage
fields = StageSerializer.Meta.fields + [ fields = StageSerializer.Meta.fields + [
"configure_flow", "configure_flow",
"friendly_name",
"provider", "provider",
"from_number", "from_number",
"account_sid", "account_sid",

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