Compare commits

..

282 Commits

Author SHA1 Message Date
1883402b3d release: 2022.5.3 2022-05-28 12:04:26 +02:00
88a8b7d2fa outposts/ldap: fix type assertion after upgrading to new API Client
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-27 21:43:58 +02:00
987f03c4be website/docs: Update flow to run only during Github logins (#2959) 2022-05-27 21:43:55 +02:00
1b3aacfa1d providers/oauth2: add migration from "*" to ".*"
closes #2970

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-27 21:43:51 +02:00
3a994ab2a4 website/docs: prepare 2022.5.3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-26 22:18:02 +02:00
d7713357f4 api: migrate to openapi generator v6 (#2968)
* migrate to openapi generator v6

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

* bump api

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
# Conflicts:
#	go.mod
#	go.sum
2022-05-26 22:17:57 +02:00
e7c03fdb14 web/admin: add note that regex is used for redirect URIs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-26 22:17:37 +02:00
6105956847 providers/oauth2: regex-escape URLs when set to blank
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-26 22:17:34 +02:00
89028f175a website/docs: Fix misconfiguration causing POST requests behing Nginx to timeout (#2967)
* Update _nginx_proxy_manager.md

* Update _nginx_standalone.md
2022-05-26 22:17:31 +02:00
f121098957 root: Add docker-compose postgresql and redis healthchecks (#2958)
* Add healthchecks to docker compose

Add healthchecks for postgresql and redis, see als #2519

* bump docker-compose version to 3.4
2022-05-26 22:17:10 +02:00
4ff32af343 flows: fix flakiness in tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-26 22:17:03 +02:00
972868c15c providers/oauth2: only set expiry on user when it was freshly created
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-26 22:16:55 +02:00
0bc57f571b api: update API browser to match admin UI and auto-switch theme
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-26 22:16:34 +02:00
9de5b6f93e build(deps): bump rapidoc from 9.2.0 to 9.3.2 in /web (#2957)
Bumps [rapidoc](https://github.com/rapi-doc/RapiDoc) from 9.2.0 to 9.3.2.
- [Release notes](https://github.com/rapi-doc/RapiDoc/releases)
- [Commits](https://github.com/rapi-doc/RapiDoc/compare/v9.2.0...v9.3.2)

---
updated-dependencies:
- dependency-name: rapidoc
  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>
2022-05-26 22:16:34 +02:00
cc744dc581 flows: fix lint
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-25 00:04:58 +02:00
47006fc9d2 website/docs: fix formatting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-24 23:38:15 +02:00
a03e48c5ce website/docs: prepare 2022.5.3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-24 23:35:09 +02:00
816b0c7d83 flows: fix re-imports of entries with identical PK re-creating objects
closes #2941

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-24 23:35:06 +02:00
0edf4296c4 web/elements: fix used_by refreshing for all elements when using DeleteBulkForm
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-24 22:14:29 +02:00
b8fdda50ec ensure all viewsets have filter and search and add tests (#2946)
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-24 22:13:59 +02:00
ab1840dd66 web: Update Web API Client version (#2944) 2022-05-24 20:05:06 +02:00
482491e93c core: fix username validator not allowing changes that can be done via flows
closes #2755

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-24 19:40:54 +02:00
2ca991ba3d website/docs: fix grammar (#2943) 2022-05-24 13:56:19 +02:00
b20c384f5a build(deps): bump @typescript-eslint/parser from 5.25.0 to 5.26.0 in /web (#2937)
build(deps): bump @typescript-eslint/parser in /web

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.25.0 to 5.26.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.26.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>
2022-05-24 10:29:21 +02:00
9ce8edbcd6 build(deps): bump country-flag-icons from 1.5.2 to 1.5.4 in /web (#2938)
Bumps [country-flag-icons](https://gitlab.com/catamphetamine/country-flag-icons) from 1.5.2 to 1.5.4.
- [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.2...v1.5.4)

---
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>
2022-05-24 10:27:25 +02:00
cb5b2148a3 build(deps): bump @typescript-eslint/eslint-plugin from 5.25.0 to 5.26.0 in /web (#2939)
build(deps): bump @typescript-eslint/eslint-plugin in /web

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.25.0 to 5.26.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.26.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>
2022-05-24 10:27:14 +02:00
d5702c6282 web/admin: fix broken flow execute link (#2940) 2022-05-24 10:26:58 +02:00
61a876b582 providers/saml: handle parse error
AUTHENTIK-1K5

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 22:03:12 +02:00
8c9748e4a0 providers/oauth2: improve error handling for invalid regular expressions
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 20:47:36 +02:00
6460245d5e website/docs: add missing docs for #2828
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 20:42:00 +02:00
b7979ad48e Revert "events: ignore silk SQLQuery object"
This reverts commit a26f25ccd6.

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 20:29:05 +02:00
cbd95848e7 web: decrease elements that refresh on global refresh signal
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 20:26:33 +02:00
4704de937a stages/user_write: fix typo in request context variable
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 20:18:37 +02:00
394d8e99a4 policies: improve error logging
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 20:18:00 +02:00
a26f25ccd6 events: ignore silk SQLQuery object
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 20:17:52 +02:00
94257e0f50 web/admin: refactor table refresh to preserve selected/expanded elements correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 20:07:56 +02:00
b2a42a68a4 web/admin: fix flow diagram not updating on flow changes
closes #2932

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-23 19:48:33 +02:00
7895d59da3 Translate '/web/src/locales/en.po' in 'zh_CN' (#2934)
Translate /web/src/locales/en.po in zh_CN

translation completed 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>
2022-05-23 14:13:17 +02:00
b54c60d7af Translate '/web/src/locales/en.po' in 'zh-Hans' (#2935)
Translate /web/src/locales/en.po in zh-Hans

translation completed 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>
2022-05-23 14:13:08 +02:00
6bab3bf68e web/elements: fix missing click handler on wizard close button
closes #2931
2022-05-23 09:33:16 +00:00
fdc09c658a web/admin: fix phrasing on LDAP provider form for bind mode 2022-05-23 09:28:22 +00:00
a690a02f99 web/admin: fix display of LDAP bind mode
closes #2930
2022-05-23 09:24:57 +00:00
0e912fd647 build(deps): bump codemirror from 5.65.3 to 5.65.4 in /web (#2923) 2022-05-23 09:11:23 +02:00
27af330932 build(deps): bump eslint from 8.15.0 to 8.16.0 in /web (#2924) 2022-05-23 09:11:12 +02:00
7187d28905 build(deps): bump country-flag-icons from 1.4.26 to 1.5.2 in /web (#2925) 2022-05-23 09:10:18 +02:00
ca832b6090 build(deps-dev): bump importlib-metadata from 4.11.3 to 4.11.4 (#2926) 2022-05-23 09:10:03 +02:00
53bd6bf06e build(deps-dev): bump coverage from 6.3.3 to 6.4 (#2927) 2022-05-23 09:09:49 +02:00
813f271bdd build(deps): bump goauthentik.io/api/v3 from 3.2022041.10 to 3.2022052.2 (#2928) 2022-05-23 09:09:31 +02:00
63dc8fe7dc crypto: set SAN in default generated Certificate to semi-random domain
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#2462
2022-05-22 23:22:06 +02:00
383f4e4dcf root: exempt question for stale
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-22 22:56:29 +02:00
2896652fef web: Update Web API Client version (#2922)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2022-05-22 19:36:17 +02:00
cfe2648b62 events: fix transport not allowing blank values
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-22 19:32:58 +02:00
8d49705c87 web/admin: add set password button to user view page
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-22 16:46:38 +02:00
c99e6d8f2c website: fix typo in title
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 19:10:16 +02:00
0996bb500c web: Update Web API Client version (#2920) 2022-05-21 18:07:18 +02:00
3d4a45c93f release: 2022.5.2 2022-05-21 17:17:21 +02:00
0642af0b78 website/docs: add 2022.5.2 changelog
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 17:16:43 +02:00
dce623dd7c web/user: fix use sub-pages not redirecting back to the subpage
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 17:07:30 +02:00
646d174dd2 internal: revert cookie path on proxy causing redirect loops
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 16:26:12 +02:00
b8fdb82adc web/admin: improve error handling in TokenCopyButton
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 15:56:06 +02:00
75d6cd1674 outposts: ensure the user and token are created on initial outpost save
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 15:55:19 +02:00
5c91658484 internal: fix nil pointer dereference in ldap outpost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 15:48:50 +02:00
ebb44c992b Revert "internal: set SameSite for outpost"
This reverts commit 7e95c756b9.
2022-05-21 14:08:40 +02:00
233bb35ebe Translate '/web/src/locales/en.po' in 'zh_CN' (#2913)
Translate /web/src/locales/en.po in zh_CN

translation completed 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>
2022-05-21 13:22:20 +02:00
f60d0b9753 Translate '/web/src/locales/en.po' in 'zh-Hans' (#2914)
Translate /web/src/locales/en.po in zh-Hans

translation completed 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>
2022-05-21 13:22:12 +02:00
7e95c756b9 internal: set SameSite for outpost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 13:21:45 +02:00
be26b92927 internal: cleanup outpost logs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 13:18:06 +02:00
dd3ed1bfb9 web/admin: make external host clickable
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 13:10:26 +02:00
6f56a61a64 website/docs: add docs for advanced SSH config
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#2916
2022-05-21 13:06:54 +02:00
2dee8034d3 outposts: allow externally managed SSH Config for outposts (#2917) 2022-05-21 12:10:08 +02:00
d9d42020cc root: fix missing curl in dockerfile
closes #2915

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 00:49:15 +02:00
90298a2b6c website/docs: fix typo
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-21 00:15:40 +02:00
7c17e7d52f web: Update Web API Client version (#2912) 2022-05-20 19:53:05 +02:00
fbb3ca98c1 website: add 2022.5 to sidebar
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-20 19:47:46 +02:00
220d21c3e0 release: 2022.5.1 2022-05-20 19:34:45 +02:00
84e74bc21e website/docs: final 2022.5 release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-20 19:34:43 +02:00
ec15060c84 web/admin: add button to empty state to clear search (#2911) 2022-05-20 18:01:26 +02:00
334898ae23 website/integrations: Fix Gitea integration manual steps (#2910) 2022-05-20 16:47:39 +02:00
b43df2ae27 stages/identification: redirect with QS to keep next parameters (#2909)
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-20 16:10:10 +02:00
a52638d898 internal: fix typo in session name constant
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-20 10:10:29 +02:00
5bc893b890 build(deps): bump @babel/plugin-transform-runtime from 7.17.12 to 7.18.0 in /web (#2904) 2022-05-20 09:45:53 +02:00
fe5d9e4cd2 build(deps): bump @babel/core from 7.17.12 to 7.18.0 in /web (#2903) 2022-05-20 09:45:27 +02:00
a7442e0043 build(deps): bump @formatjs/intl-listformat from 6.5.3 to 7.0.1 in /web (#2905) 2022-05-20 09:45:06 +02:00
8103bbf9af build(deps): bump rollup from 2.73.0 to 2.74.1 in /web (#2906) 2022-05-20 09:44:50 +02:00
056b90b590 build(deps): bump @babel/preset-env from 7.17.12 to 7.18.0 in /web (#2907) 2022-05-20 09:44:37 +02:00
70221e3d14 web: fix labels in forms for dark mode
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-19 22:03:03 +02:00
d570feffac flows: add types to diagrams (#2902)
* add policy and stage types to diagram

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

* show policies bound to the root flow

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

* fix get_build_hash being empty

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

* update tests

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-19 20:50:28 +02:00
3d52266773 flows: handle missing initial_data in challenge
AUTHENTIK-1HK

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-19 20:31:28 +02:00
7bdecd2ee6 stages/user_write: dynamic groups (#2901)
* stages/user_write: add dynamic groups

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

* simplify functions

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-19 20:28:16 +02:00
a500ff28ac website/integrations: update proxmox docs (#2899)
Signed-off-by: Victor Roest <victor@xirion.net>
2022-05-19 20:23:27 +02:00
263bcae050 web/admin: improve empty state
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	web/src/elements/table/TablePage.ts
#	web/src/pages/applications/ApplicationListPage.ts
2022-05-19 10:21:46 +02:00
8691a79204 build(deps): bump postcss from 8.4.13 to 8.4.14 in /website (#2900)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.13 to 8.4.14.
- [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.13...8.4.14)

---
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>
2022-05-19 09:29:30 +02:00
3b0b6dcf29 web: fix display of radio buttons on wizard pages
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-18 23:09:02 +02:00
11f7935155 providers/oauth2: use regex to check redirect URI
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#2799
2022-05-18 21:22:27 +02:00
450a26d1b5 build(deps): bump @typescript-eslint/parser from 5.24.0 to 5.25.0 in /web (#2895)
build(deps): bump @typescript-eslint/parser in /web

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.24.0 to 5.25.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.25.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>
2022-05-18 09:51:51 +02:00
3e42c1bad4 build(deps): bump @typescript-eslint/eslint-plugin from 5.24.0 to 5.25.0 in /web (#2896)
build(deps): bump @typescript-eslint/eslint-plugin in /web

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.24.0 to 5.25.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.25.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>
2022-05-18 09:50:15 +02:00
5abbb7657b build(deps): bump lit from 2.2.3 to 2.2.4 in /web (#2897)
Bumps [lit](https://github.com/lit/lit/tree/HEAD/packages/lit) from 2.2.3 to 2.2.4.
- [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.2.4/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>
2022-05-18 09:50:03 +02:00
75b0fb3393 sources/oauth: migrate twitter to oauth2 (#2893) 2022-05-18 00:03:02 +02:00
538c2ca4d3 stages/authenticator_*: directly save devices into db instead of session to prevent race conditions
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-17 10:02:30 +02:00
5080840ed9 admin: ensure disable_update_check is set to false for tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-17 10:00:26 +02:00
eded9bfb2d build(deps): bump @babel/preset-typescript from 7.16.7 to 7.17.12 in /web (#2885)
build(deps): bump @babel/preset-typescript in /web

Bumps [@babel/preset-typescript](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-typescript) from 7.16.7 to 7.17.12.
- [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.17.12/packages/babel-preset-typescript)

---
updated-dependencies:
- dependency-name: "@babel/preset-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>
2022-05-17 09:34:09 +02:00
b3a43ae37c build(deps): bump @typescript-eslint/parser from 5.23.0 to 5.24.0 in /web (#2884)
build(deps): bump @typescript-eslint/parser in /web

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.23.0 to 5.24.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.24.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>
2022-05-17 09:30:24 +02:00
dc78746825 build(deps): bump @babel/preset-env from 7.17.10 to 7.17.12 in /web (#2881)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.17.10 to 7.17.12.
- [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.17.12/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  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>
2022-05-17 09:29:58 +02:00
3c6828cbba Translate '/web/src/locales/en.po' in 'zh_CN' (#2878)
Translate /web/src/locales/en.po in zh_CN

translation completed 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>
2022-05-17 09:29:45 +02:00
26646264dc Translate '/web/src/locales/en.po' in 'zh-Hans' (#2879)
Translate /web/src/locales/en.po in zh-Hans

translation completed 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>
2022-05-17 09:29:36 +02:00
f7ecfdd4b6 build(deps): bump @typescript-eslint/eslint-plugin from 5.23.0 to 5.24.0 in /web (#2883)
build(deps): bump @typescript-eslint/eslint-plugin in /web

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.23.0 to 5.24.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.24.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>
2022-05-17 09:29:20 +02:00
967c80069b build(deps): bump @babel/core from 7.17.10 to 7.17.12 in /web (#2882)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.17.10 to 7.17.12.
- [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.17.12/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  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>
2022-05-17 09:28:57 +02:00
f8b0c071b7 build(deps): bump @babel/plugin-transform-runtime from 7.17.10 to 7.17.12 in /web (#2886)
build(deps): bump @babel/plugin-transform-runtime in /web

Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.17.10 to 7.17.12.
- [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.17.12/packages/babel-plugin-transform-runtime)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-runtime"
  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>
2022-05-17 09:28:40 +02:00
221ab47410 build(deps): bump actions/setup-node from 3.1.1 to 3.2.0 (#2887)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3.1.1 to 3.2.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v3.1.1...v3.2.0)

---
updated-dependencies:
- dependency-name: actions/setup-node
  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>
2022-05-17 09:27:50 +02:00
ffe162214f build(deps): bump @babel/plugin-proposal-decorators from 7.17.9 to 7.17.12 in /web (#2888)
build(deps): bump @babel/plugin-proposal-decorators in /web

Bumps [@babel/plugin-proposal-decorators](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-proposal-decorators) from 7.17.9 to 7.17.12.
- [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.17.12/packages/babel-plugin-proposal-decorators)

---
updated-dependencies:
- dependency-name: "@babel/plugin-proposal-decorators"
  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>
2022-05-17 09:27:24 +02:00
ad9d8d26ed build(deps): bump paramiko from 2.10.4 to 2.11.0 (#2889)
Bumps [paramiko](https://github.com/paramiko/paramiko) from 2.10.4 to 2.11.0.
- [Release notes](https://github.com/paramiko/paramiko/releases)
- [Changelog](https://github.com/paramiko/paramiko/blob/main/NEWS)
- [Commits](https://github.com/paramiko/paramiko/compare/2.10.4...2.11.0)

---
updated-dependencies:
- dependency-name: paramiko
  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>
2022-05-17 09:27:07 +02:00
35402ada17 website/docs: fix missing new name attribute for invitations
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-16 20:40:24 +02:00
086a44bdbd web/user: add message upon source connection deletion
closes #2522

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-16 20:28:23 +02:00
6494a0352f Translate '/web/src/locales/en.po' in 'zh-Hans' (#2877) 2022-05-16 09:20:20 +02:00
ca1fb737a8 Translate '/web/src/locales/en.po' in 'zh_CN' (#2876) 2022-05-16 09:20:02 +02:00
9e91a0a85d build(deps): bump github.com/prometheus/client_golang from 1.12.1 to 1.12.2 (#2875) 2022-05-16 09:19:36 +02:00
4e68fe2fea build(deps): bump goauthentik.io/api/v3 from 3.2022041.6 to 3.2022041.10 (#2874) 2022-05-16 09:19:26 +02:00
a36eab81eb build(deps-dev): bump pylint from 2.13.8 to 2.13.9 (#2873) 2022-05-16 09:19:09 +02:00
215b2a3224 build(deps): bump @patternfly/patternfly from 4.192.1 to 4.194.4 in /web (#2872) 2022-05-16 09:17:43 +02:00
4c3f8e446f build(deps): bump yaml from 2.0.1 to 2.1.0 in /web (#2871) 2022-05-16 09:17:31 +02:00
4b9922e5b1 build(deps): bump rollup from 2.72.1 to 2.73.0 in /web (#2870) 2022-05-16 09:17:17 +02:00
6324521424 build(deps): bump react-before-after-slider-component from 1.1.2 to 1.1.3 in /website (#2869) 2022-05-16 09:17:02 +02:00
d6b18f2833 web: Update Web API Client version (#2868) 2022-05-16 01:13:29 +02:00
333e58ce2f flows/layouts (#2867) 2022-05-16 01:10:23 +02:00
699d3ca067 ci: exclude confirmed issues from stale
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-15 23:16:52 +02:00
296779ddf1 providers/ldap: remove technical preview disclaimer
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-15 17:33:03 +02:00
8669f498f1 web: Update Web API Client version (#2866)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2022-05-14 22:43:55 +02:00
4de2ac3248 events: add task to expire seen notifications
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 22:41:50 +02:00
eb4dce91c3 events: add user filter to notifications
as superuser all notifications are returned regardless of permission so we need to filter

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 22:31:13 +02:00
c64a99345b web: fix scrolling issue on library page
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 21:58:42 +02:00
2e174a1be5 website/docs: update 2022.5 release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 21:48:28 +02:00
11ef500475 web: Update Web API Client version (#2865)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2022-05-14 21:38:38 +02:00
d4fd6153c8 api: fix OwnerFilter filtering out objects for superusers
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 21:36:00 +02:00
85b6bfbe5f sources: fix parent serializer for user connections
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 21:26:02 +02:00
5ddd138c97 web: update default flow background
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 20:08:59 +02:00
5644d5f3f7 stages/authenticator_totp: fix key error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 19:57:00 +02:00
be06adcb59 web: lazy load parts of interfaces (#2864) 2022-05-14 17:07:37 +02:00
4da350ebfc web: fix dateTimeLocal() dropping local timezone
closes #2860

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 12:47:30 +02:00
f391c33bdf providers/oauth2: fix tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 12:41:40 +02:00
18f450bd49 root: enable sentry for tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 12:29:30 +02:00
ee36b7f3eb flows: move autosubmit stage into flows package
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 12:06:19 +02:00
f56d619243 web: Update Web API Client version (#2862) 2022-05-14 00:17:33 +02:00
a9a62bbfc8 providers/oauth2: use correct title based on flow context and translated
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 00:08:29 +02:00
ddd785898b providers/saml: add title attribute to autosubmit stage and render correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 00:08:14 +02:00
8ba45a5f6a providers/oauth2: don't create events before client_id can be verified to prevent spam
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-14 00:02:01 +02:00
7d41e6227b providers/oauth2: add tests for form_post, fix attrs not being flattened
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-13 23:52:50 +02:00
1363226697 providers/saml: make SAML metadata generation consistent
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-13 17:40:18 +02:00
25910bb577 build(deps-dev): bump coverage from 6.3.2 to 6.3.3 (#2857)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 6.3.2 to 6.3.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/6.3.2...6.3.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>
2022-05-13 09:44:07 +02:00
62e54a3a51 build(deps): bump pyjwt from 2.3.0 to 2.4.0 (#2858)
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jpadilla/pyjwt/compare/2.3.0...2.4.0)

---
updated-dependencies:
- dependency-name: pyjwt
  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>
2022-05-13 09:43:54 +02:00
5f5b4c962b ci: fix website mark
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-12 22:54:29 +02:00
4a9a19eacb website/integrations: clear up home-assistant integration
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-12 21:40:58 +02:00
d4abf5621e providers/oauth2: add support for form_post response mode (#2818)
* Added request verification and parameter generation

* response_mode added to OAuthAuthorizationParams return

* Added class OauthPostFulfillmentStage
Check response_mode in initialization

* Corrected typo

* Removed separate class
Added handling for FORM_POST in create_response_uri
Added handling for FORM_POST in return class

* Fixed pylint error (trailing-whitespace)
Removed comment

* Reformatted authorize.py with black
2022-05-12 21:36:31 +02:00
1cb71b5217 web: fix invalid import paths
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-12 13:22:22 +02:00
a884f23855 build(deps-dev): bump pytest-randomly from 3.11.0 to 3.12.0 (#2855)
Bumps [pytest-randomly](https://github.com/pytest-dev/pytest-randomly) from 3.11.0 to 3.12.0.
- [Release notes](https://github.com/pytest-dev/pytest-randomly/releases)
- [Changelog](https://github.com/pytest-dev/pytest-randomly/blob/main/HISTORY.rst)
- [Commits](https://github.com/pytest-dev/pytest-randomly/compare/3.11.0...3.12.0)

---
updated-dependencies:
- dependency-name: pytest-randomly
  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>
2022-05-12 09:44:55 +02:00
421b003218 internal: set path on cookie for proxy
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#2305
2022-05-11 10:08:38 +02:00
25a4310bb1 internal: use Expires not MaxAge for LDAP session
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-11 10:04:32 +02:00
e897307548 Translate /web/src/locales/en.po in zh_CN (#2846)
translation completed 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>
2022-05-11 10:00:09 +02:00
0fd959c5c0 Translate /web/src/locales/en.po in zh-Hans (#2847)
translation completed 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>
2022-05-11 10:00:00 +02:00
ce7d18798f build(deps): bump golang from 1.18.1-bullseye to 1.18.2-bullseye (#2848)
Bumps golang from 1.18.1-bullseye to 1.18.2-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>
2022-05-11 09:59:08 +02:00
be3b034cb8 build(deps): bump fuse.js from 6.6.1 to 6.6.2 in /web (#2849)
Bumps [fuse.js](https://github.com/krisk/Fuse) from 6.6.1 to 6.6.2.
- [Release notes](https://github.com/krisk/Fuse/releases)
- [Changelog](https://github.com/krisk/Fuse/blob/master/CHANGELOG.md)
- [Commits](https://github.com/krisk/Fuse/compare/v6.6.1...v6.6.2)

---
updated-dependencies:
- dependency-name: fuse.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>
2022-05-11 09:58:59 +02:00
9f674442d3 build(deps): bump goauthentik.io/api/v3 from 3.2022041.5 to 3.2022041.6 (#2850)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2022041.5 to 3.2022041.6.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2022041.5...v3.2022041.6)

---
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>
2022-05-11 09:58:51 +02:00
c21793943d build(deps): bump sentry-sdk from 1.5.11 to 1.5.12 (#2851)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 1.5.11 to 1.5.12.
- [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.5.11...1.5.12)

---
updated-dependencies:
- dependency-name: sentry-sdk
  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>
2022-05-11 09:57:50 +02:00
ec67b60219 policies/hibp: check in prompt data (#2845)
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-10 23:47:36 +02:00
2fe553785e web: Update Web API Client version (#2844)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2022-05-10 21:08:47 +02:00
fd1d38f844 stages/authenticator_validate: remember (#2828)
* initial

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

* web: cleanup timedelta help

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

* add tooltip

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

* add tests

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

* assert response code in self.assertStageResponse

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

* add more tests, add duo

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

* add docs

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

* fix

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-10 21:05:22 +02:00
4d755dc0f6 build(deps): bump goauthentik.io/api/v3 from 3.2022041.4 to 3.2022041.5 (#2843)
* build(deps): bump goauthentik.io/api/v3 from 3.2022041.4 to 3.2022041.5

Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2022041.4 to 3.2022041.5.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2022041.4...v3.2022041.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>

* fix

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-10 20:33:19 +02:00
30c65f9e61 web: Update Web API Client version (#2840)
* web: Update Web API Client version

Signed-off-by: GitHub <noreply@github.com>

* fix

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

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-10 10:37:50 +02:00
3554406aa5 root: fix duplicate enum in api scheme
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-10 10:24:18 +02:00
5eeaac1ad9 ci: fix path for bumping web api client version
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-10 10:19:15 +02:00
5a172abdb9 ci: allow manual triggering of web API release
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-10 10:12:47 +02:00
8f861d8ecb website/docs: Expanded documentation for SAML Federation w/ examples. (#2822)
* Expanded documentation for SAML Federation w/ examples.

* Added short section for setup on IDP side

* Formatting according to guidelines
Changed example section to table instead of headings

* Escaped <> for formatting

* Fixed quotation on <>

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-10 10:11:10 +02:00
f9fdcd2d07 build(deps): bump @typescript-eslint/parser in /web (#2837)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.22.0 to 5.23.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.23.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>
2022-05-10 09:35:03 +02:00
ed58f21a21 build(deps): bump @typescript-eslint/eslint-plugin in /web (#2838)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.22.0 to 5.23.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.23.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>
2022-05-10 09:33:50 +02:00
45af8eb4be build(deps): bump @docusaurus/preset-classic in /website (#2834)
Bumps [@docusaurus/preset-classic](https://github.com/facebook/docusaurus/tree/HEAD/packages/docusaurus-preset-classic) from 2.0.0-beta.18 to 2.0.0-beta.20.
- [Release notes](https://github.com/facebook/docusaurus/releases)
- [Changelog](https://github.com/facebook/docusaurus/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/docusaurus/commits/v2.0.0-beta.20/packages/docusaurus-preset-classic)

---
updated-dependencies:
- dependency-name: "@docusaurus/preset-classic"
  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>
2022-05-09 21:33:04 +02:00
88573105a0 build(deps): bump @docusaurus/plugin-client-redirects in /website (#2835)
Bumps [@docusaurus/plugin-client-redirects](https://github.com/facebook/docusaurus/tree/HEAD/packages/docusaurus-plugin-client-redirects) from 2.0.0-beta.18 to 2.0.0-beta.20.
- [Release notes](https://github.com/facebook/docusaurus/releases)
- [Changelog](https://github.com/facebook/docusaurus/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/docusaurus/commits/v2.0.0-beta.20/packages/docusaurus-plugin-client-redirects)

---
updated-dependencies:
- dependency-name: "@docusaurus/plugin-client-redirects"
  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>
2022-05-09 21:31:03 +02:00
f9469e3f99 website: format docs with prettier (#2833)
* run prettier

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

* add scim to comparison

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-09 21:22:41 +02:00
26d92d9259 build(deps): bump kubernetes from 23.3.0 to 23.6.0 (#2832) 2022-05-09 09:11:28 +02:00
9cb0d37d51 build(deps): bump rollup from 2.72.0 to 2.72.1 in /web (#2831) 2022-05-09 09:11:23 +02:00
5a25e1524a build(deps): bump eslint from 8.14.0 to 8.15.0 in /web (#2830) 2022-05-09 09:11:17 +02:00
9e1a518689 internal: add signal handler for SIGTERM
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-08 23:05:47 +02:00
cf5771dad3 Translate /web/src/locales/en.po in zh-Hans (#2827)
translation completed 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>
2022-05-08 19:43:59 +02:00
db5aafed36 Translate /web/src/locales/en.po in zh_CN (#2826)
translation completed 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>
2022-05-08 19:43:49 +02:00
4b0324220a website/docs: prepare 2022.5 release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-08 17:32:21 +02:00
0183d2c880 root: match client-go openapi generator version
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-08 17:25:09 +02:00
c1fe18a261 ci: always generate Go API Client
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-08 16:50:58 +02:00
ab2299ba1e outposts/ldap: cached bind (#2824)
* initial cached ldap bind support

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

* add web

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

* add docs

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

* clean up api generation

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

* use gh action for golangci-lint

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-08 16:48:53 +02:00
2678b381b9 web: Update Web API Client version (#2825)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2022-05-08 16:14:02 +02:00
d3ef7920cb root: add bind mode to schema
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-08 16:08:06 +02:00
860269acf0 root: set SESSION_SAVE_EVERY_REQUEST to enable sliding sessions
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#1878
2022-05-07 22:32:56 +02:00
d2bd177b8f Apply translations in zh_CN (#2735)
translation completed 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>
2022-05-07 21:33:08 +02:00
32cc03832a Apply translations in zh-Hans (#2736)
translation completed 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>
2022-05-07 21:32:59 +02:00
948d2cbdca web/user: add missing checkbox element in user settings (#2762) 2022-05-07 21:32:11 +02:00
22026f0755 website/integration: add Weblate integration with SAML (#2786)
* added weblate integration

* added missing entry in sidebarIntegrations
2022-05-07 21:26:10 +02:00
a7a7b5aacb root: export poetry deps to requirements.txt so we don't need poetry … (#2823)
* root: export poetry deps to requirements.txt so we don't need poetry installed, removed packages we don't need anymore

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

* update docs

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-07 21:22:33 +02:00
03d5b9e7e9 build(deps): bump fuse.js from 6.6.0 to 6.6.1 in /web (#2810)
Bumps [fuse.js](https://github.com/krisk/Fuse) from 6.6.0 to 6.6.1.
- [Release notes](https://github.com/krisk/Fuse/releases)
- [Changelog](https://github.com/krisk/Fuse/blob/master/CHANGELOG.md)
- [Commits](https://github.com/krisk/Fuse/compare/v6.6.0...v6.6.1)

---
updated-dependencies:
- dependency-name: fuse.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>
2022-05-06 10:09:19 +02:00
30c7e6c94c providers/oauth2: fixed typo (PROMPT_CONSNET => PROMPT_CONSENT) (#2819) 2022-05-06 10:09:09 +02:00
1ba96586f7 build(deps): bump rollup from 2.71.1 to 2.72.0 in /web (#2811)
Bumps [rollup](https://github.com/rollup/rollup) from 2.71.1 to 2.72.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v2.71.1...v2.72.0)

---
updated-dependencies:
- dependency-name: rollup
  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>
2022-05-06 09:53:57 +02:00
607f632515 build(deps): bump docker/login-action from 1 to 2 (#2812)
Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 2.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/login-action
  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>
2022-05-06 09:53:49 +02:00
58b46fbfcd build(deps): bump docker/setup-buildx-action from 1 to 2 (#2813)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 1 to 2.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  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>
2022-05-06 09:53:40 +02:00
9b53e26ab0 build(deps): bump docker/setup-qemu-action from 1.2.0 to 2.0.0 (#2814)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 1.2.0 to 2.0.0.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v1.2.0...v2.0.0)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  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>
2022-05-06 09:53:28 +02:00
832d3175aa build(deps): bump docker/build-push-action from 2 to 3 (#2815)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 3.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  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>
2022-05-06 09:53:18 +02:00
ebea8369d6 build(deps-dev): bump selenium from 4.1.3 to 4.1.5 (#2816)
Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.1.3 to 4.1.5.
- [Release notes](https://github.com/SeleniumHQ/Selenium/releases)
- [Commits](https://github.com/SeleniumHQ/Selenium/commits)

---
updated-dependencies:
- dependency-name: selenium
  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>
2022-05-06 09:53:07 +02:00
a8508aac99 build(deps): bump github.com/go-openapi/runtime from 0.24.0 to 0.24.1 (#2817)
Bumps [github.com/go-openapi/runtime](https://github.com/go-openapi/runtime) from 0.24.0 to 0.24.1.
- [Release notes](https://github.com/go-openapi/runtime/releases)
- [Commits](https://github.com/go-openapi/runtime/compare/v0.24.0...v0.24.1)

---
updated-dependencies:
- dependency-name: github.com/go-openapi/runtime
  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>
2022-05-06 09:52:25 +02:00
59df02b3b8 root: disable stdout capturing for tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-05 23:08:36 +02:00
f00657f217 website/integrations: update opnsense integration guidance (#2808)
* website/docs: update opnsense integration guidance

* website/docs: remove `-user` opnsense integration
2022-05-05 12:26:16 +02:00
110bc762a1 build(deps): bump sentry-sdk from 1.5.10 to 1.5.11 (#2806)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 1.5.10 to 1.5.11.
- [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.5.10...1.5.11)

---
updated-dependencies:
- dependency-name: sentry-sdk
  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>
2022-05-04 10:16:57 +02:00
f35e5f79aa build(deps): bump fuse.js from 6.5.3 to 6.6.0 in /web (#2800)
Bumps [fuse.js](https://github.com/krisk/Fuse) from 6.5.3 to 6.6.0.
- [Release notes](https://github.com/krisk/Fuse/releases)
- [Changelog](https://github.com/krisk/Fuse/blob/master/CHANGELOG.md)
- [Commits](https://github.com/krisk/Fuse/compare/v6.5.3...v6.6.0)

---
updated-dependencies:
- dependency-name: fuse.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>
2022-05-03 12:31:32 +02:00
3f32109706 build(deps): bump @rollup/plugin-node-resolve in /web (#2801)
Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 13.2.1 to 13.3.0.
- [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-v13.3.0/packages/node-resolve)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-node-resolve"
  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>
2022-05-03 12:31:14 +02:00
0f042f2e4a build(deps): bump @typescript-eslint/eslint-plugin in /web (#2802)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.21.0 to 5.22.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.22.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>
2022-05-03 12:31:02 +02:00
34d1eb140b build(deps): bump @typescript-eslint/parser in /web (#2803)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.21.0 to 5.22.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.22.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>
2022-05-03 12:28:13 +02:00
62f67aabe3 build(deps-dev): bump pylint from 2.13.7 to 2.13.8 (#2804)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.13.7 to 2.13.8.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Changelog](https://github.com/PyCQA/pylint/blob/main/ChangeLog)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.13.7...v2.13.8)

---
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>
2022-05-03 10:49:18 +02:00
82c3eaa0f9 website/integrations: fix duplicate cn=
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-02 23:19:50 +02:00
31ede2ae1d build(deps): bump @babel/preset-env from 7.16.11 to 7.17.10 in /web (#2793) 2022-05-02 13:41:45 +02:00
54c672256f build(deps): bump postcss from 8.4.12 to 8.4.13 in /website (#2794) 2022-05-02 13:41:24 +02:00
5f47d46b6f build(deps): bump @babel/core from 7.17.9 to 7.17.10 in /web (#2795) 2022-05-02 13:40:57 +02:00
3f23bc0b85 build(deps): bump rollup from 2.70.2 to 2.71.1 in /web (#2796) 2022-05-02 13:40:44 +02:00
366142382b build(deps): bump @babel/plugin-transform-runtime in /web (#2797) 2022-05-02 13:40:23 +02:00
ddbe0aaf13 stages/user_delete: fix delete stage failing when pending user is not explicitly set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-05-01 13:59:33 +02:00
75320bf579 website/docs: add missing breaking change in prompt stages
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-29 21:19:51 +02:00
15d8988569 Revert "lifecycle: use worker nr instead of process id to keep number of prometheus database files low"
This reverts commit 254249e38b.

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-29 18:14:04 +02:00
84930b4924 Revert "internal: fix high cpu when backend isnt healthy"
This reverts commit eb6cfd22a7.

Revert "root: handle JSON error in metrics too"

This reverts commit 1ede972222.

Revert "root: don't force multiprocess prometheus registry"

This reverts commit cd1d1b4402.

Revert "root: add error handling for prometheus view"

This reverts commit c0a883f76f.
2022-04-29 18:13:26 +02:00
1ede972222 root: handle JSON error in metrics too
this can happen when the worker is killed while writing metrics
2022-04-29 11:01:04 +00:00
cd1d1b4402 root: don't force multiprocess prometheus registry
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-29 10:53:47 +02:00
79caba45cc build(deps): bump lit from 2.2.2 to 2.2.3 in /web (#2787)
Bumps [lit](https://github.com/lit/lit/tree/HEAD/packages/lit) from 2.2.2 to 2.2.3.
- [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.2.3/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>
2022-04-29 10:25:07 +02:00
c101357051 build(deps): bump typescript from 4.6.3 to 4.6.4 in /web (#2788)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.6.3 to 4.6.4.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.6.3...v4.6.4)

---
updated-dependencies:
- dependency-name: typescript
  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>
2022-04-29 10:24:57 +02:00
9bebb82bbf build(deps): bump webauthn from 1.5.0 to 1.5.2 (#2789)
Bumps [webauthn](https://github.com/duo-labs/py_webauthn) from 1.5.0 to 1.5.2.
- [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.5.0...v1.5.2)

---
updated-dependencies:
- dependency-name: webauthn
  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>
2022-04-29 10:24:46 +02:00
d95d2ca7fe build(deps): bump github.com/go-openapi/runtime from 0.23.3 to 0.24.0 (#2790)
Bumps [github.com/go-openapi/runtime](https://github.com/go-openapi/runtime) from 0.23.3 to 0.24.0.
- [Release notes](https://github.com/go-openapi/runtime/releases)
- [Commits](https://github.com/go-openapi/runtime/compare/v0.23.3...v0.24.0)

---
updated-dependencies:
- dependency-name: github.com/go-openapi/runtime
  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>
2022-04-29 10:24:30 +02:00
c0a883f76f root: add error handling for prometheus view
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-29 10:17:53 +02:00
eb6cfd22a7 internal: fix high cpu when backend isnt healthy
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-29 10:03:40 +02:00
254249e38b lifecycle: use worker nr instead of process id to keep number of prometheus database files low
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#2784
2022-04-28 23:09:39 +02:00
da28bb7d3c build(deps): bump @typescript-eslint/parser in /web (#2774) 2022-04-26 14:42:41 +02:00
391c1ff911 build(deps): bump @patternfly/patternfly from 4.185.1 to 4.192.1 in /web (#2773) 2022-04-26 14:42:25 +02:00
1d475d0982 build(deps): bump paramiko from 2.10.3 to 2.10.4 (#2777) 2022-04-26 14:41:31 +02:00
f92fa61101 build(deps): bump drf-spectacular from 0.22.0 to 0.22.1 (#2778) 2022-04-26 14:41:24 +02:00
ccca397a77 build(deps): bump @typescript-eslint/eslint-plugin in /web (#2775) 2022-04-26 14:41:11 +02:00
162fd26f32 build(deps): bump github/codeql-action from 1 to 2 (#2776) 2022-04-26 14:41:02 +02:00
1d7a235766 build(deps): bump node from 16 to 18 (#2753)
Bumps node from 16 to 18.

---
updated-dependencies:
- dependency-name: node
  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>
2022-04-25 12:30:08 +02:00
01a8deb77f build(deps): bump tslib from 2.3.1 to 2.4.0 in /web (#2754)
Bumps [tslib](https://github.com/Microsoft/tslib) from 2.3.1 to 2.4.0.
- [Release notes](https://github.com/Microsoft/tslib/releases)
- [Commits](https://github.com/Microsoft/tslib/compare/2.3.1...2.4.0)

---
updated-dependencies:
- dependency-name: tslib
  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>
2022-04-25 12:29:54 +02:00
cba770a551 build(deps): bump eslint from 8.13.0 to 8.14.0 in /web (#2764)
Bumps [eslint](https://github.com/eslint/eslint) from 8.13.0 to 8.14.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.13.0...v8.14.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>
2022-04-25 12:29:33 +02:00
c67afc4084 build(deps): bump @lingui/detect-locale from 3.13.2 to 3.13.3 in /web (#2765)
Bumps [@lingui/detect-locale](https://github.com/lingui/js-lingui) from 3.13.2 to 3.13.3.
- [Release notes](https://github.com/lingui/js-lingui/releases)
- [Changelog](https://github.com/lingui/js-lingui/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lingui/js-lingui/compare/v3.13.2...v3.13.3)

---
updated-dependencies:
- dependency-name: "@lingui/detect-locale"
  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>
2022-04-25 12:29:19 +02:00
4ed30fa61e build(deps): bump @lingui/cli from 3.13.2 to 3.13.3 in /web (#2768)
Bumps [@lingui/cli](https://github.com/lingui/js-lingui) from 3.13.2 to 3.13.3.
- [Release notes](https://github.com/lingui/js-lingui/releases)
- [Changelog](https://github.com/lingui/js-lingui/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lingui/js-lingui/compare/v3.13.2...v3.13.3)

---
updated-dependencies:
- dependency-name: "@lingui/cli"
  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>
2022-04-25 12:29:06 +02:00
db16a0ffbe build(deps): bump @lingui/macro from 3.13.2 to 3.13.3 in /web (#2763)
Bumps [@lingui/macro](https://github.com/lingui/js-lingui) from 3.13.2 to 3.13.3.
- [Release notes](https://github.com/lingui/js-lingui/releases)
- [Changelog](https://github.com/lingui/js-lingui/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lingui/js-lingui/compare/v3.13.2...v3.13.3)

---
updated-dependencies:
- dependency-name: "@lingui/macro"
  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>
2022-04-25 12:28:37 +02:00
99ec355710 build(deps): bump @rollup/plugin-commonjs from 21.1.0 to 22.0.0 in /web (#2766)
Bumps [@rollup/plugin-commonjs](https://github.com/rollup/plugins/tree/HEAD/packages/commonjs) from 21.1.0 to 22.0.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-v22.0.0/packages/commonjs)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-commonjs"
  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>
2022-04-25 12:27:53 +02:00
9e1882cebd build(deps): bump @types/chart.js from 2.9.36 to 2.9.37 in /web (#2767)
Bumps [@types/chart.js](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/chart.js) from 2.9.36 to 2.9.37.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/chart.js)

---
updated-dependencies:
- dependency-name: "@types/chart.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>
2022-04-25 12:27:40 +02:00
80912cace0 build(deps): bump @lingui/core from 3.13.2 to 3.13.3 in /web (#2769)
Bumps [@lingui/core](https://github.com/lingui/js-lingui) from 3.13.2 to 3.13.3.
- [Release notes](https://github.com/lingui/js-lingui/releases)
- [Changelog](https://github.com/lingui/js-lingui/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lingui/js-lingui/compare/v3.13.2...v3.13.3)

---
updated-dependencies:
- dependency-name: "@lingui/core"
  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>
2022-04-25 12:27:20 +02:00
0882894dc3 build(deps): bump country-flag-icons from 1.4.25 to 1.4.26 in /web (#2770)
Bumps [country-flag-icons](https://gitlab.com/catamphetamine/country-flag-icons) from 1.4.25 to 1.4.26.
- [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.4.25...v1.4.26)

---
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>
2022-04-25 12:27:05 +02:00
c1582147d7 build(deps-dev): bump pytest from 7.1.1 to 7.1.2 (#2771)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.1.1 to 7.1.2.
- [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.1.1...7.1.2)

---
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>
2022-04-25 12:24:58 +02:00
ab8b37a899 events: fix ignored instances not being a tuple
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-25 11:19:58 +02:00
9077eff34d root: add silk and debugging views
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-21 22:38:32 +02:00
2399fa456b policies: fix current user not being set in server-side policy deny
closes #2039

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-21 22:30:27 +02:00
c8c69a9a56 build(deps): bump codemirror from 5.65.2 to 5.65.3 in /web (#2750)
Bumps [codemirror](https://github.com/codemirror/CodeMirror) from 5.65.2 to 5.65.3.
- [Release notes](https://github.com/codemirror/CodeMirror/releases)
- [Changelog](https://github.com/codemirror/CodeMirror/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codemirror/CodeMirror/compare/5.65.2...5.65.3)

---
updated-dependencies:
- dependency-name: codemirror
  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>
2022-04-21 10:54:37 +02:00
1258f3bba2 build(deps-dev): bump pylint from 2.13.5 to 2.13.7 (#2751)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.13.5 to 2.13.7.
- [Release notes](https://github.com/PyCQA/pylint/releases)
- [Changelog](https://github.com/PyCQA/pylint/blob/main/ChangeLog)
- [Commits](https://github.com/PyCQA/pylint/compare/v2.13.5...v2.13.7)

---
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>
2022-04-21 10:54:29 +02:00
5488120e84 build(deps): bump duo-client from 4.3.2 to 4.4.0 (#2752)
Bumps [duo-client](https://github.com/duosecurity/duo_client_python) from 4.3.2 to 4.4.0.
- [Release notes](https://github.com/duosecurity/duo_client_python/releases)
- [Commits](https://github.com/duosecurity/duo_client_python/compare/4.3.2...4.4.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-21 10:54:18 +02:00
0b4ac54363 *: default to max 60 for fqdn_rand
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-20 20:07:25 +02:00
1a1434bfda *: decrease frequency of background tasks, smear tasks based on name and fqdn
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#2159
2022-04-20 18:43:40 +02:00
1328c3e62c build(deps): bump @typescript-eslint/eslint-plugin in /web (#2746)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.19.0 to 5.20.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.20.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>
2022-04-19 09:39:15 +02:00
1800b62cd6 build(deps): bump @typescript-eslint/parser in /web (#2747)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.19.0 to 5.20.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.20.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>
2022-04-19 09:36:48 +02:00
32fa4c9fcb build(deps): bump @rollup/plugin-commonjs from 21.0.3 to 21.1.0 in /web (#2740)
Bumps [@rollup/plugin-commonjs](https://github.com/rollup/plugins/tree/HEAD/packages/commonjs) from 21.0.3 to 21.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-v21.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>
2022-04-18 13:23:22 +02:00
15f0045a00 build(deps): bump rollup from 2.70.1 to 2.70.2 in /web (#2738)
Bumps [rollup](https://github.com/rollup/rollup) from 2.70.1 to 2.70.2.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v2.70.1...v2.70.2)

---
updated-dependencies:
- dependency-name: rollup
  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>
2022-04-18 13:22:32 +02:00
ac2211d9da build(deps): bump moment from 2.29.2 to 2.29.3 in /web (#2737)
Bumps [moment](https://github.com/moment/moment) from 2.29.2 to 2.29.3.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/2.29.3/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.2...2.29.3)

---
updated-dependencies:
- dependency-name: moment
  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>
2022-04-18 13:22:24 +02:00
cbd5b0dbfd build(deps): bump yaml from 2.0.0 to 2.0.1 in /web (#2739)
Bumps [yaml](https://github.com/eemeli/yaml) from 2.0.0 to 2.0.1.
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](https://github.com/eemeli/yaml/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: yaml
  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>
2022-04-18 13:22:16 +02:00
8e4896d261 build(deps): bump @rollup/plugin-node-resolve in /web (#2741)
Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 13.2.0 to 13.2.1.
- [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-v13.2.1/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>
2022-04-18 13:22:01 +02:00
9481df619a build(deps): bump sentry-sdk from 1.5.9 to 1.5.10 (#2742)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 1.5.9 to 1.5.10.
- [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.5.9...1.5.10)

---
updated-dependencies:
- dependency-name: sentry-sdk
  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>
2022-04-18 13:21:52 +02:00
d283a5236c core: add custom shell command which imports all models and creates events for model events
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-17 18:14:57 +02:00
6add88654e build(deps): bump goauthentik.io/api/v3 from 3.2022041.2 to 3.2022041.3 (#2734)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2022041.2 to 3.2022041.3.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2022041.2...v3.2022041.3)

---
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>
2022-04-17 17:30:40 +02:00
e4486b98fc web: Update Web API Client version (#2733)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-17 17:05:43 +02:00
778065f468 core: add flag to globally disable impersonation
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-17 16:52:55 +02:00
70794d79dd sources/oauth: Fix wording for OAuth source names (#2732) 2022-04-17 16:40:10 +02:00
6e5ac4bffc website/docs: add missing redis port to configuration page (#2731)
Added the `AUTHENTIK_REDIS__PORT` to the documentation.
2022-04-17 16:40:00 +02:00
4bab42fb58 Translate /locale/en/LC_MESSAGES/django.po in de (#2727) 2022-04-15 23:45:53 +02:00
c97823fe49 build(deps): bump goauthentik.io/api/v3 from 3.2022041.1 to 3.2022041.2 (#2726) 2022-04-15 11:09:56 +02:00
a3bb5d89cc events: fix created events only being logged as debug level
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-14 22:37:30 +02:00
f4f9f525d7 providers/oauth2: include application in login event
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-14 22:36:45 +02:00
555525ea9d build(deps): bump async from 2.6.3 to 2.6.4 in /website (#2725)
* root: use npm ci

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

* build(deps): bump async from 2.6.3 to 2.6.4 in /website

Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4)

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

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

Co-authored-by: Jens Langhammer <jens.langhammer@beryju.org>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-14 22:35:53 +02:00
e455e20312 root: use npm ci
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-14 22:33:36 +02:00
4c14e88a25 flows: pin dependency in migration
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-04-14 22:28:26 +02:00
7561ea15de providers/oauth2: add additional tracing to token view 2022-04-14 16:48:17 +00:00
8242b09394 flows: handle flow title formatting error better, add user to flow title context 2022-04-14 13:56:20 +00:00
6f0fa731c0 build(deps): bump golang from 1.18.0-bullseye to 1.18.1-bullseye (#2720)
Bumps golang from 1.18.0-bullseye to 1.18.1-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>
2022-04-14 09:58:38 +02:00
576bb013ed build(deps): bump @rollup/plugin-typescript from 8.3.1 to 8.3.2 in /web (#2721)
Bumps [@rollup/plugin-typescript](https://github.com/rollup/plugins/tree/HEAD/packages/typescript) from 8.3.1 to 8.3.2.
- [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/typescript-v8.3.2/packages/typescript)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-typescript"
  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>
2022-04-14 09:58:24 +02:00
aefedfb836 build(deps): bump goauthentik.io/api/v3 from 3.2022033.11 to 3.2022041.1 (#2722)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2022033.11 to 3.2022041.1.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2022033.11...v3.2022041.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>
2022-04-14 09:57:46 +02:00
4295ddb671 web: Update Web API Client version (#2718)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2022-04-13 10:34:47 +02:00
460 changed files with 12295 additions and 8138 deletions

View File

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

3
.github/stale.yml vendored
View File

@ -8,6 +8,9 @@ exemptLabels:
- security
- pr_wanted
- enhancement
- bug/confirmed
- enhancement/confirmed
- question
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had

View File

@ -136,9 +136,9 @@ jobs:
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/**') }}
- name: prepare web ui
if: steps.cache-web.outputs.cache-hit != 'true'
working-directory: web
run: |
cd web
npm i
npm ci
npm run build
- name: run e2e
run: |
@ -169,9 +169,9 @@ jobs:
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/**') }}
- name: prepare web ui
if: steps.cache-web.outputs.cache-hit != 'true'
working-directory: web/
run: |
cd web
npm i
npm ci
npm run build
- name: run e2e
run: |
@ -207,23 +207,23 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1.2.0
uses: docker/setup-qemu-action@v2.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: prepare variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
uses: ./.github/actions/docker-setup
- name: Login to Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
if: ${{ steps.ev.outputs.shouldBuild == 'true' }}
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Building Docker Image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
push: ${{ steps.ev.outputs.shouldBuild == 'true' }}
tags: |

View File

@ -18,18 +18,16 @@ jobs:
- uses: actions/setup-go@v3
with:
go-version: "^1.17"
- name: Run linter
- name: Prepare and generate API
run: |
# Create folder structure for go embeds
mkdir -p web/dist
mkdir -p website/help
touch web/dist/test website/help/test
docker run \
--rm \
-v $(pwd):/app \
-w /app \
golangci/golangci-lint:v1.43 \
golangci-lint run -v --timeout 200s
- name: Generate API
run: make gen-client-go
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
test-unittest:
runs-on: ubuntu-latest
steps:
@ -37,6 +35,8 @@ jobs:
- uses: actions/setup-go@v3
with:
go-version: "^1.17"
- name: Generate API
run: make gen-client-go
- name: Go unittests
run: |
go test -timeout 0 -v -race -coverprofile=coverage.out -covermode=atomic -cover ./...
@ -63,23 +63,25 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1.2.0
uses: docker/setup-qemu-action@v2.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: prepare variables
id: ev
uses: ./.github/actions/docker-setup
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
- name: Login to Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
if: ${{ steps.ev.outputs.shouldBuild == 'true' }}
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate API
run: make gen-client-go
- name: Building Docker Image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
push: ${{ steps.ev.outputs.shouldBuild == 'true' }}
tags: |
@ -108,15 +110,17 @@ jobs:
- uses: actions/setup-go@v3
with:
go-version: "^1.17"
- uses: actions/setup-node@v3.1.1
- uses: actions/setup-node@v3.2.0
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- name: Generate API
run: make gen-client-go
- name: Build web
working-directory: web/
run: |
cd web
npm install
npm ci
npm run build-proxy
- name: Build outpost
run: |

View File

@ -15,56 +15,50 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3.1.1
- uses: actions/setup-node@v3.2.0
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- run: |
cd web
npm install
- working-directory: web/
run: npm ci
- name: Generate API
run: make gen-web
run: make gen-client-web
- name: Eslint
run: |
cd web
npm run lint
working-directory: web/
run: npm run lint
lint-prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3.1.1
- uses: actions/setup-node@v3.2.0
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- run: |
cd web
npm install
- working-directory: web/
run: npm ci
- name: Generate API
run: make gen-web
run: make gen-client-web
- name: prettier
run: |
cd web
npm run prettier-check
working-directory: web/
run: npm run prettier-check
lint-lit-analyse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3.1.1
- uses: actions/setup-node@v3.2.0
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- run: |
cd web
npm install
- working-directory: web/
run: npm ci
- name: Generate API
run: make gen-web
run: make gen-client-web
- name: lit-analyse
run: |
cd web
npm run lit-analyse
working-directory: web/
run: npm run lit-analyse
ci-web-mark:
needs:
- lint-eslint
@ -79,17 +73,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3.1.1
- uses: actions/setup-node@v3.2.0
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- run: |
cd web
npm install
- working-directory: web/
run: npm ci
- name: Generate API
run: make gen-web
run: make gen-client-web
- name: build
run: |
cd web
npm run build
working-directory: web/
run: npm run build

33
.github/workflows/ci-website.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: authentik-ci-website
on:
push:
branches:
- master
- next
- version-*
pull_request:
branches:
- master
jobs:
lint-prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3.2.0
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: website/package-lock.json
- working-directory: website/
run: npm ci
- name: prettier
working-directory: website/
run: npm run prettier-check
ci-website-mark:
needs:
- lint-prettier
runs-on: ubuntu-latest
steps:
- run: echo mark

View File

@ -32,7 +32,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@ -43,7 +43,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -57,4 +57,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

View File

@ -11,28 +11,28 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1.2.0
uses: docker/setup-qemu-action@v2.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Docker Login Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Building Docker Image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik:2022.4.1,
beryju/authentik:2022.5.3,
beryju/authentik:latest,
ghcr.io/goauthentik/server:2022.4.1,
ghcr.io/goauthentik/server:2022.5.3,
ghcr.io/goauthentik/server:latest
platforms: linux/amd64,linux/arm64
context: .
@ -50,28 +50,28 @@ jobs:
with:
go-version: "^1.17"
- name: Set up QEMU
uses: docker/setup-qemu-action@v1.2.0
uses: docker/setup-qemu-action@v2.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Docker Login Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Building Docker Image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-${{ matrix.type }}:2022.4.1,
beryju/authentik-${{ matrix.type }}:2022.5.3,
beryju/authentik-${{ matrix.type }}:latest,
ghcr.io/goauthentik/${{ matrix.type }}:2022.4.1,
ghcr.io/goauthentik/${{ matrix.type }}:2022.5.3,
ghcr.io/goauthentik/${{ matrix.type }}:latest
file: ${{ matrix.type }}.Dockerfile
platforms: linux/amd64,linux/arm64
@ -91,15 +91,15 @@ jobs:
- uses: actions/setup-go@v3
with:
go-version: "^1.17"
- uses: actions/setup-node@v3.1.1
- uses: actions/setup-node@v3.2.0
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- name: Build web
working-directory: web/
run: |
cd web
npm install
npm ci
npm run build-proxy
- name: Build outpost
run: |
@ -152,7 +152,7 @@ jobs:
SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org
with:
version: authentik@2022.4.1
version: authentik@2022.5.3
environment: beryjuorg-prod
sourcemaps: './web/dist'
url_prefix: '~/static/dist'

View File

@ -4,29 +4,30 @@ on:
branches: [ master ]
paths:
- 'schema.yml'
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v3.1.1
- uses: actions/setup-node@v3.2.0
with:
node-version: '16'
registry-url: 'https://registry.npmjs.org'
- name: Generate API Client
run: make gen-web
run: make gen-client-web
- name: Publish package
working-directory: gen-ts-api/
run: |
cd web-api/
npm i
npm ci
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
- name: Upgrade /web
working-directory: web/
run: |
cd web/
export VERSION=`node -e 'console.log(require("../web-api/package.json").version)'`
export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'`
npm i @goauthentik/api@$VERSION
- name: Create Pull Request
uses: peter-evans/create-pull-request@v4

3
.gitignore vendored
View File

@ -202,5 +202,4 @@ media/
*mmdb
.idea/
/api/
/web-api/
/gen-*/

View File

@ -1,22 +1,35 @@
# Stage 1: Build website
FROM --platform=${BUILDPLATFORM} docker.io/node:16 as website-builder
FROM --platform=${BUILDPLATFORM} docker.io/node:18 as website-builder
COPY ./website /work/website/
ENV NODE_ENV=production
RUN cd /work/website && npm i && npm run build-docs-only
WORKDIR /work/website
RUN npm ci && npm run build-docs-only
# Stage 2: Build webui
FROM --platform=${BUILDPLATFORM} docker.io/node:16 as web-builder
FROM --platform=${BUILDPLATFORM} docker.io/node:18 as web-builder
COPY ./web /work/web/
COPY ./website /work/website/
ENV NODE_ENV=production
RUN cd /work/web && npm i && npm run build
WORKDIR /work/web
RUN npm ci && npm run build
# Stage 3: Build go proxy
FROM docker.io/golang:1.18.0-bullseye AS builder
# Stage 3: Poetry to requirements.txt export
FROM docker.io/python:3.10.4-slim-bullseye AS poetry-locker
WORKDIR /work
COPY ./pyproject.toml /work
COPY ./poetry.lock /work
RUN pip install --no-cache-dir poetry && \
poetry export -f requirements.txt --output requirements.txt && \
poetry export -f requirements.txt --dev --output requirements-dev.txt
# Stage 4: Build go proxy
FROM docker.io/golang:1.18.2-bullseye AS builder
WORKDIR /work
@ -31,7 +44,7 @@ COPY ./go.sum /work/go.sum
RUN go build -o /work/authentik ./cmd/server/main.go
# Stage 4: Run
# Stage 5: Run
FROM docker.io/python:3.10.4-slim-bullseye
LABEL org.opencontainers.image.url https://goauthentik.io
@ -43,19 +56,18 @@ WORKDIR /
ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
COPY ./pyproject.toml /
COPY ./poetry.lock /
COPY --from=poetry-locker /work/requirements.txt /
COPY --from=poetry-locker /work/requirements-dev.txt /
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl ca-certificates gnupg git runit libpq-dev \
postgresql-client build-essential libxmlsec1-dev \
pkg-config libmaxminddb0 && \
pip install poetry && \
poetry config virtualenvs.create false && \
poetry install --no-dev && \
rm -rf ~/.cache/pypoetry && \
apt-get remove --purge -y build-essential git && \
# Required for installing pip packages
apt-get install -y --no-install-recommends build-essential pkg-config libxmlsec1-dev && \
# Required for runtime
apt-get install -y --no-install-recommends libxmlsec1-openssl libmaxminddb0 && \
# Required for bootstrap & healtcheck
apt-get install -y --no-install-recommends curl runit && \
pip install --no-cache-dir -r /requirements.txt && \
apt-get remove --purge -y build-essential pkg-config libxmlsec1-dev && \
apt-get autoremove --purge -y && \
apt-get clean && \
rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/ && \

View File

@ -18,6 +18,15 @@ test-e2e-rest:
test-go:
go test -timeout 0 -v -race -cover ./...
test-docker:
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
docker-compose pull -q
docker-compose up --no-start
docker-compose start postgresql redis
docker-compose run -u root server test
rm -f .env
test:
coverage run manage.py test authentik
coverage html
@ -52,21 +61,21 @@ gen-clean:
rm -rf web/api/src/
rm -rf api/
gen-web:
gen-client-web:
docker run \
--rm -v ${PWD}:/local \
--user ${UID}:${GID} \
openapitools/openapi-generator-cli:v6.0.0-beta generate \
openapitools/openapi-generator-cli:v6.0.0 generate \
-i /local/schema.yml \
-g typescript-fetch \
-o /local/web-api \
-o /local/gen-ts-api \
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=@goauthentik/api,npmVersion=${NPM_VERSION}
mkdir -p web/node_modules/@goauthentik/api
\cp -fv scripts/web_api_readme.md web-api/README.md
cd web-api && npm i
\cp -rfv web-api/* web/node_modules/@goauthentik/api
\cp -fv scripts/web_api_readme.md gen-ts-api/README.md
cd gen-ts-api && npm i
\cp -rfv gen-ts-api/* web/node_modules/@goauthentik/api
gen-outpost:
gen-client-go:
wget https://raw.githubusercontent.com/goauthentik/client-go/main/config.yaml -O config.yaml
mkdir -p templates
wget https://raw.githubusercontent.com/goauthentik/client-go/main/templates/README.mustache -O templates/README.mustache
@ -74,15 +83,15 @@ gen-outpost:
docker run \
--rm -v ${PWD}:/local \
--user ${UID}:${GID} \
openapitools/openapi-generator-cli:v6.0.0-beta generate \
openapitools/openapi-generator-cli:v6.0.0 generate \
-i /local/schema.yml \
-g go \
-o /local/api \
-o /local/gen-go-api \
-c /local/config.yaml
go mod edit -replace goauthentik.io/api=./api
go mod edit -replace goauthentik.io/api/v3=./gen-go-api
rm -rf config.yaml ./templates/
gen: gen-build gen-clean gen-web
gen: gen-build gen-clean gen-client-web
migrate:
python -m lifecycle.migrate
@ -90,11 +99,18 @@ migrate:
run:
go run -v cmd/server/main.go
web-watch:
cd web && npm run watch
#########################
## Web
#########################
web: web-lint-fix web-lint web-extract
web-install:
cd web && npm ci
web-watch:
cd web && npm run watch
web-lint-fix:
cd web && npm run prettier
@ -105,6 +121,21 @@ web-lint:
web-extract:
cd web && npm run extract
#########################
## Website
#########################
website: website-lint-fix
website-install:
cd website && npm ci
website-lint-fix:
cd website && npm run prettier
website-watch:
cd website && npm run watch
# These targets are use by GitHub actions to allow usage of matrix
# which makes the YAML File a lot smaller
@ -130,10 +161,8 @@ ci-pyright: ci--meta-debug
ci-pending-migrations: ci--meta-debug
./manage.py makemigrations --check
install:
install: web-install website-install
poetry install
cd web && npm i
cd website && npm i
a: install
tmux \

View File

@ -2,13 +2,16 @@
from os import environ
from typing import Optional
__version__ = "2022.4.1"
__version__ = "2022.5.3"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
def get_build_hash(fallback: Optional[str] = None) -> str:
"""Get build hash"""
return environ.get(ENV_GIT_HASH_KEY, fallback if fallback else "")
build_hash = environ.get(ENV_GIT_HASH_KEY, fallback if fallback else "")
if build_hash == "" and fallback:
return fallback
return build_hash
def get_full_version() -> str:

View File

@ -1,10 +1,12 @@
"""authentik admin settings"""
from celery.schedules import crontab
from authentik.lib.utils.time import fqdn_rand
CELERY_BEAT_SCHEDULE = {
"admin_latest_version": {
"task": "authentik.admin.tasks.update_latest_version",
"schedule": crontab(minute="*/60"), # Run every hour
"schedule": crontab(minute=fqdn_rand("admin_latest_version"), hour="*"),
"options": {"queue": "authentik_scheduled"},
}
}

View File

@ -26,7 +26,7 @@ class TestAdminTasks(TestCase):
def test_version_valid_response(self):
"""Test Update checker with valid response"""
with Mocker() as mocker:
with Mocker() as mocker, CONFIG.patch("disable_update_check", False):
mocker.get("https://version.goauthentik.io/version.json", json=RESPONSE_VALID)
update_latest_version.delay().get()
self.assertEqual(cache.get(VERSION_CACHE_KEY), "99999999.9999999")

View File

@ -12,6 +12,8 @@ class OwnerFilter(BaseFilterBackend):
owner_key = "user"
def filter_queryset(self, request: Request, queryset: QuerySet, view) -> QuerySet:
if request.user.is_superuser:
return queryset
return queryset.filter(**{self.owner_key: request.user})

View File

@ -8,9 +8,6 @@ API Browser - {{ tenant.branding_title }}
{% block head %}
<script type="module" src="{% static 'dist/rapidoc-min.js' %}"></script>
{% endblock %}
{% block body %}
<script>
function getCookie(name) {
let cookieValue = "";
@ -34,16 +31,58 @@ window.addEventListener('DOMContentLoaded', (event) => {
});
});
</script>
<style>
img.logo {
width: 100%;
padding: 1rem 0.5rem 1.5rem 0.5rem;
min-height: 48px;
}
</style>
{% endblock %}
{% block body %}
<rapi-doc
spec-url="{{ path }}"
heading-text="authentik"
theme="dark"
render-style="view"
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="logo">
<img src="{% static 'dist/assets/icons/icon.png' %}" style="width:50px; height:50px" />
<div slot="nav-logo">
<img 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 %}

View File

@ -0,0 +1,29 @@
"""authentik API Modelviewset tests"""
from typing import Callable
from django.test import TestCase
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from authentik.api.v3.urls import router
class TestModelViewSets(TestCase):
"""Test Viewset"""
def viewset_tester_factory(test_viewset: type[ModelViewSet]) -> Callable:
"""Test Viewset"""
def tester(self: TestModelViewSets):
self.assertIsNotNone(getattr(test_viewset, "search_fields", None))
filterset_class = getattr(test_viewset, "filterset_class", None)
if not filterset_class:
self.assertIsNotNone(getattr(test_viewset, "filterset_fields", None))
return tester
for _, viewset, _ in router.registry:
if not issubclass(viewset, (ModelViewSet, ReadOnlyModelViewSet)):
continue
setattr(TestModelViewSets, f"test_viewset_{viewset.__name__}", viewset_tester_factory(viewset))

View File

@ -27,6 +27,7 @@ class Capabilities(models.TextChoices):
CAN_SAVE_MEDIA = "can_save_media"
CAN_GEO_IP = "can_geo_ip"
CAN_IMPERSONATE = "can_impersonate"
class ErrorReportingConfigSerializer(PassiveSerializer):
@ -63,6 +64,8 @@ class ConfigView(APIView):
caps.append(Capabilities.CAN_SAVE_MEDIA)
if GEOIP_READER.enabled:
caps.append(Capabilities.CAN_GEO_IP)
if CONFIG.y_bool("impersonation"):
caps.append(Capabilities.CAN_IMPERSONATE)
return caps
@extend_schema(responses={200: ConfigSerializer(many=False)})

View File

@ -22,11 +22,11 @@ from authentik.core.api.sources import SourceViewSet, UserSourceConnectionViewSe
from authentik.core.api.tokens import TokenViewSet
from authentik.core.api.users import UserViewSet
from authentik.crypto.api import CertificateKeyPairViewSet
from authentik.events.api.event import EventViewSet
from authentik.events.api.notification import NotificationViewSet
from authentik.events.api.notification_mapping import NotificationWebhookMappingViewSet
from authentik.events.api.notification_rule import NotificationRuleViewSet
from authentik.events.api.notification_transport import NotificationTransportViewSet
from authentik.events.api.events import EventViewSet
from authentik.events.api.notification_mappings import NotificationWebhookMappingViewSet
from authentik.events.api.notification_rules import NotificationRuleViewSet
from authentik.events.api.notification_transports import NotificationTransportViewSet
from authentik.events.api.notifications import NotificationViewSet
from authentik.flows.api.bindings import FlowStageBindingViewSet
from authentik.flows.api.flows import FlowViewSet
from authentik.flows.api.stages import StageViewSet

View File

@ -89,6 +89,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
"group",
]
lookup_field = "slug"
filterset_fields = ["name", "slug"]
ordering = ["name"]
def _filter_queryset_for_list(self, queryset: QuerySet) -> QuerySet:

View File

@ -12,7 +12,7 @@ from rest_framework.serializers import ModelSerializer, SerializerMethodField
from rest_framework.viewsets import GenericViewSet
from structlog.stdlib import get_logger
from authentik.api.authorization import OwnerFilter, OwnerPermissions
from authentik.api.authorization import OwnerFilter, OwnerSuperuserPermissions
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
from authentik.core.models import Source, UserSourceConnection
@ -66,6 +66,7 @@ class SourceViewSet(
queryset = Source.objects.none()
serializer_class = SourceSerializer
lookup_field = "slug"
search_fields = ["slug", "name"]
def get_queryset(self): # pragma: no cover
return Source.objects.select_subclasses()
@ -150,6 +151,6 @@ class UserSourceConnectionViewSet(
queryset = UserSourceConnection.objects.all()
serializer_class = UserSourceConnectionSerializer
permission_classes = [OwnerPermissions]
permission_classes = [OwnerSuperuserPermissions]
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
ordering = ["pk"]

View File

@ -17,6 +17,7 @@ from django_filters.filterset import FilterSet
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import (
OpenApiParameter,
OpenApiResponse,
extend_schema,
extend_schema_field,
inline_serializer,
@ -31,7 +32,6 @@ from rest_framework.serializers import (
ListSerializer,
ModelSerializer,
PrimaryKeyRelatedField,
Serializer,
ValidationError,
)
from rest_framework.viewsets import ModelViewSet
@ -72,6 +72,7 @@ class UserSerializer(ModelSerializer):
)
groups_obj = ListSerializer(child=GroupSerializer(), read_only=True, source="ak_groups")
uid = CharField(read_only=True)
username = CharField(max_length=150)
class Meta:
@ -351,8 +352,8 @@ class UserViewSet(UsedByMixin, ModelViewSet):
},
),
responses={
204: "",
400: "",
204: OpenApiResponse(description="Successfully changed password"),
400: OpenApiResponse(description="Bad request"),
},
)
@action(detail=True, methods=["POST"])
@ -410,8 +411,8 @@ class UserViewSet(UsedByMixin, ModelViewSet):
)
],
responses={
"204": Serializer(),
"404": Serializer(),
"204": OpenApiResponse(description="Successfully sent recover email"),
"404": OpenApiResponse(description="Bad request"),
},
)
@action(detail=True, pagination_class=None, filter_backends=[])

View File

View File

@ -0,0 +1,106 @@
"""authentik shell command"""
import code
import platform
from django.apps import apps
from django.core.management.base import BaseCommand
from django.db.models import Model
from django.db.models.signals import post_save, pre_delete
from authentik import __version__
from authentik.core.models import User
from authentik.events.middleware import IGNORED_MODELS
from authentik.events.models import Event, EventAction
from authentik.events.utils import model_to_dict
BANNER_TEXT = """### authentik shell ({authentik})
### Node {node} | Arch {arch} | Python {python} """.format(
node=platform.node(),
python=platform.python_version(),
arch=platform.machine(),
authentik=__version__,
)
class Command(BaseCommand): # pragma: no cover
"""Start the Django shell with all authentik models already imported"""
django_models = {}
def add_arguments(self, parser):
parser.add_argument(
"-c",
"--command",
help="Python code to execute (instead of starting an interactive shell)",
)
def get_namespace(self):
"""Prepare namespace with all models"""
namespace = {}
# Gather Django models and constants from each app
for app in apps.get_app_configs():
if not app.name.startswith("authentik"):
continue
# Load models from each app
for model in app.get_models():
namespace[model.__name__] = model
return namespace
@staticmethod
# pylint: disable=unused-argument
def post_save_handler(sender, instance: Model, created: bool, **_):
"""Signal handler for all object's post_save"""
if isinstance(instance, IGNORED_MODELS):
return
action = EventAction.MODEL_CREATED if created else EventAction.MODEL_UPDATED
Event.new(action, model=model_to_dict(instance)).set_user(
User(
username="authentik-shell",
pk=0,
email="",
)
).save()
@staticmethod
# pylint: disable=unused-argument
def pre_delete_handler(sender, instance: Model, **_):
"""Signal handler for all object's pre_delete"""
if isinstance(instance, IGNORED_MODELS): # pragma: no cover
return
Event.new(EventAction.MODEL_DELETED, model=model_to_dict(instance)).set_user(
User(
username="authentik-shell",
pk=0,
email="",
)
).save()
def handle(self, **options):
namespace = self.get_namespace()
post_save.connect(Command.post_save_handler)
pre_delete.connect(Command.pre_delete_handler)
# If Python code has been passed, execute it and exit.
if options["command"]:
# pylint: disable=exec-used
exec(options["command"], namespace) # nosec # noqa
return
# Try to enable tab-complete
try:
import readline
import rlcompleter
except ModuleNotFoundError:
pass
else:
readline.set_completer(rlcompleter.Completer(namespace).complete)
readline.parse_and_bind("tab: complete")
# Run interactive shell
code.interact(banner=BANNER_TEXT, local=namespace)

View File

@ -34,9 +34,9 @@ def clean_expired_models(self: MonitoredTask):
objects = (
cls.objects.all().exclude(expiring=False).exclude(expiring=True, expires__gt=now())
)
amount = objects.count()
for obj in objects:
obj.expire_action()
amount = objects.count()
LOGGER.debug("Expired models", model=cls, amount=amount)
messages.append(f"Expired {amount} {cls._meta.verbose_name_plural}")
# Special case

View File

@ -8,6 +8,12 @@
{% if flow.compatibility_mode and not inspector %}
<script>ShadyDOM = { force: !navigator.webdriver };</script>
{% endif %}
<script>
window.authentik = {};
window.authentik.flow = {
"layout": "{{ flow.layout }}",
};
</script>
{% endblock %}
{% block head %}

View File

@ -12,6 +12,25 @@
.pf-c-background-image::before {
--ak-flow-background: url("/static/dist/assets/images/flow_background.jpg");
}
/* Form with user */
.form-control-static {
margin-top: var(--pf-global--spacer--sm);
display: flex;
align-items: center;
justify-content: space-between;
}
.form-control-static .avatar {
display: flex;
align-items: center;
}
.form-control-static img {
margin-right: var(--pf-global--spacer--xs);
}
.form-control-static a {
padding-top: var(--pf-global--spacer--xs);
padding-bottom: var(--pf-global--spacer--xs);
line-height: var(--pf-global--spacer--xl);
}
</style>
{% endblock %}
@ -59,13 +78,11 @@
<a href="{{ link.href }}">{{ link.name }}</a>
</li>
{% endfor %}
{% if tenant.branding_title != "authentik" %}
<li>
<a href="https://goauthentik.io?utm_source=authentik">
{% trans 'Powered by authentik' %}
</a>
</li>
{% endif %}
</ul>
</footer>
</div>

View File

@ -1,4 +1,5 @@
"""authentik URL Configuration"""
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.urls import path
from django.views.decorators.csrf import ensure_csrf_cookie
@ -6,6 +7,7 @@ from django.views.generic import RedirectView
from django.views.generic.base import TemplateView
from authentik.core.views import apps, impersonate
from authentik.core.views.debug import AccessDeniedView
from authentik.core.views.interface import FlowInterfaceView
from authentik.core.views.session import EndSessionView
@ -60,3 +62,8 @@ urlpatterns = [
TemplateView.as_view(template_name="if/admin.html"),
),
]
if settings.DEBUG:
urlpatterns += [
path("debug/policy/deny/", AccessDeniedView.as_view(), name="debug-policy-deny"),
]

View File

@ -0,0 +1,12 @@
"""debug view"""
from django.http import HttpRequest, HttpResponse
from django.views.generic import View
from authentik.policies.denied import AccessDeniedResponse
class AccessDeniedView(View):
"""Easily access AccessDeniedResponse"""
def dispatch(self, request: HttpRequest) -> HttpResponse:
return AccessDeniedResponse(request)

View File

@ -8,6 +8,7 @@ from structlog.stdlib import get_logger
from authentik.core.middleware import SESSION_IMPERSONATE_ORIGINAL_USER, SESSION_IMPERSONATE_USER
from authentik.core.models import User
from authentik.events.models import Event, EventAction
from authentik.lib.config import CONFIG
LOGGER = get_logger()
@ -17,6 +18,9 @@ class ImpersonateInitView(View):
def get(self, request: HttpRequest, user_id: int) -> HttpResponse:
"""Impersonation handler, checks permissions"""
if not CONFIG.y_bool("impersonation"):
LOGGER.debug("User attempted to impersonate", user=request.user)
return HttpResponse("Unauthorized", status=401)
if not request.user.has_perm("impersonate"):
LOGGER.debug("User attempted to impersonate without permissions", user=request.user)
return HttpResponse("Unauthorized", status=401)

View File

@ -2,6 +2,8 @@
from django.db import migrations
from authentik.lib.generators import generate_id
def create_self_signed(apps, schema_editor):
CertificateKeyPair = apps.get_model("authentik_crypto", "CertificateKeyPair")
@ -9,7 +11,7 @@ def create_self_signed(apps, schema_editor):
from authentik.crypto.builder import CertificateBuilder
builder = CertificateBuilder()
builder.build()
builder.build(subject_alt_names=[f"{generate_id()}.self-signed.goauthentik.io"])
CertificateKeyPair.objects.using(db_alias).create(
name="authentik Self-signed Certificate",
certificate_data=builder.certificate,

View File

@ -1,10 +1,12 @@
"""Crypto task Settings"""
from celery.schedules import crontab
from authentik.lib.utils.time import fqdn_rand
CELERY_BEAT_SCHEDULE = {
"crypto_certificate_discovery": {
"task": "authentik.crypto.tasks.certificate_discovery",
"schedule": crontab(minute="*/5"),
"schedule": crontab(minute=fqdn_rand("crypto_certificate_discovery"), hour="*"),
"options": {"queue": "authentik_scheduled"},
},
}

View File

@ -26,3 +26,4 @@ class NotificationWebhookMappingViewSet(UsedByMixin, ModelViewSet):
serializer_class = NotificationWebhookMappingSerializer
filterset_fields = ["name"]
ordering = ["name"]
search_fields = ["name"]

View File

@ -32,3 +32,4 @@ class NotificationRuleViewSet(UsedByMixin, ModelViewSet):
serializer_class = NotificationRuleSerializer
filterset_fields = ["name", "severity", "group__name"]
ordering = ["name"]
search_fields = ["name", "group__name"]

View File

@ -68,6 +68,7 @@ class NotificationTransportViewSet(UsedByMixin, ModelViewSet):
queryset = NotificationTransport.objects.all()
serializer_class = NotificationTransportSerializer
filterset_fields = ["name", "mode", "webhook_url", "send_once"]
search_fields = ["name", "mode", "webhook_url"]
ordering = ["name"]
@permission_required("authentik_events.change_notificationtransport")

View File

@ -13,7 +13,7 @@ from rest_framework.viewsets import GenericViewSet
from authentik.api.authorization import OwnerFilter, OwnerPermissions
from authentik.core.api.used_by import UsedByMixin
from authentik.events.api.event import EventSerializer
from authentik.events.api.events import EventSerializer
from authentik.events.models import Notification
@ -55,6 +55,7 @@ class NotificationViewSet(
"created",
"event",
"seen",
"user",
]
permission_classes = [OwnerPermissions]
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]

View File

@ -18,13 +18,18 @@ from authentik.events.utils import model_to_dict
from authentik.lib.sentry import before_send
from authentik.lib.utils.errors import exception_to_string
IGNORED_MODELS = (
IGNORED_MODELS = [
Event,
Notification,
UserObjectPermission,
AuthenticatedSession,
StaticToken,
)
]
if settings.DEBUG:
from silk.models import Request, Response, SQLQuery
IGNORED_MODELS += [Request, Response, SQLQuery]
IGNORED_MODELS = tuple(IGNORED_MODELS)
class AuditMiddleware:

View File

@ -383,6 +383,7 @@ class Migration(migrations.Migration):
models.ManyToManyField(
help_text="Select which transports should be used to notify the user. If none are selected, the notification will only be shown in the authentik UI.",
to="authentik_events.NotificationTransport",
blank=True,
),
),
],

View File

@ -261,7 +261,7 @@ class Event(ExpiringModel):
def save(self, *args, **kwargs):
if self._state.adding:
LOGGER.debug(
LOGGER.info(
"Created Event",
action=self.action,
context=self.context,
@ -481,6 +481,7 @@ class NotificationRule(PolicyBindingModel):
"selected, the notification will only be shown in the authentik UI."
)
),
blank=True,
)
severity = models.TextField(
choices=NotificationSeverity.choices,
@ -518,7 +519,7 @@ class NotificationWebhookMapping(PropertyMapping):
@property
def serializer(self) -> type["Serializer"]:
from authentik.events.api.notification_mapping import NotificationWebhookMappingSerializer
from authentik.events.api.notification_mappings import NotificationWebhookMappingSerializer
return NotificationWebhookMappingSerializer

View File

@ -0,0 +1,12 @@
"""Event Settings"""
from celery.schedules import crontab
from authentik.lib.utils.time import fqdn_rand
CELERY_BEAT_SCHEDULE = {
"events_notification_cleanup": {
"task": "authentik.events.tasks.notification_cleanup",
"schedule": crontab(minute=fqdn_rand("notification_cleanup"), hour="*/8"),
"options": {"queue": "authentik_scheduled"},
},
}

View File

@ -1,4 +1,5 @@
"""Event notification tasks"""
from django.db.models.query_utils import Q
from guardian.shortcuts import get_anonymous_user
from structlog.stdlib import get_logger
@ -10,7 +11,12 @@ from authentik.events.models import (
NotificationTransport,
NotificationTransportError,
)
from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus
from authentik.events.monitored_tasks import (
MonitoredTask,
TaskResult,
TaskResultStatus,
prefill_task,
)
from authentik.policies.engine import PolicyEngine
from authentik.policies.models import PolicyBinding, PolicyEngineMode
from authentik.root.celery import CELERY_APP
@ -114,3 +120,15 @@ def gdpr_cleanup(user_pk: int):
events = Event.objects.filter(user__pk=user_pk)
LOGGER.debug("GDPR cleanup, removing events from user", events=events.count())
events.delete()
@CELERY_APP.task(bind=True, base=MonitoredTask)
@prefill_task
def notification_cleanup(self: MonitoredTask):
"""Cleanup seen notifications and notifications whose event expired."""
notifications = Notification.objects.filter(Q(event=None) | Q(seen=True))
amount = notifications.count()
for notification in notifications:
notification.delete()
LOGGER.debug("Expired notifications", amount=amount)
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, [f"Expired {amount} Notifications"]))

View File

@ -35,3 +35,4 @@ class FlowStageBindingViewSet(UsedByMixin, ModelViewSet):
queryset = FlowStageBinding.objects.all()
serializer_class = FlowStageBindingSerializer
filterset_fields = "__all__"
search_fields = ["stage__name"]

View File

@ -72,6 +72,7 @@ class FlowSerializer(ModelSerializer):
"policy_engine_mode",
"compatibility_mode",
"export_url",
"layout",
]
extra_kwargs = {
"background": {"read_only": True},
@ -211,12 +212,30 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
]
body: list[DiagramElement] = []
footer = []
# First, collect all elements we need
# Collect all elements we need
# First, policies bound to the flow itself
for p_index, policy_binding in enumerate(
get_objects_for_user(request.user, "authentik_policies.view_policybinding")
.filter(target=flow)
.exclude(policy__isnull=True)
.order_by("order")
):
body.append(
DiagramElement(
f"flow_policy_{p_index}",
"condition",
_("Policy (%(type)s)" % {"type": policy_binding.policy._meta.verbose_name})
+ "\n"
+ policy_binding.policy.name,
)
)
# Collect all stages
for s_index, stage_binding in enumerate(
get_objects_for_user(request.user, "authentik_flows.view_flowstagebinding")
.filter(target=flow)
.order_by("order")
):
# First all policies bound to stages since they execute before stages
for p_index, policy_binding in enumerate(
get_objects_for_user(request.user, "authentik_policies.view_policybinding")
.filter(target=stage_binding)
@ -227,14 +246,18 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
DiagramElement(
f"stage_{s_index}_policy_{p_index}",
"condition",
f"Policy\n{policy_binding.policy.name}",
_("Policy (%(type)s)" % {"type": policy_binding.policy._meta.verbose_name})
+ "\n"
+ policy_binding.policy.name,
)
)
body.append(
DiagramElement(
f"stage_{s_index}",
"operation",
f"Stage\n{stage_binding.stage.name}",
_("Stage (%(type)s)" % {"type": stage_binding.stage._meta.verbose_name})
+ "\n"
+ stage_binding.stage.name,
)
)
# If the 2nd last element is a policy, we need to have an item to point to

View File

@ -2,6 +2,7 @@
from enum import Enum
from typing import TYPE_CHECKING, Optional
from django.db import models
from django.http import JsonResponse
from rest_framework.fields import ChoiceField, DictField
from rest_framework.serializers import CharField
@ -12,6 +13,20 @@ from authentik.flows.transfer.common import DataclassEncoder
if TYPE_CHECKING:
from authentik.flows.stage import StageView
PLAN_CONTEXT_TITLE = "title"
PLAN_CONTEXT_URL = "url"
PLAN_CONTEXT_ATTRS = "attrs"
class FlowLayout(models.TextChoices):
"""Flow layouts"""
STACKED = "stacked"
CONTENT_LEFT = "content_left"
CONTENT_RIGHT = "content_right"
SIDEBAR_LEFT = "sidebar_left"
SIDEBAR_RIGHT = "sidebar_right"
class ChallengeTypes(Enum):
"""Currently defined challenge types"""
@ -34,6 +49,7 @@ class ContextualFlowInfo(PassiveSerializer):
title = CharField(required=False, allow_blank=True)
background = CharField(required=False)
cancel_url = CharField()
layout = ChoiceField(choices=[(x.value, x.name) for x in FlowLayout])
class Challenge(PassiveSerializer):
@ -97,6 +113,21 @@ class ChallengeResponse(PassiveSerializer):
super().__init__(instance=instance, data=data, **kwargs)
class AutosubmitChallenge(Challenge):
"""Autosubmit challenge used to send and navigate a POST request"""
url = CharField()
attrs = DictField(child=CharField())
title = CharField(required=False)
component = CharField(default="ak-stage-autosubmit")
class AutoSubmitChallengeResponse(ChallengeResponse):
"""Pseudo class for autosubmit response"""
component = CharField(default="ak-stage-autosubmit")
class HttpChallengeResponse(JsonResponse):
"""Subclass of JsonResponse that uses the `DataclassEncoder`"""

View File

@ -12,3 +12,7 @@ class FlowNonApplicableException(SentryIgnoredException):
class EmptyFlowException(SentryIgnoredException):
"""Flow has no stages."""
class FlowSkipStageException(SentryIgnoredException):
"""Exception to skip a stage"""

View File

@ -130,7 +130,7 @@ class Migration(migrations.Migration):
dependencies = [
("authentik_flows", "0017_auto_20210329_1334"),
("authentik_stages_user_write", "0002_auto_20200918_1653"),
("authentik_stages_user_login", "__latest__"),
("authentik_stages_user_login", "0003_session_duration_delta"),
("authentik_stages_password", "0002_passwordstage_change_flow"),
("authentik_policies", "0001_initial"),
("authentik_policies_expression", "0001_initial"),

View File

@ -0,0 +1,27 @@
# Generated by Django 4.0.4 on 2022-05-15 19:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_flows", "0021_auto_20211227_2103"),
]
operations = [
migrations.AddField(
model_name="flow",
name="layout",
field=models.TextField(
choices=[
("stacked", "Stacked"),
("content_left", "Content Left"),
("content_right", "Content Right"),
("sidebar_left", "Sidebar Left"),
("sidebar_right", "Sidebar Right"),
],
default="stacked",
),
),
]

View File

@ -13,6 +13,7 @@ from structlog.stdlib import get_logger
from authentik.core.models import Token
from authentik.core.types import UserSettingSerializer
from authentik.flows.challenge import FlowLayout
from authentik.lib.models import InheritanceForeignKey, SerializerModel
from authentik.policies.models import PolicyBindingModel
@ -107,6 +108,7 @@ class Flow(SerializerModel, PolicyBindingModel):
slug = models.SlugField(unique=True, help_text=_("Visible in the URL."))
title = models.TextField(help_text=_("Shown as the Title in Flow pages."))
layout = models.TextField(default=FlowLayout.STACKED, choices=FlowLayout.choices)
designation = models.CharField(
max_length=100,
@ -231,7 +233,7 @@ class FlowStageBinding(SerializerModel, PolicyBindingModel):
return FlowStageBindingSerializer
def __str__(self) -> str:
return f"Flow-stage binding #{self.order} to {self.target}"
return f"Flow-stage binding #{self.order} to {self.target_id}"
class Meta:

View File

@ -120,9 +120,12 @@ class ChallengeStageView(StageView):
return self.executor.flow.title
try:
return self.executor.flow.title % {
"app": self.executor.plan.context.get(PLAN_CONTEXT_APPLICATION, "")
"app": self.executor.plan.context.get(PLAN_CONTEXT_APPLICATION, ""),
"user": self.get_pending_user(for_display=True),
}
except ValueError:
# pylint: disable=broad-except
except Exception as exc:
LOGGER.warning("failed to template title", exc=exc)
return self.executor.flow.title
def _get_challenge(self, *args, **kwargs) -> Challenge:
@ -131,25 +134,32 @@ class ChallengeStageView(StageView):
description=self.__class__.__name__,
):
challenge = self.get_challenge(*args, **kwargs)
if "flow_info" not in challenge.initial_data:
flow_info = ContextualFlowInfo(
data={
"title": self.format_title(),
"background": self.executor.flow.background_url,
"cancel_url": reverse("authentik_flows:cancel"),
}
)
flow_info.is_valid()
challenge.initial_data["flow_info"] = flow_info.data
if isinstance(challenge, WithUserInfoChallenge):
# If there's a pending user, update the `username` field
# this field is only used by password managers.
# If there's no user set, an error is raised later.
if user := self.get_pending_user(for_display=True):
challenge.initial_data["pending_user"] = user.username
challenge.initial_data["pending_user_avatar"] = DEFAULT_AVATAR
if not isinstance(user, AnonymousUser):
challenge.initial_data["pending_user_avatar"] = user.avatar
with Hub.current.start_span(
op="authentik.flow.stage._get_challenge",
description=self.__class__.__name__,
):
if not hasattr(challenge, "initial_data"):
challenge.initial_data = {}
if "flow_info" not in challenge.initial_data:
flow_info = ContextualFlowInfo(
data={
"title": self.format_title(),
"background": self.executor.flow.background_url,
"cancel_url": reverse("authentik_flows:cancel"),
"layout": self.executor.flow.layout,
}
)
flow_info.is_valid()
challenge.initial_data["flow_info"] = flow_info.data
if isinstance(challenge, WithUserInfoChallenge):
# If there's a pending user, update the `username` field
# this field is only used by password managers.
# If there's no user set, an error is raised later.
if user := self.get_pending_user(for_display=True):
challenge.initial_data["pending_user"] = user.username
challenge.initial_data["pending_user_avatar"] = DEFAULT_AVATAR
if not isinstance(user, AnonymousUser):
challenge.initial_data["pending_user_avatar"] = user.avatar
return challenge
def get_challenge(self, *args, **kwargs) -> Challenge:

View File

@ -23,6 +23,7 @@ class FlowTestCase(APITestCase):
**kwargs,
) -> dict[str, Any]:
"""Assert various attributes of a stage response"""
self.assertEqual(response.status_code, 200)
raw_response = loads(response.content.decode())
self.assertIsNotNone(raw_response["component"])
self.assertIsNotNone(raw_response["type"])

View File

@ -10,11 +10,11 @@ from authentik.policies.models import PolicyBinding
from authentik.stages.dummy.models import DummyStage
DIAGRAM_EXPECTED = """st=>start: Start
stage_0=>operation: Stage
stage_0=>operation: Stage (Dummy Stage)
dummy1
stage_1_policy_0=>condition: Policy
None
stage_1=>operation: Stage
stage_1_policy_0=>condition: Policy (Dummy Policy)
test
stage_1=>operation: Stage (Dummy Stage)
dummy2
e=>end: End|future
st(right)->stage_0
@ -55,7 +55,7 @@ class TestFlowsAPI(APITestCase):
slug="test-default-context",
designation=FlowDesignation.AUTHENTICATION,
)
false_policy = DummyPolicy.objects.create(result=False, wait_min=1, wait_max=2)
false_policy = DummyPolicy.objects.create(name="test", result=False, wait_min=1, wait_max=2)
FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name="dummy1"), order=0

View File

@ -87,7 +87,6 @@ class TestFlowExecutor(FlowTestCase):
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
flow=flow,
@ -406,7 +405,6 @@ class TestFlowExecutor(FlowTestCase):
# A get request will evaluate the policies and this will return stage 4
# but it won't save it, hence we can't check the plan
response = self.client.get(exec_url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(response, flow, component="ak-stage-dummy")
# fourth request, this confirms the last stage (dummy4)
@ -479,7 +477,6 @@ class TestFlowExecutor(FlowTestCase):
exec_url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug})
# First request, run the planner
response = self.client.get(exec_url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
flow,
@ -491,5 +488,4 @@ class TestFlowExecutor(FlowTestCase):
user_fields=[UserFields.E_MAIL],
)
response = self.client.post(exec_url, {"uid_field": "invalid-string"}, follow=True)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(response, flow, component="ak-stage-access-denied")

View File

@ -9,6 +9,7 @@ from rest_framework.test import APITestCase
from authentik.core.tests.utils import create_test_admin_user
from authentik.flows.challenge import ChallengeTypes
from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding, InvalidResponseAction
from authentik.lib.generators import generate_id
from authentik.stages.dummy.models import DummyStage
from authentik.stages.identification.models import IdentificationStage, UserFields
@ -24,8 +25,8 @@ class TestFlowInspector(APITestCase):
def test(self):
"""test inspector"""
flow = Flow.objects.create(
name="test-full",
slug="test-full",
name=generate_id(),
slug=generate_id(),
designation=FlowDesignation.AUTHENTICATION,
)
@ -55,6 +56,7 @@ class TestFlowInspector(APITestCase):
"background": flow.background_url,
"cancel_url": reverse("authentik_flows:cancel"),
"title": "",
"layout": "stacked",
},
"type": ChallengeTypes.NATIVE.value,
"password_fields": False,

View File

@ -13,6 +13,26 @@ from authentik.policies.models import PolicyBinding
from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage
from authentik.stages.user_login.models import UserLoginStage
STATIC_PROMPT_EXPORT = """{
"version": 1,
"entries": [
{
"identifiers": {
"pk": "cb954fd4-65a5-4ad9-b1ee-180ee9559cf4"
},
"model": "authentik_stages_prompt.prompt",
"attrs": {
"field_key": "username",
"label": "Username",
"type": "username",
"required": true,
"placeholder": "Username",
"order": 0
}
}
]
}"""
class TestFlowTransfer(TransactionTestCase):
"""Test flow transfer"""
@ -58,6 +78,22 @@ class TestFlowTransfer(TransactionTestCase):
self.assertTrue(Flow.objects.filter(slug=flow_slug).exists())
def test_export_validate_import_re_import(self):
"""Test export and import it twice"""
count_initial = Prompt.objects.filter(field_key="username").count()
importer = FlowImporter(STATIC_PROMPT_EXPORT)
self.assertTrue(importer.validate())
self.assertTrue(importer.apply())
count_before = Prompt.objects.filter(field_key="username").count()
self.assertEqual(count_initial + 1, count_before)
importer = FlowImporter(STATIC_PROMPT_EXPORT)
self.assertTrue(importer.apply())
self.assertEqual(Prompt.objects.filter(field_key="username").count(), count_before)
def test_export_validate_import_policies(self):
"""Test export and validate it"""
flow_slug = generate_id()

View File

@ -115,6 +115,11 @@ class FlowImporter:
serializer_kwargs["instance"] = model_instance
else:
self.logger.debug("initialise new instance", model=model, **updated_identifiers)
model_instance = model()
# pk needs to be set on the model instance otherwise a new one will be generated
if "pk" in updated_identifiers:
model_instance.pk = updated_identifiers["pk"]
serializer_kwargs["instance"] = model_instance
full_data = self.__update_pks_for_attrs(entry.attrs)
full_data.update(updated_identifiers)
serializer_kwargs["data"] = full_data
@ -167,7 +172,7 @@ class FlowImporter:
def validate(self) -> bool:
"""Validate loaded flow export, ensure all models are allowed
and serializers have no errors"""
self.logger.debug("Starting flow import validaton")
self.logger.debug("Starting flow import validation")
if self.__import.version != 1:
self.logger.warning("Invalid bundle version")
return False

View File

@ -169,10 +169,11 @@ class FlowExecutorView(APIView):
self.request.session[SESSION_KEY_PLAN] = plan
# Early check if there's an active Plan for the current session
if SESSION_KEY_PLAN in self.request.session:
self.plan = self.request.session[SESSION_KEY_PLAN]
self.plan: FlowPlan = self.request.session[SESSION_KEY_PLAN]
if self.plan.flow_pk != self.flow.pk.hex:
self._logger.warning(
"f(exec): Found existing plan for other flow, deleting plan",
other_flow=self.plan.flow_pk,
)
# Existing plan is deleted from session and instance
self.plan = None

View File

@ -72,3 +72,4 @@ default_user_change_username: true
gdpr_compliance: true
cert_discovery_dir: /certs
default_token_length: 128
impersonation: true

View File

@ -18,13 +18,22 @@ from redis.exceptions import ConnectionError as RedisConnectionError
from redis.exceptions import RedisError, ResponseError
from rest_framework.exceptions import APIException
from sentry_sdk import Hub
from sentry_sdk import init as sentry_sdk_init
from sentry_sdk.api import set_tag
from sentry_sdk.integrations.celery import CeleryIntegration
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.redis import RedisIntegration
from sentry_sdk.integrations.threading import ThreadingIntegration
from sentry_sdk.tracing import Transaction
from structlog.stdlib import get_logger
from websockets.exceptions import WebSocketException
from authentik.lib.utils.reflection import class_to_path
from authentik import __version__, get_build_hash
from authentik.lib.config import CONFIG
from authentik.lib.utils.reflection import class_to_path, get_env
LOGGER = get_logger()
SENTRY_DSN = "https://a579bb09306d4f8b8d8847c052d3a1d3@sentry.beryju.org/8"
class SentryWSMiddleware(BaseMiddleware):
@ -43,6 +52,37 @@ class SentryIgnoredException(Exception):
"""Base Class for all errors that are suppressed, and not sent to sentry."""
def sentry_init(**sentry_init_kwargs):
"""Configure sentry SDK"""
sentry_env = CONFIG.y("error_reporting.environment", "customer")
kwargs = {
"traces_sample_rate": float(CONFIG.y("error_reporting.sample_rate", 0.5)),
"environment": sentry_env,
"send_default_pii": CONFIG.y_bool("error_reporting.send_pii", False),
}
kwargs.update(**sentry_init_kwargs)
# pylint: disable=abstract-class-instantiated
sentry_sdk_init(
dsn=SENTRY_DSN,
integrations=[
DjangoIntegration(transaction_style="function_name"),
CeleryIntegration(),
RedisIntegration(),
ThreadingIntegration(propagate_hub=True),
],
before_send=before_send,
release=f"authentik@{__version__}",
**kwargs,
)
set_tag("authentik.build_hash", get_build_hash("tagged"))
set_tag("authentik.env", get_env())
set_tag("authentik.component", "backend")
LOGGER.info(
"Error reporting is enabled",
env=kwargs["environment"],
)
def before_send(event: dict, hint: dict) -> Optional[dict]:
"""Check if error is database error, and ignore if so"""
# pylint: disable=no-name-in-module
@ -108,6 +148,6 @@ def before_send(event: dict, hint: dict) -> Optional[dict]:
]:
return None
LOGGER.debug("sending event to sentry", exc=exc_value, source_logger=event.get("logger", None))
if settings.DEBUG or settings.TEST:
if settings.DEBUG:
return None
return event

View File

@ -13,4 +13,4 @@ class TestSentry(TestCase):
def test_error_sent(self):
"""Test error sent"""
self.assertEqual(None, before_send({}, {"exc_info": (0, ValueError(), 0)}))
self.assertEqual({}, before_send({}, {"exc_info": (0, ValueError(), 0)}))

View File

@ -1,5 +1,8 @@
"""Time utilities"""
import datetime
from hashlib import sha256
from random import randrange, seed
from socket import getfqdn
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
@ -38,3 +41,12 @@ def timedelta_from_string(expr: str) -> datetime.timedelta:
if len(kwargs) < 1:
raise ValueError("No valid keys to pass to timedelta")
return datetime.timedelta(**kwargs)
def fqdn_rand(task: str, stop: int = 60) -> int:
"""Get a random number within max based on the FQDN and task name"""
entropy = f"{getfqdn()}:{task}"
hasher = sha256()
hasher.update(entropy.encode("utf-8"))
seed(hasher.hexdigest())
return randrange(0, stop) # nosec

View File

@ -1,7 +1,8 @@
"""URL-related utils"""
from typing import Optional
from urllib.parse import urlparse
from django.http import HttpResponse
from django.http import HttpResponse, QueryDict
from django.shortcuts import redirect
from django.urls import NoReverseMatch, reverse
from django.utils.http import urlencode
@ -15,7 +16,9 @@ def is_url_absolute(url):
return bool(urlparse(url).netloc)
def redirect_with_qs(view: str, get_query_set=None, **kwargs) -> HttpResponse:
def redirect_with_qs(
view: str, get_query_set: Optional[QueryDict] = None, **kwargs
) -> HttpResponse:
"""Wrapper to redirect whilst keeping GET Parameters"""
try:
target = reverse(view, kwargs=kwargs)
@ -28,3 +31,11 @@ def redirect_with_qs(view: str, get_query_set=None, **kwargs) -> HttpResponse:
if get_query_set:
target += "?" + urlencode(get_query_set.items())
return redirect(target)
def reverse_with_qs(view: str, query: Optional[QueryDict] = None, **kwargs) -> str:
"""Reverse a view to it's url but include get params"""
url = reverse(view, **kwargs)
if query:
url += "?" + urlencode(query.items())
return url

View File

@ -1,10 +1,12 @@
"""managed Settings"""
from celery.schedules import crontab
from authentik.lib.utils.time import fqdn_rand
CELERY_BEAT_SCHEDULE = {
"managed_reconcile": {
"task": "authentik.managed.tasks.managed_reconcile",
"schedule": crontab(minute="*/5"),
"schedule": crontab(minute=fqdn_rand("managed_reconcile"), hour="*/4"),
"options": {"queue": "authentik_scheduled"},
},
}

View File

@ -118,6 +118,7 @@ class DockerServiceConnectionViewSet(UsedByMixin, ModelViewSet):
serializer_class = DockerServiceConnectionSerializer
filterset_fields = ["name", "local", "url", "tls_verification", "tls_authentication"]
ordering = ["name"]
search_fields = ["name"]
class KubernetesServiceConnectionSerializer(ServiceConnectionSerializer):
@ -152,3 +153,4 @@ class KubernetesServiceConnectionViewSet(UsedByMixin, ModelViewSet):
serializer_class = KubernetesServiceConnectionSerializer
filterset_fields = ["name", "local"]
ordering = ["name"]
search_fields = ["name"]

View File

@ -15,7 +15,7 @@ from yaml import safe_dump
from authentik import __version__
from authentik.outposts.controllers.base import BaseClient, BaseController, ControllerException
from authentik.outposts.docker_ssh import DockerInlineSSH
from authentik.outposts.docker_ssh import DockerInlineSSH, SSHManagedExternallyException
from authentik.outposts.docker_tls import DockerInlineTLS
from authentik.outposts.managed import MANAGED_OUTPOST
from authentik.outposts.models import (
@ -35,6 +35,7 @@ class DockerClient(UpstreamDockerClient, BaseClient):
def __init__(self, connection: DockerServiceConnection):
self.tls = None
self.ssh = None
self.logger = get_logger()
if connection.local:
# Same result as DockerClient.from_env
super().__init__(**kwargs_from_env())
@ -42,8 +43,12 @@ class DockerClient(UpstreamDockerClient, BaseClient):
parsed_url = urlparse(connection.url)
tls_config = False
if parsed_url.scheme == "ssh":
self.ssh = DockerInlineSSH(parsed_url.hostname, connection.tls_authentication)
self.ssh.write()
try:
self.ssh = DockerInlineSSH(parsed_url.hostname, connection.tls_authentication)
self.ssh.write()
except SSHManagedExternallyException as exc:
# SSH config is managed externally
self.logger.info(f"SSH Managed externally: {exc}")
else:
self.tls = DockerInlineTLS(
verification_kp=connection.tls_verification,
@ -57,7 +62,6 @@ class DockerClient(UpstreamDockerClient, BaseClient):
)
except SSHException as exc:
raise ServiceConnectionInvalid from exc
self.logger = get_logger()
# Ensure the client actually works
self.containers.list()

View File

@ -16,6 +16,10 @@ def opener(path, flags):
return os.open(path, flags, 0o700)
class SSHManagedExternallyException(DockerException):
"""Raised when the ssh config file is managed externally."""
class DockerInlineSSH:
"""Create paramiko ssh config from CertificateKeyPair"""
@ -29,9 +33,15 @@ class DockerInlineSSH:
def __init__(self, host: str, keypair: CertificateKeyPair) -> None:
self.host = host
self.keypair = keypair
self.config_path = Path("~/.ssh/config").expanduser()
if self.config_path.exists() and HEADER not in self.config_path.read_text(encoding="utf-8"):
# SSH Config file already exists and there's no header from us, meaning that it's
# been externally mapped into the container for more complex configs
raise SSHManagedExternallyException(
"SSH Config exists and does not contain authentik header"
)
if not self.keypair:
raise DockerException("keypair must be set for SSH connections")
self.config_path = Path("~/.ssh/config").expanduser()
self.header = f"{HEADER} - {self.host}\n"
def write_config(self, key_path: str) -> bool:

View File

@ -1,25 +1,27 @@
"""Outposts Settings"""
from celery.schedules import crontab
from authentik.lib.utils.time import fqdn_rand
CELERY_BEAT_SCHEDULE = {
"outposts_controller": {
"task": "authentik.outposts.tasks.outpost_controller_all",
"schedule": crontab(minute="*/5"),
"schedule": crontab(minute=fqdn_rand("outposts_controller"), hour="*/4"),
"options": {"queue": "authentik_scheduled"},
},
"outposts_service_connection_check": {
"task": "authentik.outposts.tasks.outpost_service_connection_monitor",
"schedule": crontab(minute="*/5"),
"schedule": crontab(minute="3-59/15"),
"options": {"queue": "authentik_scheduled"},
},
"outpost_token_ensurer": {
"task": "authentik.outposts.tasks.outpost_token_ensurer",
"schedule": crontab(minute="*/5"),
"schedule": crontab(minute=fqdn_rand("outpost_token_ensurer"), hour="*/8"),
"options": {"queue": "authentik_scheduled"},
},
"outpost_local_connection": {
"task": "authentik.outposts.tasks.outpost_local_connection",
"schedule": crontab(minute="*/60"),
"schedule": crontab(minute=fqdn_rand("outpost_local_connection"), hour="*/8"),
"options": {"queue": "authentik_scheduled"},
},
}

View File

@ -52,7 +52,7 @@ def m2m_changed_update(sender, instance: Model, action: str, **_):
@receiver(post_save)
# pylint: disable=unused-argument
def post_save_update(sender, instance: Model, **_):
def post_save_update(sender, instance: Model, created: bool, **_):
"""If an Outpost is saved, Ensure that token is created/updated
If an OutpostModel, or a model that is somehow connected to an OutpostModel is saved,
@ -63,6 +63,9 @@ def post_save_update(sender, instance: Model, **_):
return
if not isinstance(instance, UPDATE_TRIGGERING_MODELS):
return
if isinstance(instance, Outpost) and created:
LOGGER.info("New outpost saved, ensuring initial token and user are created")
_ = instance.token
outpost_post_save.delay(class_to_path(instance.__class__), instance.pk)

View File

@ -3,6 +3,7 @@ from typing import Any, Optional
from django.http.request import HttpRequest
from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.translation import gettext as _
from authentik.core.models import USER_ATTRIBUTE_DEBUG
@ -37,4 +38,5 @@ class AccessDeniedResponse(TemplateResponse):
self._request
).get(USER_ATTRIBUTE_DEBUG, False):
context["policy_result"] = self.policy_result
context["cancel"] = reverse("authentik_flows:cancel")
return context

View File

@ -21,3 +21,4 @@ class DummyPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = DummyPolicySerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]

View File

@ -25,3 +25,4 @@ class EventMatcherPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = EventMatcherPolicySerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]

View File

@ -21,3 +21,4 @@ class PasswordExpiryPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = PasswordExpiryPolicySerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]

View File

@ -28,3 +28,4 @@ class ExpressionPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = ExpressionPolicySerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]

View File

@ -20,4 +20,5 @@ class HaveIBeenPwendPolicyViewSet(UsedByMixin, ModelViewSet):
queryset = HaveIBeenPwendPolicy.objects.all()
serializer_class = HaveIBeenPwendPolicySerializer
filterset_fields = "__all__"
search_fields = ["name", "password_field"]
ordering = ["name"]

View File

@ -9,6 +9,7 @@ from structlog.stdlib import get_logger
from authentik.lib.utils.http import get_http_session
from authentik.policies.models import Policy, PolicyResult
from authentik.policies.types import PolicyRequest
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
LOGGER = get_logger()
@ -38,14 +39,17 @@ class HaveIBeenPwendPolicy(Policy):
"""Check if password is in HIBP DB. Hashes given Password with SHA1, uses the first 5
characters of Password in request and checks if full hash is in response. Returns 0
if Password is not in result otherwise the count of how many times it was used."""
if self.password_field not in request.context:
password = request.context.get(PLAN_CONTEXT_PROMPT, {}).get(
self.password_field, request.context.get(self.password_field)
)
if not password:
LOGGER.warning(
"Password field not set in Policy Request",
field=self.password_field,
fields=request.context.keys(),
)
return PolicyResult(False, _("Password not set in context"))
password = str(request.context[self.password_field])
password = str(password)
pw_hash = sha1(password.encode("utf-8")).hexdigest() # nosec
url = f"https://api.pwnedpasswords.com/range/{pw_hash[:5]}"

View File

@ -5,6 +5,7 @@ from guardian.shortcuts import get_anonymous_user
from authentik.lib.generators import generate_key
from authentik.policies.hibp.models import HaveIBeenPwendPolicy
from authentik.policies.types import PolicyRequest, PolicyResult
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
class TestHIBPPolicy(TestCase):
@ -26,7 +27,7 @@ class TestHIBPPolicy(TestCase):
name="test_false",
)
request = PolicyRequest(get_anonymous_user())
request.context["password"] = "password" # nosec
request.context[PLAN_CONTEXT_PROMPT] = {"password": "password"} # nosec
result: PolicyResult = policy.passes(request)
self.assertFalse(result.passing)
self.assertTrue(result.messages[0].startswith("Password exists on "))
@ -37,7 +38,7 @@ class TestHIBPPolicy(TestCase):
name="test_true",
)
request = PolicyRequest(get_anonymous_user())
request.context["password"] = generate_key()
request.context[PLAN_CONTEXT_PROMPT] = {"password": generate_key()}
result: PolicyResult = policy.passes(request)
self.assertTrue(result.passing)
self.assertEqual(result.messages, tuple())

View File

@ -30,3 +30,4 @@ class PasswordPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = PasswordPolicySerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]

View File

@ -50,7 +50,6 @@ class TestPasswordPolicyFlow(FlowTestCase):
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
{"password": "akadmin"},
)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,

View File

@ -151,5 +151,5 @@ class PolicyProcess(PROCESS_CLASS):
try:
self.connection.send(self.profiling_wrapper())
except Exception as exc: # pylint: disable=broad-except
LOGGER.warning(str(exc))
LOGGER.warning("Policy failed to run", exc=exc)
self.connection.send(PolicyResult(False, str(exc)))

View File

@ -26,6 +26,7 @@ class ReputationPolicyViewSet(UsedByMixin, ModelViewSet):
queryset = ReputationPolicy.objects.all()
serializer_class = ReputationPolicySerializer
filterset_fields = "__all__"
search_fields = ["name", "threshold"]
ordering = ["name"]

View File

@ -4,7 +4,7 @@ from celery.schedules import crontab
CELERY_BEAT_SCHEDULE = {
"policies_reputation_save": {
"task": "authentik.policies.reputation.tasks.save_reputation",
"schedule": crontab(minute="*/5"),
"schedule": crontab(minute="1-59/5"),
"options": {"queue": "authentik_scheduled"},
},
}

View File

@ -12,8 +12,21 @@
{% endblock %}
{% block card %}
<form method="POST" class="pf-c-form">
<form class="pf-c-form">
{% csrf_token %}
{% if user.is_authenticated %}
<div class="pf-c-form__group">
<div class="form-control-static">
<div class="avatar">
<img class="pf-c-avatar" src="{{ user.avatar }}" alt="{% trans "User's avatar" %}" />
{{ user.username }}
</div>
<div slot="link">
<a href="{{ cancel }}">{% trans "Not you?" %}</a>
</div>
</div>
</div>
{% endif %}
<div class="pf-c-form__group">
<p>
<i class="pf-icon pf-icon-error-circle-o"></i>

View File

@ -25,6 +25,7 @@ class LDAPProviderSerializer(ProviderSerializer):
"gid_start_number",
"outpost_set",
"search_mode",
"bind_mode",
]
@ -46,6 +47,7 @@ class LDAPProviderViewSet(UsedByMixin, ModelViewSet):
"uid_start_number": ["iexact"],
"gid_start_number": ["iexact"],
}
search_fields = ["name"]
ordering = ["name"]
@ -70,6 +72,7 @@ class LDAPOutpostConfigSerializer(ModelSerializer):
"uid_start_number",
"gid_start_number",
"search_mode",
"bind_mode",
]
@ -79,3 +82,5 @@ class LDAPOutpostConfigViewSet(ReadOnlyModelViewSet):
queryset = LDAPProvider.objects.filter(application__isnull=False)
serializer_class = LDAPOutpostConfigSerializer
ordering = ["name"]
search_fields = ["name"]
filterset_fields = ["name"]

View File

@ -0,0 +1,20 @@
# Generated by Django 4.0.4 on 2022-05-08 13:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_ldap", "0001_squashed_0005_ldapprovider_search_mode"),
]
operations = [
migrations.AddField(
model_name="ldapprovider",
name="bind_mode",
field=models.TextField(
choices=[("direct", "Direct"), ("cached", "Cached")], default="direct"
),
),
]

View File

@ -10,8 +10,8 @@ from authentik.crypto.models import CertificateKeyPair
from authentik.outposts.models import OutpostModel
class SearchModes(models.TextChoices):
"""Search modes"""
class APIAccessMode(models.TextChoices):
"""API Access modes"""
DIRECT = "direct"
CACHED = "cached"
@ -66,7 +66,8 @@ class LDAPProvider(OutpostModel, Provider):
),
)
search_mode = models.TextField(default=SearchModes.DIRECT, choices=SearchModes.choices)
bind_mode = models.TextField(default=APIAccessMode.DIRECT, choices=APIAccessMode.choices)
search_mode = models.TextField(default=APIAccessMode.DIRECT, choices=APIAccessMode.choices)
@property
def launch_url(self) -> Optional[str]:

View File

@ -71,6 +71,7 @@ class OAuth2ProviderViewSet(UsedByMixin, ModelViewSet):
"property_mappings",
"issuer_mode",
]
search_fields = ["name"]
ordering = ["name"]
@extend_schema(

View File

@ -39,3 +39,4 @@ class ScopeMappingViewSet(UsedByMixin, ModelViewSet):
serializer_class = ScopeMappingSerializer
filterset_class = ScopeMappingFilter
ordering = ["scope_name", "name"]
search_fields = ["name", "scope_name"]

View File

@ -11,7 +11,7 @@ CLIENT_ASSERTION = "client_assertion"
CLIENT_ASSERTION_TYPE_JWT = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
PROMPT_NONE = "none"
PROMPT_CONSNET = "consent"
PROMPT_CONSENT = "consent"
PROMPT_LOGIN = "login"
SCOPE_OPENID = "openid"

View File

@ -24,7 +24,7 @@ class OAuth2Error(SentryIgnoredException):
return self.error
def to_event(self, message: Optional[str] = None, **kwargs) -> Event:
"""Create configuration_error Event and save it."""
"""Create configuration_error Event."""
return Event.new(
EventAction.CONFIGURATION_ERROR,
message=message or self.description,

View File

@ -50,6 +50,7 @@ class ResponseMode(models.TextChoices):
QUERY = "query"
FRAGMENT = "fragment"
FORM_POST = "form_post"
class SubModes(models.TextChoices):

View File

@ -5,7 +5,6 @@ from django.urls import reverse
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
from authentik.flows.challenge import ChallengeTypes
from authentik.flows.models import Flow
from authentik.lib.generators import generate_id, generate_key
from authentik.providers.oauth2.errors import AuthorizeError, ClientIdError, RedirectUriError
from authentik.providers.oauth2.models import (
@ -79,6 +78,28 @@ class TestAuthorize(OAuthTestCase):
)
OAuthAuthorizationParams.from_request(request)
def test_invalid_redirect_uri_regex(self):
"""test missing/invalid redirect URI"""
OAuth2Provider.objects.create(
name="test",
client_id="test",
authorization_flow=create_test_flow(),
redirect_uris="+",
)
with self.assertRaises(RedirectUriError):
request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
OAuthAuthorizationParams.from_request(request)
with self.assertRaises(RedirectUriError):
request = self.factory.get(
"/",
data={
"response_type": "code",
"client_id": "test",
"redirect_uri": "http://localhost",
},
)
OAuthAuthorizationParams.from_request(request)
def test_empty_redirect_uri(self):
"""test empty redirect URI (configure in provider)"""
OAuth2Provider.objects.create(
@ -178,7 +199,7 @@ class TestAuthorize(OAuthTestCase):
def test_full_code(self):
"""Test full authorization"""
flow = Flow.objects.create(slug="empty")
flow = create_test_flow()
provider = OAuth2Provider.objects.create(
name="test",
client_id="test",
@ -214,7 +235,7 @@ class TestAuthorize(OAuthTestCase):
def test_full_implicit(self):
"""Test full authorization"""
flow = Flow.objects.create(slug="empty")
flow = create_test_flow()
provider = OAuth2Provider.objects.create(
name="test",
client_id="test",
@ -255,3 +276,52 @@ class TestAuthorize(OAuthTestCase):
},
)
self.validate_jwt(token, provider)
def test_full_form_post(self):
"""Test full authorization (form_post response)"""
flow = create_test_flow()
provider = OAuth2Provider.objects.create(
name="test",
client_id="test",
client_secret=generate_key(),
authorization_flow=flow,
redirect_uris="http://localhost",
signing_key=create_test_cert(),
)
Application.objects.create(name="app", slug="app", provider=provider)
state = generate_id()
user = create_test_admin_user()
self.client.force_login(user)
# Step 1, initiate params and get redirect to flow
self.client.get(
reverse("authentik_providers_oauth2:authorize"),
data={
"response_type": "id_token",
"response_mode": "form_post",
"client_id": "test",
"state": state,
"scope": "openid",
"redirect_uri": "http://localhost",
},
)
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
token: RefreshToken = RefreshToken.objects.filter(user=user).first()
self.assertJSONEqual(
response.content.decode(),
{
"component": "ak-stage-autosubmit",
"type": ChallengeTypes.NATIVE.value,
"url": "http://localhost",
"title": "Redirecting to app...",
"attrs": {
"access_token": token.access_token,
"id_token": provider.encode(token.id_token.to_dict()),
"token_type": "bearer",
"expires_in": "60",
"state": state,
},
},
)
self.validate_jwt(token, provider)

View File

@ -1,6 +1,8 @@
"""authentik OAuth2 Authorization views"""
from dataclasses import dataclass, field
from datetime import timedelta
from re import error as RegexError
from re import escape, fullmatch
from typing import Optional
from urllib.parse import parse_qs, urlencode, urlparse, urlsplit, urlunsplit
from uuid import uuid4
@ -15,6 +17,12 @@ from structlog.stdlib import get_logger
from authentik.core.models import Application
from authentik.events.models import Event, EventAction
from authentik.events.utils import get_user
from authentik.flows.challenge import (
PLAN_CONTEXT_TITLE,
AutosubmitChallenge,
ChallengeTypes,
HttpChallengeResponse,
)
from authentik.flows.models import in_memory_stage
from authentik.flows.planner import (
PLAN_CONTEXT_APPLICATION,
@ -30,7 +38,7 @@ from authentik.lib.views import bad_request_message
from authentik.policies.types import PolicyRequest
from authentik.policies.views import PolicyAccessView, RequestValidationError
from authentik.providers.oauth2.constants import (
PROMPT_CONSNET,
PROMPT_CONSENT,
PROMPT_LOGIN,
PROMPT_NONE,
SCOPE_OPENID,
@ -63,7 +71,7 @@ LOGGER = get_logger()
PLAN_CONTEXT_PARAMS = "params"
SESSION_NEEDS_LOGIN = "authentik_oauth2_needs_login"
ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSNET, PROMPT_LOGIN}
ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN}
@dataclass
@ -74,6 +82,7 @@ class OAuthAuthorizationParams:
client_id: str
redirect_uri: str
response_type: str
response_mode: Optional[str]
scope: list[str]
state: str
nonce: Optional[str]
@ -125,11 +134,22 @@ class OAuthAuthorizationParams:
LOGGER.warning("Invalid response type", type=response_type)
raise AuthorizeError(redirect_uri, "unsupported_response_type", "", state)
# Validate and check the response_mode against the predefined dict
# Set to Query or Fragment if not defined in request
response_mode = query_dict.get("response_mode", False)
if response_mode not in ResponseMode.values:
response_mode = ResponseMode.QUERY
if grant_type in [GrantTypes.IMPLICIT, GrantTypes.HYBRID]:
response_mode = ResponseMode.FRAGMENT
max_age = query_dict.get("max_age")
return OAuthAuthorizationParams(
client_id=query_dict.get("client_id", ""),
redirect_uri=redirect_uri,
response_type=response_type,
response_mode=response_mode,
grant_type=grant_type,
scope=query_dict.get("scope", "").split(),
state=state,
@ -155,31 +175,32 @@ class OAuthAuthorizationParams:
def check_redirect_uri(self):
"""Redirect URI validation."""
allowed_redirect_urls = self.provider.redirect_uris.split()
# We don't want to actually lowercase the final URL we redirect to,
# we only lowercase it for comparison
redirect_uri = self.redirect_uri.lower()
if not redirect_uri:
if not self.redirect_uri:
LOGGER.warning("Missing redirect uri.")
raise RedirectUriError("", allowed_redirect_urls)
if self.provider.redirect_uris == "":
LOGGER.info("Setting redirect for blank redirect_uris", redirect=self.redirect_uri)
self.provider.redirect_uris = self.redirect_uri
self.provider.redirect_uris = escape(self.redirect_uri)
self.provider.save()
allowed_redirect_urls = self.provider.redirect_uris.split()
if self.provider.redirect_uris == "*":
LOGGER.warning(
"Provider has wildcard allowed redirect_uri set, allowing all.",
allow=self.redirect_uri,
)
return
if redirect_uri not in [x.lower() for x in allowed_redirect_urls]:
LOGGER.warning(
"Invalid redirect uri",
redirect_uri=self.redirect_uri,
excepted=allowed_redirect_urls,
)
LOGGER.info("Converting redirect_uris to regex", redirect=self.redirect_uri)
self.provider.redirect_uris = ".*"
self.provider.save()
allowed_redirect_urls = self.provider.redirect_uris.split()
try:
if not any(fullmatch(x, self.redirect_uri) for x in allowed_redirect_urls):
LOGGER.warning(
"Invalid redirect uri",
redirect_uri=self.redirect_uri,
excepted=allowed_redirect_urls,
)
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
except RegexError as exc:
LOGGER.warning("Invalid regular expression configured", exc=exc)
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
if self.request:
raise AuthorizeError(
@ -239,167 +260,6 @@ class OAuthAuthorizationParams:
return code
class OAuthFulfillmentStage(StageView):
"""Final stage, restores params from Flow."""
params: OAuthAuthorizationParams
provider: OAuth2Provider
def redirect(self, uri: str) -> HttpResponse:
"""Redirect using HttpResponseRedirectScheme, compatible with non-http schemes"""
parsed = urlparse(uri)
return HttpResponseRedirectScheme(uri, allowed_schemes=[parsed.scheme])
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""Wrapper when this stage gets hit with a post request"""
return self.get(request, *args, **kwargs)
# pylint: disable=unused-argument
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""final Stage of an OAuth2 Flow"""
if PLAN_CONTEXT_PARAMS not in self.executor.plan.context:
LOGGER.warning("Got to fulfillment stage with no pending context")
return HttpResponseBadRequest()
self.params: OAuthAuthorizationParams = self.executor.plan.context.pop(PLAN_CONTEXT_PARAMS)
application: Application = self.executor.plan.context.pop(PLAN_CONTEXT_APPLICATION)
self.provider = get_object_or_404(OAuth2Provider, pk=application.provider_id)
try:
# At this point we don't need to check permissions anymore
if {PROMPT_NONE, PROMPT_CONSNET}.issubset(self.params.prompt):
raise AuthorizeError(
self.params.redirect_uri,
"consent_required",
self.params.grant_type,
self.params.state,
)
Event.new(
EventAction.AUTHORIZE_APPLICATION,
authorized_application=application,
flow=self.executor.plan.flow_pk,
scopes=", ".join(self.params.scope),
).from_http(self.request)
return self.redirect(self.create_response_uri())
except (ClientIdError, RedirectUriError) as error:
error.to_event(application=application).from_http(request)
self.executor.stage_invalid()
# pylint: disable=no-member
return bad_request_message(request, error.description, title=error.error)
except AuthorizeError as error:
error.to_event(application=application).from_http(request)
self.executor.stage_invalid()
return self.redirect(error.create_uri())
def create_response_uri(self) -> str:
"""Create a final Response URI the user is redirected to."""
uri = urlsplit(self.params.redirect_uri)
query_params = parse_qs(uri.query)
try:
code = None
if self.params.grant_type in [
GrantTypes.AUTHORIZATION_CODE,
GrantTypes.HYBRID,
]:
code = self.params.create_code(self.request)
code.save(force_insert=True)
query_dict = self.request.POST if self.request.method == "POST" else self.request.GET
response_mode = ResponseMode.QUERY
# Get response mode from url param, otherwise decide based on grant type
if "response_mode" in query_dict:
response_mode = query_dict["response_mode"]
elif self.params.grant_type == GrantTypes.AUTHORIZATION_CODE:
response_mode = ResponseMode.QUERY
elif self.params.grant_type in [GrantTypes.IMPLICIT, GrantTypes.HYBRID]:
response_mode = ResponseMode.FRAGMENT
if response_mode == ResponseMode.QUERY:
query_params["code"] = code.code
query_params["state"] = [str(self.params.state) if self.params.state else ""]
uri = uri._replace(query=urlencode(query_params, doseq=True))
return urlunsplit(uri)
if response_mode == ResponseMode.FRAGMENT:
query_fragment = self.create_implicit_response(code)
uri = uri._replace(
fragment=uri.fragment + urlencode(query_fragment, doseq=True),
)
return urlunsplit(uri)
raise OAuth2Error()
except OAuth2Error as error:
LOGGER.warning("Error when trying to create response uri", error=error)
raise AuthorizeError(
self.params.redirect_uri,
"server_error",
self.params.grant_type,
self.params.state,
)
def create_implicit_response(self, code: Optional[AuthorizationCode]) -> dict:
"""Create implicit response's URL Fragment dictionary"""
query_fragment = {}
token = self.provider.create_refresh_token(
user=self.request.user,
scope=self.params.scope,
request=self.request,
)
# Check if response_type must include access_token in the response.
if self.params.response_type in [
ResponseTypes.ID_TOKEN_TOKEN,
ResponseTypes.CODE_ID_TOKEN_TOKEN,
ResponseTypes.ID_TOKEN,
ResponseTypes.CODE_TOKEN,
]:
query_fragment["access_token"] = token.access_token
# We don't need id_token if it's an OAuth2 request.
if SCOPE_OPENID in self.params.scope:
id_token = token.create_id_token(
user=self.request.user,
request=self.request,
)
id_token.nonce = self.params.nonce
# Include at_hash when access_token is being returned.
if "access_token" in query_fragment:
id_token.at_hash = token.at_hash
if self.params.response_type in [
ResponseTypes.CODE_ID_TOKEN,
ResponseTypes.CODE_ID_TOKEN_TOKEN,
]:
id_token.c_hash = code.c_hash
# Check if response_type must include id_token in the response.
if self.params.response_type in [
ResponseTypes.ID_TOKEN,
ResponseTypes.ID_TOKEN_TOKEN,
ResponseTypes.CODE_ID_TOKEN,
ResponseTypes.CODE_ID_TOKEN_TOKEN,
]:
query_fragment["id_token"] = self.provider.encode(id_token.to_dict())
token.id_token = id_token
# Store the token.
token.save()
# Code parameter must be present if it's Hybrid Flow.
if self.params.grant_type == GrantTypes.HYBRID:
query_fragment["code"] = code.code
query_fragment["token_type"] = "bearer" # nosec
query_fragment["expires_in"] = int(
timedelta_from_string(self.provider.access_code_validity).total_seconds()
)
query_fragment["state"] = self.params.state if self.params.state else ""
return query_fragment
class AuthorizationFlowInitView(PolicyAccessView):
"""OAuth2 Flow initializer, checks access to application and starts flow"""
@ -414,10 +274,10 @@ class AuthorizationFlowInitView(PolicyAccessView):
try:
self.params = OAuthAuthorizationParams.from_request(self.request)
except AuthorizeError as error:
error.to_event(redirect_uri=error.redirect_uri).from_http(self.request)
LOGGER.warning(error.description, redirect_uri=error.redirect_uri)
raise RequestValidationError(HttpResponseRedirect(error.create_uri()))
except OAuth2Error as error:
error.to_event().from_http(self.request)
LOGGER.warning(error.description)
raise RequestValidationError(
bad_request_message(self.request, error.description, title=error.error)
)
@ -494,7 +354,7 @@ class AuthorizationFlowInitView(PolicyAccessView):
)
# OpenID clients can specify a `prompt` parameter, and if its set to consent we
# need to inject a consent stage
if PROMPT_CONSNET in self.params.prompt:
if PROMPT_CONSENT in self.params.prompt:
if not any(isinstance(x.stage, ConsentStageView) for x in plan.bindings):
# Plan does not have any consent stage, so we add an in-memory one
stage = ConsentStage(
@ -502,10 +362,206 @@ class AuthorizationFlowInitView(PolicyAccessView):
mode=ConsentMode.ALWAYS_REQUIRE,
)
plan.append_stage(stage)
plan.append_stage(in_memory_stage(OAuthFulfillmentStage))
self.request.session[SESSION_KEY_PLAN] = plan
return redirect_with_qs(
"authentik_core:if-flow",
self.request.GET,
flow_slug=self.provider.authorization_flow.slug,
)
class OAuthFulfillmentStage(StageView):
"""Final stage, restores params from Flow."""
params: OAuthAuthorizationParams
provider: OAuth2Provider
application: Application
def redirect(self, uri: str) -> HttpResponse:
"""Redirect using HttpResponseRedirectScheme, compatible with non-http schemes"""
parsed = urlparse(uri)
if self.params.response_mode == ResponseMode.FORM_POST:
# parse_qs returns a dictionary with values wrapped in lists, however
# we need a flat dictionary for the autosubmit challenge
# this picks the first item in the list if the value is a list,
# otherwise just the value as-is
query_params = dict(
(k, v[0] if isinstance(v, list) else v) for k, v in parse_qs(parsed.query).items()
)
challenge = AutosubmitChallenge(
data={
"type": ChallengeTypes.NATIVE.value,
"component": "ak-stage-autosubmit",
"title": (
self.executor.plan.context.get(
PLAN_CONTEXT_TITLE,
_("Redirecting to %(app)s..." % {"app": self.application.name}),
)
),
"url": self.params.redirect_uri,
"attrs": query_params,
}
)
challenge.is_valid()
return HttpChallengeResponse(
challenge=challenge,
)
return HttpResponseRedirectScheme(uri, allowed_schemes=[parsed.scheme])
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""Wrapper when this stage gets hit with a post request"""
return self.get(request, *args, **kwargs)
# pylint: disable=unused-argument
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""final Stage of an OAuth2 Flow"""
if PLAN_CONTEXT_PARAMS not in self.executor.plan.context:
LOGGER.warning("Got to fulfillment stage with no pending context")
return HttpResponseBadRequest()
self.params: OAuthAuthorizationParams = self.executor.plan.context.pop(PLAN_CONTEXT_PARAMS)
self.application: Application = self.executor.plan.context.pop(PLAN_CONTEXT_APPLICATION)
self.provider = get_object_or_404(OAuth2Provider, pk=self.application.provider_id)
try:
# At this point we don't need to check permissions anymore
if {PROMPT_NONE, PROMPT_CONSENT}.issubset(self.params.prompt):
raise AuthorizeError(
self.params.redirect_uri,
"consent_required",
self.params.grant_type,
self.params.state,
)
Event.new(
EventAction.AUTHORIZE_APPLICATION,
authorized_application=self.application,
flow=self.executor.plan.flow_pk,
scopes=", ".join(self.params.scope),
).from_http(self.request)
return self.redirect(self.create_response_uri())
except (ClientIdError, RedirectUriError) as error:
error.to_event(application=self.application).from_http(request)
self.executor.stage_invalid()
# pylint: disable=no-member
return bad_request_message(request, error.description, title=error.error)
except AuthorizeError as error:
error.to_event(application=self.application).from_http(request)
self.executor.stage_invalid()
return self.redirect(error.create_uri())
def create_response_uri(self) -> str:
"""Create a final Response URI the user is redirected to."""
uri = urlsplit(self.params.redirect_uri)
query_params = parse_qs(uri.query)
try:
code = None
if self.params.grant_type in [
GrantTypes.AUTHORIZATION_CODE,
GrantTypes.HYBRID,
]:
code = self.params.create_code(self.request)
code.save(force_insert=True)
if self.params.response_mode == ResponseMode.QUERY:
query_params["code"] = code.code
query_params["state"] = [str(self.params.state) if self.params.state else ""]
uri = uri._replace(query=urlencode(query_params, doseq=True))
return urlunsplit(uri)
if self.params.response_mode == ResponseMode.FRAGMENT:
query_fragment = self.create_implicit_response(code)
uri = uri._replace(
fragment=uri.fragment + urlencode(query_fragment, doseq=True),
)
return urlunsplit(uri)
if self.params.response_mode == ResponseMode.FORM_POST:
post_params = self.create_implicit_response(code)
uri = uri._replace(query=urlencode(post_params, doseq=True))
return urlunsplit(uri)
raise OAuth2Error()
except OAuth2Error as error:
LOGGER.warning("Error when trying to create response uri", error=error)
raise AuthorizeError(
self.params.redirect_uri,
"server_error",
self.params.grant_type,
self.params.state,
)
def create_implicit_response(self, code: Optional[AuthorizationCode]) -> dict:
"""Create implicit response's URL Fragment dictionary"""
query_fragment = {}
token = self.provider.create_refresh_token(
user=self.request.user,
scope=self.params.scope,
request=self.request,
)
# Check if response_type must include access_token in the response.
if self.params.response_type in [
ResponseTypes.ID_TOKEN_TOKEN,
ResponseTypes.CODE_ID_TOKEN_TOKEN,
ResponseTypes.ID_TOKEN,
ResponseTypes.CODE_TOKEN,
]:
query_fragment["access_token"] = token.access_token
# We don't need id_token if it's an OAuth2 request.
if SCOPE_OPENID in self.params.scope:
id_token = token.create_id_token(
user=self.request.user,
request=self.request,
)
id_token.nonce = self.params.nonce
# Include at_hash when access_token is being returned.
if "access_token" in query_fragment:
id_token.at_hash = token.at_hash
if self.params.response_type in [
ResponseTypes.CODE_ID_TOKEN,
ResponseTypes.CODE_ID_TOKEN_TOKEN,
]:
id_token.c_hash = code.c_hash
# Check if response_type must include id_token in the response.
if self.params.response_type in [
ResponseTypes.ID_TOKEN,
ResponseTypes.ID_TOKEN_TOKEN,
ResponseTypes.CODE_ID_TOKEN,
ResponseTypes.CODE_ID_TOKEN_TOKEN,
]:
query_fragment["id_token"] = self.provider.encode(id_token.to_dict())
token.id_token = id_token
# Store the token.
token.save()
# Code parameter must be present if it's Hybrid Flow.
if self.params.grant_type == GrantTypes.HYBRID:
query_fragment["code"] = code.code
query_fragment["token_type"] = "bearer" # nosec
query_fragment["expires_in"] = int(
timedelta_from_string(self.provider.access_code_validity).total_seconds()
)
query_fragment["state"] = self.params.state if self.params.state else ""
return query_fragment

View File

@ -2,12 +2,15 @@
from base64 import urlsafe_b64encode
from dataclasses import InitVar, dataclass
from hashlib import sha256
from re import error as RegexError
from re import fullmatch
from typing import Any, Optional
from django.http import HttpRequest, HttpResponse
from django.utils.timezone import datetime, now
from django.views import View
from jwt import InvalidTokenError, decode
from sentry_sdk.hub import Hub
from structlog.stdlib import get_logger
from authentik.core.models import (
@ -94,16 +97,19 @@ class TokenParams:
)
def __check_policy_access(self, app: Application, request: HttpRequest, **kwargs):
engine = PolicyEngine(app, self.user, request)
engine.request.context["oauth_scopes"] = self.scope
engine.request.context["oauth_grant_type"] = self.grant_type
engine.request.context["oauth_code_verifier"] = self.code_verifier
engine.request.context.update(kwargs)
engine.build()
result = engine.result
if not result.passing:
LOGGER.info("User not authenticated for application", user=self.user, app=app)
raise TokenError("invalid_grant")
with Hub.current.start_span(
op="authentik.providers.oauth2.token.policy",
):
engine = PolicyEngine(app, self.user, request)
engine.request.context["oauth_scopes"] = self.scope
engine.request.context["oauth_grant_type"] = self.grant_type
engine.request.context["oauth_code_verifier"] = self.code_verifier
engine.request.context.update(kwargs)
engine.build()
result = engine.result
if not result.passing:
LOGGER.info("User not authenticated for application", user=self.user, app=app)
raise TokenError("invalid_grant")
def __post_init__(self, raw_code: str, raw_token: str, request: HttpRequest):
if self.grant_type in [GRANT_TYPE_AUTHORIZATION_CODE, GRANT_TYPE_REFRESH_TOKEN]:
@ -118,11 +124,20 @@ class TokenParams:
raise TokenError("invalid_client")
if self.grant_type == GRANT_TYPE_AUTHORIZATION_CODE:
self.__post_init_code(raw_code)
with Hub.current.start_span(
op="authentik.providers.oauth2.post.parse.code",
):
self.__post_init_code(raw_code)
elif self.grant_type == GRANT_TYPE_REFRESH_TOKEN:
self.__post_init_refresh(raw_token, request)
with Hub.current.start_span(
op="authentik.providers.oauth2.post.parse.refresh",
):
self.__post_init_refresh(raw_token, request)
elif self.grant_type in [GRANT_TYPE_CLIENT_CREDENTIALS, GRANT_TYPE_PASSWORD]:
self.__post_init_client_credentials(request)
with Hub.current.start_span(
op="authentik.providers.oauth2.post.parse.client_credentials",
):
self.__post_init_client_credentials(request)
else:
LOGGER.warning("Invalid grant type", grant_type=self.grant_type)
raise TokenError("unsupported_grant_type")
@ -133,19 +148,18 @@ class TokenParams:
raise TokenError("invalid_grant")
allowed_redirect_urls = self.provider.redirect_uris.split()
if self.provider.redirect_uris == "*":
LOGGER.warning(
"Provider has wildcard allowed redirect_uri set, allowing all.",
redirect=self.redirect_uri,
)
# At this point, no provider should have a blank redirect_uri, in case they do
# this will check an empty array and raise an error
elif self.redirect_uri not in [x.lower() for x in allowed_redirect_urls]:
LOGGER.warning(
"Invalid redirect uri",
redirect=self.redirect_uri,
expected=self.provider.redirect_uris.split(),
)
try:
if not any(fullmatch(x, self.redirect_uri) for x in allowed_redirect_urls):
LOGGER.warning(
"Invalid redirect uri",
redirect_uri=self.redirect_uri,
excepted=allowed_redirect_urls,
)
raise TokenError("invalid_client")
except RegexError as exc:
LOGGER.warning("Invalid regular expression configured", exc=exc)
raise TokenError("invalid_client")
try:
@ -228,6 +242,11 @@ class TokenParams:
if not token or token.user.uid != user.uid:
raise TokenError("invalid_grant")
self.user = user
# Authorize user access
app = Application.objects.filter(provider=self.provider).first()
if not app or not app.provider:
raise TokenError("invalid_grant")
self.__check_policy_access(app, request)
Event.new(
action=EventAction.LOGIN,
@ -235,13 +254,8 @@ class TokenParams:
PLAN_CONTEXT_METHOD_ARGS={
"identifier": token.identifier,
},
PLAN_CONTEXT_APPLICATION=app,
).from_http(request, user=user)
# Authorize user access
app = Application.objects.filter(provider=self.provider).first()
if not app or not app.provider:
raise TokenError("invalid_grant")
self.__check_policy_access(app, request)
return None
def __post_init_client_credentials_jwt(self, request: HttpRequest):
@ -288,18 +302,7 @@ class TokenParams:
raise TokenError("invalid_grant")
self.__check_policy_access(app, request, oauth_jwt=token)
self.user, _ = User.objects.update_or_create(
username=f"{self.provider.name}-{token.get('sub')}",
defaults={
"attributes": {
USER_ATTRIBUTE_GENERATED: True,
USER_ATTRIBUTE_EXPIRES: token.get("exp"),
},
"last_login": now(),
"name": f"Autogenerated user from application {app.name} (client credentials JWT)",
},
)
self.__create_user_from_jwt(token, app)
Event.new(
action=EventAction.LOGIN,
@ -307,8 +310,26 @@ class TokenParams:
PLAN_CONTEXT_METHOD_ARGS={
"jwt": token,
},
PLAN_CONTEXT_APPLICATION=app,
).from_http(request, user=self.user)
def __create_user_from_jwt(self, token: dict[str, Any], app: Application):
"""Create user from JWT"""
exp = token.get("exp")
self.user, created = User.objects.update_or_create(
username=f"{self.provider.name}-{token.get('sub')}",
defaults={
"attributes": {
USER_ATTRIBUTE_GENERATED: True,
},
"last_login": now(),
"name": f"Autogenerated user from application {app.name} (client credentials JWT)",
},
)
if created and exp:
self.user.attributes[USER_ATTRIBUTE_EXPIRES] = exp
self.user.save()
class TokenView(View):
"""Generate tokens for clients"""
@ -330,27 +351,33 @@ class TokenView(View):
def post(self, request: HttpRequest) -> HttpResponse:
"""Generate tokens for clients"""
try:
client_id, client_secret = extract_client_auth(request)
try:
self.provider = OAuth2Provider.objects.get(client_id=client_id)
except OAuth2Provider.DoesNotExist:
LOGGER.warning("OAuth2Provider does not exist", client_id=client_id)
raise TokenError("invalid_client")
with Hub.current.start_span(
op="authentik.providers.oauth2.post.parse",
):
client_id, client_secret = extract_client_auth(request)
try:
self.provider = OAuth2Provider.objects.get(client_id=client_id)
except OAuth2Provider.DoesNotExist:
LOGGER.warning("OAuth2Provider does not exist", client_id=client_id)
raise TokenError("invalid_client")
if not self.provider:
raise ValueError
self.params = TokenParams.parse(request, self.provider, client_id, client_secret)
if not self.provider:
raise ValueError
self.params = TokenParams.parse(request, self.provider, client_id, client_secret)
if self.params.grant_type == GRANT_TYPE_AUTHORIZATION_CODE:
LOGGER.debug("Converting authorization code to refresh token")
return TokenResponse(self.create_code_response())
if self.params.grant_type == GRANT_TYPE_REFRESH_TOKEN:
LOGGER.debug("Refreshing refresh token")
return TokenResponse(self.create_refresh_response())
if self.params.grant_type == GRANT_TYPE_CLIENT_CREDENTIALS:
LOGGER.debug("Client credentials grant")
return TokenResponse(self.create_client_credentials_response())
raise ValueError(f"Invalid grant_type: {self.params.grant_type}")
with Hub.current.start_span(
op="authentik.providers.oauth2.post.response",
):
if self.params.grant_type == GRANT_TYPE_AUTHORIZATION_CODE:
LOGGER.debug("Converting authorization code to refresh token")
return TokenResponse(self.create_code_response())
if self.params.grant_type == GRANT_TYPE_REFRESH_TOKEN:
LOGGER.debug("Refreshing refresh token")
return TokenResponse(self.create_refresh_response())
if self.params.grant_type == GRANT_TYPE_CLIENT_CREDENTIALS:
LOGGER.debug("Client credentials grant")
return TokenResponse(self.create_client_credentials_response())
raise ValueError(f"Invalid grant_type: {self.params.grant_type}")
except TokenError as error:
return TokenResponse(error.create_dict(), status=400)
except UserAuthError as error:

View File

@ -103,6 +103,7 @@ class ProxyProviderViewSet(UsedByMixin, ModelViewSet):
"redirect_uris": ["iexact"],
"cookie_domain": ["iexact"],
}
search_fields = ["name"]
ordering = ["name"]
@ -166,3 +167,5 @@ class ProxyOutpostConfigViewSet(ReadOnlyModelViewSet):
queryset = ProxyProvider.objects.filter(application__isnull=False)
serializer_class = ProxyOutpostConfigSerializer
ordering = ["name"]
search_fields = ["name"]
filterset_fields = ["name"]

View File

@ -99,6 +99,7 @@ class SAMLProviderViewSet(UsedByMixin, ModelViewSet):
serializer_class = SAMLProviderSerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]
@extend_schema(
responses={
@ -216,4 +217,5 @@ class SAMLPropertyMappingViewSet(UsedByMixin, ModelViewSet):
queryset = SAMLPropertyMapping.objects.all()
serializer_class = SAMLPropertyMappingSerializer
filterset_class = SAMLPropertyMappingFilter
search_fields = ["name"]
ordering = ["name"]

View File

@ -1,4 +1,5 @@
"""SAML Identity Provider Metadata Processor"""
from hashlib import sha256
from typing import Iterator, Optional
import xmlsec # nosec
@ -7,7 +8,6 @@ from django.urls import reverse
from lxml.etree import Element, SubElement, tostring # nosec
from authentik.providers.saml.models import SAMLProvider
from authentik.providers.saml.utils import get_random_id
from authentik.providers.saml.utils.encoding import strip_pem_header
from authentik.sources.saml.processors.constants import (
DIGEST_ALGORITHM_TRANSLATION_MAP,
@ -35,7 +35,7 @@ class MetadataProcessor:
self.provider = provider
self.http_request = request
self.force_binding = None
self.xml_id = get_random_id()
self.xml_id = sha256(f"{provider.name}-{provider.pk}".encode("ascii")).hexdigest()
def get_signing_key_descriptor(self) -> Optional[Element]:
"""Get Signing KeyDescriptor, if enabled for the provider"""

View File

@ -3,6 +3,7 @@ from base64 import b64decode
from dataclasses import dataclass
from typing import Optional
from urllib.parse import quote_plus
from xml.etree.ElementTree import ParseError # nosec
import xmlsec
from defusedxml import ElementTree
@ -175,7 +176,10 @@ class AuthNRequestParser:
)
except xmlsec.Error as exc:
raise CannotHandleAssertion(ERROR_FAILED_TO_VERIFY) from exc
return self._parse_xml(decoded_xml, relay_state)
try:
return self._parse_xml(decoded_xml, relay_state)
except ParseError as exc:
raise CannotHandleAssertion(ERROR_FAILED_TO_VERIFY) from exc
def idp_initiated(self) -> AuthNRequest:
"""Create IdP Initiated AuthNRequest"""

View File

@ -1,10 +1,12 @@
"""Test Service-Provider Metadata Parser"""
# flake8: noqa
from django.test import TestCase
from django.test import RequestFactory, TestCase
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_cert, create_test_flow
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.metadata import MetadataProcessor
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
METADATA_SIMPLE = """<?xml version="1.0"?>
@ -66,6 +68,23 @@ class TestServiceProviderMetadataParser(TestCase):
def setUp(self) -> None:
self.flow = create_test_flow()
self.factory = RequestFactory()
def test_consistent(self):
"""Test that metadata generation is consistent"""
provider = SAMLProvider.objects.create(
name="test",
authorization_flow=self.flow,
)
Application.objects.create(
name="test",
slug="test",
provider=provider,
)
request = self.factory.get("/")
metadata_a = MetadataProcessor(provider, request).build_entity_descriptor()
metadata_b = MetadataProcessor(provider, request).build_entity_descriptor()
self.assertEqual(metadata_a, metadata_b)
def test_simple(self):
"""Test simple metadata without Signing"""

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