Compare commits

..

561 Commits

Author SHA1 Message Date
276d8fe5cf release: 2021.8.4 2021-09-02 20:21:21 +02:00
92ce5f0931 web: improve error display when only {'detail'} is returned
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-02 19:55:37 +02:00
7fea20375f *: fix tests not using APITestCase
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-02 19:14:21 +02:00
d4d4034d2c web: Update Web API Client version (#1336)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-02 17:42:55 +02:00
f0db408699 api: add v3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-02 17:40:02 +02:00
5e200655d9 web: Update Web API Client version (#1335)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-02 17:13:16 +02:00
d5d1f2a645 web: show version in logs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-02 17:10:43 +02:00
cc5cc43baa api: fix sentry endpoint not working due to mime-media
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-02 16:56:53 +02:00
e512f085db root: allow enabling s3 backup ssl verification
closes #1332

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-02 09:41:55 +02:00
f323c01bd8 build(deps): bump django from 3.2.6 to 3.2.7 (#1333) 2021-09-02 09:12:24 +02:00
f56cacb406 build(deps): bump boto3 from 1.18.33 to 1.18.34 (#1334) 2021-09-02 09:12:03 +02:00
eaecd31e9f ci: always run codecov and testspace
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 22:59:51 +02:00
36989d82e1 ci: merge on testspace
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 22:35:17 +02:00
50777d9022 ci: re-add testspace (#1331)
* ci: re-add testspace

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

* ci: fix double k3d

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 22:33:10 +02:00
a15571bd3e outposts/proxy: detect empty authentik_host
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 22:09:07 +02:00
26fd66d831 stages/authenticator_validate: fix variable shadowing, optimization
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 19:54:54 +02:00
0be873025a ci: fix bumpversion path
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 19:38:04 +02:00
28ada49910 website/docs: final 2021.8.4 release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 19:37:00 +02:00
4fc8e61f8c stages/authenticator_validate: show single button for multiple webauthn authenticators
tested with browser + yubikey 5

closes #1096

The order of allowCredentials doesn't seem to matter, chrome seems to always choose the internal authenticator first.

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 19:28:52 +02:00
7d26ea1a9c web/admin: fix list of webauthn devices not updating after rename
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 19:05:18 +02:00
3a58dc62e1 ci: fix missing branch
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 18:34:57 +02:00
71fe7bc827 ci: fix sha being used instead of timestamp
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 17:10:42 +02:00
933336c38b ci: fix images not being pushed with correct tags
* ci: debug

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

* ci: fix branch and sha

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 16:19:29 +02:00
371feb9a31 ci: fix images not being pushed
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 15:07:13 +02:00
95a2fd3c9e web: Update Web API Client version (#1327)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-01 14:48:48 +02:00
17cb76c334 stages/invitation: fix invitation not inheriting ExpiringModel
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 14:25:19 +02:00
88f0dfc8cc web/admin: fallback for invitation list on first load
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 13:33:05 +02:00
f82aada23b web/admin: fix flow executor not opening in new tab
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-01 13:19:09 +02:00
ecaee92634 build(deps): bump @sentry/tracing from 6.11.0 to 6.12.0 in /web (#1322)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 6.11.0 to 6.12.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/6.11.0...6.12.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-01 09:26:53 +02:00
89252ec47b build(deps): bump @sentry/tracing from 6.11.0 to 6.12.0 in /website (#1320)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 6.11.0 to 6.12.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/6.11.0...6.12.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-01 09:26:33 +02:00
f0f25ab291 build(deps): bump @sentry/react from 6.11.0 to 6.12.0 in /website (#1321) 2021-09-01 08:40:07 +02:00
e4d0fec15a build(deps): bump @sentry/browser from 6.11.0 to 6.12.0 in /web (#1323) 2021-09-01 08:39:56 +02:00
6b10baf086 build(deps): bump docker from 5.0.0 to 5.0.1 (#1324) 2021-09-01 08:39:21 +02:00
f148b5d341 build(deps): bump boto3 from 1.18.32 to 1.18.33 (#1326) 2021-09-01 08:39:12 +02:00
1471ff8940 build(deps): bump drf-spectacular from 0.18.0 to 0.18.1 (#1325) 2021-09-01 08:39:01 +02:00
d9a6ec2ac0 webiste/docs: update extensionvs/v1beta ingress
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-31 21:11:01 +02:00
5745ffa0a8 ci: don't login to docker on forks
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-31 09:31:10 +02:00
b26202db35 build(deps): bump @typescript-eslint/parser in /web (#1316) 2021-08-31 08:42:14 +02:00
6318577a51 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1317) 2021-08-31 08:16:59 +02:00
6a2cd45847 build(deps-dev): bump pytest from 6.2.4 to 6.2.5 (#1318) 2021-08-31 08:16:44 +02:00
ef5cea2c01 build(deps): bump boto3 from 1.18.31 to 1.18.32 (#1319) 2021-08-31 08:16:32 +02:00
69f4d54bae ci: migrate ci to gh actions (#1315) 2021-08-30 20:21:15 +02:00
b1eec5a7d2 outposts/proxy: add more logging
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-30 17:18:52 +02:00
1b8271d767 flows: disable compatibility_mode by default
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-30 17:18:43 +02:00
3e9f5ec5ef providers/proxy: improve error handling for non-tls ingresses
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-30 14:43:57 +02:00
63f57b6a77 events: improve logging for task exceptions
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-30 14:43:44 +02:00
a016f99450 core: fix user_obj being empty on token API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-30 12:51:17 +02:00
adc18b2991 build(deps): bump boto3 from 1.18.30 to 1.18.31 (#1314)
Bumps [boto3](https://github.com/boto/boto3) from 1.18.30 to 1.18.31.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.18.30...1.18.31)

---
updated-dependencies:
- dependency-name: boto3
  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>
2021-08-30 09:12:58 +02:00
e37a326b95 website/docs: prepare 8.4 docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 22:12:49 +02:00
048467e97d outpost/ldap: delay user information removal upon closing of connection
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 21:13:46 +02:00
cc2cd6919f outpost/embedded: only send requests for non-akprox paths when we're doing proxy mode
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 21:13:28 +02:00
0c6e781e5b providers/proxy: fix traefik middleware being generated with wrong ports for embedded outposts
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 20:49:11 +02:00
7294d8fca5 website/docs: add note for cross-namespace reference in traefik
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 20:46:17 +02:00
16ec5680b4 web: Update Web API Client version (#1313)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-29 19:51:10 +02:00
87920fb1d7 website/docs: add docs for websocket connections
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 19:49:18 +02:00
523b96a6d2 api: add basic rate limiting for sentry endpoint
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 19:33:18 +02:00
45731d8069 cmd: add option to disable embedded outpost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 19:19:13 +02:00
e872371970 website/docs: add embedded outpost docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 14:43:13 +02:00
08e8cf850a web/flows: fix FlowExecutor not updating when challenge changes from outside
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 13:49:57 +02:00
b1ed2154ac policies/password: fix PasswordStage not being usable with prompt stages, rework validation logic
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-29 00:40:36 +02:00
7ef2aa3eb9 web: Update Web API Client version (#1312) 2021-08-28 19:08:38 +02:00
160139813d release: 2021.8.3 2021-08-28 16:58:44 +02:00
582ad92c76 outposts/k8s: improve error handling
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-28 14:58:26 +02:00
f61736e3d1 stages/identification: add error handling when password isn't set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-28 12:54:10 +02:00
eb02c96281 website/docs: make it clearer to use context[]
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-28 12:53:57 +02:00
8619552920 website/docs: prepare 2021.8.3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 23:12:53 +02:00
6237352e25 web/flows: fix checkboxes not being rendered correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 23:09:53 +02:00
2d8b4f543b providers/proxy: fix url parsing for traefik labels on docker containers
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 22:21:16 +02:00
8542dc10ab providers/proxy: fix docker container labels not being inherited correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 20:20:34 +02:00
c55b63337c web/flows: fix post-challenge updates not always being called by using setter
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 19:45:23 +02:00
12ddee3bb6 outpost: add additional labels to docker container
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 19:26:27 +02:00
dc41d0af27 outposts: add configurable docker_network for outpost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 19:26:11 +02:00
3323b50036 web/flows: also check for redirects as result of posting challenge
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 10:08:15 +02:00
8acb15a7fd outpost: fix flow executor not sending password for identification stage
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 09:43:07 +02:00
f601e04b38 web/flows: assign location from redirect challenge in request handler not render
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-27 09:43:00 +02:00
f50529cb5b build(deps): bump @docusaurus/preset-classic in /website (#1307)
Bumps [@docusaurus/preset-classic](https://github.com/facebook/docusaurus/tree/HEAD/packages/docusaurus-preset-classic) from 2.0.0-beta.4 to 2.0.0-beta.5.
- [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.5/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>
2021-08-27 09:20:09 +02:00
3f1b6f9ed4 build(deps): bump typescript from 4.3.5 to 4.4.2 in /web (#1306) 2021-08-27 08:36:43 +02:00
f1ab0f4314 build(deps): bump @patternfly/patternfly from 4.125.3 to 4.132.2 in /web (#1308) 2021-08-27 08:36:34 +02:00
4d1129f385 build(deps): bump boto3 from 1.18.29 to 1.18.30 (#1310) 2021-08-27 08:36:19 +02:00
03ac9c6e16 build(deps): bump @docusaurus/plugin-client-redirects in /website (#1309) 2021-08-27 08:36:11 +02:00
c0839924f1 build(deps): bump github.com/go-openapi/runtime from 0.19.30 to 0.19.31 (#1311) 2021-08-27 08:35:57 +02:00
91e3aa760a web: Update Web API Client version (#1305)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-26 19:06:13 +02:00
5c0681d57b website/docs: add 2021.8.2 docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-26 18:56:42 +02:00
c4f72c2bc1 release: 2021.8.2 2021-08-26 17:58:20 +02:00
e92f9836e3 root: allow django auth backend for upgrading users with cache
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-26 17:57:25 +02:00
3818dc834b web: Update Web API Client version (#1304)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-26 16:57:12 +02:00
cda011a049 website/docs: add 2021.8.1 release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-26 16:06:27 +02:00
897f6f3473 release: 2021.8.1 2021-08-26 16:03:45 +02:00
b70b44490b root: Require PG_PASS to be set (#1303)
This raises an error when PG_PASS is not set.

docker-compose recently changed the way .env files are searched for (see
for example https://github.com/docker/compose/issues/8347) and with the
current setup, authentik will not work anyway without a password set.
2021-08-26 10:24:35 +02:00
77a5a58cb9 root: Fix table of contents for CONTRIBUTING.md (#1302) 2021-08-26 10:08:07 +02:00
f3b227434e web: Update Web API Client version (#1301)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-26 10:06:46 +02:00
2ae164df78 *: cleanup api schema warnings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-26 09:36:41 +02:00
9b09793230 build(deps): bump drf-spectacular from 0.17.3 to 0.18.0 (#1299) 2021-08-26 08:54:59 +02:00
f8a401aeca build(deps): bump boto3 from 1.18.28 to 1.18.29 (#1300) 2021-08-26 08:53:56 +02:00
ffbab2cd68 outpost/ldap: set request_id in sentry
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-25 22:36:08 +02:00
734e5fcab4 web: Update Web API Client version (#1298)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-25 21:52:32 +02:00
78578c6c9d web/admin: allow admins to create tokens
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-25 21:23:32 +02:00
0ccec96490 core: make user optional in token creation
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-25 21:21:51 +02:00
8022d0801d web/elements: add support for datetime-local
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-25 21:14:32 +02:00
d79975c409 core: fix user object for token not be setable
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-25 20:43:34 +02:00
20d65035d5 core: fix error when user updates themselves
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-25 17:52:50 +02:00
8d6227377f core: fix error for asgi error handler with websockets
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-25 10:24:01 +02:00
4bc50e7f57 build(deps): bump boto3 from 1.18.27 to 1.18.28 (#1296) 2021-08-25 08:35:12 +02:00
945e42c940 web: Update Web API Client version (#1295) 2021-08-24 22:35:08 +02:00
052bb28086 ci: only generate NPM API package on master
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 21:44:47 +02:00
4a84b7e2d5 web: Update Web API Client version (#1294)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-24 21:32:29 +02:00
4d27694706 release: 2021.8.1-rc2 2021-08-24 21:29:29 +02:00
16cfa8cae2 web/admin: add ServiceAccount creation form
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 20:13:08 +02:00
1a20c8ffc1 web: Update Web API Client version (#1293)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-24 20:12:46 +02:00
d7ad5f6a16 core: add API to create service account with token for app password
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 20:09:22 +02:00
5af9a3d3be sources/saml: fix error when getting metadata
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 16:51:08 +02:00
dec34bc948 stages/password: fix replace_inbuilt not being called
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 16:37:39 +02:00
cff37caa57 web: Update Web API Client version (#1292) 2021-08-24 14:32:33 +02:00
cc6d5765f2 web/admin: fix inconsistent ordering for ldap property mappings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 13:04:19 +02:00
2ec1ff2ebb sources/ldap: fix error when modifying ldap source with password write-back
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 13:03:41 +02:00
884c2bd0e9 root: fix missing ldap backend
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 13:03:19 +02:00
2c938ec9dc stages/password: sort backends in migration
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 12:44:45 +02:00
9733caf3b7 admin: use copy for environ api
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 11:39:49 +02:00
494af0a430 web: Update Web API Client version (#1291)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-24 11:01:51 +02:00
10e50bc77f stages/user_login: improve logging
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 10:58:50 +02:00
44bfbb9e49 Merge branch 'master' into next 2021-08-24 10:58:27 +02:00
5be152e12d stages/password: fix migration error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 10:57:20 +02:00
b0efab6d6d admin: add env to API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 10:55:46 +02:00
f2725b88c8 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1289) 2021-08-24 10:33:59 +02:00
24cc123029 build(deps): bump @typescript-eslint/parser in /web (#1288) 2021-08-24 10:16:49 +02:00
d75c9997f6 build(deps): bump boto3 from 1.18.26 to 1.18.27 (#1290) 2021-08-24 10:16:41 +02:00
0a20a30af3 ci: remove zeus.ci :(
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-24 00:07:02 +02:00
c60ba91fee core: fix auth saving entire models into session
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 23:59:43 +02:00
37927c9361 web: Update Web API Client version (#1287)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-23 22:06:25 +02:00
0a63441935 website/docs: update release notes 2021.8
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 21:24:53 +02:00
6b7a8b6ac7 core: add new token intent and auth backend (#1284)
* core: add new token intent and auth backend

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

* root: update schema

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

* web/admin: allow users to create app password tokens

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

* web/admin: display token's intents

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

* stages/password: auto-enable app password backend

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

* web/admin: fix missing app passwords backend

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

* core: use custom inbuilt backend, set backend login information in flow plan for events

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

* website/docs: add docs for `auth_method` and `auth_method_args` fields

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

* website: fix example flows using incorrect backend

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

* root: add alias for akflow files

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

* core: fix token intent not defaulting correctly

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

* website: update akflows orders

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

* web/admin: improve delete modal for stage bindings and policy bindings

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

* events: fix linting

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

* website: make default login-2fa flow ignore 2fa with app passwords

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

* web/admin: select all password stage backends by default

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

* root: fix mis-matched postgres version for CI

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

* web: fix lint error

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

* core: fix authentication error when no request is given

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

* ci: set debug log level

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

* stages/user_write: fix wrong fallback authentication backend

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

* core: add token tests for invalid intent and token auth

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 21:21:39 +02:00
cba255eaaa Merge branch 'master' into app-passwords
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	authentik/core/tests/test_source_flow_manager.py
#	authentik/stages/authenticator_validate/tests.py
#	authentik/stages/password/tests.py
#	scripts/generate_ci_config.py
2021-08-23 21:21:12 +02:00
859cf2bd8f lib: move id and key generators to lib (#1286)
* lib: move generators to lib

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

* core: bump default token key size

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

* *: fix split being used for http basic auth instead of partition

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

* web/elements: don't rethrow error in ActionButton

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 20:27:38 +02:00
a2578ffaad core: add token tests for invalid intent and token auth
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 20:21:54 +02:00
888526a2a7 stages/user_write: fix wrong fallback authentication backend
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 19:31:23 +02:00
0d00b9cc0d ci: set debug log level
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 19:14:24 +02:00
27cc5d7138 core: fix authentication error when no request is given
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 19:09:53 +02:00
b2f077645a web: fix lint error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 18:38:35 +02:00
2878597603 root: fix mis-matched postgres version for CI
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 18:25:31 +02:00
5face5410f web/admin: select all password stage backends by default
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 18:08:29 +02:00
1b8750e13b website: make default login-2fa flow ignore 2fa with app passwords
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:50:42 +02:00
e27a6fdeeb events: fix linting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:48:28 +02:00
a9af40f85c web/admin: improve delete modal for stage bindings and policy bindings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:46:51 +02:00
59f04963be website: update akflows orders
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:39:19 +02:00
033c9a3bd3 core: fix token intent not defaulting correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:33:35 +02:00
09e3d616e9 root: add alias for akflow files
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:29:12 +02:00
0b280c0a47 website: fix example flows using incorrect backend
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:26:07 +02:00
07a4f474f4 website/docs: add docs for auth_method and auth_method_args fields
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:23:55 +02:00
244dc671db Merge branch 'master' into app-passwords 2021-08-23 17:12:17 +02:00
4308136108 root: fix error_handler for websocket
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:12:11 +02:00
69a0153619 core: use custom inbuilt backend, set backend login information in flow plan for events
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 17:09:53 +02:00
2655768f5a Merge branch 'master' into app-passwords 2021-08-23 16:48:43 +02:00
73c55b56a0 ci: update commit message for web api update
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 16:48:28 +02:00
bcbdd6c26f web: Update Web API Client version (#1283)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-08-23 16:47:56 +02:00
00e9b91f56 web/admin: fix missing app passwords backend
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 16:47:38 +02:00
4cf76fdcda stages/password: auto-enable app password backend
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 16:39:39 +02:00
c4832206fa web/admin: display token's intents
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 16:33:12 +02:00
d05562a388 Merge branch 'master' into app-passwords 2021-08-23 16:28:25 +02:00
f217d34a98 web/admin: allow users to create app password tokens
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 16:27:39 +02:00
89f2967f69 ci: only run npm client push on master and version branches
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 16:21:27 +02:00
9a6a3e66b8 root: update schema
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 16:14:33 +02:00
2f4b18ebbd web: fix license for API Client
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 16:12:31 +02:00
20572c728d core: add new token intent and auth backend
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 16:05:29 +02:00
aad753de68 ci: fix extraction of generated client
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:57:56 +02:00
a79a150a1f root: test schema auto-update
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:55:26 +02:00
8b23e4701a ci: upgrade web api client when schema changes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:54:58 +02:00
a366d61891 root: add License to NPM package
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:41:49 +02:00
9a13dfd63a website/docs: update release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:40:15 +02:00
32d80829e2 web/admin: show system status first
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:25:35 +02:00
f6953296d8 outposts: add recursion limit for docker controller
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:25:28 +02:00
e4790f9060 core: handle error when ?for_user is not numberical
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:25:18 +02:00
58712047e1 root: add ASGI Error handler
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:15:12 +02:00
85915905dc web/flows: fix error during error handling
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 15:11:30 +02:00
52f2838f57 lifecycle: rename to ak
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 14:54:02 +02:00
12e2f7b945 outposts: add repair_permissions command
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 14:53:53 +02:00
45d47f828a outpost: handle non-existant permission
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 14:39:47 +02:00
cf7eb88661 web: add custom readme to api client
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 12:00:35 +02:00
6a14ae7975 web: Merge pull request #1258 from goauthentik/publish-api-to-npm
Publish api to npm
2021-08-23 11:43:25 +02:00
08f3294a1d web: add ESM to generated Client
https://github.com/OpenAPITools/openapi-generator/issues/8881
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 11:11:18 +02:00
ac47fc9295 web: use custom client for web linting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 10:36:32 +02:00
1ff19e1467 web: fix formatting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 10:33:45 +02:00
439454a71b website: add docs for making schema changes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 10:32:37 +02:00
2a11964e1a Merge branch 'master' into publish-api-to-npm 2021-08-23 10:16:35 +02:00
507b8d43fb root: remove remainders from gen
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 10:16:24 +02:00
7efec281be build(deps-dev): bump pylint from 2.9.6 to 2.10.2 (#1280)
* build(deps-dev): bump pylint from 2.9.6 to 2.10.2

Bumps [pylint](https://github.com/PyCQA/pylint) from 2.9.6 to 2.10.2.
- [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.9.6...v2.10.2)

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

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

* *: add missing encoding to open() calls

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>
2021-08-23 10:10:31 +02:00
9469f86f65 web: improve api client versioning
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 10:09:56 +02:00
e998919097 web: fix build not working
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 10:02:39 +02:00
450d69a1a4 web: build. api in different folder
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-23 09:49:09 +02:00
b74681f22c Merge branch 'master' into publish-api-to-npm
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	web/package-lock.json
#	web/src/pages/sources/oauth/OAuthSourceForm.ts
2021-08-23 09:40:52 +02:00
f95a7c26e5 build(deps): bump github.com/go-openapi/strfmt from 0.20.1 to 0.20.2 (#1281)
Bumps [github.com/go-openapi/strfmt](https://github.com/go-openapi/strfmt) from 0.20.1 to 0.20.2.
- [Release notes](https://github.com/go-openapi/strfmt/releases)
- [Commits](https://github.com/go-openapi/strfmt/compare/v0.20.1...v0.20.2)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-23 07:44:28 +02:00
ffc9bd2cec build(deps): bump boto3 from 1.18.25 to 1.18.26 (#1282) 2021-08-23 07:06:16 +02:00
bb7db0c828 build(deps): bump codemirror from 5.62.2 to 5.62.3 in /web (#1279) 2021-08-23 07:06:04 +02:00
aec3e08201 Merge branch 'version-2021.8' into next 2021-08-22 21:57:14 +02:00
0651fbba06 website/docs: add 2021.8 to sidebar
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-22 20:19:23 +02:00
7639cdad0a release: 2021.8.1-rc1 2021-08-22 20:17:35 +02:00
6533f48912 web: add topMost attribute to ak-loading-overlay to force it over codemirror
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 19:26:06 +02:00
2024dac39a web: lock overflow when showing loading overlay on modals
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 19:19:23 +02:00
33d5cd2973 web: add notice for Certificate for LDAP Provider
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 18:48:02 +02:00
b003e8e1e8 sources/oauth: fix openidconnect provider name
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 18:36:06 +02:00
294d70ae4d outposts/ldap: move virtual groups to other OU for lookups, conditionally skip requests based on search filter
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 17:53:09 +02:00
23fd257624 outposts/ldap: fix nil pointer dereference when search self
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 16:51:47 +02:00
3e909ae6bb core: allow filtering users by the groups they are in
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 16:27:48 +02:00
ff24bc8cb8 outpost/ldap: regularly pre-heat flow executor cache to increase bind performance
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 16:17:30 +02:00
ecf35cfd1d web: fix mis-matched oauth source icon names
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 16:10:03 +02:00
673520c9f8 web: fix OAuthSource not setting providerType
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 16:08:50 +02:00
b4f738492d sources/oauth: improve UI with prefilled urls (when customizable) and hiding provider type
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 15:52:41 +02:00
00a666856d web: expand parent FormGroup when containing element has error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 15:24:31 +02:00
bff7addb55 stages/password: adjust name of default prompt stage
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 15:16:18 +02:00
2a90c0b35e sources/oauth2: migrate to microsoft graph instead of azure graph
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 15:15:29 +02:00
93e27d1959 web: improve failed request handling
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 14:40:45 +02:00
02c736d784 lib: ignore installation specific errors
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 14:14:18 +02:00
2015d91484 outpost: load global config
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 14:14:18 +02:00
6433b5982e api: add cache timeouts to config API for outposts
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-21 14:14:18 +02:00
f0bc90738f build(deps): bump actions/github-script from 4.0.2 to 4.1 (#1276) 2021-08-20 08:42:54 +02:00
970a4baf49 build(deps): bump boto3 from 1.18.24 to 1.18.25 (#1277) 2021-08-20 08:42:42 +02:00
5fbefef56f build(deps): bump chart.js from 3.5.0 to 3.5.1 in /web (#1274) 2021-08-19 08:37:12 +02:00
1110038eb0 build(deps): bump boto3 from 1.18.23 to 1.18.24 (#1275) 2021-08-19 08:36:43 +02:00
e945c250db ci: make zeus optional
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-18 10:33:25 +02:00
b46d08cc97 build(deps): bump boto3 from 1.18.22 to 1.18.23 (#1273) 2021-08-18 09:59:17 +02:00
18eccd995d sources/plex: fix linting error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-17 13:44:54 +02:00
6f06ba06d0 website/docs: fixed a typo and pronounce problem (#1271) 2021-08-17 13:29:25 +02:00
495b068be5 web: add plex connection deletion support
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-17 13:02:40 +02:00
84c4547005 sources/plex: add API for user connections
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-17 13:02:40 +02:00
065121d280 build(deps): bump @typescript-eslint/parser in /web (#1267) 2021-08-17 09:58:35 +02:00
8c943e187b build(deps): bump golang from 1.16.7 to 1.17.0 (#1265) 2021-08-17 09:04:49 +02:00
ee54a8b33d build(deps): bump @typescript-eslint/eslint-plugin in /web (#1266) 2021-08-17 09:04:27 +02:00
373d94635f build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.0 to 3.4.1 (#1268) 2021-08-17 09:04:19 +02:00
31422c6836 build(deps): bump kubernetes from 17.17.0 to 18.20.0 (#1269) 2021-08-17 09:04:05 +02:00
bca59a2b5a build(deps): bump boto3 from 1.18.21 to 1.18.22 (#1270) 2021-08-17 09:03:17 +02:00
4ff3bc59b7 website/docs: Fixed two typos in Wordpress integration (#1264)
* Create index.mdx

Add Wekan example

* updated to include wekan entry

* Update and rename website/docs/sources.md to website/docs/sources/index.md

Break Sources into individual pages.

* Update and rename website/docs/sources/index.md to website/docs/sources/ldap/index.md

* Create index.md

* Update index.md

* Update index.md

* Create index.md

* Create index.md

* Create index.md

* Update index.md

* Update index.md

* Update index.md

* Create index.md

* discord images

* spacing

* Added discord

* discord changes

* Added sources breakdown to the sidebar

* Fixed the saml title

* Added github examples

* fixed formatting

* Changed file path, updated sidebar, added google.

* fixed a spelling mistake

* Cleaned up formatting

* Fixed Notes

* docs: fix typo in logout url

* docs: added wordpress integration

* docs: fixed two typos for wordpress
2021-08-16 17:31:33 +02:00
bd9cd086a0 Merge branch 'master' into publish-api-to-npm 2021-08-16 17:29:36 +02:00
a6b1ee949d web: fix mis-matched height of application cards
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-16 11:33:12 +02:00
f93e2c5eb6 website/docs: Add Wordpress to Integrations (#1259)
* Create index.mdx

Add Wekan example

* updated to include wekan entry

* Update and rename website/docs/sources.md to website/docs/sources/index.md

Break Sources into individual pages.

* Update and rename website/docs/sources/index.md to website/docs/sources/ldap/index.md

* Create index.md

* Update index.md

* Update index.md

* Create index.md

* Create index.md

* Create index.md

* Update index.md

* Update index.md

* Update index.md

* Create index.md

* discord images

* spacing

* Added discord

* discord changes

* Added sources breakdown to the sidebar

* Fixed the saml title

* Added github examples

* fixed formatting

* Changed file path, updated sidebar, added google.

* fixed a spelling mistake

* Cleaned up formatting

* Fixed Notes

* docs: fix typo in logout url

* docs: added wordpress integration
2021-08-16 10:33:53 +02:00
8fe38b528b outposts: fix managed check
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-16 09:36:01 +02:00
38dbde191c build(deps): bump github.com/go-ldap/ldap/v3 from 3.3.0 to 3.4.0 (#1262)
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.3.0...v3.4.0)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/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>
2021-08-16 09:28:14 +02:00
39434053b9 build(deps): bump boto3 from 1.18.20 to 1.18.21 (#1263)
Bumps [boto3](https://github.com/boto/boto3) from 1.18.20 to 1.18.21.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.18.20...1.18.21)

---
updated-dependencies:
- dependency-name: boto3
  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>
2021-08-16 09:28:03 +02:00
5bdc1a3ddc build(deps): bump uvicorn from 0.14.0 to 0.15.0 (#1261)
Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.14.0 to 0.15.0.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.14.0...0.15.0)

---
updated-dependencies:
- dependency-name: uvicorn
  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>
2021-08-16 09:27:47 +02:00
14fb0c3d61 web: cleanup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 22:18:03 +02:00
c52afe5952 Merge branch 'master' into publish-api-to-npm 2021-08-15 21:40:11 +02:00
36e6d5e394 website/docs: fix image reference typo
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 21:39:24 +02:00
1d4b941a3b web: migrate to @goauthentik/api
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 21:32:28 +02:00
0344e5d9b3 root: remove usage of make-gen
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 21:32:17 +02:00
d8e8cc062b ci: add pipeline to build and push js api package
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 21:32:06 +02:00
0a6efab7cb outposts: fix syntax
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 20:59:37 +02:00
c8dc299ae3 website/docs: Add Portainer to Integrations Providers docs (#1256)
* Create index.mdx

Add Wekan example

* updated to include wekan entry

* Update and rename website/docs/sources.md to website/docs/sources/index.md

Break Sources into individual pages.

* Update and rename website/docs/sources/index.md to website/docs/sources/ldap/index.md

* Create index.md

* Update index.md

* Update index.md

* Create index.md

* Create index.md

* Create index.md

* Update index.md

* Update index.md

* Update index.md

* Create index.md

* discord images

* spacing

* Added discord

* discord changes

* Added sources breakdown to the sidebar

* Fixed the saml title

* Added github examples

* fixed formatting

* Changed file path, updated sidebar, added google.

* fixed a spelling mistake

* Cleaned up formatting

* Fixed Notes

* Added Bookstack to the intergrations

* Fixed a typo with formatting

* Added a line break for Advanced protocol settings

* Added Vikunja to integration providers docs

* web: update tsconfig

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

* Add Portainer to integration provider docs

Co-authored-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 20:58:52 +02:00
700c66f312 web/library: Updated applications card display (#1257) 2021-08-15 20:19:50 +02:00
04861b1b00 web: update package-lock
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 18:14:37 +02:00
06badf88b2 web: fix missing import
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 18:14:02 +02:00
67ab4305ad website/developer-docs: simplify .env file
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 18:13:25 +02:00
b35e62e5ae outposts: don't start docker container for embedded outpost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 18:10:49 +02:00
051016f613 web: fix missing app description
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 18:09:48 +02:00
295f0fe730 Revert "build(deps): bump construct-style-sheets-polyfill in /web (#1252)"
This reverts commit 0d5a7f9b44.
2021-08-15 18:05:52 +02:00
54b7ef42f5 outpost/ldap: add sAMAccountName on groups for compatibility
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 15:59:24 +02:00
669b5db8e5 web: update tsconfig
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-15 11:27:48 +02:00
4882de6ade website/developer-docs: add note for node16 and npm i for api
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-14 22:09:45 +02:00
95ceabe1ba website/docs: Forward authentication proxy and Grafana considerations (#1254)
* docs: Updated forward authentication proxy nginx buffer config, grafana oauth integration considerations

* docs: Cover edge-case when default grafana org id is not 1
2021-08-14 22:05:23 +02:00
769a3424dc web/elements: fix unchecking all elements not unchecking select-all
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-14 21:38:05 +02:00
47070261b0 web/elements: fix select all not working in tables
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-14 21:34:11 +02:00
0d5a7f9b44 build(deps): bump construct-style-sheets-polyfill in /web (#1252) 2021-08-13 09:23:12 +02:00
07ceaa20f3 build(deps): bump boto3 from 1.18.19 to 1.18.20 (#1253) 2021-08-13 09:22:26 +02:00
d1403f6f7d web: implement bulk-delete form
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-12 23:21:29 +02:00
9430a2eea2 web/elements: add bulk delete form
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-12 21:42:52 +02:00
2592fc3826 sources/ldap: allow for anonymous binds, fix sync_users_password not working correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-12 19:09:29 +02:00
d9ece98bbc core: fix token expiration not being updated upon key rotation
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-12 17:22:42 +02:00
1524efcf51 core: fix expired tokens not being returned by API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-12 17:21:53 +02:00
8cceacb33f website: fix typo in example flow
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-12 17:16:39 +02:00
3b13f322de build(deps): bump tslib from 2.3.0 to 2.3.1 in /web (#1250) 2021-08-12 09:34:12 +02:00
a570189c73 build(deps): bump boto3 from 1.18.18 to 1.18.19 (#1251) 2021-08-12 09:34:04 +02:00
c92c0102ca website/docs: add database port parameter
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-12 02:24:36 +02:00
c6dddc97f0 core: fix error when migrating with AK_ADMIN_TOKEN set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 22:36:52 +02:00
38292a588b website/docs: add docs for automated installs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 21:57:58 +02:00
01e54cb986 website/docs: update compose install
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 21:53:20 +02:00
e90da9283e core: add support to bootstrap token on initial install using AK_ADMIN_TOKEN in environment
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 21:45:49 +02:00
e0e0f4fa6c core: fix users's group list not allowing blank values
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 20:16:45 +02:00
90426802fd website/docs: update 2021.8 release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 19:54:03 +02:00
8b28039c1b web: re-add sentry error dialog
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 19:53:52 +02:00
cdf57d7eea web/elements: add support for dot-notation in input names
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 19:48:19 +02:00
b237f2ddfb web/elements: fix loading overlay not being removed on error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 17:44:09 +02:00
784a3efaa5 web: fix websocket connecting double
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 16:53:47 +02:00
9e0c4e7e08 web/admin: fix version API being called too much
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 16:46:23 +02:00
7e62b82d56 outpost/embedded: fix login URL not being set correctly from outpost config
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 12:39:27 +02:00
c079f9e339 build(deps): bump rollup from 2.56.1 to 2.56.2 in /web (#1247) 2021-08-11 09:15:43 +02:00
72d42249e2 build(deps): bump boto3 from 1.18.17 to 1.18.18 (#1248) 2021-08-11 09:15:34 +02:00
f9e826d553 web: improve loading indication for modals
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-11 00:00:07 +02:00
0f5e0a774a web/admin: fix ScopeMapping requiring description
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 23:33:27 +02:00
34fe250fb0 web/elements: fix resetForm is not a function
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 23:22:25 +02:00
92990b4ded web/elements: properly cleanup event handlers
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 23:22:13 +02:00
9e2f165dd8 web: update tsconfig
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 23:21:59 +02:00
88891c99bc web/admin: fix drawers being openable via tab focus
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 22:50:03 +02:00
93de363c86 website/developer-docs: add notice for translation requirements
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 21:42:59 +02:00
7db3be604c web/admin: allow modification of users groups from user view
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 21:27:41 +02:00
ec95a2bddc core: allow changing of groups a user is in from user api
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 19:31:30 +02:00
de9d483b9f admin: add API to show embedded outpost status, add notice when its not configured properly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 19:16:11 +02:00
0c9c3153b5 tests/e2e: fix LDAP provider tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 14:10:06 +02:00
557724768a core: add API to directly send recovery link to user
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 13:54:59 +02:00
68608087ec web: fix class for propertymapping test button
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 12:46:50 +02:00
3118365118 Merge branch 'master' into next 2021-08-10 12:45:40 +02:00
1f821521c6 outposts/ldap: add sAMAccountName field for compatibility
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 12:45:29 +02:00
281a460960 providers/ldap: fix error in outpost when certificate is configured
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-10 12:45:29 +02:00
0e131e6b2f build(deps): bump @typescript-eslint/parser in /web (#1243) 2021-08-10 10:34:16 +02:00
ca9e632b57 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1244) 2021-08-10 09:45:48 +02:00
184aa25513 build(deps): bump boto3 from 1.18.16 to 1.18.17 (#1245) 2021-08-10 09:45:38 +02:00
80df444067 outposts/ldap: add sAMAccountName field for compatibility
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-09 21:00:02 +02:00
d18e829d80 providers/ldap: fix error in outpost when certificate is configured
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-09 20:47:26 +02:00
c5dfe189f7 build(deps): bump @sentry/tracing from 6.10.0 to 6.11.0 in /web (#1237)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 6.10.0 to 6.11.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/6.10.0...6.11.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-09 10:17:42 +02:00
29f6f1d54f build(deps): bump @sentry/tracing from 6.10.0 to 6.11.0 in /website (#1238)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 6.10.0 to 6.11.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/6.10.0...6.11.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-09 09:53:16 +02:00
e952bd671f build(deps): bump @sentry/browser from 6.10.0 to 6.11.0 in /web (#1239)
Bumps [@sentry/browser](https://github.com/getsentry/sentry-javascript) from 6.10.0 to 6.11.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/6.10.0...6.11.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-09 09:53:03 +02:00
421c7df536 build(deps): bump rollup from 2.56.0 to 2.56.1 in /web (#1236) 2021-08-09 09:03:23 +02:00
f322198020 build(deps): bump @sentry/react from 6.10.0 to 6.11.0 in /website (#1240) 2021-08-09 09:02:53 +02:00
c392aa607d build(deps): bump boto3 from 1.18.15 to 1.18.16 (#1241) 2021-08-09 09:02:43 +02:00
4e368d1e8d build(deps): bump github.com/go-openapi/runtime from 0.19.29 to 0.19.30 (#1242) 2021-08-09 09:02:29 +02:00
229468175a lifecycle: fix error in gunicorn config
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-09 01:07:50 +02:00
e1f7421c6a web: fix error from trying to clone the request
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-09 00:38:43 +02:00
7a836e0d7e api: fix backup capability not being detected correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-09 00:32:29 +02:00
5b57d67b5f cmd: improve error message for local config loading
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-09 00:28:08 +02:00
4cd3466e56 root: ignore known warnings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-09 00:27:29 +02:00
f496b8b5d7 providers/oauth2: add more test cases for token view
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-09 00:20:32 +02:00
3d5eebda3b Merge branch 'next' 2021-08-09 00:12:04 +02:00
a26e5f3b17 website/docs: Add Vikunja Instructions to Integrations as Provider (#1235)
* Create index.mdx

Add Wekan example

* updated to include wekan entry

* Update and rename website/docs/sources.md to website/docs/sources/index.md

Break Sources into individual pages.

* Update and rename website/docs/sources/index.md to website/docs/sources/ldap/index.md

* Create index.md

* Update index.md

* Update index.md

* Create index.md

* Create index.md

* Create index.md

* Update index.md

* Update index.md

* Update index.md

* Create index.md

* discord images

* spacing

* Added discord

* discord changes

* Added sources breakdown to the sidebar

* Fixed the saml title

* Added github examples

* fixed formatting

* Changed file path, updated sidebar, added google.

* fixed a spelling mistake

* Cleaned up formatting

* Fixed Notes

* Added Bookstack to the intergrations

* Fixed a typo with formatting

* Added a line break for Advanced protocol settings

* Added Vikunja to integration providers docs
2021-08-09 00:11:48 +02:00
fe91bff854 outpost/embedded: fix schema
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 23:09:35 +02:00
03958d170b outpost/proxy: fix string substitution for internal
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 22:24:10 +02:00
837fa23af0 outpost: only set embedded outpost config on creation
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 22:23:33 +02:00
665c1aa81b providers/proxy: don't create ingress when no hosts are defined
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 21:46:05 +02:00
ebc6afe015 outpost: fix detection of embedded outpost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 21:39:08 +02:00
45bee4b4dc outposts: fix test for config validation
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 17:14:05 +02:00
c025d64ba3 outpost: revert managed config, make authentik_host field optional
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 16:58:01 +02:00
a9ef1a3190 web/admin: link build hash when set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 16:57:27 +02:00
2a53bc4330 outpost: add fallback for authentik_host when its not set in config
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 16:32:26 +02:00
8180d6f9e8 outposts: don't override authentik_host for embedded outpost authentik_host
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 16:29:33 +02:00
ccfc1dbcc2 *: make all PropertyMappings filterable by multiple managed attributes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 16:06:44 +02:00
16f0f89a9d outpost/embedded: fix embedded outpost redirecting to localhost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 15:39:52 +02:00
c5976de500 web/admin: fix UI inconsistency
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 15:18:32 +02:00
1781ab59ba web/admin: fix requests on API Drawer vanishing when the drawer is closed
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 15:17:06 +02:00
3367b83368 providers/saml: use idp-initiated sso flow as launch url
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 15:01:52 +02:00
f21bb319d0 web/admin: fix Outpost's detailed health not being shown in columns
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 14:04:50 +02:00
f0a8c30ce9 outposts: create different service when using embedded outpost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 14:01:39 +02:00
571049219f web: fix API Drawer not opening in new tab by default
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 13:39:39 +02:00
260f0b8710 web: fix width for ViewPages
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-08 13:19:13 +02:00
787f5a1e96 website/docs: prepare next release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 22:38:26 +02:00
b36a3100e6 outposts: allow empty provider list for embedded provider
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 22:32:44 +02:00
e02207f38d outpost/embedded: use redis session backend
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 22:12:22 +02:00
3eafa4711e web: fix lint errors
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 21:43:04 +02:00
9a8240bdd1 proviers/saml: fix validation error not being raised
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 21:39:30 +02:00
f6ab241219 providers/oauth2: fix accessing undefined variable
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 21:35:17 +02:00
ff579fd387 web: update default flow background for 2021.8
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 21:32:40 +02:00
1693118df7 web/admin: cleanup display of outpost health
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 21:11:28 +02:00
b0f09eb2c4 web/admin: fix Table not updating selectedElements correctly after update
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 20:53:28 +02:00
9c9addb0ce *: ensure all resources can be filtered
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-07 16:34:14 +02:00
decb91e5f1 build(deps): bump boto3 from 1.18.14 to 1.18.15 (#1233) 2021-08-06 09:00:10 +02:00
b39339409a build(deps): bump golang from 1.16.6 to 1.16.7 (#1231) 2021-08-06 08:59:59 +02:00
0d75ce45c3 build(deps): bump actions/setup-node from 2.3.2 to 2.4.0 (#1232) 2021-08-06 08:59:50 +02:00
8801e39e65 build(deps): bump @patternfly/patternfly from 4.115.2 to 4.125.3 in /web (#1230) 2021-08-06 08:59:41 +02:00
0faa91c1fe build(deps): bump rollup from 2.55.1 to 2.56.0 in /web (#1229) 2021-08-06 08:59:33 +02:00
2d5094fdf7 root: fix formatting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-06 00:11:24 +02:00
8044818a4d core: add additional cleanup for authenticated sessions
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 23:25:40 +02:00
9703e32c1b web: migrate gallery to grid
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 23:13:55 +02:00
f28bfdaeb9 web: fix minor styling issues
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 22:04:45 +02:00
fdd8e66b91 web: add API Drawer
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 22:04:31 +02:00
562eb8af95 website/docs: remove traefik and fix compose port
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 20:24:47 +02:00
a43fb026a0 Merge branch 'version-2021.7'
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	authentik/core/api/users.py
#	authentik/providers/saml/processors/metadata_parser.py
#	web/src/pages/sources/oauth/OAuthSourceForm.ts
#	web/src/pages/sources/plex/PlexSourceForm.ts
#	web/src/pages/users/UserForm.ts
2021-08-05 20:23:32 +02:00
29b88d0e5c website/docs: add 2021.7.3 changelog
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 19:26:25 +02:00
18211a2033 release: 2021.7.3 2021-08-05 19:23:03 +02:00
48c980e8e7 website/docs: add Bookstack Integration Instructions (#1228)
* Create index.mdx

Add Wekan example

* updated to include wekan entry

* Update and rename website/docs/sources.md to website/docs/sources/index.md

Break Sources into individual pages.

* Update and rename website/docs/sources/index.md to website/docs/sources/ldap/index.md

* Create index.md

* Update index.md

* Update index.md

* Create index.md

* Create index.md

* Create index.md

* Update index.md

* Update index.md

* Update index.md

* Create index.md

* discord images

* spacing

* Added discord

* discord changes

* Added sources breakdown to the sidebar

* Fixed the saml title

* Added github examples

* fixed formatting

* Changed file path, updated sidebar, added google.

* fixed a spelling mistake

* Cleaned up formatting

* Fixed Notes

* Added Bookstack to the intergrations

* Fixed a typo with formatting

* Added a line break for Advanced protocol settings
2021-08-05 17:17:19 +00:00
b4cfc56e5e web/admin: fix source form's userMatchingMode being swapped
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	web/src/pages/sources/oauth/OAuthSourceForm.ts
#	web/src/pages/sources/plex/PlexSourceForm.ts
2021-08-05 18:48:02 +02:00
667ccbe00e web/admin: fix source form's userMatchingMode being swapped
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 18:45:24 +02:00
6af2c6a014 outpost/ldap: fix errors with new UserSelf serializer
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 18:20:24 +02:00
8e797fa76b outpost/ldap: fix errors with new UserSelf serializer
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 18:16:06 +02:00
1b91543add core: add UserSelfSerializer and separate method for users to update themselves with limited fields
rework user settings page to better use form
closes #1227

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

# Conflicts:
#	authentik/core/api/users.py
#	web/src/elements/forms/ModelForm.ts
#	web/src/pages/user-settings/UserDetailsPage.ts
#	web/src/pages/user-settings/UserSettingsPage.ts
2021-08-05 17:47:45 +02:00
1cd59be8dc web/admin: fix email being required
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	web/src/pages/user-settings/UserDetailsPage.ts
#	web/src/pages/users/UserForm.ts
2021-08-05 17:46:28 +02:00
6fe5175f21 core: add UserSelfSerializer and separate method for users to update themselves with limited fields
rework user settings page to better use form
closes #1227

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 17:42:19 +02:00
90775d5122 web/admin: fix email being required
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 14:50:32 +02:00
e52390aa28 web: fix alignment issues in application list page
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 14:14:39 +02:00
fea493f3a0 web/admin: fix table width for policies for bound stages
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 13:47:23 +02:00
5803575ee2 web/admin: fix launch button on app list
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 13:47:13 +02:00
1a17ce24f9 web: use single delete button with checkbox and icon-based action buttons
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 12:30:43 +02:00
ddd5047cc3 web: better label table actions
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 10:40:44 +02:00
919946609d web/elements: add separate flag for chips when checkboxes are enabled
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 10:16:13 +02:00
d861a0cec9 web/elements: fix select-all not selecting previously unselected rows
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 10:15:03 +02:00
6ea83edd9f web: disable showReportDialog
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 09:57:58 +02:00
66bb68a747 lifecycle: decrease default worker count on compose
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 09:44:58 +02:00
13a8ad3126 lifecycle: decrease default worker count on compose
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-05 09:37:14 +02:00
e83465517b build(deps): bump @babel/plugin-transform-runtime in /web (#1221)
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.14.5 to 7.15.0.
- [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.15.0/packages/babel-plugin-transform-runtime)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-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>
2021-08-05 09:30:02 +02:00
bc23197643 build(deps): bump @babel/preset-typescript from 7.14.5 to 7.15.0 in /web (#1223)
Bumps [@babel/preset-typescript](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-typescript) from 7.14.5 to 7.15.0.
- [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.15.0/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>
2021-08-05 09:29:46 +02:00
f887c257f8 build(deps): bump boto3 from 1.18.13 to 1.18.14 (#1226) 2021-08-05 08:35:26 +02:00
1d4017d94a build(deps): bump @babel/core from 7.14.8 to 7.15.0 in /web (#1225) 2021-08-05 08:35:17 +02:00
8f9e8bb9dd build(deps): bump actions/setup-node from 2.3.1 to 2.3.2 (#1224) 2021-08-05 08:35:07 +02:00
ded9060af2 build(deps): bump @babel/preset-env from 7.14.9 to 7.15.0 in /web (#1222) 2021-08-05 08:34:45 +02:00
579697b978 build(deps): bump @fortawesome/fontawesome-free in /web (#1220) 2021-08-05 08:34:35 +02:00
200391c533 build(deps): bump actions/setup-node from 2.3.0 to 2.3.1 (#1217) 2021-08-04 08:48:09 +02:00
5384a06cb5 build(deps): bump boto3 from 1.18.12 to 1.18.13 (#1218) 2021-08-04 08:47:59 +02:00
aa4f7fb2b6 providers/saml: fix error when PropertyMapping return value isn't string
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-04 00:22:07 +02:00
4f1c11c5ef providers/saml: add WantAssertionsSigned
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	authentik/providers/saml/processors/metadata_parser.py
2021-08-04 00:21:54 +02:00
04486d65dc web: fully re-label service connection to integration
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-04 00:18:15 +02:00
a449f9c69b providers/saml: fix error when PropertyMapping return value isn't string
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-03 22:40:56 +02:00
36b346662c providers/saml: add WantAssertionsSigned
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-03 22:40:13 +02:00
9d392931df root: fix lint errors from re-format
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-03 18:09:16 +02:00
2c60ec50be web: re-format with prettier
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-03 17:52:21 +02:00
77ed25ae34 root: reformat to 100 line width
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-03 17:45:16 +02:00
b87903a209 build(deps): bump @typescript-eslint/parser in /web (#1211)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 4.28.5 to 4.29.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.29.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>
2021-08-03 09:43:09 +02:00
87a418de25 build(deps): bump @webcomponents/webcomponentsjs in /web (#1212)
Bumps [@webcomponents/webcomponentsjs](https://github.com/webcomponents/polyfills/tree/HEAD/packages/webcomponentsjs) from 2.5.0 to 2.6.0.
- [Release notes](https://github.com/webcomponents/polyfills/releases)
- [Changelog](https://github.com/webcomponents/polyfills/blob/master/packages/webcomponentsjs/CHANGELOG.md)
- [Commits](https://github.com/webcomponents/polyfills/commits/@webcomponents/webcomponentsjs@2.6.0/packages/webcomponentsjs)

---
updated-dependencies:
- dependency-name: "@webcomponents/webcomponentsjs"
  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>
2021-08-03 09:23:25 +02:00
683d10fa70 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1213)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.28.5 to 4.29.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.29.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>
2021-08-03 09:23:14 +02:00
8e84d74634 build(deps): bump boto3 from 1.18.11 to 1.18.12 (#1214)
Bumps [boto3](https://github.com/boto/boto3) from 1.18.11 to 1.18.12.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.18.11...1.18.12)

---
updated-dependencies:
- dependency-name: boto3
  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>
2021-08-03 09:23:05 +02:00
d783c632ad build(deps): bump django from 3.2.5 to 3.2.6 (#1215)
Bumps [django](https://github.com/django/django) from 3.2.5 to 3.2.6.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/commits)

---
updated-dependencies:
- dependency-name: django
  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>
2021-08-03 09:22:52 +02:00
756f3dbedc web: add centered icon
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-02 19:43:46 +02:00
eff2e3aeb0 root: fix readme
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-02 19:42:58 +02:00
fb3e302f44 root: update readme
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-02 12:47:28 +02:00
24d2c94e7c website/docs: fix "new application" typo (#1210) 2021-08-02 08:27:07 +00:00
400adaa282 build(deps): bump @babel/preset-env from 7.14.8 to 7.14.9 in /web (#1207) 2021-08-02 08:38:01 +02:00
6d67ad8451 build(deps): bump eslint from 7.31.0 to 7.32.0 in /web (#1206) 2021-08-02 08:37:50 +02:00
7ad1656369 build(deps): bump @rollup/plugin-typescript from 8.2.4 to 8.2.5 in /web (#1208) 2021-08-02 08:37:41 +02:00
79b1b21931 build(deps): bump boto3 from 1.18.10 to 1.18.11 (#1209) 2021-08-02 08:37:28 +02:00
9c9bcb7a01 Merge branch 'version-2021.7' 2021-08-01 19:23:22 +02:00
add7a80fdc release: 2021.7.2 2021-08-01 19:11:50 +02:00
aac91c2e9d stages/email: handle OSError
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 18:25:53 +02:00
85e86351cd flows: fix flows not redirecting correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 18:25:53 +02:00
75fec19079 website/docs: add note for nginx header size
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 18:22:50 +02:00
a939e224fc stages/email: handle OSError
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 17:53:13 +02:00
1fc2bcf02b flows: fix flows not redirecting correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 17:50:43 +02:00
b7bfb93928 website/docs: update 2021.7.2 changelog again
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 15:24:59 +02:00
d767504474 flows: don't check redirect URL when set from flow plan (set from authentik or policy)
closes #1203

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 15:23:46 +02:00
f84cd6208c flows: fix unhandled error in stage execution not being logged as SYSTEM_EXCEPTION event
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 15:23:46 +02:00
1ec540ea9a providers/saml: fix metadata being inaccessible without authentication
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 15:23:46 +02:00
4e5dba1d0b flows: don't check redirect URL when set from flow plan (set from authentik or policy)
closes #1203

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 15:10:45 +02:00
92a448b677 flows: fix unhandled error in stage execution not being logged as SYSTEM_EXCEPTION event
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 14:56:48 +02:00
f875149983 providers/saml: fix metadata being inaccessible without authentication
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 14:50:17 +02:00
29fe731bbf providers/saml: fix Error when getting metadata for invalid ID
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 14:09:22 +02:00
d70b81fe43 providers/saml: fix Error when getting metadata for invalid ID
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 13:50:54 +02:00
a64dbc94c1 website/docs: update 2021.7.2
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 13:24:04 +02:00
26e66969c9 stages/invitation: delete invite only after full enrollment flow is completed
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 13:22:02 +02:00
fe629f8b51 web/admin: fix empty column when no invitation expiry was set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 13:22:02 +02:00
b58c913618 stages/invitation: delete invite only after full enrollment flow is completed
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 13:21:27 +02:00
9665e33156 website/docs: add note for invitation via prompt
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 13:07:50 +02:00
96d7a5a27f web/admin: fix empty column when no invitation expiry was set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:44:10 +02:00
05aefefb61 website/docs: add category for old releases
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:43:59 +02:00
f5dc8c045e website/docs: prepare 2021.7.2
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:37:56 +02:00
72b7642c5a outposts: catch invalid ServiceConnection error in outpost controller
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:33:21 +02:00
a97f842112 sources/plex: add background task to monitor validity of plex token
closes #1205

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:33:21 +02:00
16e6e4c3b7 web/admin: add re-authenticate button for plex
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#1205
2021-08-01 12:33:21 +02:00
dc0d715885 web/admin: add UI to copy invitation link
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:33:20 +02:00
7ecd57ecff outpost: bump timer for periodic config reloads
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:33:20 +02:00
1e1f17aceb website/docs: add example Email template
closes #1204

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:32:13 +02:00
35c1476bbe outposts: catch invalid ServiceConnection error in outpost controller
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:25:11 +02:00
18bb4fd0bf sources/plex: add background task to monitor validity of plex token
closes #1205

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 12:24:52 +02:00
ac77291b6d web/admin: add re-authenticate button for plex
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#1205
2021-08-01 11:47:39 +02:00
5571aa32b6 web/admin: add UI to copy invitation link
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-08-01 11:47:22 +02:00
66c3535bcb outpost: bump timer for periodic config reloads
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-31 21:57:33 +02:00
293c479364 outposts: ensure embedded outpost is created with integration selected
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-31 21:09:38 +02:00
f9382b8458 web/admin: fix embedded outpost showing version
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-31 14:59:16 +02:00
c9fe28dad7 website/docs: add usage for invitation stage
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-31 14:14:10 +02:00
8bb57a1283 web/admin: re-name service connection to integration
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-31 13:48:26 +02:00
55a5300bd2 website/docs: add notice for psql password length
closes #1184

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-30 09:52:18 +02:00
0cb4d64b57 stages/email: fix error when re-requesting email after token has expired
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-30 09:39:42 +02:00
a4fd58a0db events: ensure fallback result is set for on_failure
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-30 09:39:42 +02:00
8ceef82c55 stages/email: fix error when re-requesting email after token has expired
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-30 09:39:24 +02:00
f933cd99ad events: ensure fallback result is set for on_failure
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-30 09:37:53 +02:00
e5b63377a0 build(deps): bump boto3 from 1.18.9 to 1.18.10 (#1202) 2021-07-30 09:07:12 +02:00
6c81a1929d build(deps): bump @rollup/plugin-typescript from 8.2.3 to 8.2.4 in /web (#1201) 2021-07-30 09:07:03 +02:00
e5269306df build(deps): bump rollup from 2.55.0 to 2.55.1 in /web (#1200) 2021-07-30 09:06:53 +02:00
fb6e8ca1eb events: remove default result for MonitoredTasks, only save when result was set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 22:43:29 +02:00
7ac5091e5a events: remove default result for MonitoredTasks, only save when result was set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 22:42:56 +02:00
bc9ff792a8 outposts: manage config for embedded outpost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 22:29:38 +02:00
4c41948e75 e2e: fix broken selenium by locking images
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 21:53:09 +02:00
a5c8caf909 providers/oauth2: fix error when requesting jwks keys with no rs256 aet
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 21:22:59 +02:00
970655ab21 ci: fix sentry sourcemap path
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 21:22:52 +02:00
8495ff9fc0 providers/oauth2: fix error when requesting jwks keys with no rs256 aet
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 21:22:31 +02:00
309cd90c43 ci: fix sentry sourcemap path
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 21:06:40 +02:00
acbc0ee5cc Revert "tests: re-add firefox e2e tests"
This reverts commit a60f6e426f.
2021-07-29 19:45:12 +02:00
a60f6e426f tests: re-add firefox e2e tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 18:52:59 +02:00
6fd86aa357 e2e: fix broken selenium by locking images
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 18:49:08 +02:00
f1e32b989d Revert "tests: add firefox e2e tests"
This reverts commit 5693a794b4.
2021-07-29 18:02:46 +02:00
6aebbec270 Revert "tests/e2e: remove chrome requirement"
This reverts commit b86fd7b716.
2021-07-29 18:02:42 +02:00
b86fd7b716 tests/e2e: remove chrome requirement
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 15:24:54 +02:00
5693a794b4 tests: add firefox e2e tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 15:07:13 +02:00
c8c7202c61 web/admin: fix LDAP Provider bind flow list being empty
closes #1192

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 11:35:54 +02:00
a3981dd3cd providers/proxy: fix hosts for ingress not being compared correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 11:35:50 +02:00
affafc31cf sources/ldap: improve ms-ad password complexity checking
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 11:35:47 +02:00
602aed674b web/admin: fully remove response cloning due to errors
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 11:35:44 +02:00
f01bc20d44 Embedded outpost (#1193)
* api: allow API requests as managed outpost's account when using secret_key

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

* root: load secret key from env

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

* outposts: make listener IP configurable

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

* outpost/proxy: run outpost in background and pass requests conditionally

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

* outpost: unify branding to embedded

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

* web/admin: fix embedded outpost not being editable

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

* web: fix mismatched host detection

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

* tests/e2e: fix LDAP test not including user for embedded outpost

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

* tests/e2e: fix user matching

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

* api: add tests for secret_key auth

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

* root: load environment variables using github.com/Netflix/go-env

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-29 11:30:30 +02:00
1b03aae7aa build(deps): bump @docusaurus/preset-classic in /website (#1196)
Bumps [@docusaurus/preset-classic](https://github.com/facebook/docusaurus/tree/HEAD/packages/docusaurus-preset-classic) from 2.0.0-beta.3 to 2.0.0-beta.4.
- [Release notes](https://github.com/facebook/docusaurus/releases)
- [Changelog](https://github.com/facebook/docusaurus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/docusaurus/commits/v2.0.0-beta.4/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>
2021-07-29 09:28:59 +02:00
7eb97cd2bc build(deps): bump twisted from 20.3.0 to 21.7.0 (#1198)
Bumps [twisted](https://github.com/twisted/twisted) from 20.3.0 to 21.7.0.
- [Release notes](https://github.com/twisted/twisted/releases)
- [Changelog](https://github.com/twisted/twisted/blob/trunk/NEWS.rst)
- [Commits](https://github.com/twisted/twisted/compare/twisted-20.3.0...twisted-21.7.0)

---
updated-dependencies:
- dependency-name: twisted
  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>
2021-07-29 09:22:44 +02:00
8aaec3b149 build(deps): bump boto3 from 1.18.8 to 1.18.9 (#1199)
Bumps [boto3](https://github.com/boto/boto3) from 1.18.8 to 1.18.9.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.18.8...1.18.9)

---
updated-dependencies:
- dependency-name: boto3
  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>
2021-07-29 09:22:31 +02:00
4c9b49e7a6 build(deps-dev): bump pylint from 2.9.5 to 2.9.6 (#1197)
Bumps [pylint](https://github.com/PyCQA/pylint) from 2.9.5 to 2.9.6.
- [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.9.5...v2.9.6)

---
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>
2021-07-29 09:22:23 +02:00
903d1ecc6e build(deps): bump @docusaurus/plugin-client-redirects in /website (#1195)
Bumps [@docusaurus/plugin-client-redirects](https://github.com/facebook/docusaurus/tree/HEAD/packages/docusaurus-plugin-client-redirects) from 2.0.0-beta.3 to 2.0.0-beta.4.
- [Release notes](https://github.com/facebook/docusaurus/releases)
- [Changelog](https://github.com/facebook/docusaurus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/docusaurus/commits/v2.0.0-beta.4/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>
2021-07-29 09:22:08 +02:00
f2197d63f1 build(deps): bump rollup from 2.54.0 to 2.55.0 in /web (#1194)
Bumps [rollup](https://github.com/rollup/rollup) from 2.54.0 to 2.55.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.54.0...v2.55.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>
2021-07-29 09:21:53 +02:00
9c0f7e0018 web/admin: fix LDAP Provider bind flow list being empty
closes #1192

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-28 21:01:10 +02:00
75ff2480e2 providers/proxy: fix hosts for ingress not being compared correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-28 16:08:06 +02:00
bc7f84fff4 sources/ldap: improve ms-ad password complexity checking
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-28 12:47:52 +02:00
1b638adf89 web/admin: fully remove response cloning due to errors
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-28 12:26:50 +02:00
7eebc40e00 ci: add codeql 2021-07-28 09:58:13 +02:00
33ddccf066 build(deps): bump boto3 from 1.18.7 to 1.18.8 (#1190) 2021-07-28 09:22:36 +02:00
efc8452e72 build(deps): bump sentry-sdk from 1.3.0 to 1.3.1 (#1191) 2021-07-28 09:22:26 +02:00
e6b515e3f7 release: 2021.7.1 2021-07-27 10:35:45 +02:00
36eaecfdec build(deps): bump drf-spectacular from 0.17.2 to 0.17.3 (#1188)
Bumps [drf-spectacular](https://github.com/tfranzel/drf-spectacular) from 0.17.2 to 0.17.3.
- [Release notes](https://github.com/tfranzel/drf-spectacular/releases)
- [Changelog](https://github.com/tfranzel/drf-spectacular/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tfranzel/drf-spectacular/compare/0.17.2...0.17.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-27 09:27:06 +02:00
3973efae19 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1185)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.28.4 to 4.28.5.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.28.5/packages/eslint-plugin)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-27 09:26:58 +02:00
d8492e0df5 build(deps): bump @typescript-eslint/parser in /web (#1186) 2021-07-27 08:47:31 +02:00
b64da0dd28 build(deps): bump boto3 from 1.18.6 to 1.18.7 (#1187) 2021-07-27 08:46:56 +02:00
c3ae3e02f3 website/docs: add go requirement
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-26 22:52:58 +02:00
7c6a96394b root: add code of conduct and PR template
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-26 22:49:17 +02:00
0fe43f8319 root: add contributing file
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-26 22:42:00 +02:00
7e32723748 website/docs: update terminology for dark mode
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-26 21:50:49 +02:00
577aa7ba79 web/admin: add status card for https and timedrift
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-26 19:58:26 +02:00
b752540800 core: fix pagination not working correctly with applications API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-26 19:12:23 +02:00
64c8ca9b5d web/admin: default to authentication flow for LDAP provider
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-26 18:47:59 +02:00
5552e0ffa7 web/admin: add notice for event_retention
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-26 18:47:46 +02:00
e7b7bfddd6 providers/oauth2: fix blank redirect_uri not working with TokenView
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-26 11:29:16 +02:00
28f970c795 build(deps): bump boto3 from 1.18.5 to 1.18.6 (#1183) 2021-07-26 08:40:05 +02:00
d1dbdfa9fe build(deps): bump chart.js from 3.4.1 to 3.5.0 in /web (#1182) 2021-07-26 08:39:57 +02:00
c4f4e3eac7 build(deps): bump rollup from 2.53.3 to 2.54.0 in /web (#1181) 2021-07-26 08:39:49 +02:00
f21ebf5488 core: add tests for flow_manager
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-25 23:20:38 +02:00
5615613ed1 core: fix CheckApplication's for_user flag not being checked correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-25 22:29:15 +02:00
669329e49c tenants: set tenant uuid in sentry
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-25 22:28:09 +02:00
0587ab26e8 web/admin: fix ApplicationView's CheckAccess not sending UserID correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-25 21:03:32 +02:00
3c9cc9d421 Merge branch 'version-2021.7' 2021-07-24 20:07:42 +02:00
1972464a20 tenants: make event retention configurable on tenant level
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-24 20:07:12 +02:00
3041a30193 release: 2021.7.1-rc2 2021-07-24 18:32:05 +02:00
1e28a1e311 ci: fix relative path for sourcemaps
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-24 17:25:37 +02:00
5a1b912b76 web: fix lint error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 22:42:45 +02:00
464c27ef17 web: improve UI for event actions
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 22:27:51 +02:00
a745022f06 website/docs: prepare 2021.7.1-rc2
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 21:30:15 +02:00
0b34f70205 web/admin: fix missing dark theme for notifications
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 21:27:56 +02:00
a4b051fcc1 web: fix icon flashing in header, fix notification header icon in dark mode
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 20:57:06 +02:00
5ff3e9b418 outposts/ldap: add support for member query
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 20:00:23 +02:00
8ae7403abc core: add group filter by member username and pk
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 19:35:41 +02:00
f6e1bfdfc8 outpost: fix 100% CPU Usage when not connected to websocket
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 18:57:26 +02:00
aca3a5c458 outpost: add tracing for http client
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 17:37:06 +02:00
d16c24fd53 website/docs: clear up outpost uuids
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 16:07:47 +02:00
6a8be0dc71 outposts/ldap: improve parsing of LDAP filters
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-23 15:41:09 +02:00
81b9b37e5e build(deps): bump @sentry/tracing from 6.9.0 to 6.10.0 in /web (#1174)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 6.9.0 to 6.10.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/6.9.0...6.10.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-23 10:11:16 +02:00
22b01962fb build(deps): bump @sentry/tracing from 6.9.0 to 6.10.0 in /website (#1175)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 6.9.0 to 6.10.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/6.9.0...6.10.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-23 10:11:05 +02:00
86cc99be35 build(deps): bump @sentry/react from 6.9.0 to 6.10.0 in /website (#1176) 2021-07-23 09:05:26 +02:00
416f917c4a build(deps): bump @sentry/browser from 6.9.0 to 6.10.0 in /web (#1177) 2021-07-23 09:05:04 +02:00
f77bece790 build(deps): bump boto3 from 1.18.4 to 1.18.5 (#1178) 2021-07-23 09:04:50 +02:00
a8dd846437 Revert "root: fix root dir for coverage"
This reverts commit 4c50769040.
2021-07-22 23:52:58 +02:00
4c50769040 root: fix root dir for coverage
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 23:15:52 +02:00
34189fcc06 outposts/ldap: search users and group in parallel
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 22:55:23 +02:00
fb5c8f3d7f ci: attempt to load variable group
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 22:18:58 +02:00
049a55a761 ci: add zeus
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 21:34:17 +02:00
4cd53f3d11 ci: remove unused variables
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 21:05:55 +02:00
0d0dcf8de0 outposts/ldap: optimise backend Search API requests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 20:38:30 +02:00
8cd1223081 core: add email filter for user
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 20:10:42 +02:00
1b4654bb1d outposts/ldap: add tracing for LDAP bind and search
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 19:23:56 +02:00
0a3fade1fd providers/proxy: remove deprecated field
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 16:20:26 +02:00
ff64814f40 web/admin: improve UI for notification toggle
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 14:17:56 +02:00
cbeb6e58ac web: separate websocket connection from messages
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 13:47:27 +02:00
285a9b8b1d website/docs: remove duplicate proxy docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 10:48:10 +02:00
66bfa6879d outposts/proxy: add X-Auth-Groups header to pass groups
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 10:47:58 +02:00
c05240afbf lib: fix outpost fake-ip not working, add tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 10:10:25 +02:00
7370dd5f3f outposts: ensure outpost SAs always have permissions to fake IP
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 10:02:20 +02:00
477c8b099e build(deps-dev): bump pylint from 2.9.4 to 2.9.5 (#1173) 2021-07-22 09:32:24 +02:00
2c761da883 build(deps): bump boto3 from 1.18.3 to 1.18.4 (#1172) 2021-07-22 09:32:16 +02:00
75070232b1 build(deps): bump codemirror from 5.62.1 to 5.62.2 in /web (#1170) 2021-07-22 09:32:08 +02:00
690b35e1a3 build(deps): bump postcss from 8.3.5 to 8.3.6 in /website (#1169) 2021-07-22 09:31:59 +02:00
bd67f2362f build(deps): bump rollup from 2.53.2 to 2.53.3 in /web (#1171) 2021-07-22 09:31:43 +02:00
896e5adce2 sources/ldap: fix lint
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 00:40:55 +02:00
7f25b6311d web/admin: fix negative count for policies when more cached than total policies
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-22 00:01:28 +02:00
253f345fc4 outposts: save certificate fingerprint and check before re-fetching to cleanup logs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-21 23:53:43 +02:00
a3abbcec6a sources/ldap: improve error handling for property mappings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-21 23:49:09 +02:00
70e000d327 providers/saml: improve error handling for property mappings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-21 23:14:03 +02:00
a7467e6740 providers/oauth2: handler PropertyMapping exceptions and create event
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-21 22:51:39 +02:00
b3da94bbb8 core: broaden error catching for propertymappings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-21 22:50:39 +02:00
e62f5a75e4 outposts: fix git hash not being set in outposts
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-07-21 21:31:25 +02:00
750 changed files with 28488 additions and 19035 deletions

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 2021.7.1-rc1
current_version = 2021.8.4
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*)
@ -23,7 +23,7 @@ values =
[bumpversion:file:schema.yml]
[bumpversion:file:.github/workflows/release.yml]
[bumpversion:file:.github/workflows/release-publish.yml]
[bumpversion:file:authentik/__init__.py]

19
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,19 @@
<!--
👋 Hello there! Welcome.
Please check the [Contributing guidelines](https://github.com/goauthentik/authentik/blob/master/CONTRIBUTING.md#how-can-i-contribute).
-->
# Details
* **Does this resolve an issue?**
Resolves #
## Changes
### New Features
* Adds feature which does x, y, and z.
### Breaking Changes
* Adds breaking change which causes \<issue\>.
## Additional
Any further notes or comments you want to make.

240
.github/workflows/ci-main.yml vendored Normal file
View File

@ -0,0 +1,240 @@
name: authentik-ci-main
on:
push:
paths-ignore:
- website
env:
POSTGRES_DB: authentik
POSTGRES_USER: authentik
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
jobs:
lint-pylint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: prepare
run: scripts/ci_prepare.sh
- name: run pylint
run: pipenv run pylint authentik tests lifecycle
lint-black:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: prepare
run: scripts/ci_prepare.sh
- name: run black
run: pipenv run black --check authentik tests lifecycle
lint-isort:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: prepare
run: scripts/ci_prepare.sh
- name: run isort
run: pipenv run isort --check authentik tests lifecycle
lint-bandit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: prepare
run: scripts/ci_prepare.sh
- name: run bandit
run: pipenv run bandit -r authentik tests lifecycle
lint-pyright:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- uses: actions/setup-node@v2
with:
node-version: '16'
- name: prepare
run: |
scripts/ci_prepare.sh
npm install -g pyright@1.1.136
- name: run bandit
run: pipenv run pyright e2e lifecycle
test-migrations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: prepare
run: scripts/ci_prepare.sh
- name: run migrations
run: pipenv run python -m lifecycle.migrate
test-migrations-from-stable:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: checkout stable
run: |
# Copy current, latest config to local
cp authentik/lib/default.yml local.env.yml
git checkout $(git describe --abbrev=0 --match 'version/*')
- name: prepare
run: scripts/ci_prepare.sh
- name: run migrations to stable
run: pipenv run python -m lifecycle.migrate
- name: checkout current code
run: |
set -x
git checkout $GITHUB_REF
pipenv sync --dev
- name: migrate to latest
run: pipenv run python -m lifecycle.migrate
test-unittest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: prepare
run: scripts/ci_prepare.sh
- uses: testspace-com/setup-testspace@v1
with:
domain: ${{github.repository_owner}}
- name: run unittest
run: |
pipenv run make test
pipenv run coverage xml
- name: run testspace
if: ${{ always() }}
run: |
testspace unittest.xml ?add
- if: ${{ always() }}
uses: codecov/codecov-action@v2
test-integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: prepare
run: scripts/ci_prepare.sh
- uses: testspace-com/setup-testspace@v1
with:
domain: ${{github.repository_owner}}
- name: prepare k3d
run: |
wget -q -O - https://raw.githubusercontent.com/rancher/k3d/main/install.sh | bash
- name: run integration
run: |
pipenv run make test-integration
pipenv run coverage xml
- name: run testspace
if: ${{ always() }}
run: |
testspace unittest.xml ?add
- if: ${{ always() }}
uses: codecov/codecov-action@v2
test-e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- uses: actions/setup-node@v2
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- uses: testspace-com/setup-testspace@v1
with:
domain: ${{github.repository_owner}}
- name: prepare
run: |
scripts/ci_prepare.sh
docker-compose -f tests/e2e/ci.docker-compose.yml up -d
- name: prepare web ui
run: |
cd web
npm i
npm run build
- name: run e2e
run: |
pipenv run make test-e2e
pipenv run coverage xml
- name: run testspace
if: ${{ always() }}
run: |
testspace unittest.xml ?add
- if: ${{ always() }}
uses: codecov/codecov-action@v2
report:
if: ${{ always() }}
needs:
- test-unittest
- test-integration
- test-e2e
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: testspace-com/setup-testspace@v1
with:
domain: ${{github.repository_owner}}
- name: finish testspace
run: |
testspace ?finish
build:
needs:
- lint-pylint
- lint-black
- lint-isort
- lint-bandit
- lint-pyright
- test-migrations
- test-migrations-from-stable
- test-unittest
- test-integration
- test-e2e
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: prepare variables
id: ev
run: |
python ./scripts/gh_do_set_branch.py
- name: Login to Container Registry
uses: docker/login-action@v1
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
with:
registry: beryju.org
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Building Docker Image
uses: docker/build-push-action@v2
with:
push: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
tags: |
beryju.org/authentik/server:gh-${{ steps.ev.outputs.branchName }}
beryju.org/authentik/server:gh-${{ steps.ev.outputs.branchName }}-${{ steps.ev.outputs.timestamp }}
build-args: |
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}

66
.github/workflows/ci-outpost.yml vendored Normal file
View File

@ -0,0 +1,66 @@
name: authentik-ci-outpost
on:
push:
jobs:
lint-golint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '^1.16.3'
- name: Generate API
run: |
make gen-outpost
- name: Run linter
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.39.0 \
golangci-lint run -v --timeout 200s
build:
needs:
- lint-golint
strategy:
matrix:
type:
- proxy
- ldap
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1.2.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: prepare variables
id: ev
run: |
python ./scripts/gh_do_set_branch.py
- name: Login to Container Registry
uses: docker/login-action@v1
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
with:
registry: beryju.org
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Building Docker Image
uses: docker/build-push-action@v2
with:
push: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
tags: |
beryju.org/authentik/outpost-${{ matrix.type }}:gh-${{ steps.ev.outputs.branchName }}
beryju.org/authentik/outpost-${{ matrix.type }}:gh-${{ steps.ev.outputs.branchName }}-${{ steps.ev.outputs.timestamp }}
beryju.org/authentik/outpost-${{ matrix.type }}:gh-${{ steps.ev.outputs.sha }}
file: ${{ matrix.type }}.Dockerfile
platforms: linux/amd64,linux/arm64
build-args: |
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}

82
.github/workflows/ci-web.yml vendored Normal file
View File

@ -0,0 +1,82 @@
name: authentik-ci-web
on:
push:
jobs:
lint-eslint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- run: |
cd web
npm install
- name: Generate API
run: make gen-web
- name: Eslint
run: |
cd web
npm run lint
lint-prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- run: |
cd web
npm install
- name: Generate API
run: make gen-web
- name: prettier
run: |
cd web
npm run prettier-check
lint-lit-analyse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- run: |
cd web
npm install
- name: Generate API
run: make gen-web
- name: prettier
run: |
cd web
npm run lit-analyse
build:
needs:
- lint-eslint
- lint-prettier
- lint-lit-analyse
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- run: |
cd web
npm install
- name: Generate API
run: make gen-web
- name: build
run: |
cd web
npm run build

60
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,60 @@
name: "CodeQL"
on:
push:
branches: [ master, '*', next, version* ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '30 6 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go', 'javascript', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# 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
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -33,14 +33,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik:2021.7.1-rc1,
beryju/authentik:2021.8.4,
beryju/authentik:latest,
ghcr.io/goauthentik/server:2021.7.1-rc1,
ghcr.io/goauthentik/server:2021.8.4,
ghcr.io/goauthentik/server:latest
platforms: linux/amd64,linux/arm64
context: .
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.7.1-rc1', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.8.4', 'rc') }}
run: |
docker pull beryju/authentik:latest
docker tag beryju/authentik:latest beryju/authentik:stable
@ -75,14 +75,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-proxy:2021.7.1-rc1,
beryju/authentik-proxy:2021.8.4,
beryju/authentik-proxy:latest,
ghcr.io/goauthentik/proxy:2021.7.1-rc1,
ghcr.io/goauthentik/proxy:2021.8.4,
ghcr.io/goauthentik/proxy:latest
file: proxy.Dockerfile
platforms: linux/amd64,linux/arm64
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.7.1-rc1', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.8.4', 'rc') }}
run: |
docker pull beryju/authentik-proxy:latest
docker tag beryju/authentik-proxy:latest beryju/authentik-proxy:stable
@ -117,14 +117,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-ldap:2021.7.1-rc1,
beryju/authentik-ldap:2021.8.4,
beryju/authentik-ldap:latest,
ghcr.io/goauthentik/ldap:2021.7.1-rc1,
ghcr.io/goauthentik/ldap:2021.8.4,
ghcr.io/goauthentik/ldap:latest
file: ldap.Dockerfile
platforms: linux/amd64,linux/arm64
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.7.1-rc1', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.8.4', 'rc') }}
run: |
docker pull beryju/authentik-ldap:latest
docker tag beryju/authentik-ldap:latest beryju/authentik-ldap:stable
@ -157,13 +157,12 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Setup Node.js environment
uses: actions/setup-node@v2.3.0
uses: actions/setup-node@v2.4.0
with:
node-version: 12.x
- name: Build web api client and web ui
run: |
export NODE_ENV=production
make gen-web
cd web
npm i
npm run build
@ -176,6 +175,7 @@ jobs:
SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org
with:
version: authentik@2021.7.1-rc1
version: authentik@2021.8.4
environment: beryjuorg-prod
sourcemaps: './web/dist'
url_prefix: '~/static/dist'

View File

@ -27,7 +27,7 @@ jobs:
docker-compose run -u root server test
- name: Extract version number
id: get_version
uses: actions/github-script@v4.0.2
uses: actions/github-script@v4.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |

39
.github/workflows/web-api-publish.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: authentik-web-api-publish
on:
push:
branches: [ master ]
paths:
- 'schema.yml'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v2
with:
node-version: '16.x'
registry-url: 'https://registry.npmjs.org'
- name: Generate API Client
run: make gen-web
- name: Publish package
run: |
cd web-api/
npm i
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
- name: Upgrade /web
run: |
cd web/
export VERSION=`node -e 'console.log(require("../web-api/package.json").version)'`
npm i @goauthentik/api@$VERSION
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: update-web-api-client
commit-message: "web: Update Web API Client version"
title: "web: Update Web API Client version"
delete-branch: true
signoff: true

3
.gitignore vendored
View File

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

22
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,22 @@
{
"cSpell.words": [
"asgi",
"authentik",
"authn",
"goauthentik",
"jwks",
"oidc",
"openid",
"plex",
"saml",
"totp",
"webauthn"
],
"python.linting.pylintEnabled": true,
"todo-tree.tree.showCountsInTree": true,
"todo-tree.tree.showBadges": true,
"python.formatting.provider": "black",
"files.associations": {
"*.akflow": "json"
}
}

128
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
hello@beryju.org.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

175
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,175 @@
# Contributing to authentik
:+1::tada: Thanks for taking the time to contribute! :tada::+1:
The following is a set of guidelines for contributing to authentik and its components, which are hosted in the [goauthentik Organization](https://github.com/goauthentik) on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
#### Table Of Contents
[Code of Conduct](#code-of-conduct)
[I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question)
[What should I know before I get started?](#what-should-i-know-before-i-get-started)
* [The components](#the-components)
* [authentik's structure](#authentiks-structure)
[How Can I Contribute?](#how-can-i-contribute)
* [Reporting Bugs](#reporting-bugs)
* [Suggesting Enhancements](#suggesting-enhancements)
* [Your First Code Contribution](#your-first-code-contribution)
* [Pull Requests](#pull-requests)
[Styleguides](#styleguides)
* [Git Commit Messages](#git-commit-messages)
* [Python Styleguide](#python-styleguide)
* [Documentation Styleguide](#documentation-styleguide)
## Code of Conduct
Basically, don't be a dickhead. This is an open-source non-profit project, that is made in the free time of Volunteers. If there's something you dislike or think can be done better, tell us! We'd love to hear any suggestions for improvement.
## I don't want to read this whole thing I just have a question!!!
Either [create a question on GitHub](https://github.com/goauthentik/authentik/issues/new?assignees=&labels=question&template=question.md&title=) or join [the Discord server](https://discord.gg/jg33eMhnj6)
## What should I know before I get started?
### The components
authentik consists of a few larger components:
- *authentik* the actual application server, is described below.
- *outpost-proxy* is a Go application based on a forked version of oauth2_proxy, which does identity-aware reverse proxying.
- *outpost-ldap* is a Go LDAP server that uses the *authentik* application server as its backend
- *web* is the web frontend, both for administrating and using authentik. It is written in TypeScript using lit-html and the PatternFly CSS Library.
- *website* is the Website/documentation, which uses docusaurus.
### authentik's structure
authentik is at it's very core a Django project. It consists of many individual django applications. These applications are intended to separate concerns, and they may share code between each other.
These are the current packages:
<a id="authentik-packages"/>
```
authentik
├── admin - Administrative tasks and APIs, no models (Version updates, Metrics, system tasks)
├── api - General API Configuration (Routes, Schema and general API utilities)
├── core - Core authentik functionality, central routes, core Models
├── crypto - Cryptography, currently used to generate and hold Certificates and Private Keys
├── events - Event Log, middleware and signals to generate signals
├── flows - Flows, the FlowPlanner and the FlowExecutor, used for all flows for authentication, authorization, etc
├── lib - Generic library of functions, few dependencies on other packages.
├── managed - Handle managed models and their state.
├── outposts - Configure and deploy outposts on kubernetes and docker.
├── policies - General PolicyEngine
│   ├── dummy - A Dummy policy used for testing
│   ├── event_matcher - Match events based on different criteria
│   ├── expiry - Check when a user's password was last set
│   ├── expression - Execute any arbitrary python code
│   ├── hibp - Check a password against HaveIBeenPwned
│   ├── password - Check a password against several rules
│   └── reputation - Check the user's/client's reputation
├── providers
│   ├── ldap - Provide LDAP access to authentik users/groups using an outpost
│   ├── oauth2 - OIDC-compliant OAuth2 provider
│   ├── proxy - Provides an identity-aware proxy using an outpost
│   └── saml - SAML2 Provider
├── recovery - Generate keys to use in case you lock yourself out
├── root - Root django application, contains global settings and routes
├── sources
│   ├── ldap - Sync LDAP users from OpenLDAP or Active Directory into authentik
│   ├── oauth - OAuth1 and OAuth2 Source
│   ├── plex - Plex source
│   └── saml - SAML2 Source
├── stages
│   ├── authenticator_duo - Configure a DUO authenticator
│   ├── authenticator_static - Configure TOTP backup keys
│   ├── authenticator_totp - Configure a TOTP authenticator
│   ├── authenticator_validate - Validate any authenticator
│   ├── authenticator_webauthn - Configure a WebAuthn authenticator
│   ├── captcha - Make the user pass a captcha
│   ├── consent - Let the user decide if they want to consent to an action
│   ├── deny - Static deny, can be used with policies
│   ├── dummy - Dummy stage to test
│   ├── email - Send the user an email and block execution until they click the link
│   ├── identification - Identify a user with any combination of fields
│   ├── invitation - Invitation system to limit flows to certain users
│   ├── password - Password authentication
│   ├── prompt - Arbitrary prompts
│   ├── user_delete - Delete the currently pending user
│   ├── user_login - Login the currently pending user
│   ├── user_logout - Logout the currently pending user
│   └── user_write - Write any currenetly pending data to the user.
└── tenants - Soft tennancy, configure defaults and branding per domain
```
This django project is running in gunicorn, which spawns multiple workers and threads. Gunicorn is run from a lightweight Go application which reverse-proxies it, handles static files and will eventually gain more functionality as more code is migrated to go.
There are also several background tasks which run in Celery, the root celery application is defined in `authentik.root.celery`.
## How Can I Contribute?
### Reporting Bugs
This section guides you through submitting a bug report for authentik. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports.
Whenever authentik encounters an error, it will be logged as an Event with the type `system_exception`. This event type has a button to directly open a pre-filled GitHub issue form.
This form will have the full stack trace of the error that ocurred and shouldn't contain any sensitive data.
### Suggesting Enhancements
This section guides you through submitting an enhancement suggestion for authentik, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion and find related suggestions.
When you are creating an enhancement suggestion, please fill in [the template](https://github.com/goauthentik/authentik/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=), including the steps that you imagine you would take if the feature you're requesting existed.
### Your First Code Contribution
#### Local development
authentik can be run locally, all though depending on which part you want to work on, different pre-requisites are required.
This is documented in the [developer docs](https://goauthentik.io/developer-docs/)
### Pull Requests
The process described here has several goals:
- Maintain authentik's quality
- Fix problems that are important to users
- Engage the community in working toward the best possible authentik
- Enable a sustainable system for authentik's maintainers to review contributions
Please follow these steps to have your contribution considered by the maintainers:
1. Follow the [styleguides](#styleguides)
2. After you submit your pull request, verify that all [status checks](https://help.github.com/articles/about-status-checks/) are passing <details><summary>What if the status checks are failing?</summary>If a status check is failing, and you believe that the failure is unrelated to your change, please leave a comment on the pull request explaining why you believe the failure is unrelated. A maintainer will re-run the status check for you. If we conclude that the failure was a false positive, then we will open an issue to track that problem with our status check suite.</details>
3. Ensure your Code has tests. While it is not always possible to test every single case, the majority of the code should be tested.
While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted.
## Styleguides
### Git Commit Messages
* Use the format of `<package>: <verb> <description>`
- See [here](#authentik-packages) for `package`
- Example: `providers/saml2: fix parsing of requests`
* Reference issues and pull requests liberally after the first line
### Python Styleguide
All Python code is linted with [black](https://black.readthedocs.io/en/stable/), [PyLint](https://www.pylint.org/) and [isort](https://pycqa.github.io/isort/).
authentik runs on Python 3.9 at the time of writing this.
* Use native type-annotations wherever possible.
* Add meaningful docstrings when possible.
* Ensure any database migrations work properly from the last stable version (this is checked via CI)
* If your code changes central functions, make sure nothing else is broken.
### Documentation Styleguide
* Use [MDX](https://mdxjs.com/) whenever appropriate.

View File

@ -18,17 +18,6 @@ COPY ./website /static/
ENV NODE_ENV=production
RUN cd /static && npm i && npm run build-docs-only
# Stage 3: Build web API
FROM openapitools/openapi-generator-cli as web-api-builder
COPY ./schema.yml /local/schema.yml
RUN docker-entrypoint.sh generate \
-i /local/schema.yml \
-g typescript-fetch \
-o /local/web/api \
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
# Stage 3: Generate API Client
FROM openapitools/openapi-generator-cli as go-api-builder
@ -48,13 +37,12 @@ RUN docker-entrypoint.sh generate \
FROM node as web-builder
COPY ./web /static/
COPY --from=web-api-builder /local/web/api /static/api
ENV NODE_ENV=production
RUN cd /static && npm i && npm run build
# Stage 5: Build go proxy
FROM golang:1.16.6 AS builder
FROM golang:1.17.0 AS builder
WORKDIR /work
@ -110,4 +98,5 @@ COPY --from=builder /work/authentik /authentik-proxy
USER authentik
ENV TMPDIR /dev/shm/
ENV PYTHONUBUFFERED 1
ENTRYPOINT [ "/lifecycle/bootstrap.sh" ]
ENV PATH "/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/lifecycle"
ENTRYPOINT [ "/lifecycle/ak" ]

View File

@ -2,6 +2,7 @@
PWD = $(shell pwd)
UID = $(shell id -u)
GID = $(shell id -g)
NPM_VERSION = $(shell python -m scripts.npm_version)
all: lint-fix lint test gen
@ -41,9 +42,13 @@ gen-web:
openapitools/openapi-generator-cli generate \
-i /local/schema.yml \
-g typescript-fetch \
-o /local/web/api \
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
cd web/api && npx tsc
-o /local/web-api \
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=@goauthentik/api,npmVersion=${NPM_VERSION}
mkdir -p web/node_modules/@goauthentik/api
python -m scripts.web_api_esm
\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
gen-outpost:
docker run \

View File

@ -39,7 +39,7 @@ sentry-sdk = "*"
service_identity = "*"
structlog = "*"
swagger-spec-validator = "*"
twisted = "==20.3.0"
twisted = "==21.7.0"
urllib3 = {extras = ["secure"],version = "*"}
uvicorn = {extras = ["standard"],version = "*"}
webauthn = "*"

356
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "e4f2e57bd5c709809515ab2b95eb3f5fa337d4a9334f4110a24bf28c3f9d5f8f"
"sha256": "f0befa9b3dacc1c3363b9442fa7a43f6be2c46a8fcb80a994230d288a384e54d"
},
"pipfile-spec": 6,
"requires": {
@ -122,19 +122,19 @@
},
"boto3": {
"hashes": [
"sha256:13e60f88d13161df951d6e52bd483cdbe1a36a31f818746289d8ba0879465710",
"sha256:3be2f259b279d69495433e3288db3670817fdb1813cfde92abf867bba3ad8148"
"sha256:5116e9bdec19adcc5531a9b7b535be77d5314eef092aaf7033ace48a9be65036",
"sha256:658ddf4ba552f654fd4d48335fa95ff4e3e1a4e82f90021a1a1d3de4a5428ba4"
],
"index": "pypi",
"version": "==1.18.3"
"version": "==1.18.34"
},
"botocore": {
"hashes": [
"sha256:0b6f378c9efbc72eee61aba1e16cab90bde53a37bd2d861f6435552fd7030adf",
"sha256:285ab9459cdd49d4a9322692c6e13772b97af723a03c0eed519b589446491a5b"
"sha256:1b4999fb0e1a4c050c4d9118ebdaac8d83761ef32c3c0f13a25f9204045998fe",
"sha256:ec2cdf1c8ed64a7f392f352125d248c76103fa9d137b275b7c76836776cedf56"
],
"markers": "python_version >= '3.6'",
"version": "==1.21.3"
"version": "==1.21.34"
},
"cachetools": {
"hashes": [
@ -146,22 +146,22 @@
},
"cbor2": {
"hashes": [
"sha256:059363ae716c60f6ba29aa61b3d9c57896189c351c4119095f0542aec169e4dc",
"sha256:0b80a4a4fca830af3d3cf36b725c31f0a98106e9c2b02004ab73b0ec7f139446",
"sha256:0d22b47fb24b384200277fcfb0582c3a3551c413ad51f3bd3ee334caaf79a483",
"sha256:3c586a6e328ba5020802346f5e0304f81b982dcafeb51ee4109c9be9cccbc4a0",
"sha256:4dd142764607b1a8b5e3e3b474d2b84099e9cbb323596a15ee8db0d78901d95f",
"sha256:6f8a7911c2307ee8f8d4940bdcfb8bd21608f14203a83b651fcd7868bce377a5",
"sha256:7ecc4e9c548282a5d296d4535244efa69c7f67cda959f28e14929cf1d6af8a97",
"sha256:8bc9f5054650d05e6d3e90f6490dcd6ef6c01ad9c1568958a48dde2702824cb1",
"sha256:98410520482796a547af2d5ffe11a8a2dc3b9f2124834fa7c12db8264935ed61",
"sha256:a7926f7244b08c413f1a4fa71a81aa256771c75bdf1a4fd77308547a2d63dd48",
"sha256:ae31d3b5966807fdff6c9e6f894b0aa10474295d9ff8467a8b978a569c8fec47",
"sha256:ce6219986385778b1ab7f9b542f160bb4d3558f52975e914a27b774e47016fb7",
"sha256:d562b2773e14ee1d65ea5b85351a83a64d4f3fd011bc2b4c70a6e813e78203ce"
"sha256:0144ba1f44e4e36f7a8e8408eea72e1af6fc3ee42a704dacd4446307024e5231",
"sha256:15102b45dd8b1879b8743159af4538cbf4b3240fe3ebc4e747f6842cd7775888",
"sha256:40aa7c9dc9f69c38a2f9954e0adec266b04c55ed3188dc7a0213a92a2054220e",
"sha256:4b62aa7a95960d1c382e858c2c4cb24375cde3cae137d11875bb9a4667731011",
"sha256:6288b22cd3c0c842db2a4896473512fe83d24fa8ef4bc592d970635a2bb42e0e",
"sha256:81676dc7802029299dc168a1240cf1058c1fe5303fbc64598fe14bdb1f8bc076",
"sha256:8684c6ffbd35258cb9790ef2722559f585fb971288d6f55ee5efd9ba75dcc81b",
"sha256:8ce511337cbac10ccb97093649d6597aacb648ce3198e6afe8b4931fd1cabc61",
"sha256:986a8a9a4d3598008ece7241b746261118ef8d7c0efe7e6e9ce8b275f0421646",
"sha256:a8bf432f6cb595f50aeb8fed2a4aa3b3f7caa7f135fb57e4378eaa39242feac9",
"sha256:ba5e8065ca901ebec7ae390a183f3c13560454b6bd7dd81bf72c320e252b6461",
"sha256:d66350d1323460e1e9dcb2f9caa591b60833623f909173b840a0891a245cad83",
"sha256:e921d445575fbbe62ae68dc8ff3c6e05b341077fd24c6310c917b96fabe5e64a"
],
"markers": "python_version >= '3.6'",
"version": "==5.4.0"
"version": "==5.4.1"
},
"celery": {
"hashes": [
@ -254,11 +254,11 @@
},
"charset-normalizer": {
"hashes": [
"sha256:88fce3fa5b1a84fdcb3f603d889f723d1dd89b26059d0123ca435570e848d5e1",
"sha256:c46c3ace2d744cfbdebceaa3c19ae691f53ae621b39fd7570f59d14fb7f2fd12"
"sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b",
"sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"
],
"markers": "python_version >= '3'",
"version": "==2.0.3"
"version": "==2.0.4"
},
"click": {
"hashes": [
@ -305,20 +305,25 @@
},
"cryptography": {
"hashes": [
"sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d",
"sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959",
"sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6",
"sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873",
"sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2",
"sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713",
"sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1",
"sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177",
"sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250",
"sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca",
"sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d",
"sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"
"sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e",
"sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b",
"sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7",
"sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085",
"sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc",
"sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a",
"sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498",
"sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9",
"sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c",
"sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7",
"sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb",
"sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14",
"sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af",
"sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e",
"sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5",
"sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06",
"sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7"
],
"version": "==3.4.7"
"version": "==3.4.8"
},
"dacite": {
"hashes": [
@ -354,11 +359,11 @@
},
"django": {
"hashes": [
"sha256:3da05fea54fdec2315b54a563d5b59f3b4e2b1e69c3a5841dda35019c01855cd",
"sha256:c58b5f19c5ae0afe6d75cbdd7df561e6eb929339985dbbda2565e1cabb19a62e"
"sha256:95b318319d6997bac3595517101ad9cc83fe5672ac498ba48d1a410f47afecd2",
"sha256:e93c93565005b37ddebf2396b4dc4b6913c1838baa82efdfb79acedd5816c240"
],
"index": "pypi",
"version": "==3.2.5"
"version": "==3.2.7"
},
"django-dbbackup": {
"git": "https://github.com/django-dbbackup/django-dbbackup.git",
@ -438,19 +443,19 @@
},
"docker": {
"hashes": [
"sha256:3e8bc47534e0ca9331d72c32f2881bb13b93ded0bcdeab3c833fb7cf61c0a9a5",
"sha256:fc961d622160e8021c10d1bcabc388c57d55fb1f917175afbe24af442e6879bd"
"sha256:5aafaec0d2a1de0e32010b43b5eac9f6f851c9db99a46ad32b8e44eeeb55616d",
"sha256:b88eef725b33c0ed59c67506631bbb09b480b7ca5a739bbbb948b446443fe914"
],
"index": "pypi",
"version": "==5.0.0"
"version": "==5.0.1"
},
"drf-spectacular": {
"hashes": [
"sha256:6ffbfde7d96a4a2febd19182cc405217e1e86a50280fc739402291c93d1a32b7",
"sha256:77593024bb899f69227abedcf87def7851a11c9978f781aa4b385a10f67a38b7"
"sha256:98681add6671db9e6dba5f0d3dcf8aab5950cbb978497390507356e593bf082f",
"sha256:a430bab0f4ecfc90786b7b63bbee3f9a56094201fbed9bdfbf952e99e6469104"
],
"index": "pypi",
"version": "==0.17.2"
"version": "==0.18.1"
},
"duo-client": {
"hashes": [
@ -485,11 +490,11 @@
},
"google-auth": {
"hashes": [
"sha256:036dd68c1e8baa422b6b61619b8e02793da2e20f55e69514612de6c080468755",
"sha256:7665c04f2df13cc938dc7d9066cddb1f8af62b038bc8b2306848c1b23121865f"
"sha256:104475dc4d57bbae49017aea16fffbb763204fa2d6a70f1f3cc79962c1a383a4",
"sha256:cde472372e030e1e0bc64dac00fb53e6c095d7ab641f4281e2c995e85e205d8b"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.33.1"
"markers": "python_version >= '3.6'",
"version": "==2.0.2"
},
"gunicorn": {
"hashes": [
@ -628,11 +633,11 @@
},
"kubernetes": {
"hashes": [
"sha256:225a95a0aadbd5b645ab389d941a7980db8cdad2a776fde64d1b43fc3299bde9",
"sha256:c69b318696ba797dcf63eb928a8d4370c52319f4140023c502d7dfdf2080eb79"
"sha256:0c72d00e7883375bd39ae99758425f5e6cb86388417cf7cc84305c211b2192cf",
"sha256:ff31ec17437293e7d4e1459f1228c42d27c7724dfb56b4868aba7a901a5b72c9"
],
"index": "pypi",
"version": "==17.17.0"
"version": "==18.20.0"
},
"ldap3": {
"hashes": [
@ -666,6 +671,7 @@
"sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83",
"sha256:5a0a14e264069c03e46f926be0d8919f4105c1623d620e7ec0e612a2e9bf1c04",
"sha256:5c8c163396cc0df3fd151b927e74f6e4acd67160d6c33304e805b84293351d16",
"sha256:64812391546a18896adaa86c77c59a4998f33c24788cadc35789e55b727a37f4",
"sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791",
"sha256:6f12e1427285008fd32a6025e38e977d44d6382cf28e7201ed10d6c1698d2a9a",
"sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51",
@ -680,6 +686,7 @@
"sha256:b007cbb845b28db4fb8b6a5cdcbf65bacb16a8bd328b53cbc0698688a68e1caa",
"sha256:bc4313cbeb0e7a416a488d72f9680fffffc645f8a838bd2193809881c67dd106",
"sha256:bccbfc27563652de7dc9bdc595cb25e90b59c5f8e23e806ed0fd623755b6565d",
"sha256:c1a40c06fd5ba37ad39caa0b3144eb3772e813b5fb5b084198a985431c2f1e8d",
"sha256:c47ff7e0a36d4efac9fd692cfa33fbd0636674c102e9e8d9b26e1b93a94e7617",
"sha256:c4f05c5a7c49d2fb70223d0d5bcfbe474cf928310ac9fa6a7c6dddc831d0b1d4",
"sha256:cdaf11d2bd275bf391b5308f86731e5194a21af45fbaaaf1d9e8147b9160ea92",
@ -806,11 +813,11 @@
},
"prompt-toolkit": {
"hashes": [
"sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f",
"sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"
"sha256:6076e46efae19b1e0ca1ec003ed37a933dc94b4d20f486235d436e64771dcd5c",
"sha256:eb71d5a6b72ce6db177af4a7d4d7085b99756bf656d98ffcc4fecd36850eea6c"
],
"markers": "python_full_version >= '3.6.1'",
"version": "==3.0.19"
"markers": "python_full_version >= '3.6.2'",
"version": "==3.0.20"
},
"psycopg2-binary": {
"hashes": [
@ -927,14 +934,6 @@
"index": "pypi",
"version": "==3.10.1"
},
"pyhamcrest": {
"hashes": [
"sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316",
"sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29"
],
"markers": "python_version >= '3.5'",
"version": "==2.0.2"
},
"pyjwt": {
"hashes": [
"sha256:934d73fbba91b0483d3857d1aff50e96b2a892384ee2c17417ed3203f173fca1",
@ -995,10 +994,10 @@
},
"python-dotenv": {
"hashes": [
"sha256:dd8fe852847f4fbfadabf6183ddd4c824a9651f02d51714fa075c95561959c7d",
"sha256:effaac3c1e58d89b3ccb4d04a40dc7ad6e0275fda25fd75ae9d323e2465e202d"
"sha256:aae25dc1ebe97c420f50b81fb0e5c949659af713f31fdb63c749ca68748f34b1",
"sha256:f521bc2ac9a8e03c736f62911605c5d83970021e3fa95b37d769e2bbbe9b6172"
],
"version": "==0.18.0"
"version": "==0.19.0"
},
"pytz": {
"hashes": [
@ -1072,7 +1071,7 @@
"sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2",
"sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"
],
"markers": "python_version >= '3.6'",
"markers": "python_version >= '3.5' and python_version < '4'",
"version": "==4.7.2"
},
"s3transfer": {
@ -1085,11 +1084,11 @@
},
"sentry-sdk": {
"hashes": [
"sha256:5210a712dd57d88d225c1fc3fe3a3626fee493637bcd54e204826cf04b8d769c",
"sha256:6864dcb6f7dec692635e5518c2a5c80010adf673c70340817f1a1b713d65bb41"
"sha256:ebe99144fa9618d4b0e7617e7929b75acd905d258c3c779edcd34c0adfffe26c",
"sha256:f33d34c886d0ba24c75ea8885a8b3a172358853c7cbde05979fc99c29ef7bc52"
],
"index": "pypi",
"version": "==1.3.0"
"version": "==1.3.1"
},
"service-identity": {
"hashes": [
@ -1136,32 +1135,11 @@
"tls"
],
"hashes": [
"sha256:040eb6641125d2a9a09cf198ec7b83dd8858c6f51f6770325ed9959c00f5098f",
"sha256:147780b8caf21ba2aef3688628eaf13d7e7fe02a86747cd54bfaf2140538f042",
"sha256:158ddb80719a4813d292293ac44ba41d8b56555ed009d90994a278237ee63d2c",
"sha256:2182000d6ffc05d269e6c03bfcec8b57e20259ca1086180edaedec3f1e689292",
"sha256:25ffcf37944bdad4a99981bc74006d735a678d2b5c193781254fbbb6d69e3b22",
"sha256:3281d9ce889f7b21bdb73658e887141aa45a102baf3b2320eafcfba954fcefec",
"sha256:356e8d8dd3590e790e3dba4db139eb8a17aca64b46629c622e1b1597a4a92478",
"sha256:70952c56e4965b9f53b180daecf20a9595cf22b8d0935cd3bd664c90273c3ab2",
"sha256:7408c6635ee1b96587289283ebe90ee15dbf9614b05857b446055116bc822d29",
"sha256:7c547fd0215db9da8a1bc23182b309e84a232364cc26d829e9ee196ce840b114",
"sha256:894f6f3cfa57a15ea0d0714e4283913a5f2511dbd18653dd148eba53b3919797",
"sha256:94ac3d55a58c90e2075c5fe1853f2aa3892b73e3bf56395f743aefde8605eeaa",
"sha256:a58e61a2a01e5bcbe3b575c0099a2bcb8d70a75b1a087338e0c48dd6e01a5f15",
"sha256:c09c47ff9750a8e3aa60ad169c4b95006d455a29b80ad0901f031a103b2991cd",
"sha256:ca3a0b8c9110800e576d89b5337373e52018b41069bc879f12fa42b7eb2d0274",
"sha256:cd1dc5c85b58494138a3917752b54bb1daa0045d234b7c132c37a61d5483ebad",
"sha256:cdbc4c7f0cd7a2218b575844e970f05a1be1861c607b0e048c9bceca0c4d42f7",
"sha256:d267125cc0f1e8a0eed6319ba4ac7477da9b78a535601c49ecd20c875576433a",
"sha256:d72c55b5d56e176563b91d11952d13b01af8725c623e498db5507b6614fc1e10",
"sha256:d95803193561a243cb0401b0567c6b7987d3f2a67046770e1dccd1c9e49a9780",
"sha256:e92703bed0cc21d6cb5c61d66922b3b1564015ca8a51325bd164a5e33798d504",
"sha256:f058bd0168271de4dcdc39845b52dd0a4a2fecf5f1246335f13f5e96eaebb467",
"sha256:f3c19e5bd42bbe4bf345704ad7c326c74d3fd7a1b3844987853bef180be638d4"
"sha256:13c1d1d2421ae556d91e81e66cf0d4f4e4e1e4a36a0486933bee4305c6a4fb9b",
"sha256:2cd652542463277378b0d349f47c62f20d9306e57d1247baabd6d1d38a109006"
],
"index": "pypi",
"version": "==20.3.0"
"version": "==21.7.0"
},
"txaio": {
"hashes": [
@ -1173,11 +1151,11 @@
},
"typing-extensions": {
"hashes": [
"sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497",
"sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342",
"sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"
"sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e",
"sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7",
"sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"
],
"version": "==3.10.0.0"
"version": "==3.10.0.2"
},
"ua-parser": {
"hashes": [
@ -1211,26 +1189,32 @@
"standard"
],
"hashes": [
"sha256:2a76bb359171a504b3d1c853409af3adbfa5cef374a4a59e5881945a97a93eae",
"sha256:45ad7dfaaa7d55cab4cd1e85e03f27e9d60bc067ddc59db52a2b0aeca8870292"
"sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1",
"sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"
],
"index": "pypi",
"version": "==0.14.0"
"version": "==0.15.0"
},
"uvloop": {
"hashes": [
"sha256:0de811931e90ae2da9e19ce70ffad73047ab0c1dba7c6e74f9ae1a3aabeb89bd",
"sha256:1ff05116ede1ebdd81802df339e5b1d4cab1dfbd99295bf27e90b4cec64d70e9",
"sha256:2d8ffe44ae709f839c54bacf14ed283f41bee90430c3b398e521e10f8d117b3a",
"sha256:5cda65fc60a645470b8525ce014516b120b7057b576fa876cdfdd5e60ab1efbb",
"sha256:63a3288abbc9c8ee979d7e34c34e780b2fbab3e7e53d00b6c80271119f277399",
"sha256:7522df4e45e4f25b50adbbbeb5bb9847495c438a628177099d2721f2751ff825",
"sha256:7f4b8a905df909a407c5791fb582f6c03b0d3b491ecdc1cdceaefbc9bf9e08f6",
"sha256:905f0adb0c09c9f44222ee02f6b96fd88b493478fffb7a345287f9444e926030",
"sha256:ae2b325c0f6d748027f7463077e457006b4fdb35a8788f01754aadba825285ee",
"sha256:e71fb9038bfcd7646ca126c5ef19b17e48d4af9e838b2bcfda7a9f55a6552a32"
"sha256:04ff57aa137230d8cc968f03481176041ae789308b4d5079118331ab01112450",
"sha256:089b4834fd299d82d83a25e3335372f12117a7d38525217c2258e9b9f4578897",
"sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861",
"sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c",
"sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805",
"sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d",
"sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464",
"sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f",
"sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9",
"sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab",
"sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f",
"sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638",
"sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64",
"sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee",
"sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382",
"sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228"
],
"version": "==0.15.3"
"version": "==0.16.0"
},
"vine": {
"hashes": [
@ -1264,11 +1248,11 @@
},
"websocket-client": {
"hashes": [
"sha256:b68e4959d704768fa20e35c9d508c8dc2bbc041fd8d267c0d7345cffe2824568",
"sha256:e5c333bfa9fa739538b652b6f8c8fc2559f1d364243c8a689d7c0e1d41c2e611"
"sha256:0133d2f784858e59959ce82ddac316634229da55b498aac311f1620567a710ec",
"sha256:8dfb715d8a992f5712fff8c843adae94e22b22a99b2c5e6b0ec4a1a981cc4e0d"
],
"markers": "python_version >= '3.6'",
"version": "==1.1.0"
"version": "==1.2.1"
},
"websockets": {
"hashes": [
@ -1436,11 +1420,11 @@
},
"astroid": {
"hashes": [
"sha256:6021561b2e87ed6b3c93c2682ac50079c65ab08f1e4e0277ba38f97e0e492185",
"sha256:a670dd7af3fe603f51aa7117462588b7c3bdcd58007edfaee752bf82eceecd28"
"sha256:3b680ce0419b8a771aba6190139a3998d14b413852506d99aff8dc2bf65ee67c",
"sha256:dc1e8b28427d6bbef6b8842b18765ab58f558c42bb80540bd7648c98412af25e"
],
"markers": "python_version ~= '3.6'",
"version": "==2.6.4"
"version": "==2.7.3"
},
"attrs": {
"hashes": [
@ -1483,11 +1467,11 @@
},
"charset-normalizer": {
"hashes": [
"sha256:88fce3fa5b1a84fdcb3f603d889f723d1dd89b26059d0123ca435570e848d5e1",
"sha256:c46c3ace2d744cfbdebceaa3c19ae691f53ae621b39fd7570f59d14fb7f2fd12"
"sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b",
"sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"
],
"markers": "python_version >= '3'",
"version": "==2.0.3"
"version": "==2.0.4"
},
"click": {
"hashes": [
@ -1595,11 +1579,11 @@
},
"isort": {
"hashes": [
"sha256:eed17b53c3e7912425579853d078a0832820f023191561fcee9d7cae424e0813",
"sha256:f65ce5bd4cbc6abdfbe29afc2f0245538ab358c14590912df638033f157d555e"
"sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899",
"sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"
],
"markers": "python_version < '4.0' and python_full_version >= '3.6.1'",
"version": "==5.9.2"
"markers": "python_version < '4' and python_full_version >= '3.6.1'",
"version": "==5.9.3"
},
"lazy-object-proxy": {
"hashes": [
@ -1666,13 +1650,21 @@
"markers": "python_version >= '2.6'",
"version": "==5.6.0"
},
"platformdirs": {
"hashes": [
"sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f",
"sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"
],
"markers": "python_version >= '3.6'",
"version": "==2.3.0"
},
"pluggy": {
"hashes": [
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
"sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
"sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.13.1"
"markers": "python_version >= '3.6'",
"version": "==1.0.0"
},
"py": {
"hashes": [
@ -1684,11 +1676,11 @@
},
"pylint": {
"hashes": [
"sha256:2a971129fb2d594068913a7e531d4b6d2785b2a68c6857e2baa40d3214da30f4",
"sha256:a622c4c4c79dc8fe5e784efccacec3afe9d5e5ffab5fda2264fb5afa7c9b5797"
"sha256:6758cce3ddbab60c52b57dcc07f0c5d779e5daf0cf50f6faacbef1d3ea62d2a1",
"sha256:e178e96b6ba171f8ef51fbce9ca30931e6acbea4a155074d80cc081596c9e852"
],
"index": "pypi",
"version": "==2.9.4"
"version": "==2.10.2"
},
"pylint-django": {
"hashes": [
@ -1715,11 +1707,11 @@
},
"pytest": {
"hashes": [
"sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b",
"sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"
"sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89",
"sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"
],
"index": "pypi",
"version": "==6.2.4"
"version": "==6.2.5"
},
"pytest-django": {
"hashes": [
@ -1766,49 +1758,49 @@
},
"regex": {
"hashes": [
"sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f",
"sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad",
"sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a",
"sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf",
"sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59",
"sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d",
"sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895",
"sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4",
"sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3",
"sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222",
"sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0",
"sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c",
"sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417",
"sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d",
"sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d",
"sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761",
"sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0",
"sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026",
"sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854",
"sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb",
"sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d",
"sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068",
"sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde",
"sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d",
"sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec",
"sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa",
"sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd",
"sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b",
"sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26",
"sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2",
"sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f",
"sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694",
"sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0",
"sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407",
"sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874",
"sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035",
"sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d",
"sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c",
"sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5",
"sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985",
"sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58"
"sha256:04f6b9749e335bb0d2f68c707f23bb1773c3fb6ecd10edf0f04df12a8920d468",
"sha256:08d74bfaa4c7731b8dac0a992c63673a2782758f7cfad34cf9c1b9184f911354",
"sha256:0fc1f8f06977c2d4f5e3d3f0d4a08089be783973fc6b6e278bde01f0544ff308",
"sha256:121f4b3185feaade3f85f70294aef3f777199e9b5c0c0245c774ae884b110a2d",
"sha256:1413b5022ed6ac0d504ba425ef02549a57d0f4276de58e3ab7e82437892704fc",
"sha256:1743345e30917e8c574f273f51679c294effba6ad372db1967852f12c76759d8",
"sha256:28fc475f560d8f67cc8767b94db4c9440210f6958495aeae70fac8faec631797",
"sha256:31a99a4796bf5aefc8351e98507b09e1b09115574f7c9dbb9cf2111f7220d2e2",
"sha256:328a1fad67445550b982caa2a2a850da5989fd6595e858f02d04636e7f8b0b13",
"sha256:473858730ef6d6ff7f7d5f19452184cd0caa062a20047f6d6f3e135a4648865d",
"sha256:4cde065ab33bcaab774d84096fae266d9301d1a2f5519d7bd58fc55274afbf7a",
"sha256:5f6a808044faae658f546dd5f525e921de9fa409de7a5570865467f03a626fc0",
"sha256:610b690b406653c84b7cb6091facb3033500ee81089867ee7d59e675f9ca2b73",
"sha256:66256b6391c057305e5ae9209941ef63c33a476b73772ca967d4a2df70520ec1",
"sha256:6eebf512aa90751d5ef6a7c2ac9d60113f32e86e5687326a50d7686e309f66ed",
"sha256:79aef6b5cd41feff359acaf98e040844613ff5298d0d19c455b3d9ae0bc8c35a",
"sha256:808ee5834e06f57978da3e003ad9d6292de69d2bf6263662a1a8ae30788e080b",
"sha256:8e44769068d33e0ea6ccdf4b84d80c5afffe5207aa4d1881a629cf0ef3ec398f",
"sha256:999ad08220467b6ad4bd3dd34e65329dd5d0df9b31e47106105e407954965256",
"sha256:9b006628fe43aa69259ec04ca258d88ed19b64791693df59c422b607b6ece8bb",
"sha256:9d05ad5367c90814099000442b2125535e9d77581855b9bee8780f1b41f2b1a2",
"sha256:a577a21de2ef8059b58f79ff76a4da81c45a75fe0bfb09bc8b7bb4293fa18983",
"sha256:a617593aeacc7a691cc4af4a4410031654f2909053bd8c8e7db837f179a630eb",
"sha256:abb48494d88e8a82601af905143e0de838c776c1241d92021e9256d5515b3645",
"sha256:ac88856a8cbccfc14f1b2d0b829af354cc1743cb375e7f04251ae73b2af6adf8",
"sha256:b4c220a1fe0d2c622493b0a1fd48f8f991998fb447d3cd368033a4b86cf1127a",
"sha256:b844fb09bd9936ed158ff9df0ab601e2045b316b17aa8b931857365ea8586906",
"sha256:bdc178caebd0f338d57ae445ef8e9b737ddf8fbc3ea187603f65aec5b041248f",
"sha256:c206587c83e795d417ed3adc8453a791f6d36b67c81416676cad053b4104152c",
"sha256:c61dcc1cf9fd165127a2853e2c31eb4fb961a4f26b394ac9fe5669c7a6592892",
"sha256:c7cb4c512d2d3b0870e00fbbac2f291d4b4bf2634d59a31176a87afe2777c6f0",
"sha256:d4a332404baa6665b54e5d283b4262f41f2103c255897084ec8f5487ce7b9e8e",
"sha256:d5111d4c843d80202e62b4fdbb4920db1dcee4f9366d6b03294f45ed7b18b42e",
"sha256:e1e8406b895aba6caa63d9fd1b6b1700d7e4825f78ccb1e5260551d168db38ed",
"sha256:e8690ed94481f219a7a967c118abaf71ccc440f69acd583cab721b90eeedb77c",
"sha256:ed283ab3a01d8b53de3a05bfdf4473ae24e43caee7dcb5584e86f3f3e5ab4374",
"sha256:ed4b50355b066796dacdd1cf538f2ce57275d001838f9b132fab80b75e8c84dd",
"sha256:ee329d0387b5b41a5dddbb6243a21cb7896587a651bebb957e2d2bb8b63c0791",
"sha256:f3bf1bc02bc421047bfec3343729c4bbbea42605bcfd6d6bfe2c07ade8b12d2a",
"sha256:f585cbbeecb35f35609edccb95efd95a3e35824cd7752b586503f7e6087303f1",
"sha256:f60667673ff9c249709160529ab39667d1ae9fd38634e006bec95611f632e759"
],
"version": "==2021.7.6"
"version": "==2021.8.28"
},
"requests": {
"hashes": [
@ -1852,11 +1844,11 @@
},
"stevedore": {
"hashes": [
"sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee",
"sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"
"sha256:59b58edb7f57b11897f150475e7bc0c39c5381f0b8e3fa9f5c20ce6c89ec4aa1",
"sha256:920ce6259f0b2498aaa4545989536a27e4e4607b8318802d7ddc3a533d3d069e"
],
"markers": "python_version >= '3.6'",
"version": "==3.3.0"
"version": "==3.4.0"
},
"toml": {
"hashes": [

View File

@ -4,14 +4,15 @@
---
[![](https://img.shields.io/discord/809154715984199690?label=Discord&style=flat-square)](https://discord.gg/jg33eMhnj6)
[![CI Build status](https://img.shields.io/azure-devops/build/beryjuorg/authentik/6?style=flat-square)](https://dev.azure.com/beryjuorg/authentik/_build?definitionId=6)
[![Tests](https://img.shields.io/azure-devops/tests/beryjuorg/authentik/6?compact_message&style=flat-square)](https://dev.azure.com/beryjuorg/authentik/_build?definitionId=6)
[![Code Coverage](https://img.shields.io/codecov/c/gh/goauthentik/authentik?style=flat-square)](https://codecov.io/gh/goauthentik/authentik)
![Docker pulls](https://img.shields.io/docker/pulls/beryju/authentik.svg?style=flat-square)
![Latest version](https://img.shields.io/docker/v/beryju/authentik?sort=semver&style=flat-square)
![LGTM Grade](https://img.shields.io/lgtm/grade/python/github/goauthentik/authentik?style=flat-square)
[Transifex](https://www.transifex.com/beryjuorg/authentik/)
[![](https://img.shields.io/discord/809154715984199690?label=Discord&style=for-the-badge)](https://discord.gg/jg33eMhnj6)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/goauthentik/authentik/authentik-ci-main?label=core%20build&style=for-the-badge)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/goauthentik/authentik/authentik-ci-web?label=web%20build&style=for-the-badge)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/goauthentik/authentik/authentik-ci-outpost?label=outpost%20build&style=for-the-badge)
[![Code Coverage](https://img.shields.io/codecov/c/gh/goauthentik/authentik?style=for-the-badge)](https://codecov.io/gh/goauthentik/authentik)
![Docker pulls](https://img.shields.io/docker/pulls/beryju/authentik.svg?style=for-the-badge)
![Latest version](https://img.shields.io/docker/v/beryju/authentik?sort=semver&style=for-the-badge)
![LGTM Grade](https://img.shields.io/lgtm/grade/python/github/goauthentik/authentik?style=for-the-badge)
[![](https://img.shields.io/badge/Help%20translate-transifex-blue?style=for-the-badge)](https://www.transifex.com/beryjuorg/authentik/)
## What is authentik?
@ -21,7 +22,7 @@ authentik is an open-source Identity Provider focused on flexibility and versati
For small/test setups it is recommended to use docker-compose, see the [documentation](https://goauthentik.io/docs/installation/docker-compose/)
For bigger setups, there is a Helm Chart [here])(https://github.com/goauthentik/helm). This is documented [here](https://goauthentik.io/docs/installation/kubernetes/)
For bigger setups, there is a Helm Chart [here](https://github.com/goauthentik/helm). This is documented [here](https://goauthentik.io/docs/installation/kubernetes/)
## Screenshots

View File

@ -2,10 +2,13 @@
## Supported Versions
(.x being the latest patch release for each version)
| Version | Supported |
| ---------- | ------------------ |
| 2021.4.x | :white_check_mark: |
| 2021.5.x | :white_check_mark: |
| 2021.6.x | :white_check_mark: |
| 2021.7.x | :white_check_mark: |
## Reporting a Vulnerability

View File

@ -1,3 +1,3 @@
"""authentik"""
__version__ = "2021.7.1-rc1"
__version__ = "2021.8.4"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -23,9 +23,7 @@ def get_events_per_1h(**filter_kwargs) -> list[dict[str, int]]:
date_from = now() - timedelta(days=1)
result = (
Event.objects.filter(created__gte=date_from, **filter_kwargs)
.annotate(
age=ExpressionWrapper(now() - F("created"), output_field=DurationField())
)
.annotate(age=ExpressionWrapper(now() - F("created"), output_field=DurationField()))
.annotate(age_hours=ExtractHour("age"))
.values("age_hours")
.annotate(count=Count("pk"))
@ -37,8 +35,7 @@ def get_events_per_1h(**filter_kwargs) -> list[dict[str, int]]:
for hour in range(0, -24, -1):
results.append(
{
"x_cord": time.mktime((_now + timedelta(hours=hour)).timetuple())
* 1000,
"x_cord": time.mktime((_now + timedelta(hours=hour)).timetuple()) * 1000,
"y_cord": data[hour * -1],
}
)

View File

@ -16,6 +16,8 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from authentik.core.api.utils import PassiveSerializer
from authentik.outposts.managed import MANAGED_OUTPOST
from authentik.outposts.models import Outpost
class RuntimeDict(TypedDict):
@ -32,12 +34,18 @@ class RuntimeDict(TypedDict):
class SystemSerializer(PassiveSerializer):
"""Get system information."""
env = SerializerMethodField()
http_headers = SerializerMethodField()
http_host = SerializerMethodField()
http_is_secure = SerializerMethodField()
runtime = SerializerMethodField()
tenant = SerializerMethodField()
server_time = SerializerMethodField()
embedded_outpost_host = SerializerMethodField()
def get_env(self, request: Request) -> dict[str, str]:
"""Get Environment"""
return os.environ.copy()
def get_http_headers(self, request: Request) -> dict[str, str]:
"""Get HTTP Request headers"""
@ -61,9 +69,7 @@ class SystemSerializer(PassiveSerializer):
return {
"python_version": python_version,
"gunicorn_version": ".".join(str(x) for x in gunicorn_version),
"environment": "kubernetes"
if SERVICE_HOST_ENV_NAME in os.environ
else "compose",
"environment": "kubernetes" if SERVICE_HOST_ENV_NAME in os.environ else "compose",
"architecture": platform.machine(),
"platform": platform.platform(),
"uname": " ".join(platform.uname()),
@ -77,6 +83,13 @@ class SystemSerializer(PassiveSerializer):
"""Current server time"""
return now()
def get_embedded_outpost_host(self, request: Request) -> str:
"""Get the FQDN configured on the embeddded outpost"""
outposts = Outpost.objects.filter(managed=MANAGED_OUTPOST)
if not outposts.exists():
return ""
return outposts.first().config.authentik_host
class SystemView(APIView):
"""Get system information."""

View File

@ -92,10 +92,7 @@ class TaskViewSet(ViewSet):
task_func.delay(*task.task_call_args, **task.task_call_kwargs)
messages.success(
self.request,
_(
"Successfully re-scheduled Task %(name)s!"
% {"name": task.task_name}
),
_("Successfully re-scheduled Task %(name)s!" % {"name": task.task_name}),
)
return Response(status=204)
except ImportError: # pragma: no cover

View File

@ -41,9 +41,7 @@ class VersionSerializer(PassiveSerializer):
def get_outdated(self, instance) -> bool:
"""Check if we're running the latest version"""
return parse(self.get_version_current(instance)) < parse(
self.get_version_latest(instance)
)
return parse(self.get_version_current(instance)) < parse(self.get_version_latest(instance))
class VersionView(APIView):

View File

@ -17,9 +17,7 @@ class WorkerView(APIView):
permission_classes = [IsAdminUser]
@extend_schema(
responses=inline_serializer("Workers", fields={"count": IntegerField()})
)
@extend_schema(responses=inline_serializer("Workers", fields={"count": IntegerField()}))
def get(self, request: Request) -> Response:
"""Get currently connected worker count."""
count = len(CELERY_APP.control.ping(timeout=0.5))

View File

@ -37,18 +37,14 @@ def _set_prom_info():
def update_latest_version(self: MonitoredTask):
"""Update latest version info"""
try:
response = get(
"https://api.github.com/repos/goauthentik/authentik/releases/latest"
)
response = get("https://api.github.com/repos/goauthentik/authentik/releases/latest")
response.raise_for_status()
data = response.json()
tag_name = data.get("tag_name")
upstream_version = tag_name.split("/")[1]
cache.set(VERSION_CACHE_KEY, upstream_version, VERSION_CACHE_TIMEOUT)
self.set_status(
TaskResult(
TaskResultStatus.SUCCESSFUL, ["Successfully updated latest Version"]
)
TaskResult(TaskResultStatus.SUCCESSFUL, ["Successfully updated latest Version"])
)
_set_prom_info()
# Check if upstream version is newer than what we're running,

View File

@ -27,9 +27,7 @@ class TestAdminAPI(TestCase):
response = self.client.get(reverse("authentik_api:admin_system_tasks-list"))
self.assertEqual(response.status_code, 200)
body = loads(response.content)
self.assertTrue(
any(task["task_name"] == "clean_expired_models" for task in body)
)
self.assertTrue(any(task["task_name"] == "clean_expired_models" for task in body))
def test_tasks_single(self):
"""Test Task API (read single)"""
@ -45,9 +43,7 @@ class TestAdminAPI(TestCase):
self.assertEqual(body["status"], TaskResultStatus.SUCCESSFUL.name)
self.assertEqual(body["task_name"], "clean_expired_models")
response = self.client.get(
reverse(
"authentik_api:admin_system_tasks-detail", kwargs={"pk": "qwerqwer"}
)
reverse("authentik_api:admin_system_tasks-detail", kwargs={"pk": "qwerqwer"})
)
self.assertEqual(response.status_code, 404)

View File

@ -3,18 +3,20 @@ from base64 import b64decode
from binascii import Error
from typing import Any, Optional, Union
from django.conf import settings
from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.request import Request
from structlog.stdlib import get_logger
from authentik.core.models import Token, TokenIntents, User
from authentik.outposts.models import Outpost
LOGGER = get_logger()
# pylint: disable=too-many-return-statements
def token_from_header(raw_header: bytes) -> Optional[Token]:
def bearer_auth(raw_header: bytes) -> Optional[User]:
"""raw_header in the Format of `Bearer dGVzdDp0ZXN0`"""
auth_credentials = raw_header.decode()
if auth_credentials == "" or " " not in auth_credentials:
@ -31,15 +33,33 @@ def token_from_header(raw_header: bytes) -> Optional[Token]:
raise AuthenticationFailed("Malformed header")
# Accept credentials with username and without
if ":" in auth_credentials:
_, password = auth_credentials.split(":")
_, _, password = auth_credentials.partition(":")
else:
password = auth_credentials
if password == "": # nosec
raise AuthenticationFailed("Malformed header")
tokens = Token.filter_not_expired(key=password, intent=TokenIntents.INTENT_API)
if not tokens.exists():
raise AuthenticationFailed("Token invalid/expired")
return tokens.first()
LOGGER.info("Authenticating via secret_key")
user = token_secret_key(password)
if not user:
raise AuthenticationFailed("Token invalid/expired")
return user
return tokens.first().user
def token_secret_key(value: str) -> Optional[User]:
"""Check if the token is the secret key
and return the service account for the managed outpost"""
from authentik.outposts.managed import MANAGED_OUTPOST
if value != settings.SECRET_KEY:
return None
outposts = Outpost.objects.filter(managed=MANAGED_OUTPOST)
if not outposts:
return None
outpost = outposts.first()
return outpost.user
class TokenAuthentication(BaseAuthentication):
@ -49,9 +69,9 @@ class TokenAuthentication(BaseAuthentication):
"""Token-based authentication using HTTP Bearer authentication"""
auth = get_authorization_header(request)
token = token_from_header(auth)
user = bearer_auth(auth)
# None is only returned when the header isn't set.
if not token:
if not user:
return None
return (token.user, None) # pragma: no cover
return (user, None) # pragma: no cover

View File

@ -7,9 +7,7 @@ from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
def permission_required(
perm: Optional[str] = None, other_perms: Optional[list[str]] = None
):
def permission_required(perm: Optional[str] = None, other_perms: Optional[list[str]] = None):
"""Check permissions for a single custom action"""
def wrapper_outter(func: Callable):

View File

@ -63,9 +63,7 @@ def postprocess_schema_responses(result, generator, **kwargs): # noqa: W0613
method["responses"].setdefault("400", validation_error.ref)
method["responses"].setdefault("403", generic_error.ref)
result["components"] = generator.registry.build(
spectacular_settings.APPEND_COMPONENTS
)
result["components"] = generator.registry.build(spectacular_settings.APPEND_COMPONENTS)
# This is a workaround for authentik/stages/prompt/stage.py
# since the serializer PromptChallengeResponse

View File

@ -1,12 +1,14 @@
"""Test API Authentication"""
from base64 import b64encode
from django.conf import settings
from django.test import TestCase
from guardian.shortcuts import get_anonymous_user
from rest_framework.exceptions import AuthenticationFailed
from authentik.api.authentication import token_from_header
from authentik.core.models import Token, TokenIntents
from authentik.api.authentication import bearer_auth
from authentik.core.models import USER_ATTRIBUTE_SA, Token, TokenIntents
from authentik.outposts.managed import OutpostManager
class TestAPIAuth(TestCase):
@ -14,36 +16,41 @@ class TestAPIAuth(TestCase):
def test_valid_basic(self):
"""Test valid token"""
token = Token.objects.create(
intent=TokenIntents.INTENT_API, user=get_anonymous_user()
)
token = Token.objects.create(intent=TokenIntents.INTENT_API, user=get_anonymous_user())
auth = b64encode(f":{token.key}".encode()).decode()
self.assertEqual(token_from_header(f"Basic {auth}".encode()), token)
self.assertEqual(bearer_auth(f"Basic {auth}".encode()), token.user)
def test_valid_bearer(self):
"""Test valid token"""
token = Token.objects.create(
intent=TokenIntents.INTENT_API, user=get_anonymous_user()
)
self.assertEqual(token_from_header(f"Bearer {token.key}".encode()), token)
token = Token.objects.create(intent=TokenIntents.INTENT_API, user=get_anonymous_user())
self.assertEqual(bearer_auth(f"Bearer {token.key}".encode()), token.user)
def test_invalid_type(self):
"""Test invalid type"""
with self.assertRaises(AuthenticationFailed):
token_from_header("foo bar".encode())
bearer_auth("foo bar".encode())
def test_invalid_decode(self):
"""Test invalid bas64"""
with self.assertRaises(AuthenticationFailed):
token_from_header("Basic bar".encode())
bearer_auth("Basic bar".encode())
def test_invalid_empty_password(self):
"""Test invalid with empty password"""
with self.assertRaises(AuthenticationFailed):
token_from_header("Basic :".encode())
bearer_auth("Basic :".encode())
def test_invalid_no_token(self):
"""Test invalid with no token"""
with self.assertRaises(AuthenticationFailed):
auth = b64encode(":abc".encode()).decode()
self.assertIsNone(token_from_header(f"Basic :{auth}".encode()))
self.assertIsNone(bearer_auth(f"Basic :{auth}".encode()))
def test_managed_outpost(self):
"""Test managed outpost"""
with self.assertRaises(AuthenticationFailed):
user = bearer_auth(f"Bearer {settings.SECRET_KEY}".encode())
OutpostManager().run()
user = bearer_auth(f"Bearer {settings.SECRET_KEY}".encode())
self.assertEqual(user.attributes[USER_ATTRIBUTE_SA], True)

View File

@ -1,8 +1,10 @@
"""authentik api urls"""
from django.urls import include, path
from authentik.api.v2.urls import urlpatterns as v2_urls
from authentik.api.v3.urls import urlpatterns as v3_urls
urlpatterns = [
path("v2beta/", include(v2_urls)),
# Remove in 2022.1
path("v2beta/", include(v3_urls)),
path("v3/", include(v3_urls)),
]

View File

@ -5,7 +5,7 @@ from django.conf import settings
from django.db import models
from drf_spectacular.utils import extend_schema
from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME
from rest_framework.fields import BooleanField, CharField, ChoiceField, ListField
from rest_framework.fields import BooleanField, CharField, ChoiceField, IntegerField, ListField
from rest_framework.permissions import AllowAny
from rest_framework.request import Request
from rest_framework.response import Response
@ -33,6 +33,11 @@ class ConfigSerializer(PassiveSerializer):
capabilities = ListField(child=ChoiceField(choices=Capabilities.choices))
cache_timeout = IntegerField(required=True)
cache_timeout_flows = IntegerField(required=True)
cache_timeout_policies = IntegerField(required=True)
cache_timeout_reputation = IntegerField(required=True)
class ConfigView(APIView):
"""Read-only view set that returns the current session's Configs"""
@ -49,7 +54,7 @@ class ConfigView(APIView):
caps.append(Capabilities.CAN_GEO_IP)
if SERVICE_HOST_ENV_NAME in environ:
# Running in k8s, only s3 backup is supported
if CONFIG.y_bool("postgresql.s3_backup"):
if CONFIG.y("postgresql.s3_backup"):
caps.append(Capabilities.CAN_BACKUP)
else:
# Running in compose, backup is always supported
@ -65,6 +70,10 @@ class ConfigView(APIView):
"error_reporting_environment": CONFIG.y("error_reporting.environment"),
"error_reporting_send_pii": CONFIG.y("error_reporting.send_pii"),
"capabilities": self.get_capabilities(),
"cache_timeout": int(CONFIG.y("redis.cache_timeout")),
"cache_timeout_flows": int(CONFIG.y("redis.cache_timeout_flows")),
"cache_timeout_policies": int(CONFIG.y("redis.cache_timeout_policies")),
"cache_timeout_reputation": int(CONFIG.y("redis.cache_timeout_reputation")),
}
)
return Response(config.data)

View File

@ -4,16 +4,44 @@ from json import loads
from django.conf import settings
from django.http.request import HttpRequest
from django.http.response import HttpResponse
from django.views.generic.base import View
from requests import post
from requests.exceptions import RequestException
from rest_framework.authentication import SessionAuthentication
from rest_framework.parsers import BaseParser
from rest_framework.permissions import AllowAny
from rest_framework.request import Request
from rest_framework.throttling import AnonRateThrottle
from rest_framework.views import APIView
from authentik.lib.config import CONFIG
class SentryTunnelView(View):
class PlainTextParser(BaseParser):
"""Plain text parser."""
media_type = "text/plain"
def parse(self, stream, media_type=None, parser_context=None) -> str:
"""Simply return a string representing the body of the request."""
return stream.read()
class CsrfExemptSessionAuthentication(SessionAuthentication):
"""CSRF-exempt Session authentication"""
def enforce_csrf(self, request: Request):
return # To not perform the csrf check previously happening
class SentryTunnelView(APIView):
"""Sentry tunnel, to prevent ad blockers from blocking sentry"""
serializer_class = None
parser_classes = [PlainTextParser]
throttle_classes = [AnonRateThrottle]
permission_classes = [AllowAny]
authentication_classes = [CsrfExemptSessionAuthentication]
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""Sentry tunnel, to prevent ad blockers from blocking sentry"""
# Only allow usage of this endpoint when error reporting is enabled

View File

@ -1,4 +1,4 @@
"""api v2 urls"""
"""api v3 urls"""
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from drf_spectacular.views import SpectacularAPIView
@ -10,8 +10,8 @@ from authentik.admin.api.system import SystemView
from authentik.admin.api.tasks import TaskViewSet
from authentik.admin.api.version import VersionView
from authentik.admin.api.workers import WorkerView
from authentik.api.v2.config import ConfigView
from authentik.api.v2.sentry import SentryTunnelView
from authentik.api.v3.config import ConfigView
from authentik.api.v3.sentry import SentryTunnelView
from authentik.api.views import APIBrowserView
from authentik.core.api.applications import ApplicationViewSet
from authentik.core.api.authenticated_sessions import AuthenticatedSessionViewSet
@ -52,21 +52,14 @@ from authentik.policies.reputation.api import (
from authentik.providers.ldap.api import LDAPOutpostConfigViewSet, LDAPProviderViewSet
from authentik.providers.oauth2.api.provider import OAuth2ProviderViewSet
from authentik.providers.oauth2.api.scope import ScopeMappingViewSet
from authentik.providers.oauth2.api.tokens import (
AuthorizationCodeViewSet,
RefreshTokenViewSet,
)
from authentik.providers.proxy.api import (
ProxyOutpostConfigViewSet,
ProxyProviderViewSet,
)
from authentik.providers.oauth2.api.tokens import AuthorizationCodeViewSet, RefreshTokenViewSet
from authentik.providers.proxy.api import ProxyOutpostConfigViewSet, ProxyProviderViewSet
from authentik.providers.saml.api import SAMLPropertyMappingViewSet, SAMLProviderViewSet
from authentik.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet
from authentik.sources.oauth.api.source import OAuthSourceViewSet
from authentik.sources.oauth.api.source_connection import (
UserOAuthSourceConnectionViewSet,
)
from authentik.sources.plex.api import PlexSourceViewSet
from authentik.sources.oauth.api.source_connection import UserOAuthSourceConnectionViewSet
from authentik.sources.plex.api.source import PlexSourceViewSet
from authentik.sources.plex.api.source_connection import PlexSourceConnectionViewSet
from authentik.sources.saml.api import SAMLSourceViewSet
from authentik.stages.authenticator_duo.api import (
AuthenticatorDuoStageViewSet,
@ -83,9 +76,7 @@ from authentik.stages.authenticator_totp.api import (
TOTPAdminDeviceViewSet,
TOTPDeviceViewSet,
)
from authentik.stages.authenticator_validate.api import (
AuthenticatorValidateStageViewSet,
)
from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageViewSet
from authentik.stages.authenticator_webauthn.api import (
AuthenticateWebAuthnStageViewSet,
WebAuthnAdminDeviceViewSet,
@ -122,9 +113,7 @@ router.register("core/tenants", TenantViewSet)
router.register("outposts/instances", OutpostViewSet)
router.register("outposts/service_connections/all", ServiceConnectionViewSet)
router.register("outposts/service_connections/docker", DockerServiceConnectionViewSet)
router.register(
"outposts/service_connections/kubernetes", KubernetesServiceConnectionViewSet
)
router.register("outposts/service_connections/kubernetes", KubernetesServiceConnectionViewSet)
router.register("outposts/proxy", ProxyOutpostConfigViewSet)
router.register("outposts/ldap", LDAPOutpostConfigViewSet)
@ -139,7 +128,8 @@ router.register("events/transports", NotificationTransportViewSet)
router.register("events/rules", NotificationRuleViewSet)
router.register("sources/all", SourceViewSet)
router.register("sources/oauth_user_connections", UserOAuthSourceConnectionViewSet)
router.register("sources/user_connections/oauth", UserOAuthSourceConnectionViewSet)
router.register("sources/user_connections/plex", PlexSourceConnectionViewSet)
router.register("sources/ldap", LDAPSourceViewSet)
router.register("sources/saml", SAMLSourceViewSet)
router.register("sources/oauth", OAuthSourceViewSet)
@ -184,9 +174,7 @@ router.register(
StaticAdminDeviceViewSet,
basename="admin-staticdevice",
)
router.register(
"authenticators/admin/totp", TOTPAdminDeviceViewSet, basename="admin-totpdevice"
)
router.register("authenticators/admin/totp", TOTPAdminDeviceViewSet, basename="admin-totpdevice")
router.register(
"authenticators/admin/webauthn",
WebAuthnAdminDeviceViewSet,

View File

@ -4,14 +4,9 @@ from django.db.models import QuerySet
from django.http.response import HttpResponseBadRequest
from django.shortcuts import get_object_or_404
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import (
OpenApiParameter,
OpenApiResponse,
extend_schema,
inline_serializer,
)
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import BooleanField, CharField, FileField, ReadOnlyField
from rest_framework.fields import ReadOnlyField
from rest_framework.parsers import MultiPartParser
from rest_framework.request import Request
from rest_framework.response import Response
@ -24,6 +19,7 @@ from authentik.admin.api.metrics import CoordinateSerializer, get_events_per_1h
from authentik.api.decorators import permission_required
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import FilePathSerializer, FileUploadSerializer
from authentik.core.models import Application, User
from authentik.events.models import EventAction
from authentik.policies.api.exec import PolicyTestResultSerializer
@ -114,23 +110,26 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
},
)
@action(detail=True, methods=["GET"])
# pylint: disable=unused-argument
def check_access(self, request: Request, slug: str) -> Response:
"""Check access to a single application by slug"""
# Don't use self.get_object as that checks for view_application permission
# which the user might not have, even if they have access
application = get_object_or_404(Application, slug=slug)
# If the current user is superuser, they can set `for_user`
for_user = self.request.user
if self.request.user.is_superuser and "for_user" in request.data:
for_user = get_object_or_404(User, pk=request.data.get("for_user"))
engine = PolicyEngine(application, for_user, self.request)
for_user = request.user
if request.user.is_superuser and "for_user" in request.query_params:
try:
for_user = get_object_or_404(User, pk=request.query_params.get("for_user"))
except ValueError:
return HttpResponseBadRequest("for_user must be numerical")
engine = PolicyEngine(application, for_user, request)
engine.use_cache = False
engine.build()
result = engine.result
response = PolicyTestResultSerializer(PolicyResult(False))
if result.passing:
response = PolicyTestResultSerializer(PolicyResult(True))
if self.request.user.is_superuser:
if request.user.is_superuser:
response = PolicyTestResultSerializer(result)
return Response(response.data)
@ -145,19 +144,19 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
)
def list(self, request: Request) -> Response:
"""Custom list method that checks Policy based access instead of guardian"""
should_cache = request.GET.get("search", "") == ""
superuser_full_list = str(request.GET.get("superuser_full_list", "false")).lower() == "true"
if superuser_full_list and request.user.is_superuser:
return super().list(request)
# To prevent the user from having to double login when prompt is set to login
# and the user has just signed it. This session variable is set in the UserLoginStage
# and is (quite hackily) removed from the session in applications's API's List method
self.request.session.pop(USER_LOGIN_AUTHENTICATED, None)
queryset = self._filter_queryset_for_list(self.get_queryset())
self.paginate_queryset(queryset)
should_cache = request.GET.get("search", "") == ""
superuser_full_list = (
str(request.GET.get("superuser_full_list", "false")).lower() == "true"
)
if superuser_full_list and request.user.is_superuser:
serializer = self.get_serializer(queryset, many=True)
return self.get_paginated_response(serializer.data)
allowed_applications = []
if not should_cache:
allowed_applications = self._get_allowed_applications(queryset)
@ -177,13 +176,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
@permission_required("authentik_core.change_application")
@extend_schema(
request={
"multipart/form-data": inline_serializer(
"SetIcon",
fields={
"file": FileField(required=False),
"clear": BooleanField(default=False),
},
)
"multipart/form-data": FileUploadSerializer,
},
responses={
200: OpenApiResponse(description="Success"),
@ -215,7 +208,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
@permission_required("authentik_core.change_application")
@extend_schema(
request=inline_serializer("SetIconURL", fields={"url": CharField()}),
request=FilePathSerializer,
responses={
200: OpenApiResponse(description="Success"),
400: OpenApiResponse(description="Bad request"),
@ -238,9 +231,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
app.save()
return Response({})
@permission_required(
"authentik_core.view_application", ["authentik_events.view_event"]
)
@permission_required("authentik_core.view_application", ["authentik_events.view_event"])
@extend_schema(responses={200: CoordinateSerializer(many=True)})
@action(detail=True, pagination_class=None, filter_backends=[])
# pylint: disable=unused-argument

View File

@ -68,9 +68,7 @@ class AuthenticatedSessionSerializer(ModelSerializer):
"""Get parsed user agent"""
return user_agent_parser.Parse(instance.last_user_agent)
def get_geo_ip(
self, instance: AuthenticatedSession
) -> Optional[GeoIPDict]: # pragma: no cover
def get_geo_ip(self, instance: AuthenticatedSession) -> Optional[GeoIPDict]: # pragma: no cover
"""Get parsed user agent"""
return GEOIP_READER.city_dict(instance.last_ip)

View File

@ -1,5 +1,7 @@
"""Groups API Viewset"""
from django.db.models.query import QuerySet
from django_filters.filters import ModelMultipleChoiceFilter
from django_filters.filterset import FilterSet
from rest_framework.fields import BooleanField, CharField, JSONField
from rest_framework.serializers import ListSerializer, ModelSerializer
from rest_framework.viewsets import ModelViewSet
@ -57,13 +59,32 @@ class GroupSerializer(ModelSerializer):
]
class GroupFilter(FilterSet):
"""Filter for groups"""
members_by_username = ModelMultipleChoiceFilter(
field_name="users__username",
to_field_name="username",
queryset=User.objects.all(),
)
members_by_pk = ModelMultipleChoiceFilter(
field_name="users",
queryset=User.objects.all(),
)
class Meta:
model = Group
fields = ["name", "is_superuser", "members_by_pk", "members_by_username"]
class GroupViewSet(UsedByMixin, ModelViewSet):
"""Group Viewset"""
queryset = Group.objects.all()
serializer_class = GroupSerializer
search_fields = ["name", "is_superuser"]
filterset_fields = ["name", "is_superuser"]
filterset_class = GroupFilter
ordering = ["name"]
def _filter_queryset_for_list(self, queryset: QuerySet) -> QuerySet:

View File

@ -15,11 +15,7 @@ from rest_framework.viewsets import GenericViewSet
from authentik.api.decorators import permission_required
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import (
MetaNameSerializer,
PassiveSerializer,
TypeCreateSerializer,
)
from authentik.core.api.utils import MetaNameSerializer, PassiveSerializer, TypeCreateSerializer
from authentik.core.expression import PropertyMappingEvaluator
from authentik.core.models import PropertyMapping
from authentik.lib.utils.reflection import all_subclasses
@ -141,9 +137,7 @@ class PropertyMappingViewSet(
self.request,
**test_params.validated_data.get("context", {}),
)
response_data["result"] = dumps(
result, indent=(4 if format_result else None)
)
response_data["result"] = dumps(result, indent=(4 if format_result else None))
except Exception as exc: # pylint: disable=broad-except
response_data["result"] = str(exc)
response_data["successful"] = False

View File

@ -74,6 +74,8 @@ class SourceViewSet(
for subclass in all_subclasses(self.queryset.model):
subclass: Source
component = ""
if len(subclass.__subclasses__()) > 0:
continue
if subclass._meta.abstract:
component = subclass.__bases__[0]().component
else:
@ -93,9 +95,7 @@ class SourceViewSet(
@action(detail=False, pagination_class=None, filter_backends=[])
def user_settings(self, request: Request) -> Response:
"""Get all sources the user can configure"""
_all_sources: Iterable[Source] = Source.objects.filter(
enabled=True
).select_subclasses()
_all_sources: Iterable[Source] = Source.objects.filter(enabled=True).select_subclasses()
matching_sources: list[UserSettingSerializer] = []
for source in _all_sources:
user_settings = source.ui_user_settings

View File

@ -1,7 +1,10 @@
"""Tokens API Viewset"""
from typing import Any
from django.http.response import Http404
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField
from rest_framework.request import Request
from rest_framework.response import Response
@ -20,7 +23,16 @@ from authentik.managed.api import ManagedSerializer
class TokenSerializer(ManagedSerializer, ModelSerializer):
"""Token Serializer"""
user = UserSerializer(required=False)
user_obj = UserSerializer(required=False, source="user")
def validate(self, attrs: dict[Any, str]) -> dict[Any, str]:
"""Ensure only API or App password tokens are created."""
request: Request = self.context["request"]
attrs.setdefault("user", request.user)
attrs.setdefault("intent", TokenIntents.INTENT_API)
if attrs.get("intent") not in [TokenIntents.INTENT_API, TokenIntents.INTENT_APP_PASSWORD]:
raise ValidationError(f"Invalid intent {attrs.get('intent')}")
return attrs
class Meta:
@ -31,11 +43,14 @@ class TokenSerializer(ManagedSerializer, ModelSerializer):
"identifier",
"intent",
"user",
"user_obj",
"description",
"expires",
"expiring",
]
depth = 2
extra_kwargs = {
"user": {"required": False},
}
class TokenViewSerializer(PassiveSerializer):
@ -48,7 +63,7 @@ class TokenViewSet(UsedByMixin, ModelViewSet):
"""Token Viewset"""
lookup_field = "identifier"
queryset = Token.filter_not_expired()
queryset = Token.objects.all()
serializer_class = TokenSerializer
search_fields = [
"identifier",
@ -69,10 +84,7 @@ class TokenViewSet(UsedByMixin, ModelViewSet):
def perform_create(self, serializer: TokenSerializer):
serializer.save(
user=self.request.user,
intent=TokenIntents.INTENT_API,
expiring=self.request.user.attributes.get(
USER_ATTRIBUTE_TOKEN_EXPIRING, True
),
expiring=self.request.user.attributes.get(USER_ATTRIBUTE_TOKEN_EXPIRING, True),
)
@permission_required("authentik_core.view_token_key")
@ -89,7 +101,5 @@ class TokenViewSet(UsedByMixin, ModelViewSet):
token: Token = self.get_object()
if token.is_expired:
raise Http404
Event.new(EventAction.SECRET_VIEW, secret=token).from_http( # noqa # nosec
request
)
Event.new(EventAction.SECRET_VIEW, secret=token).from_http(request) # noqa # nosec
return Response(TokenViewSerializer({"key": token.key}).data)

View File

@ -79,9 +79,7 @@ class UsedByMixin:
).all():
# Only merge shadows on first object
if first_object:
shadows += getattr(
manager.model._meta, "authentik_used_by_shadows", []
)
shadows += getattr(manager.model._meta, "authentik_used_by_shadows", [])
first_object = False
serializer = UsedBySerializer(
data={

View File

@ -1,39 +1,62 @@
"""User API Views"""
from json import loads
from typing import Optional
from django.db.models.query import QuerySet
from django.db.transaction import atomic
from django.db.utils import IntegrityError
from django.urls import reverse_lazy
from django.utils.http import urlencode
from django_filters.filters import BooleanFilter, CharFilter
from django.utils.translation import gettext as _
from django_filters.filters import BooleanFilter, CharFilter, ModelMultipleChoiceFilter
from django_filters.filterset import FilterSet
from drf_spectacular.utils import extend_schema, extend_schema_field
from guardian.utils import get_anonymous_user
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import (
OpenApiParameter,
extend_schema,
extend_schema_field,
inline_serializer,
)
from guardian.shortcuts import get_anonymous_user, get_objects_for_user
from rest_framework.decorators import action
from rest_framework.fields import CharField, JSONField, SerializerMethodField
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import (
BooleanField,
ListSerializer,
ModelSerializer,
PrimaryKeyRelatedField,
Serializer,
ValidationError,
)
from rest_framework.viewsets import ModelViewSet
from rest_framework_guardian.filters import ObjectPermissionsFilter
from structlog.stdlib import get_logger
from authentik.admin.api.metrics import CoordinateSerializer, get_events_per_1h
from authentik.api.decorators import permission_required
from authentik.core.api.groups import GroupSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import LinkSerializer, PassiveSerializer, is_dict
from authentik.core.middleware import (
SESSION_IMPERSONATE_ORIGINAL_USER,
SESSION_IMPERSONATE_USER,
from authentik.core.middleware import SESSION_IMPERSONATE_ORIGINAL_USER, SESSION_IMPERSONATE_USER
from authentik.core.models import (
USER_ATTRIBUTE_SA,
USER_ATTRIBUTE_TOKEN_EXPIRING,
Group,
Token,
TokenIntents,
User,
)
from authentik.core.models import Token, TokenIntents, User
from authentik.events.models import EventAction
from authentik.stages.email.models import EmailStage
from authentik.stages.email.tasks import send_mails
from authentik.stages.email.utils import TemplateEmailMessage
from authentik.tenants.models import Tenant
LOGGER = get_logger()
class UserSerializer(ModelSerializer):
"""User Serializer"""
@ -41,7 +64,10 @@ class UserSerializer(ModelSerializer):
is_superuser = BooleanField(read_only=True)
avatar = CharField(read_only=True)
attributes = JSONField(validators=[is_dict], required=False)
groups = ListSerializer(child=GroupSerializer(), read_only=True, source="ak_groups")
groups = PrimaryKeyRelatedField(
allow_empty=True, many=True, source="ak_groups", queryset=Group.objects.all()
)
groups_obj = ListSerializer(child=GroupSerializer(), read_only=True, source="ak_groups")
uid = CharField(read_only=True)
class Meta:
@ -55,6 +81,7 @@ class UserSerializer(ModelSerializer):
"last_login",
"is_superuser",
"groups",
"groups_obj",
"email",
"avatar",
"attributes",
@ -62,12 +89,40 @@ class UserSerializer(ModelSerializer):
]
class UserSelfSerializer(ModelSerializer):
"""User Serializer for information a user can retrieve about themselves and
update about themselves"""
is_superuser = BooleanField(read_only=True)
avatar = CharField(read_only=True)
groups = ListSerializer(child=GroupSerializer(), read_only=True, source="ak_groups")
uid = CharField(read_only=True)
class Meta:
model = User
fields = [
"pk",
"username",
"name",
"is_active",
"is_superuser",
"groups",
"email",
"avatar",
"uid",
]
extra_kwargs = {
"is_active": {"read_only": True},
}
class SessionUserSerializer(PassiveSerializer):
"""Response for the /user/me endpoint, returns the currently active user (as `user` property)
and, if this user is being impersonated, the original user in the `original` property."""
user = UserSerializer()
original = UserSerializer(required=False)
user = UserSelfSerializer()
original = UserSelfSerializer(required=False)
class UserMetricsSerializer(PassiveSerializer):
@ -87,17 +142,13 @@ class UserMetricsSerializer(PassiveSerializer):
def get_logins_failed_per_1h(self, _):
"""Get failed logins per hour for the last 24 hours"""
user = self.context["user"]
return get_events_per_1h(
action=EventAction.LOGIN_FAILED, context__username=user.username
)
return get_events_per_1h(action=EventAction.LOGIN_FAILED, context__username=user.username)
@extend_schema_field(CoordinateSerializer(many=True))
def get_authorizations_per_1h(self, _):
"""Get failed logins per hour for the last 24 hours"""
user = self.context["user"]
return get_events_per_1h(
action=EventAction.AUTHORIZE_APPLICATION, user__pk=user.pk
)
return get_events_per_1h(action=EventAction.AUTHORIZE_APPLICATION, user__pk=user.pk)
class UsersFilter(FilterSet):
@ -112,6 +163,16 @@ class UsersFilter(FilterSet):
is_superuser = BooleanFilter(field_name="ak_groups", lookup_expr="is_superuser")
groups_by_name = ModelMultipleChoiceFilter(
field_name="ak_groups__name",
to_field_name="name",
queryset=Group.objects.all(),
)
groups_by_pk = ModelMultipleChoiceFilter(
field_name="ak_groups",
queryset=Group.objects.all(),
)
# pylint: disable=unused-argument
def filter_attributes(self, queryset, name, value):
"""Filter attributes by query args"""
@ -128,7 +189,16 @@ class UsersFilter(FilterSet):
class Meta:
model = User
fields = ["username", "name", "is_active", "is_superuser", "attributes"]
fields = [
"username",
"email",
"name",
"is_active",
"is_superuser",
"attributes",
"groups_by_name",
"groups_by_pk",
]
class UserViewSet(UsedByMixin, ModelViewSet):
@ -136,27 +206,114 @@ class UserViewSet(UsedByMixin, ModelViewSet):
queryset = User.objects.none()
serializer_class = UserSerializer
search_fields = ["username", "name", "is_active"]
search_fields = ["username", "name", "is_active", "email"]
filterset_class = UsersFilter
def get_queryset(self): # pragma: no cover
return User.objects.all().exclude(pk=get_anonymous_user().pk)
def _create_recovery_link(self) -> tuple[Optional[str], Optional[Token]]:
"""Create a recovery link (when the current tenant has a recovery flow set),
that can either be shown to an admin or sent to the user directly"""
tenant: Tenant = self.request._request.tenant
# Check that there is a recovery flow, if not return an error
flow = tenant.flow_recovery
if not flow:
LOGGER.debug("No recovery flow set")
return None, None
user: User = self.get_object()
token, __ = Token.objects.get_or_create(
identifier=f"{user.uid}-password-reset",
user=user,
intent=TokenIntents.INTENT_RECOVERY,
)
querystring = urlencode({"token": token.key})
link = self.request.build_absolute_uri(
reverse_lazy("authentik_core:if-flow", kwargs={"flow_slug": flow.slug})
+ f"?{querystring}"
)
return link, token
@permission_required(None, ["authentik_core.add_user", "authentik_core.add_token"])
@extend_schema(
request=inline_serializer(
"UserServiceAccountSerializer",
{
"name": CharField(required=True),
"create_group": BooleanField(default=False),
},
),
responses={
200: inline_serializer(
"UserServiceAccountResponse",
{
"username": CharField(required=True),
"token": CharField(required=True),
},
)
},
)
@action(detail=False, methods=["POST"], pagination_class=None, filter_backends=[])
def service_account(self, request: Request) -> Response:
"""Create a new user account that is marked as a service account"""
username = request.data.get("name")
create_group = request.data.get("create_group", False)
with atomic():
try:
user = User.objects.create(
username=username,
name=username,
attributes={USER_ATTRIBUTE_SA: True, USER_ATTRIBUTE_TOKEN_EXPIRING: False},
)
if create_group:
group = Group.objects.create(
name=username,
)
group.users.add(user)
token = Token.objects.create(
identifier=f"service-account-{username}-password",
intent=TokenIntents.INTENT_APP_PASSWORD,
user=user,
)
return Response({"username": user.username, "token": token.key})
except (IntegrityError) as exc:
return Response(data={"non_field_errors": [str(exc)]}, status=400)
@extend_schema(responses={200: SessionUserSerializer(many=False)})
@action(detail=False, pagination_class=None, filter_backends=[])
# pylint: disable=invalid-name
def me(self, request: Request) -> Response:
"""Get information about current user"""
serializer = SessionUserSerializer(
data={"user": UserSerializer(request.user).data}
)
serializer = SessionUserSerializer(data={"user": UserSelfSerializer(request.user).data})
if SESSION_IMPERSONATE_USER in request._request.session:
serializer.initial_data["original"] = UserSerializer(
serializer.initial_data["original"] = UserSelfSerializer(
request._request.session[SESSION_IMPERSONATE_ORIGINAL_USER]
).data
serializer.is_valid()
return Response(serializer.data)
@extend_schema(request=UserSelfSerializer, responses={200: SessionUserSerializer(many=False)})
@action(
methods=["PUT"],
detail=False,
pagination_class=None,
filter_backends=[],
permission_classes=[IsAuthenticated],
)
def update_self(self, request: Request) -> Response:
"""Allow users to change information on their own profile"""
data = UserSelfSerializer(instance=User.objects.get(pk=request.user.pk), data=request.data)
if not data.is_valid():
return Response(data.errors)
new_user = data.save()
# If we're impersonating, we need to update that user object
# since it caches the full object
if SESSION_IMPERSONATE_USER in request.session:
request.session[SESSION_IMPERSONATE_USER] = new_user
serializer = SessionUserSerializer(data={"user": UserSelfSerializer(request.user).data})
serializer.is_valid()
return Response(serializer.data)
@permission_required("authentik_core.view_user", ["authentik_events.view_event"])
@extend_schema(responses={200: UserMetricsSerializer(many=False)})
@action(detail=True, pagination_class=None, filter_backends=[])
@ -179,24 +336,60 @@ class UserViewSet(UsedByMixin, ModelViewSet):
# pylint: disable=invalid-name, unused-argument
def recovery(self, request: Request, pk: int) -> Response:
"""Create a temporary link that a user can use to recover their accounts"""
tenant: Tenant = request._request.tenant
# Check that there is a recovery flow, if not return an error
flow = tenant.flow_recovery
if not flow:
link, _ = self._create_recovery_link()
if not link:
LOGGER.debug("Couldn't create token")
return Response({"link": ""}, status=404)
user: User = self.get_object()
token, __ = Token.objects.get_or_create(
identifier=f"{user.uid}-password-reset",
user=user,
intent=TokenIntents.INTENT_RECOVERY,
)
querystring = urlencode({"token": token.key})
link = request.build_absolute_uri(
reverse_lazy("authentik_core:if-flow", kwargs={"flow_slug": flow.slug})
+ f"?{querystring}"
)
return Response({"link": link})
@permission_required("authentik_core.reset_user_password")
@extend_schema(
parameters=[
OpenApiParameter(
name="email_stage",
location=OpenApiParameter.QUERY,
type=OpenApiTypes.STR,
required=True,
)
],
responses={
"204": Serializer(),
"404": Serializer(),
},
)
@action(detail=True, pagination_class=None, filter_backends=[])
# pylint: disable=invalid-name, unused-argument
def recovery_email(self, request: Request, pk: int) -> Response:
"""Create a temporary link that a user can use to recover their accounts"""
for_user = self.get_object()
if for_user.email == "":
LOGGER.debug("User doesn't have an email address")
return Response(status=404)
link, token = self._create_recovery_link()
if not link:
LOGGER.debug("Couldn't create token")
return Response(status=404)
# Lookup the email stage to assure the current user can access it
stages = get_objects_for_user(
request.user, "authentik_stages_email.view_emailstage"
).filter(pk=request.query_params.get("email_stage"))
if not stages.exists():
LOGGER.debug("Email stage does not exist/user has no permissions")
return Response(status=404)
email_stage: EmailStage = stages.first()
message = TemplateEmailMessage(
subject=_(email_stage.subject),
template_name=email_stage.template,
to=[for_user.email],
template_context={
"url": link,
"user": for_user,
"expires": token.expires,
},
)
send_mails(email_stage, message)
return Response(status=204)
def _filter_queryset_for_list(self, queryset: QuerySet) -> QuerySet:
"""Custom filter_queryset method which ignores guardian, but still supports sorting"""
for backend in list(self.filter_backends):
@ -206,6 +399,6 @@ class UserViewSet(UsedByMixin, ModelViewSet):
return queryset
def filter_queryset(self, queryset):
if self.request.user.has_perm("authentik_core.view_group"):
if self.request.user.has_perm("authentik_core.view_user"):
return self._filter_queryset_for_list(queryset)
return super().filter_queryset(queryset)

View File

@ -2,21 +2,15 @@
from typing import Any
from django.db.models import Model
from rest_framework.fields import CharField, IntegerField
from rest_framework.serializers import (
Serializer,
SerializerMethodField,
ValidationError,
)
from rest_framework.fields import BooleanField, CharField, FileField, IntegerField
from rest_framework.serializers import Serializer, SerializerMethodField, ValidationError
def is_dict(value: Any):
"""Ensure a value is a dictionary, useful for JSONFields"""
if isinstance(value, dict):
return
raise ValidationError(
"Value must be a dictionary, and not have any duplicate keys."
)
raise ValidationError("Value must be a dictionary, and not have any duplicate keys.")
class PassiveSerializer(Serializer):
@ -25,13 +19,21 @@ class PassiveSerializer(Serializer):
def create(self, validated_data: dict) -> Model: # pragma: no cover
return Model()
def update(
self, instance: Model, validated_data: dict
) -> Model: # pragma: no cover
def update(self, instance: Model, validated_data: dict) -> Model: # pragma: no cover
return Model()
class Meta:
model = Model
class FileUploadSerializer(PassiveSerializer):
"""Serializer to upload file"""
file = FileField(required=False)
clear = BooleanField(default=False)
class FilePathSerializer(PassiveSerializer):
"""Serializer to upload file"""
url = CharField()
class MetaNameSerializer(PassiveSerializer):

59
authentik/core/auth.py Normal file
View File

@ -0,0 +1,59 @@
"""Authenticate with tokens"""
from typing import Any, Optional
from django.contrib.auth.backends import ModelBackend
from django.http.request import HttpRequest
from authentik.core.models import Token, TokenIntents, User
from authentik.events.utils import cleanse_dict, sanitize_dict
from authentik.flows.planner import FlowPlan
from authentik.flows.views import SESSION_KEY_PLAN
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
class InbuiltBackend(ModelBackend):
"""Inbuilt backend"""
def authenticate(
self, request: HttpRequest, username: Optional[str], password: Optional[str], **kwargs: Any
) -> Optional[User]:
user = super().authenticate(request, username=username, password=password, **kwargs)
if not user:
return None
self.set_method("password", request)
return user
def set_method(self, method: str, request: Optional[HttpRequest], **kwargs):
"""Set method data on current flow, if possbiel"""
if not request:
return
# Since we can't directly pass other variables to signals, and we want to log the method
# and the token used, we assume we're running in a flow and set a variable in the context
flow_plan: FlowPlan = request.session[SESSION_KEY_PLAN]
flow_plan.context[PLAN_CONTEXT_METHOD] = method
flow_plan.context[PLAN_CONTEXT_METHOD_ARGS] = cleanse_dict(sanitize_dict(kwargs))
request.session[SESSION_KEY_PLAN] = flow_plan
class TokenBackend(InbuiltBackend):
"""Authenticate with token"""
def authenticate(
self, request: HttpRequest, username: Optional[str], password: Optional[str], **kwargs: Any
) -> Optional[User]:
try:
user = User._default_manager.get_by_natural_key(username)
except User.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
User().set_password(password)
return None
tokens = Token.filter_not_expired(
user=user, key=password, intent=TokenIntents.INTENT_APP_PASSWORD
)
if not tokens.exists():
return None
token = tokens.first()
self.set_method("password", request, token=token)
return token.user

View File

@ -4,7 +4,7 @@ from channels.generic.websocket import JsonWebsocketConsumer
from rest_framework.exceptions import AuthenticationFailed
from structlog.stdlib import get_logger
from authentik.api.authentication import token_from_header
from authentik.api.authentication import bearer_auth
from authentik.core.models import User
LOGGER = get_logger()
@ -24,12 +24,12 @@ class AuthJsonConsumer(JsonWebsocketConsumer):
raw_header = headers[b"authorization"]
try:
token = token_from_header(raw_header)
# token is only None when no header was given, in which case we deny too
if not token:
user = bearer_auth(raw_header)
# user is only None when no header was given, in which case we deny too
if not user:
raise DenyConnection()
except AuthenticationFailed as exc:
LOGGER.warning("Failed to authenticate", exc=exc)
raise DenyConnection()
self.user = token.user
self.user = user

View File

@ -38,9 +38,7 @@ class Migration(migrations.Migration):
("password", models.CharField(max_length=128, verbose_name="password")),
(
"last_login",
models.DateTimeField(
blank=True, null=True, verbose_name="last login"
),
models.DateTimeField(blank=True, null=True, verbose_name="last login"),
),
(
"is_superuser",
@ -53,35 +51,25 @@ class Migration(migrations.Migration):
(
"username",
models.CharField(
error_messages={
"unique": "A user with that username already exists."
},
error_messages={"unique": "A user with that username already exists."},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[
django.contrib.auth.validators.UnicodeUsernameValidator()
],
validators=[django.contrib.auth.validators.UnicodeUsernameValidator()],
verbose_name="username",
),
),
(
"first_name",
models.CharField(
blank=True, max_length=30, verbose_name="first name"
),
models.CharField(blank=True, max_length=30, verbose_name="first name"),
),
(
"last_name",
models.CharField(
blank=True, max_length=150, verbose_name="last name"
),
models.CharField(blank=True, max_length=150, verbose_name="last name"),
),
(
"email",
models.EmailField(
blank=True, max_length=254, verbose_name="email address"
),
models.EmailField(blank=True, max_length=254, verbose_name="email address"),
),
(
"is_staff",
@ -217,9 +205,7 @@ class Migration(migrations.Migration):
),
(
"expires",
models.DateTimeField(
default=authentik.core.models.default_token_duration
),
models.DateTimeField(default=authentik.core.models.default_token_duration),
),
("expiring", models.BooleanField(default=True)),
("description", models.TextField(blank=True, default="")),
@ -306,9 +292,7 @@ class Migration(migrations.Migration):
("name", models.TextField(help_text="Application's display Name.")),
(
"slug",
models.SlugField(
help_text="Internal application name, used in URLs."
),
models.SlugField(help_text="Internal application name, used in URLs."),
),
("skip_authorization", models.BooleanField(default=False)),
("meta_launch_url", models.URLField(blank=True, default="")),

View File

@ -17,9 +17,7 @@ def create_default_user(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
username="akadmin", email="root@localhost", name="authentik Default Admin"
)
if "TF_BUILD" in environ or "AK_ADMIN_PASS" in environ or settings.TEST:
akadmin.set_password(
environ.get("AK_ADMIN_PASS", "akadmin"), signal=False
) # noqa # nosec
akadmin.set_password(environ.get("AK_ADMIN_PASS", "akadmin"), signal=False) # noqa # nosec
else:
akadmin.set_unusable_password()
akadmin.save()

View File

@ -13,8 +13,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name="source",
name="slug",
field=models.SlugField(
help_text="Internal source name, used in URLs.", unique=True
),
field=models.SlugField(help_text="Internal source name, used in URLs.", unique=True),
),
]

View File

@ -13,8 +13,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name="user",
name="first_name",
field=models.CharField(
blank=True, max_length=150, verbose_name="first name"
),
field=models.CharField(blank=True, max_length=150, verbose_name="first name"),
),
]

View File

@ -40,9 +40,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name="user",
name="pb_groups",
field=models.ManyToManyField(
related_name="users", to="authentik_core.Group"
),
field=models.ManyToManyField(related_name="users", to="authentik_core.Group"),
),
migrations.AddField(
model_name="group",

View File

@ -42,9 +42,7 @@ class Migration(migrations.Migration):
),
migrations.AddIndex(
model_name="token",
index=models.Index(
fields=["identifier"], name="authentik_co_identif_1a34a8_idx"
),
index=models.Index(fields=["identifier"], name="authentik_co_identif_1a34a8_idx"),
),
migrations.RunPython(set_default_token_key),
]

View File

@ -17,8 +17,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name="application",
name="meta_icon",
field=models.FileField(
blank=True, default="", upload_to="application-icons/"
),
field=models.FileField(blank=True, default="", upload_to="application-icons/"),
),
]

View File

@ -25,9 +25,7 @@ class Migration(migrations.Migration):
),
migrations.AddIndex(
model_name="token",
index=models.Index(
fields=["identifier"], name="authentik_c_identif_d9d032_idx"
),
index=models.Index(fields=["identifier"], name="authentik_c_identif_d9d032_idx"),
),
migrations.AddIndex(
model_name="token",

View File

@ -32,16 +32,12 @@ class Migration(migrations.Migration):
fields=[
(
"expires",
models.DateTimeField(
default=authentik.core.models.default_token_duration
),
models.DateTimeField(default=authentik.core.models.default_token_duration),
),
("expiring", models.BooleanField(default=True)),
(
"uuid",
models.UUIDField(
default=uuid.uuid4, primary_key=True, serialize=False
),
models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False),
),
("session_key", models.CharField(max_length=40)),
("last_ip", models.TextField()),

View File

@ -13,8 +13,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name="application",
name="meta_icon",
field=models.FileField(
default=None, null=True, upload_to="application-icons/"
),
field=models.FileField(default=None, null=True, upload_to="application-icons/"),
),
]

View File

@ -17,4 +17,11 @@ class Migration(migrations.Migration):
default=None, max_length=500, null=True, upload_to="application-icons/"
),
),
migrations.AlterModelOptions(
name="authenticatedsession",
options={
"verbose_name": "Authenticated Session",
"verbose_name_plural": "Authenticated Sessions",
},
),
]

View File

@ -0,0 +1,37 @@
# Generated by Django 3.2.5 on 2021-08-11 19:40
from os import environ
from django.apps.registry import Apps
from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def create_default_user_token(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
# We have to use a direct import here, otherwise we get an object manager error
from authentik.core.models import Token, TokenIntents, User
db_alias = schema_editor.connection.alias
akadmin = User.objects.using(db_alias).filter(username="akadmin")
if not akadmin.exists():
return
if "AK_ADMIN_TOKEN" not in environ:
return
Token.objects.using(db_alias).create(
identifier="authentik-boostrap-token",
user=akadmin.first(),
intent=TokenIntents.INTENT_API,
expiring=False,
key=environ["AK_ADMIN_TOKEN"],
)
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0026_alter_application_meta_icon"),
]
operations = [
migrations.RunPython(create_default_user_token),
]

View File

@ -0,0 +1,26 @@
# Generated by Django 3.2.6 on 2021-08-23 14:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0027_bootstrap_token"),
]
operations = [
migrations.AlterField(
model_name="token",
name="intent",
field=models.TextField(
choices=[
("verification", "Intent Verification"),
("api", "Intent Api"),
("recovery", "Intent Recovery"),
("app_password", "Intent App Password"),
],
default="verification",
),
),
]

View File

@ -28,6 +28,7 @@ from authentik.core.signals import password_changed
from authentik.core.types import UILoginButton, UserSettingSerializer
from authentik.flows.models import Flow
from authentik.lib.config import CONFIG
from authentik.lib.generators import generate_id
from authentik.lib.models import CreatedUpdatedModel, SerializerModel
from authentik.lib.utils.http import get_client_ip
from authentik.managed.models import ManagedModel
@ -54,7 +55,9 @@ def default_token_duration():
def default_token_key():
"""Default token key"""
return uuid4().hex
# We use generate_id since the chars in the key should be easy
# to use in Emails (for verification) and URLs (for recovery)
return generate_id(128)
class Group(models.Model):
@ -154,9 +157,7 @@ class User(GuardianUserMixin, AbstractUser):
("s", "158"),
("r", "g"),
]
gravatar_url = (
f"{GRAVATAR_URL}/avatar/{mail_hash}?{urlencode(parameters, doseq=True)}"
)
gravatar_url = f"{GRAVATAR_URL}/avatar/{mail_hash}?{urlencode(parameters, doseq=True)}"
return escape(gravatar_url)
return mode % {
"username": self.username,
@ -186,9 +187,7 @@ class Provider(SerializerModel):
related_name="provider_authorization",
)
property_mappings = models.ManyToManyField(
"PropertyMapping", default=None, blank=True
)
property_mappings = models.ManyToManyField("PropertyMapping", default=None, blank=True)
objects = InheritanceManager()
@ -218,9 +217,7 @@ class Application(PolicyBindingModel):
add custom fields and other properties"""
name = models.TextField(help_text=_("Application's display Name."))
slug = models.SlugField(
help_text=_("Internal application name, used in URLs."), unique=True
)
slug = models.SlugField(help_text=_("Internal application name, used in URLs."), unique=True)
provider = models.OneToOneField(
"Provider", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT
)
@ -244,9 +241,7 @@ class Application(PolicyBindingModel):
it is returned as-is"""
if not self.meta_icon:
return None
if self.meta_icon.name.startswith("http") or self.meta_icon.name.startswith(
"/static"
):
if self.meta_icon.name.startswith("http") or self.meta_icon.name.startswith("/static"):
return self.meta_icon.name
return self.meta_icon.url
@ -301,14 +296,10 @@ class Source(ManagedModel, SerializerModel, PolicyBindingModel):
"""Base Authentication source, i.e. an OAuth Provider, SAML Remote or LDAP Server"""
name = models.TextField(help_text=_("Source's display Name."))
slug = models.SlugField(
help_text=_("Internal source name, used in URLs."), unique=True
)
slug = models.SlugField(help_text=_("Internal source name, used in URLs."), unique=True)
enabled = models.BooleanField(default=True)
property_mappings = models.ManyToManyField(
"PropertyMapping", default=None, blank=True
)
property_mappings = models.ManyToManyField("PropertyMapping", default=None, blank=True)
authentication_flow = models.ForeignKey(
Flow,
@ -420,6 +411,9 @@ class TokenIntents(models.TextChoices):
# Recovery use for the recovery app
INTENT_RECOVERY = "recovery"
# App-specific passwords
INTENT_APP_PASSWORD = "app_password" # nosec
class Token(ManagedModel, ExpiringModel):
"""Token used to authenticate the User for API Access or confirm another Stage like Email."""
@ -438,6 +432,7 @@ class Token(ManagedModel, ExpiringModel):
from authentik.events.models import Event, EventAction
self.key = default_token_key()
self.expires = default_token_duration()
self.save(*args, **kwargs)
Event.new(
action=EventAction.SECRET_ROTATE,
@ -481,9 +476,7 @@ class PropertyMapping(SerializerModel, ManagedModel):
"""Get serializer for this model"""
raise NotImplementedError
def evaluate(
self, user: Optional[User], request: Optional[HttpRequest], **kwargs
) -> Any:
def evaluate(self, user: Optional[User], request: Optional[HttpRequest], **kwargs) -> Any:
"""Evaluate `self.expression` using `**kwargs` as Context."""
from authentik.core.expression import PropertyMappingEvaluator
@ -491,8 +484,8 @@ class PropertyMapping(SerializerModel, ManagedModel):
evaluator.set_context(user, request, self, **kwargs)
try:
return evaluator.evaluate(self.expression)
except (ValueError, SyntaxError) as exc:
raise PropertyMappingExpressionException from exc
except Exception as exc:
raise PropertyMappingExpressionException(str(exc)) from exc
def __str__(self):
return f"Property Mapping {self.name}"
@ -522,9 +515,7 @@ class AuthenticatedSession(ExpiringModel):
last_used = models.DateTimeField(auto_now=True)
@staticmethod
def from_request(
request: HttpRequest, user: User
) -> Optional["AuthenticatedSession"]:
def from_request(request: HttpRequest, user: User) -> Optional["AuthenticatedSession"]:
"""Create a new session from a http request"""
if not hasattr(request, "session") or not request.session.session_key:
return None
@ -535,3 +526,8 @@ class AuthenticatedSession(ExpiringModel):
last_user_agent=request.META.get("HTTP_USER_AGENT", ""),
expires=request.session.get_expiry_date(),
)
class Meta:
verbose_name = _("Authenticated Session")
verbose_name_plural = _("Authenticated Sessions")

View File

@ -14,9 +14,7 @@ from prometheus_client import Gauge
# Arguments: user: User, password: str
password_changed = Signal()
GAUGE_MODELS = Gauge(
"authentik_models", "Count of various objects", ["model_name", "app"]
)
GAUGE_MODELS = Gauge("authentik_models", "Count of various objects", ["model_name", "app"])
if TYPE_CHECKING:
from authentik.core.models import AuthenticatedSession, User
@ -60,15 +58,11 @@ def user_logged_out_session(sender, request: HttpRequest, user: "User", **_):
"""Delete AuthenticatedSession if it exists"""
from authentik.core.models import AuthenticatedSession
AuthenticatedSession.objects.filter(
session_key=request.session.session_key
).delete()
AuthenticatedSession.objects.filter(session_key=request.session.session_key).delete()
@receiver(pre_delete)
def authenticated_session_delete(
sender: Type[Model], instance: "AuthenticatedSession", **_
):
def authenticated_session_delete(sender: Type[Model], instance: "AuthenticatedSession", **_):
"""Delete session when authenticated session is deleted"""
from authentik.core.models import AuthenticatedSession

View File

@ -11,16 +11,8 @@ from django.urls import reverse
from django.utils.translation import gettext as _
from structlog.stdlib import get_logger
from authentik.core.models import (
Source,
SourceUserMatchingModes,
User,
UserSourceConnection,
)
from authentik.core.sources.stage import (
PLAN_CONTEXT_SOURCES_CONNECTION,
PostUserEnrollmentStage,
)
from authentik.core.models import Source, SourceUserMatchingModes, User, UserSourceConnection
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION, PostUserEnrollmentStage
from authentik.events.models import Event, EventAction
from authentik.flows.models import Flow, Stage, in_memory_stage
from authentik.flows.planner import (
@ -33,7 +25,7 @@ from authentik.flows.planner import (
from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN
from authentik.lib.utils.urls import redirect_with_qs
from authentik.policies.utils import delete_none_keys
from authentik.stages.password import BACKEND_DJANGO
from authentik.stages.password import BACKEND_INBUILT
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
@ -76,9 +68,7 @@ class SourceFlowManager:
# pylint: disable=too-many-return-statements
def get_action(self, **kwargs) -> tuple[Action, Optional[UserSourceConnection]]:
"""decide which action should be taken"""
new_connection = self.connection_type(
source=self.source, identifier=self.identifier
)
new_connection = self.connection_type(source=self.source, identifier=self.identifier)
# When request is authenticated, always link
if self.request.user.is_authenticated:
new_connection.user = self.request.user
@ -113,9 +103,7 @@ class SourceFlowManager:
SourceUserMatchingModes.USERNAME_DENY,
]:
if not self.enroll_info.get("username", None):
self._logger.warning(
"Refusing to use none username", source=self.source
)
self._logger.warning("Refusing to use none username", source=self.source)
return Action.DENY, None
query = Q(username__exact=self.enroll_info.get("username", None))
self._logger.debug("trying to link with existing user", query=query)
@ -141,11 +129,11 @@ class SourceFlowManager:
self._logger.info("denying source because user exists", user=user)
return Action.DENY, None
# Should never get here as default enroll case is returned above.
return Action.DENY, None
return Action.DENY, None # pragma: no cover
def update_connection(
self, connection: UserSourceConnection, **kwargs
) -> UserSourceConnection:
) -> UserSourceConnection: # pragma: no cover
"""Optionally make changes to the connection after it is looked up/created."""
return connection
@ -178,7 +166,7 @@ class SourceFlowManager:
% {"source": self.source.name}
),
)
return redirect("/")
return redirect(reverse("authentik_core:root-redirect"))
# pylint: disable=unused-argument
def get_stages_to_append(self, flow: Flow) -> list[Stage]:
@ -201,7 +189,7 @@ class SourceFlowManager:
kwargs.update(
{
# Since we authenticate the user by their token, they have no backend set
PLAN_CONTEXT_AUTHENTICATION_BACKEND: BACKEND_DJANGO,
PLAN_CONTEXT_AUTHENTICATION_BACKEND: BACKEND_INBUILT,
PLAN_CONTEXT_SSO: True,
PLAN_CONTEXT_SOURCE: self.source,
PLAN_CONTEXT_REDIRECT: final_redirect,
@ -229,10 +217,7 @@ class SourceFlowManager:
"""Login user and redirect."""
messages.success(
self.request,
_(
"Successfully authenticated with %(source)s!"
% {"source": self.source.name}
),
_("Successfully authenticated with %(source)s!" % {"source": self.source.name}),
)
flow_kwargs = {PLAN_CONTEXT_PENDING_USER: connection.user}
return self._handle_login_flow(self.source.authentication_flow, **flow_kwargs)
@ -270,10 +255,7 @@ class SourceFlowManager:
"""User was not authenticated and previous request was not authenticated."""
messages.success(
self.request,
_(
"Successfully authenticated with %(source)s!"
% {"source": self.source.name}
),
_("Successfully authenticated with %(source)s!" % {"source": self.source.name}),
)
# We run the Flow planner here so we can pass the Pending user in the context

View File

@ -7,12 +7,14 @@ from boto3.exceptions import Boto3Error
from botocore.exceptions import BotoCoreError, ClientError
from dbbackup.db.exceptions import CommandConnectorError
from django.contrib.humanize.templatetags.humanize import naturaltime
from django.contrib.sessions.backends.cache import KEY_PREFIX
from django.core import management
from django.core.cache import cache
from django.utils.timezone import now
from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME
from structlog.stdlib import get_logger
from authentik.core.models import ExpiringModel
from authentik.core.models import AuthenticatedSession, ExpiringModel
from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus
from authentik.lib.config import CONFIG
from authentik.root.celery import CELERY_APP
@ -27,15 +29,23 @@ def clean_expired_models(self: MonitoredTask):
for cls in ExpiringModel.__subclasses__():
cls: ExpiringModel
objects = (
cls.objects.all()
.exclude(expiring=False)
.exclude(expiring=True, expires__gt=now())
cls.objects.all().exclude(expiring=False).exclude(expiring=True, expires__gt=now())
)
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
amount = 0
for session in AuthenticatedSession.objects.all():
cache_key = f"{KEY_PREFIX}{session.session_key}"
value = cache.get(cache_key)
if not value:
session.delete()
amount += 1
LOGGER.debug("Expired sessions", model=AuthenticatedSession, amount=amount)
messages.append(f"Expired {amount} {AuthenticatedSession._meta.verbose_name_plural}")
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, messages))

View File

@ -17,9 +17,7 @@ class TestApplicationsAPI(APITestCase):
self.denied = Application.objects.create(name="denied", slug="denied")
PolicyBinding.objects.create(
target=self.denied,
policy=DummyPolicy.objects.create(
name="deny", result=False, wait_min=1, wait_max=2
),
policy=DummyPolicy.objects.create(name="deny", result=False, wait_min=1, wait_max=2),
order=0,
)
@ -33,9 +31,7 @@ class TestApplicationsAPI(APITestCase):
)
)
self.assertEqual(response.status_code, 200)
self.assertJSONEqual(
force_str(response.content), {"messages": [], "passing": True}
)
self.assertJSONEqual(force_str(response.content), {"messages": [], "passing": True})
response = self.client.get(
reverse(
"authentik_api:application-check-access",
@ -43,9 +39,7 @@ class TestApplicationsAPI(APITestCase):
)
)
self.assertEqual(response.status_code, 200)
self.assertJSONEqual(
force_str(response.content), {"messages": ["dummy"], "passing": False}
)
self.assertJSONEqual(force_str(response.content), {"messages": ["dummy"], "passing": False})
def test_list(self):
"""Test list operation without superuser_full_list"""

View File

@ -46,9 +46,7 @@ class TestImpersonation(TestCase):
self.client.force_login(self.other_user)
self.client.get(
reverse(
"authentik_core:impersonate-init", kwargs={"user_id": self.akadmin.pk}
)
reverse("authentik_core:impersonate-init", kwargs={"user_id": self.akadmin.pk})
)
response = self.client.get(reverse("authentik_api:user-me"))

View File

@ -22,9 +22,7 @@ class TestModels(TestCase):
def test_token_expire_no_expire(self):
"""Test token expiring with "expiring" set"""
token = Token.objects.create(
expires=now(), user=get_anonymous_user(), expiring=False
)
token = Token.objects.create(expires=now(), user=get_anonymous_user(), expiring=False)
sleep(0.5)
self.assertFalse(token.is_expired)

View File

@ -16,9 +16,7 @@ class TestPropertyMappings(TestCase):
def test_expression(self):
"""Test expression"""
mapping = PropertyMapping.objects.create(
name="test", expression="return 'test'"
)
mapping = PropertyMapping.objects.create(name="test", expression="return 'test'")
self.assertEqual(mapping.evaluate(None, None), "test")
def test_expression_syntax(self):
@ -31,7 +29,7 @@ class TestPropertyMappings(TestCase):
"""Test expression error"""
expr = "return aaa"
mapping = PropertyMapping.objects.create(name="test", expression=expr)
with self.assertRaises(NameError):
with self.assertRaises(PropertyMappingExpressionException):
mapping.evaluate(None, None)
events = Event.objects.filter(
action=EventAction.PROPERTY_MAPPING_EXCEPTION, context__expression=expr
@ -44,7 +42,7 @@ class TestPropertyMappings(TestCase):
expr = "return aaa"
request = self.factory.get("/")
mapping = PropertyMapping.objects.create(name="test", expression=expr)
with self.assertRaises(NameError):
with self.assertRaises(PropertyMappingExpressionException):
mapping.evaluate(get_anonymous_user(), request)
events = Event.objects.filter(
action=EventAction.PROPERTY_MAPPING_EXCEPTION, context__expression=expr

View File

@ -23,9 +23,7 @@ class TestPropertyMappingAPI(APITestCase):
def test_test_call(self):
"""Test PropertMappings's test endpoint"""
response = self.client.post(
reverse(
"authentik_api:propertymapping-test", kwargs={"pk": self.mapping.pk}
),
reverse("authentik_api:propertymapping-test", kwargs={"pk": self.mapping.pk}),
data={
"user": self.user.pk,
},

View File

@ -0,0 +1,145 @@
"""Test Source flow_manager"""
from django.contrib.auth.models import AnonymousUser
from django.test import TestCase
from django.test.client import RequestFactory
from guardian.utils import get_anonymous_user
from authentik.core.models import SourceUserMatchingModes, User
from authentik.core.sources.flow_manager import Action
from authentik.lib.generators import generate_id
from authentik.lib.tests.utils import get_request
from authentik.sources.oauth.models import OAuthSource, UserOAuthSourceConnection
from authentik.sources.oauth.views.callback import OAuthSourceFlowManager
class TestSourceFlowManager(TestCase):
"""Test Source flow_manager"""
def setUp(self) -> None:
super().setUp()
self.source = OAuthSource.objects.create(name="test")
self.factory = RequestFactory()
self.identifier = generate_id()
def test_unauthenticated_enroll(self):
"""Test un-authenticated user enrolling"""
flow_manager = OAuthSourceFlowManager(
self.source, get_request("/", user=AnonymousUser()), self.identifier, {}
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.ENROLL)
flow_manager.get_flow()
def test_unauthenticated_auth(self):
"""Test un-authenticated user authenticating"""
UserOAuthSourceConnection.objects.create(
user=get_anonymous_user(), source=self.source, identifier=self.identifier
)
flow_manager = OAuthSourceFlowManager(
self.source, get_request("/", user=AnonymousUser()), self.identifier, {}
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.AUTH)
flow_manager.get_flow()
def test_authenticated_link(self):
"""Test authenticated user linking"""
UserOAuthSourceConnection.objects.create(
user=get_anonymous_user(), source=self.source, identifier=self.identifier
)
user = User.objects.create(username="foo", email="foo@bar.baz")
flow_manager = OAuthSourceFlowManager(
self.source, get_request("/", user=user), self.identifier, {}
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.LINK)
flow_manager.get_flow()
def test_unauthenticated_enroll_email(self):
"""Test un-authenticated user enrolling (link on email)"""
User.objects.create(username="foo", email="foo@bar.baz")
self.source.user_matching_mode = SourceUserMatchingModes.EMAIL_LINK
# Without email, deny
flow_manager = OAuthSourceFlowManager(
self.source, get_request("/", user=AnonymousUser()), self.identifier, {}
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.DENY)
flow_manager.get_flow()
# With email
flow_manager = OAuthSourceFlowManager(
self.source,
get_request("/", user=AnonymousUser()),
self.identifier,
{"email": "foo@bar.baz"},
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.LINK)
flow_manager.get_flow()
def test_unauthenticated_enroll_username(self):
"""Test un-authenticated user enrolling (link on username)"""
User.objects.create(username="foo", email="foo@bar.baz")
self.source.user_matching_mode = SourceUserMatchingModes.USERNAME_LINK
# Without username, deny
flow_manager = OAuthSourceFlowManager(
self.source, get_request("/", user=AnonymousUser()), self.identifier, {}
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.DENY)
flow_manager.get_flow()
# With username
flow_manager = OAuthSourceFlowManager(
self.source,
get_request("/", user=AnonymousUser()),
self.identifier,
{"username": "foo"},
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.LINK)
flow_manager.get_flow()
def test_unauthenticated_enroll_username_deny(self):
"""Test un-authenticated user enrolling (deny on username)"""
User.objects.create(username="foo", email="foo@bar.baz")
self.source.user_matching_mode = SourceUserMatchingModes.USERNAME_DENY
# With non-existent username, enroll
flow_manager = OAuthSourceFlowManager(
self.source,
get_request("/", user=AnonymousUser()),
self.identifier,
{
"username": "bar",
},
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.ENROLL)
flow_manager.get_flow()
# With username
flow_manager = OAuthSourceFlowManager(
self.source,
get_request("/", user=AnonymousUser()),
self.identifier,
{"username": "foo"},
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.DENY)
flow_manager.get_flow()
def test_unauthenticated_enroll_link_non_existent(self):
"""Test un-authenticated user enrolling (link on username), username doesn't exist"""
self.source.user_matching_mode = SourceUserMatchingModes.USERNAME_LINK
flow_manager = OAuthSourceFlowManager(
self.source,
get_request("/", user=AnonymousUser()),
self.identifier,
{"username": "foo"},
)
action, _ = flow_manager.get_action()
self.assertEqual(action, Action.ENROLL)
flow_manager.get_flow()

View File

@ -4,12 +4,7 @@ from django.utils.timezone import now
from guardian.shortcuts import get_anonymous_user
from rest_framework.test import APITestCase
from authentik.core.models import (
USER_ATTRIBUTE_TOKEN_EXPIRING,
Token,
TokenIntents,
User,
)
from authentik.core.models import USER_ATTRIBUTE_TOKEN_EXPIRING, Token, TokenIntents, User
from authentik.core.tasks import clean_expired_models
@ -32,6 +27,14 @@ class TestTokenAPI(APITestCase):
self.assertEqual(token.intent, TokenIntents.INTENT_API)
self.assertEqual(token.expiring, True)
def test_token_create_invalid(self):
"""Test token creation endpoint (invalid data)"""
response = self.client.post(
reverse("authentik_api:token-list"),
{"identifier": "test-token", "intent": TokenIntents.INTENT_RECOVERY},
)
self.assertEqual(response.status_code, 400)
def test_token_create_non_expiring(self):
"""Test token creation endpoint"""
self.user.attributes[USER_ATTRIBUTE_TOKEN_EXPIRING] = False

View File

@ -0,0 +1,40 @@
"""Test token auth"""
from django.test import TestCase
from authentik.core.auth import TokenBackend
from authentik.core.models import Token, TokenIntents, User
from authentik.flows.planner import FlowPlan
from authentik.flows.views import SESSION_KEY_PLAN
from authentik.lib.tests.utils import get_request
class TestTokenAuth(TestCase):
"""Test token auth"""
def setUp(self) -> None:
self.user = User.objects.create(username="test-user")
self.token = Token.objects.create(
expiring=False, user=self.user, intent=TokenIntents.INTENT_APP_PASSWORD
)
# To test with session we need to create a request and pass it through all middlewares
self.request = get_request("/")
self.request.session[SESSION_KEY_PLAN] = FlowPlan("test")
def test_token_auth(self):
"""Test auth with token"""
self.assertEqual(
TokenBackend().authenticate(self.request, "test-user", self.token.key), self.user
)
def test_token_auth_none(self):
"""Test auth with token (non-existent user)"""
self.assertIsNone(
TokenBackend().authenticate(self.request, "test-user-foo", self.token.key), self.user
)
def test_token_auth_invalid(self):
"""Test auth with token (invalid token)"""
self.assertIsNone(
TokenBackend().authenticate(self.request, "test-user", self.token.key + "foo"),
self.user,
)

View File

@ -3,6 +3,9 @@ from django.urls.base import reverse
from rest_framework.test import APITestCase
from authentik.core.models import User
from authentik.flows.models import Flow, FlowDesignation
from authentik.stages.email.models import EmailStage
from authentik.tenants.models import Tenant
class TestUsersAPI(APITestCase):
@ -27,3 +30,114 @@ class TestUsersAPI(APITestCase):
reverse("authentik_api:user-metrics", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 403)
def test_recovery_no_flow(self):
"""Test user recovery link (no recovery flow set)"""
self.client.force_login(self.admin)
response = self.client.get(
reverse("authentik_api:user-recovery", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 404)
def test_recovery(self):
"""Test user recovery link (no recovery flow set)"""
flow = Flow.objects.create(
name="test", title="test", slug="test", designation=FlowDesignation.RECOVERY
)
tenant: Tenant = Tenant.objects.first()
tenant.flow_recovery = flow
tenant.save()
self.client.force_login(self.admin)
response = self.client.get(
reverse("authentik_api:user-recovery", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 200)
def test_recovery_email_no_flow(self):
"""Test user recovery link (no recovery flow set)"""
self.client.force_login(self.admin)
response = self.client.get(
reverse("authentik_api:user-recovery-email", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 404)
self.user.email = "foo@bar.baz"
self.user.save()
response = self.client.get(
reverse("authentik_api:user-recovery-email", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 404)
def test_recovery_email_no_stage(self):
"""Test user recovery link (no email stage)"""
self.user.email = "foo@bar.baz"
self.user.save()
flow = Flow.objects.create(
name="test", title="test", slug="test", designation=FlowDesignation.RECOVERY
)
tenant: Tenant = Tenant.objects.first()
tenant.flow_recovery = flow
tenant.save()
self.client.force_login(self.admin)
response = self.client.get(
reverse("authentik_api:user-recovery-email", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 404)
def test_recovery_email(self):
"""Test user recovery link"""
self.user.email = "foo@bar.baz"
self.user.save()
flow = Flow.objects.create(
name="test", title="test", slug="test", designation=FlowDesignation.RECOVERY
)
tenant: Tenant = Tenant.objects.first()
tenant.flow_recovery = flow
tenant.save()
stage = EmailStage.objects.create(name="email")
self.client.force_login(self.admin)
response = self.client.get(
reverse(
"authentik_api:user-recovery-email",
kwargs={"pk": self.user.pk},
)
+ f"?email_stage={stage.pk}"
)
self.assertEqual(response.status_code, 204)
def test_service_account(self):
"""Service account creation"""
self.client.force_login(self.admin)
response = self.client.post(reverse("authentik_api:user-service-account"))
self.assertEqual(response.status_code, 400)
response = self.client.post(
reverse("authentik_api:user-service-account"),
data={
"name": "test-sa",
"create_group": True,
},
)
self.assertEqual(response.status_code, 200)
self.assertTrue(User.objects.filter(username="test-sa").exists())
def test_service_account_invalid(self):
"""Service account creation (twice with same name, expect error)"""
self.client.force_login(self.admin)
response = self.client.post(
reverse("authentik_api:user-service-account"),
data={
"name": "test-sa",
"create_group": True,
},
)
self.assertEqual(response.status_code, 200)
self.assertTrue(User.objects.filter(username="test-sa").exists())
response = self.client.post(
reverse("authentik_api:user-service-account"),
data={
"name": "test-sa",
"create_group": True,
},
)
self.assertEqual(response.status_code, 400)

View File

@ -5,10 +5,7 @@ from django.shortcuts import get_object_or_404, redirect
from django.views import View
from structlog.stdlib import get_logger
from authentik.core.middleware import (
SESSION_IMPERSONATE_ORIGINAL_USER,
SESSION_IMPERSONATE_USER,
)
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
@ -21,9 +18,7 @@ class ImpersonateInitView(View):
def get(self, request: HttpRequest, user_id: int) -> HttpResponse:
"""Impersonation handler, checks permissions"""
if not request.user.has_perm("impersonate"):
LOGGER.debug(
"User attempted to impersonate without permissions", user=request.user
)
LOGGER.debug("User attempted to impersonate without permissions", user=request.user)
return HttpResponse("Unauthorized", status=401)
user_to_be = get_object_or_404(User, pk=user_id)

View File

@ -14,9 +14,7 @@ class EndSessionView(TemplateView, PolicyAccessView):
template_name = "if/end_session.html"
def resolve_provider_application(self):
self.application = get_object_or_404(
Application, slug=self.kwargs["application_slug"]
)
self.application = get_object_or_404(Application, slug=self.kwargs["application_slug"])
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
context = super().get_context_data(**kwargs)

View File

@ -10,12 +10,7 @@ from django_filters.filters import BooleanFilter
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import (
CharField,
DateTimeField,
IntegerField,
SerializerMethodField,
)
from rest_framework.fields import CharField, DateTimeField, IntegerField, SerializerMethodField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer, ValidationError
@ -86,9 +81,7 @@ class CertificateKeyPairSerializer(ModelSerializer):
backend=default_backend(),
)
except (ValueError, TypeError):
raise ValidationError(
"Unable to load private key (possibly encrypted?)."
)
raise ValidationError("Unable to load private key (possibly encrypted?).")
return value
class Meta:
@ -123,9 +116,7 @@ class CertificateGenerationSerializer(PassiveSerializer):
"""Certificate generation parameters"""
common_name = CharField()
subject_alt_name = CharField(
required=False, allow_blank=True, label=_("Subject-alt name")
)
subject_alt_name = CharField(required=False, allow_blank=True, label=_("Subject-alt name"))
validity_days = IntegerField(initial=365)
@ -170,9 +161,7 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
builder = CertificateBuilder()
builder.common_name = data.validated_data["common_name"]
builder.build(
subject_alt_names=data.validated_data.get("subject_alt_name", "").split(
","
),
subject_alt_names=data.validated_data.get("subject_alt_name", "").split(","),
validity_days=int(data.validated_data["validity_days"]),
)
instance = builder.save()
@ -208,9 +197,7 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
"Content-Disposition"
] = f'attachment; filename="{certificate.name}_certificate.pem"'
return response
return Response(
CertificateDataSerializer({"data": certificate.certificate_data}).data
)
return Response(CertificateDataSerializer({"data": certificate.certificate_data}).data)
@extend_schema(
parameters=[
@ -234,9 +221,7 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
).from_http(request)
if "download" in request._request.GET:
# Mime type from https://pki-tutorial.readthedocs.io/en/latest/mime.html
response = HttpResponse(
certificate.key_data, content_type="application/x-pem-file"
)
response = HttpResponse(certificate.key_data, content_type="application/x-pem-file")
response[
"Content-Disposition"
] = f'attachment; filename="{certificate.name}_private_key.pem"'

View File

@ -46,9 +46,7 @@ class CertificateBuilder:
public_exponent=65537, key_size=2048, backend=default_backend()
)
self.__public_key = self.__private_key.public_key()
alt_names: list[x509.GeneralName] = [
x509.DNSName(x) for x in subject_alt_names or []
]
alt_names: list[x509.GeneralName] = [x509.DNSName(x) for x in subject_alt_names or []]
self.__builder = (
x509.CertificateBuilder()
.subject_name(
@ -59,9 +57,7 @@ class CertificateBuilder:
self.common_name,
),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "authentik"),
x509.NameAttribute(
NameOID.ORGANIZATIONAL_UNIT_NAME, "Self-signed"
),
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "Self-signed"),
]
)
)
@ -77,9 +73,7 @@ class CertificateBuilder:
)
.add_extension(x509.SubjectAlternativeName(alt_names), critical=True)
.not_valid_before(datetime.datetime.today() - one_day)
.not_valid_after(
datetime.datetime.today() + datetime.timedelta(days=validity_days)
)
.not_valid_after(datetime.datetime.today() + datetime.timedelta(days=validity_days))
.serial_number(int(uuid.uuid4()))
.public_key(self.__public_key)
)

View File

@ -57,9 +57,7 @@ class CertificateKeyPair(CreatedUpdatedModel):
if not self._private_key and self._private_key != "":
try:
self._private_key = load_pem_private_key(
str.encode(
"\n".join([x.strip() for x in self.key_data.split("\n")])
),
str.encode("\n".join([x.strip() for x in self.key_data.split("\n")])),
password=None,
backend=default_backend(),
)
@ -70,24 +68,18 @@ class CertificateKeyPair(CreatedUpdatedModel):
@property
def fingerprint_sha256(self) -> str:
"""Get SHA256 Fingerprint of certificate_data"""
return hexlify(self.certificate.fingerprint(hashes.SHA256()), ":").decode(
"utf-8"
)
return hexlify(self.certificate.fingerprint(hashes.SHA256()), ":").decode("utf-8")
@property
def fingerprint_sha1(self) -> str:
"""Get SHA1 Fingerprint of certificate_data"""
return hexlify(
self.certificate.fingerprint(hashes.SHA1()), ":" # nosec
).decode("utf-8")
return hexlify(self.certificate.fingerprint(hashes.SHA1()), ":").decode("utf-8") # nosec
@property
def kid(self):
"""Get Key ID used for JWKS"""
return "{0}".format(
md5(self.key_data.encode("utf-8")).hexdigest() # nosec
if self.key_data
else ""
md5(self.key_data.encode("utf-8")).hexdigest() if self.key_data else "" # nosec
)
def __str__(self) -> str:

View File

@ -10,7 +10,7 @@ from authentik.crypto.api import CertificateKeyPairSerializer
from authentik.crypto.builder import CertificateBuilder
from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow
from authentik.providers.oauth2.generators import generate_client_secret
from authentik.lib.generators import generate_key
from authentik.providers.oauth2.models import OAuth2Provider
@ -103,7 +103,7 @@ class TestCrypto(TestCase):
provider = OAuth2Provider.objects.create(
name="test",
client_id="test",
client_secret=generate_client_secret(),
client_secret=generate_key(),
authorization_flow=Flow.objects.first(),
redirect_uris="http://localhost",
rsa_key=CertificateKeyPair.objects.first(),

View File

@ -143,7 +143,5 @@ class EventViewSet(ModelViewSet):
"""Get all actions"""
data = []
for value, name in EventAction.choices:
data.append(
{"name": name, "description": "", "component": value, "model_name": ""}
)
data.append({"name": name, "description": "", "component": value, "model_name": ""})
return Response(TypeCreateSerializer(data, many=True).data)

View File

@ -30,3 +30,5 @@ class NotificationRuleViewSet(UsedByMixin, ModelViewSet):
queryset = NotificationRule.objects.all()
serializer_class = NotificationRuleSerializer
filterset_fields = ["name", "severity", "group__name"]
ordering = ["name"]

View File

@ -5,11 +5,12 @@ from rest_framework.decorators import action
from rest_framework.fields import CharField, ListField, SerializerMethodField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer, Serializer
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet
from authentik.api.decorators import permission_required
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer
from authentik.events.models import (
Notification,
NotificationSeverity,
@ -41,23 +42,19 @@ class NotificationTransportSerializer(ModelSerializer):
]
class NotificationTransportTestSerializer(Serializer):
class NotificationTransportTestSerializer(PassiveSerializer):
"""Notification test serializer"""
messages = ListField(child=CharField())
def create(self, validated_data: Request) -> Response:
raise NotImplementedError
def update(self, request: Request) -> Response:
raise NotImplementedError
class NotificationTransportViewSet(UsedByMixin, ModelViewSet):
"""NotificationTransport Viewset"""
queryset = NotificationTransport.objects.all()
serializer_class = NotificationTransportSerializer
filterset_fields = ["name", "mode", "webhook_url", "send_once"]
ordering = ["name"]
@permission_required("authentik_events.change_notificationtransport")
@extend_schema(

View File

@ -29,12 +29,8 @@ class AuditMiddleware:
def __call__(self, request: HttpRequest) -> HttpResponse:
# Connect signal for automatic logging
if hasattr(request, "user") and getattr(
request.user, "is_authenticated", False
):
post_save_handler = partial(
self.post_save_handler, user=request.user, request=request
)
if hasattr(request, "user") and getattr(request.user, "is_authenticated", False):
post_save_handler = partial(self.post_save_handler, user=request.user, request=request)
pre_delete_handler = partial(
self.pre_delete_handler, user=request.user, request=request
)
@ -94,13 +90,9 @@ class AuditMiddleware:
@staticmethod
# pylint: disable=unused-argument
def pre_delete_handler(
user: User, request: HttpRequest, sender, instance: Model, **_
):
def pre_delete_handler(user: User, request: HttpRequest, sender, instance: Model, **_):
"""Signal handler for all object's pre_delete"""
if isinstance(
instance, (Event, Notification, UserObjectPermission)
): # pragma: no cover
if isinstance(instance, (Event, Notification, UserObjectPermission)): # pragma: no cover
return
EventNewThread(

View File

@ -14,9 +14,7 @@ def convert_user_to_json(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
event.delete()
# Because event objects cannot be updated, we have to re-create them
event.pk = None
event.user_json = (
authentik.events.models.get_user(event.user) if event.user else {}
)
event.user_json = authentik.events.models.get_user(event.user) if event.user else {}
event._state.adding = True
event.save()
@ -58,7 +56,5 @@ class Migration(migrations.Migration):
model_name="event",
name="user",
),
migrations.RenameField(
model_name="event", old_name="user_json", new_name="user"
),
migrations.RenameField(model_name="event", old_name="user_json", new_name="user"),
]

View File

@ -11,16 +11,12 @@ def notify_configuration_error(apps: Apps, schema_editor: BaseDatabaseSchemaEdit
db_alias = schema_editor.connection.alias
Group = apps.get_model("authentik_core", "Group")
PolicyBinding = apps.get_model("authentik_policies", "PolicyBinding")
EventMatcherPolicy = apps.get_model(
"authentik_policies_event_matcher", "EventMatcherPolicy"
)
EventMatcherPolicy = apps.get_model("authentik_policies_event_matcher", "EventMatcherPolicy")
NotificationRule = apps.get_model("authentik_events", "NotificationRule")
NotificationTransport = apps.get_model("authentik_events", "NotificationTransport")
admin_group = (
Group.objects.using(db_alias)
.filter(name="authentik Admins", is_superuser=True)
.first()
Group.objects.using(db_alias).filter(name="authentik Admins", is_superuser=True).first()
)
policy, _ = EventMatcherPolicy.objects.using(db_alias).update_or_create(
@ -32,9 +28,7 @@ def notify_configuration_error(apps: Apps, schema_editor: BaseDatabaseSchemaEdit
defaults={"group": admin_group, "severity": NotificationSeverity.ALERT},
)
trigger.transports.set(
NotificationTransport.objects.using(db_alias).filter(
name="default-email-transport"
)
NotificationTransport.objects.using(db_alias).filter(name="default-email-transport")
)
trigger.save()
PolicyBinding.objects.using(db_alias).update_or_create(
@ -50,16 +44,12 @@ def notify_update(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Group = apps.get_model("authentik_core", "Group")
PolicyBinding = apps.get_model("authentik_policies", "PolicyBinding")
EventMatcherPolicy = apps.get_model(
"authentik_policies_event_matcher", "EventMatcherPolicy"
)
EventMatcherPolicy = apps.get_model("authentik_policies_event_matcher", "EventMatcherPolicy")
NotificationRule = apps.get_model("authentik_events", "NotificationRule")
NotificationTransport = apps.get_model("authentik_events", "NotificationTransport")
admin_group = (
Group.objects.using(db_alias)
.filter(name="authentik Admins", is_superuser=True)
.first()
Group.objects.using(db_alias).filter(name="authentik Admins", is_superuser=True).first()
)
policy, _ = EventMatcherPolicy.objects.using(db_alias).update_or_create(
@ -71,9 +61,7 @@ def notify_update(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
defaults={"group": admin_group, "severity": NotificationSeverity.ALERT},
)
trigger.transports.set(
NotificationTransport.objects.using(db_alias).filter(
name="default-email-transport"
)
NotificationTransport.objects.using(db_alias).filter(name="default-email-transport")
)
trigger.save()
PolicyBinding.objects.using(db_alias).update_or_create(
@ -89,16 +77,12 @@ def notify_exception(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Group = apps.get_model("authentik_core", "Group")
PolicyBinding = apps.get_model("authentik_policies", "PolicyBinding")
EventMatcherPolicy = apps.get_model(
"authentik_policies_event_matcher", "EventMatcherPolicy"
)
EventMatcherPolicy = apps.get_model("authentik_policies_event_matcher", "EventMatcherPolicy")
NotificationRule = apps.get_model("authentik_events", "NotificationRule")
NotificationTransport = apps.get_model("authentik_events", "NotificationTransport")
admin_group = (
Group.objects.using(db_alias)
.filter(name="authentik Admins", is_superuser=True)
.first()
Group.objects.using(db_alias).filter(name="authentik Admins", is_superuser=True).first()
)
policy_policy_exc, _ = EventMatcherPolicy.objects.using(db_alias).update_or_create(
@ -114,9 +98,7 @@ def notify_exception(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
defaults={"group": admin_group, "severity": NotificationSeverity.ALERT},
)
trigger.transports.set(
NotificationTransport.objects.using(db_alias).filter(
name="default-email-transport"
)
NotificationTransport.objects.using(db_alias).filter(name="default-email-transport")
)
trigger.save()
PolicyBinding.objects.using(db_alias).update_or_create(

View File

@ -38,9 +38,7 @@ def progress_bar(
def print_progress_bar(iteration):
"""Progress Bar Printing Function"""
percent = ("{0:." + str(decimals) + "f}").format(
100 * (iteration / float(total))
)
percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = fill * filledLength + "-" * (length - filledLength)
print(f"\r{prefix} |{bar}| {percent}% {suffix}", end=print_end)
@ -78,9 +76,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name="event",
name="expires",
field=models.DateTimeField(
default=authentik.events.models.default_event_duration
),
field=models.DateTimeField(default=authentik.events.models.default_event_duration),
),
migrations.AddField(
model_name="event",

View File

@ -15,9 +15,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name="event",
name="tenant",
field=models.JSONField(
blank=True, default=authentik.events.models.default_tenant
),
field=models.JSONField(blank=True, default=authentik.events.models.default_tenant),
),
migrations.AlterField(
model_name="event",

View File

@ -15,17 +15,16 @@ from requests import RequestException, post
from structlog.stdlib import get_logger
from authentik import __version__
from authentik.core.middleware import (
SESSION_IMPERSONATE_ORIGINAL_USER,
SESSION_IMPERSONATE_USER,
)
from authentik.core.middleware import SESSION_IMPERSONATE_ORIGINAL_USER, SESSION_IMPERSONATE_USER
from authentik.core.models import ExpiringModel, Group, User
from authentik.events.geo import GEOIP_READER
from authentik.events.utils import cleanse_dict, get_user, model_to_dict, sanitize_dict
from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.http import get_client_ip
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.models import PolicyBindingModel
from authentik.stages.email.utils import TemplateEmailMessage
from authentik.tenants.models import Tenant
from authentik.tenants.utils import DEFAULT_TENANT
LOGGER = get_logger("authentik.events")
@ -37,7 +36,8 @@ GAUGE_EVENTS = Gauge(
def default_event_duration():
"""Default duration an Event is saved"""
"""Default duration an Event is saved.
This is used as a fallback when no tenant is available"""
return now() + timedelta(days=365)
@ -147,13 +147,16 @@ class Event(ExpiringModel):
"method": request.method,
}
if hasattr(request, "tenant"):
self.tenant = sanitize_dict(model_to_dict(request.tenant))
tenant: Tenant = request.tenant
# Because self.created only gets set on save, we can't use it's value here
# hence we set self.created to now and then use it
self.created = now()
self.expires = self.created + timedelta_from_string(tenant.event_retention)
self.tenant = sanitize_dict(model_to_dict(tenant))
if hasattr(request, "user"):
original_user = None
if hasattr(request, "session"):
original_user = request.session.get(
SESSION_IMPERSONATE_ORIGINAL_USER, None
)
original_user = request.session.get(SESSION_IMPERSONATE_ORIGINAL_USER, None)
self.user = get_user(request.user, original_user)
if user:
self.user = get_user(user)
@ -161,9 +164,7 @@ class Event(ExpiringModel):
if hasattr(request, "session"):
if SESSION_IMPERSONATE_ORIGINAL_USER in request.session:
self.user = get_user(request.session[SESSION_IMPERSONATE_ORIGINAL_USER])
self.user["on_behalf_of"] = get_user(
request.session[SESSION_IMPERSONATE_USER]
)
self.user["on_behalf_of"] = get_user(request.session[SESSION_IMPERSONATE_USER])
# User 255.255.255.255 as fallback if IP cannot be determined
self.client_ip = get_client_ip(request)
# Apply GeoIP Data, when enabled
@ -406,9 +407,7 @@ class NotificationRule(PolicyBindingModel):
severity = models.TextField(
choices=NotificationSeverity.choices,
default=NotificationSeverity.NOTICE,
help_text=_(
"Controls which severity level the created notifications will have."
),
help_text=_("Controls which severity level the created notifications will have."),
)
group = models.ForeignKey(
Group,

View File

@ -11,6 +11,7 @@ from django.core.cache import cache
from prometheus_client import Gauge
from authentik.events.models import Event, EventAction
from authentik.lib.utils.errors import exception_to_string
GAUGE_TASKS = Gauge(
"authentik_system_tasks",
@ -114,7 +115,7 @@ class MonitoredTask(Task):
# For tasks that should only be listed if they failed, set this to False
save_on_success: bool
_result: TaskResult
_result: Optional[TaskResult]
_uid: Optional[str]
@ -122,7 +123,7 @@ class MonitoredTask(Task):
super().__init__(*args, **kwargs)
self.save_on_success = True
self._uid = None
self._result = TaskResult(status=TaskResultStatus.ERROR, messages=[])
self._result = None
self.result_timeout_hours = 6
self.start = default_timer()
@ -135,28 +136,29 @@ class MonitoredTask(Task):
self._result = result
# pylint: disable=too-many-arguments
def after_return(
self, status, retval, task_id, args: list[Any], kwargs: dict[str, Any], einfo
):
if not self._result.uid:
self._result.uid = self._uid
if self.save_on_success:
TaskInfo(
task_name=self.__name__,
task_description=self.__doc__,
start_timestamp=self.start,
finish_timestamp=default_timer(),
finish_time=datetime.now(),
result=self._result,
task_call_module=self.__module__,
task_call_func=self.__name__,
task_call_args=args,
task_call_kwargs=kwargs,
).save(self.result_timeout_hours)
def after_return(self, status, retval, task_id, args: list[Any], kwargs: dict[str, Any], einfo):
if self._result:
if not self._result.uid:
self._result.uid = self._uid
if self.save_on_success:
TaskInfo(
task_name=self.__name__,
task_description=self.__doc__,
start_timestamp=self.start,
finish_timestamp=default_timer(),
finish_time=datetime.now(),
result=self._result,
task_call_module=self.__module__,
task_call_func=self.__name__,
task_call_args=args,
task_call_kwargs=kwargs,
).save(self.result_timeout_hours)
return super().after_return(status, retval, task_id, args, kwargs, einfo=einfo)
# pylint: disable=too-many-arguments
def on_failure(self, exc, task_id, args, kwargs, einfo):
if not self._result:
self._result = TaskResult(status=TaskResultStatus.ERROR, messages=[str(exc)])
if not self._result.uid:
self._result.uid = self._uid
TaskInfo(
@ -173,10 +175,7 @@ class MonitoredTask(Task):
).save(self.result_timeout_hours)
Event.new(
EventAction.SYSTEM_TASK_EXCEPTION,
message=(
f"Task {self.__name__} encountered an error: "
"\n".join(self._result.messages)
),
message=(f"Task {self.__name__} encountered an error: {exception_to_string(exc)}"),
).save()
return super().on_failure(exc, task_id, args, kwargs, einfo=einfo)

View File

@ -2,11 +2,7 @@
from threading import Thread
from typing import Any, Optional
from django.contrib.auth.signals import (
user_logged_in,
user_logged_out,
user_login_failed,
)
from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.http import HttpRequest
@ -19,6 +15,7 @@ from authentik.flows.planner import PLAN_CONTEXT_SOURCE, FlowPlan
from authentik.flows.views import SESSION_KEY_PLAN
from authentik.stages.invitation.models import Invitation
from authentik.stages.invitation.signals import invitation_used
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
from authentik.stages.user_write.signals import user_write
@ -30,9 +27,7 @@ class EventNewThread(Thread):
kwargs: dict[str, Any]
user: Optional[User] = None
def __init__(
self, action: str, request: HttpRequest, user: Optional[User] = None, **kwargs
):
def __init__(self, action: str, request: HttpRequest, user: Optional[User] = None, **kwargs):
super().__init__()
self.action = action
self.request = request
@ -52,7 +47,13 @@ def on_user_logged_in(sender, request: HttpRequest, user: User, **_):
flow_plan: FlowPlan = request.session[SESSION_KEY_PLAN]
if PLAN_CONTEXT_SOURCE in flow_plan.context:
# Login request came from an external source, save it in the context
thread.kwargs["using_source"] = flow_plan.context[PLAN_CONTEXT_SOURCE]
thread.kwargs[PLAN_CONTEXT_SOURCE] = flow_plan.context[PLAN_CONTEXT_SOURCE]
if PLAN_CONTEXT_METHOD in flow_plan.context:
thread.kwargs[PLAN_CONTEXT_METHOD] = flow_plan.context[PLAN_CONTEXT_METHOD]
# Save the login method used
thread.kwargs[PLAN_CONTEXT_METHOD_ARGS] = flow_plan.context.get(
PLAN_CONTEXT_METHOD_ARGS, {}
)
thread.user = user
thread.run()
@ -68,9 +69,7 @@ def on_user_logged_out(sender, request: HttpRequest, user: User, **_):
@receiver(user_write)
# pylint: disable=unused-argument
def on_user_write(
sender, request: HttpRequest, user: User, data: dict[str, Any], **kwargs
):
def on_user_write(sender, request: HttpRequest, user: User, data: dict[str, Any], **kwargs):
"""Log User write"""
thread = EventNewThread(EventAction.USER_WRITE, request, **data)
thread.kwargs["created"] = kwargs.get("created", False)
@ -80,9 +79,7 @@ def on_user_write(
@receiver(user_login_failed)
# pylint: disable=unused-argument
def on_user_login_failed(
sender, credentials: dict[str, str], request: HttpRequest, **_
):
def on_user_login_failed(sender, credentials: dict[str, str], request: HttpRequest, **_):
"""Failed Login"""
thread = EventNewThread(EventAction.LOGIN_FAILED, request, **credentials)
thread.run()

View File

@ -22,9 +22,7 @@ LOGGER = get_logger()
def event_notification_handler(event_uuid: str):
"""Start task for each trigger definition"""
for trigger in NotificationRule.objects.all():
event_trigger_handler.apply_async(
args=[event_uuid, trigger.name], queue="authentik_events"
)
event_trigger_handler.apply_async(args=[event_uuid, trigger.name], queue="authentik_events")
@CELERY_APP.task()
@ -43,17 +41,13 @@ def event_trigger_handler(event_uuid: str, trigger_name: str):
if "policy_uuid" in event.context:
policy_uuid = event.context["policy_uuid"]
if PolicyBinding.objects.filter(
target__in=NotificationRule.objects.all().values_list(
"pbm_uuid", flat=True
),
target__in=NotificationRule.objects.all().values_list("pbm_uuid", flat=True),
policy=policy_uuid,
).exists():
# If policy that caused this event to be created is attached
# to *any* NotificationRule, we return early.
# This is the most effective way to prevent infinite loops.
LOGGER.debug(
"e(trigger): attempting to prevent infinite loop", trigger=trigger
)
LOGGER.debug("e(trigger): attempting to prevent infinite loop", trigger=trigger)
return
if not trigger.group:
@ -62,9 +56,7 @@ def event_trigger_handler(event_uuid: str, trigger_name: str):
LOGGER.debug("e(trigger): checking if trigger applies", trigger=trigger)
try:
user = (
User.objects.filter(pk=event.user.get("pk")).first() or get_anonymous_user()
)
user = User.objects.filter(pk=event.user.get("pk")).first() or get_anonymous_user()
except User.DoesNotExist:
LOGGER.warning("e(trigger): failed to get user", trigger=trigger)
return
@ -99,20 +91,14 @@ def event_trigger_handler(event_uuid: str, trigger_name: str):
retry_backoff=True,
base=MonitoredTask,
)
def notification_transport(
self: MonitoredTask, notification_pk: int, transport_pk: int
):
def notification_transport(self: MonitoredTask, notification_pk: int, transport_pk: int):
"""Send notification over specified transport"""
self.save_on_success = False
try:
notification: Notification = Notification.objects.filter(
pk=notification_pk
).first()
notification: Notification = Notification.objects.filter(pk=notification_pk).first()
if not notification:
return
transport: NotificationTransport = NotificationTransport.objects.get(
pk=transport_pk
)
transport: NotificationTransport = NotificationTransport.objects.get(pk=transport_pk)
transport.send(notification)
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL))
except NotificationTransportError as exc:

View File

@ -38,7 +38,5 @@ class TestEvents(TestCase):
event = Event.new("unittest", model=temp_model)
event.save() # We save to ensure nothing is un-saveable
model_content_type = ContentType.objects.get_for_model(temp_model)
self.assertEqual(
event.context.get("model").get("app"), model_content_type.app_label
)
self.assertEqual(event.context.get("model").get("app"), model_content_type.app_label)
self.assertEqual(event.context.get("model").get("pk"), temp_model.pk.hex)

View File

@ -81,12 +81,8 @@ class TestEventsNotifications(TestCase):
execute_mock = MagicMock()
passes = MagicMock(side_effect=PolicyException)
with patch(
"authentik.policies.event_matcher.models.EventMatcherPolicy.passes", passes
):
with patch(
"authentik.events.models.NotificationTransport.send", execute_mock
):
with patch("authentik.policies.event_matcher.models.EventMatcherPolicy.passes", passes):
with patch("authentik.events.models.NotificationTransport.send", execute_mock):
Event.new(EventAction.CUSTOM_PREFIX).save()
self.assertEqual(passes.call_count, 1)
@ -96,9 +92,7 @@ class TestEventsNotifications(TestCase):
self.group.users.add(user2)
self.group.save()
transport = NotificationTransport.objects.create(
name="transport", send_once=True
)
transport = NotificationTransport.objects.create(name="transport", send_once=True)
NotificationRule.objects.filter(name__startswith="default").delete()
trigger = NotificationRule.objects.create(name="trigger", group=self.group)
trigger.transports.add(transport)

View File

@ -7,25 +7,25 @@ from django.http.response import HttpResponseBadRequest, JsonResponse
from django.urls import reverse
from django.utils.translation import gettext as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer
from drf_spectacular.utils import OpenApiResponse, extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action
from rest_framework.fields import BooleanField, FileField, ReadOnlyField
from rest_framework.fields import ReadOnlyField
from rest_framework.parsers import MultiPartParser
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import (
CharField,
ModelSerializer,
Serializer,
SerializerMethodField,
)
from rest_framework.serializers import CharField, ModelSerializer, Serializer, SerializerMethodField
from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger
from authentik.api.decorators import permission_required
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import CacheSerializer, LinkSerializer
from authentik.core.api.utils import (
CacheSerializer,
FilePathSerializer,
FileUploadSerializer,
LinkSerializer,
)
from authentik.flows.exceptions import FlowNonApplicableException
from authentik.flows.models import Flow
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner, cache_key
@ -152,11 +152,7 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
],
)
@extend_schema(
request={
"multipart/form-data": inline_serializer(
"SetIcon", fields={"file": FileField()}
)
},
request={"multipart/form-data": FileUploadSerializer},
responses={
204: OpenApiResponse(description="Successfully imported flow"),
400: OpenApiResponse(description="Bad request"),
@ -221,9 +217,7 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
.order_by("order")
):
for p_index, policy_binding in enumerate(
get_objects_for_user(
request.user, "authentik_policies.view_policybinding"
)
get_objects_for_user(request.user, "authentik_policies.view_policybinding")
.filter(target=stage_binding)
.exclude(policy__isnull=True)
.order_by("order")
@ -256,33 +250,21 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
element: DiagramElement = body[index]
if element.type == "condition":
# Policy passes, link policy yes to next stage
footer.append(
f"{element.identifier}(yes, right)->{body[index + 1].identifier}"
)
footer.append(f"{element.identifier}(yes, right)->{body[index + 1].identifier}")
# Policy doesn't pass, go to stage after next stage
no_element = body[index + 1]
if no_element.type != "end":
no_element = body[index + 2]
footer.append(
f"{element.identifier}(no, bottom)->{no_element.identifier}"
)
footer.append(f"{element.identifier}(no, bottom)->{no_element.identifier}")
elif element.type == "operation":
footer.append(
f"{element.identifier}(bottom)->{body[index + 1].identifier}"
)
footer.append(f"{element.identifier}(bottom)->{body[index + 1].identifier}")
diagram = "\n".join([str(x) for x in header + body + footer])
return Response({"diagram": diagram})
@permission_required("authentik_flows.change_flow")
@extend_schema(
request={
"multipart/form-data": inline_serializer(
"SetIcon",
fields={
"file": FileField(required=False),
"clear": BooleanField(default=False),
},
)
"multipart/form-data": FileUploadSerializer,
},
responses={
200: OpenApiResponse(description="Success"),
@ -318,7 +300,7 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
@permission_required("authentik_core.change_application")
@extend_schema(
request=inline_serializer("SetIconURL", fields={"url": CharField()}),
request=FilePathSerializer,
responses={
200: OpenApiResponse(description="Success"),
400: OpenApiResponse(description="Bad request"),

View File

@ -11,7 +11,7 @@ class Command(BaseCommand): # pragma: no cover
def handle(self, *args, **options):
"""Apply all flows in order, abort when one fails to import"""
for flow_path in options.get("flows", []):
with open(flow_path, "r") as flow_file:
with open(flow_path, "r", encoding="utf8") as flow_file:
importer = FlowImporter(flow_file.read())
valid = importer.validate()
if not valid:

View File

@ -31,6 +31,7 @@ class FlowPlanProcess(PROCESS_CLASS): # pragma: no cover
self.request = RequestFactory().get("/")
def run(self):
"""Execute 1000 flow plans"""
print(f"Proc {self.index} Running")
def test_inner():
@ -95,9 +96,7 @@ class Command(BaseCommand): # pragma: no cover
"""Output results human readable"""
total_max: int = max([max(inner) for inner in values])
total_min: int = min([min(inner) for inner in values])
total_avg = sum([sum(inner) for inner in values]) / sum(
[len(inner) for inner in values]
)
total_avg = sum([sum(inner) for inner in values]) / sum([len(inner) for inner in values])
print(f"Version: {__version__}")
print(f"Processes: {len(values)}")

View File

@ -6,24 +6,18 @@ from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from authentik.flows.models import FlowDesignation
from authentik.stages.identification.models import UserFields
from authentik.stages.password import BACKEND_DJANGO, BACKEND_LDAP
from authentik.stages.password import BACKEND_APP_PASSWORD, BACKEND_INBUILT, BACKEND_LDAP
def create_default_authentication_flow(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
def create_default_authentication_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
Flow = apps.get_model("authentik_flows", "Flow")
FlowStageBinding = apps.get_model("authentik_flows", "FlowStageBinding")
PasswordStage = apps.get_model("authentik_stages_password", "PasswordStage")
UserLoginStage = apps.get_model("authentik_stages_user_login", "UserLoginStage")
IdentificationStage = apps.get_model(
"authentik_stages_identification", "IdentificationStage"
)
IdentificationStage = apps.get_model("authentik_stages_identification", "IdentificationStage")
db_alias = schema_editor.connection.alias
identification_stage, _ = IdentificationStage.objects.using(
db_alias
).update_or_create(
identification_stage, _ = IdentificationStage.objects.using(db_alias).update_or_create(
name="default-authentication-identification",
defaults={
"user_fields": [UserFields.E_MAIL, UserFields.USERNAME],
@ -32,7 +26,7 @@ def create_default_authentication_flow(
password_stage, _ = PasswordStage.objects.using(db_alias).update_or_create(
name="default-authentication-password",
defaults={"backends": [BACKEND_DJANGO, BACKEND_LDAP]},
defaults={"backends": [BACKEND_INBUILT, BACKEND_LDAP, BACKEND_APP_PASSWORD]},
)
login_stage, _ = UserLoginStage.objects.using(db_alias).update_or_create(
@ -69,17 +63,13 @@ def create_default_authentication_flow(
)
def create_default_invalidation_flow(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
def create_default_invalidation_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
Flow = apps.get_model("authentik_flows", "Flow")
FlowStageBinding = apps.get_model("authentik_flows", "FlowStageBinding")
UserLogoutStage = apps.get_model("authentik_stages_user_logout", "UserLogoutStage")
db_alias = schema_editor.connection.alias
UserLogoutStage.objects.using(db_alias).update_or_create(
name="default-invalidation-logout"
)
UserLogoutStage.objects.using(db_alias).update_or_create(name="default-invalidation-logout")
flow, _ = Flow.objects.using(db_alias).update_or_create(
slug="default-invalidation-flow",

View File

@ -15,16 +15,12 @@ PROMPT_POLICY_EXPRESSION = """# Check if we've not been given a username by the
return 'username' not in context.get('prompt_data', {})"""
def create_default_source_enrollment_flow(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
def create_default_source_enrollment_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
Flow = apps.get_model("authentik_flows", "Flow")
FlowStageBinding = apps.get_model("authentik_flows", "FlowStageBinding")
PolicyBinding = apps.get_model("authentik_policies", "PolicyBinding")
ExpressionPolicy = apps.get_model(
"authentik_policies_expression", "ExpressionPolicy"
)
ExpressionPolicy = apps.get_model("authentik_policies_expression", "ExpressionPolicy")
PromptStage = apps.get_model("authentik_stages_prompt", "PromptStage")
Prompt = apps.get_model("authentik_stages_prompt", "Prompt")
@ -99,16 +95,12 @@ def create_default_source_enrollment_flow(
)
def create_default_source_authentication_flow(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
def create_default_source_authentication_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
Flow = apps.get_model("authentik_flows", "Flow")
FlowStageBinding = apps.get_model("authentik_flows", "FlowStageBinding")
PolicyBinding = apps.get_model("authentik_policies", "PolicyBinding")
ExpressionPolicy = apps.get_model(
"authentik_policies_expression", "ExpressionPolicy"
)
ExpressionPolicy = apps.get_model("authentik_policies_expression", "ExpressionPolicy")
UserLoginStage = apps.get_model("authentik_stages_user_login", "UserLoginStage")

View File

@ -7,9 +7,7 @@ from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from authentik.flows.models import FlowDesignation
def create_default_provider_authorization_flow(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
def create_default_provider_authorization_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
Flow = apps.get_model("authentik_flows", "Flow")
FlowStageBinding = apps.get_model("authentik_flows", "FlowStageBinding")

View File

@ -32,9 +32,7 @@ def create_default_oobe_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor
PromptStage = apps.get_model("authentik_stages_prompt", "PromptStage")
Prompt = apps.get_model("authentik_stages_prompt", "Prompt")
ExpressionPolicy = apps.get_model(
"authentik_policies_expression", "ExpressionPolicy"
)
ExpressionPolicy = apps.get_model("authentik_policies_expression", "ExpressionPolicy")
db_alias = schema_editor.connection.alias
@ -52,9 +50,7 @@ def create_default_oobe_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor
name="default-oobe-prefill-user",
defaults={"expression": PREFILL_POLICY_EXPRESSION},
)
password_usable_policy, _ = ExpressionPolicy.objects.using(
db_alias
).update_or_create(
password_usable_policy, _ = ExpressionPolicy.objects.using(db_alias).update_or_create(
name="default-oobe-password-usable",
defaults={"expression": PW_USABLE_POLICY_EXPRESSION},
)
@ -83,9 +79,7 @@ def create_default_oobe_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor
prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create(
name="default-oobe-password",
)
prompt_stage.fields.set(
[prompt_header, prompt_email, password_first, password_second]
)
prompt_stage.fields.set([prompt_header, prompt_email, password_first, password_second])
prompt_stage.save()
user_write, _ = UserWriteStage.objects.using(db_alias).update_or_create(

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