Compare commits

..

572 Commits

Author SHA1 Message Date
2a3b049b01 release: 2021.10.4 2021-11-12 12:31:24 +01:00
e4a5e86c93 sources/oauth: Fixed the incorrect padding issue in apple.py (#1773)
* Fixed the incorrect padding issue in apple.py

Fixed the incorrect padding issue in apple.py by adding proper padding to the raw_payload.

* Fixed the incorrect encoding of client_secret in apple.py

In the get_client_secret() method, the "sub" in the payload must be only the client ID. So I have changed self.source.consumer_key to parts[0]

* Added the decode method for the id_token

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-12 12:10:29 +01:00
3a51bcd890 tests/e2e: add retry for webdriver init
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-12 09:37:05 +01:00
c28f68400d build(deps): bump @sentry/tracing from 6.14.1 to 6.14.3 in /web (#1783) 2021-11-12 08:30:16 +01:00
5d50fc281a build(deps): bump boto3 from 1.20.3 to 1.20.4 (#1785) 2021-11-12 08:30:02 +01:00
9f7d1466e9 build(deps): bump @sentry/browser from 6.14.1 to 6.14.3 in /web (#1784) 2021-11-12 08:29:22 +01:00
c815d24806 build(deps): bump psycopg2-binary from 2.9.1 to 2.9.2 (#1786) 2021-11-12 08:29:05 +01:00
d1200a7e40 website/docs: Mention correct logo in Gitea docs (#1782) 2021-11-12 01:02:17 +01:00
edd4f9ceae root: update security
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 23:50:46 +01:00
1cfe81887b stages/authenticator_validate: improve logging
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 23:33:41 +01:00
bb5e0ebab1 website/docs: Add Integrations/Provider/Gitea (#1781) 2021-11-11 23:23:32 +01:00
dfda76d896 tests/e2e: use cached LDAP lookup for tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 23:20:32 +01:00
8fc5114ce4 website/docs: prepare 2021.10.4 docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 23:20:17 +01:00
e7b4363d21 outposts/ldap: fix logic error in cached ldap searcher
closes #1779

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 23:18:32 +01:00
53905d1a89 stages/authenticator_validate: enable all device classes by default
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 22:49:30 +01:00
0ad1392632 web/admin: use more natural default ordering for objects
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 22:47:10 +01:00
6db1c914ee stages/authenticator_duo: fix devices created with name
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 22:16:47 +01:00
00324f922d outposts: send SelectedChallenge when using MFA with Go FlowExecutor
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 21:27:06 +01:00
8a24ddad28 website/docs: Added missing SSO server URL field for Zabbix (#1780) 2021-11-11 21:06:33 +01:00
0f85fe3c29 website/docs: authentik starts lowercase (#1778)
* website/docs: Add Integrations/Provider/OPNsense

* website/docs: Add missing steps + fix recs

* website/docs: authentik starts lowercase

* website/docs: authentik starts lowercase
2021-11-11 16:53:46 +01:00
1f05eaa420 website/docs: Add Integrations/Provider/OPNsense (#1777)
* website/docs: Add Integrations/Provider/OPNsense

* website/docs: Add missing steps + fix recs

* website/docs: authentik starts lowercase
2021-11-11 16:44:02 +01:00
84e126a32c website/docs: add group hierarchy docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 16:15:40 +01:00
9ae69866bd web/admin: fix display issues with flow execute buttons
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-11 13:51:33 +01:00
56576a7f44 build(deps): bump boto3 from 1.20.2 to 1.20.3 (#1769) 2021-11-11 08:43:22 +01:00
7f0295ba53 build(deps): bump @trivago/prettier-plugin-sort-imports in /web (#1768) 2021-11-11 08:43:13 +01:00
5553b3ff36 build(deps): bump drf-spectacular from 0.20.2 to 0.21.0 (#1771) 2021-11-11 08:43:03 +01:00
6f969525fe build(deps): bump webauthn from 1.0.1 to 1.1.0 (#1770) 2021-11-11 08:42:33 +01:00
bac12246fb build(deps-dev): bump coverage from 6.1.1 to 6.1.2 (#1772) 2021-11-11 08:42:19 +01:00
b53ef6e529 build(deps): bump goauthentik.io/api from 0.2021103.1 to 0.2021103.2 (#1767)
Bumps [goauthentik.io/api](https://github.com/goauthentik/client-go) from 0.2021103.1 to 0.2021103.2.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v0.2021103.1...v0.2021103.2)

---
updated-dependencies:
- dependency-name: goauthentik.io/api
  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-11-10 23:26:13 +01:00
39c62afb93 web: Update Web API Client version (#1766)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-10 23:11:26 +01:00
c98bdbacc5 providers/proxy: return list of configured scope names so outpost requests custom scopes
closes #1762

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 23:06:21 +01:00
1e8d45dc15 web: write interfaces to different folders and remove custom chunk names
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 17:54:50 +01:00
202b057ce9 outposts/proxy: fix static files not being served in proxy mode
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 17:16:13 +01:00
d5d8641b37 stages/*: disable trim_whitespace on important fields
closes #1765

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 16:48:19 +01:00
9dd37689e3 ci: remove cache from translation compile
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 13:19:57 +01:00
cc0832f487 core: force lowercase emails for gravatar usage
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 12:40:20 +01:00
b515bf7d2e ci: disable cache again...
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 11:57:22 +01:00
34fbf3941b website/docs: add air-gapped docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 11:28:59 +01:00
e73606b54d root: catch error in analytics on startup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 11:28:08 +01:00
0a413fe21a web/admin: show warnings above tab bar
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 10:05:35 +01:00
d1b9f1e6b8 ci: limit pipeline to 2 hours
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-10 09:31:59 +01:00
e5a6e128e4 build(deps): bump boto3 from 1.20.0 to 1.20.2 (#1763) 2021-11-10 08:16:19 +01:00
9295d1ed0b website/docs: fix missing SAML cert in sentry docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-09 23:42:16 +01:00
5d479a6c8f root: set utm_source
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-09 23:23:47 +01:00
4a773b2b4f sources/ldap: set connect/receive timeout (default to 15s)
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-09 22:27:58 +01:00
8003d67844 sources/ldap: fix typo
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-09 22:24:33 +01:00
58baf97e2d website/docs: Add additionalHeaders to attributes list (#1754)
* Add additionalHeaders to attributes list

Added additional headers with example of usage

* Update user.md
2021-11-09 21:17:36 +01:00
51783c1cbb sorces/ldap: fix user/group sync overwriting attributes instead of merging them
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-09 21:16:59 +01:00
94290c7e36 root: remove pipenv constraint
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-09 14:19:33 +01:00
123ff7ad1f website/docs: Fix typo (#1761) 2021-11-09 13:27:52 +01:00
8f3e863cce root: use python slim-bullseye as base
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-09 11:34:42 +01:00
3d6c459349 build(deps): bump @typescript-eslint/parser from 5.3.0 to 5.3.1 in /web (#1756) 2021-11-09 08:24:51 +01:00
6a583bae49 build(deps): bump goauthentik.io/api from 0.2021102.6 to 0.2021103.1 (#1758) 2021-11-09 08:24:18 +01:00
78e5879d9a build(deps): bump boto3 from 1.19.12 to 1.20.0 (#1757) 2021-11-09 08:24:09 +01:00
fdcac2a9ed build(deps): bump @typescript-eslint/eslint-plugin in /web (#1755) 2021-11-09 08:23:47 +01:00
e81715caef web: Update Web API Client version (#1753)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-08 21:19:00 +01:00
ab2b13938e release: 2021.10.3 2021-11-08 20:52:11 +01:00
5c97a3aef3 website/docs: final 2021.10.3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-08 20:51:59 +01:00
e6963c543d outpost: remove analytics
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-08 19:35:53 +01:00
9ca15983a2 root: keep last 30 backups
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-08 17:46:25 +01:00
99ef94b7aa stages/prompt: only set placeholder when in context
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-08 15:10:32 +01:00
133bedafba web: Update Web API Client version (#1752)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-08 14:53:50 +01:00
c3faa61ed9 stages/prompt: set field placeholder based on plan context
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-08 14:47:50 +01:00
da74304221 stages/prompt: add text_read_only field
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-08 14:45:56 +01:00
ed6659a46d outpost/ldap: don't cleanup user info as it is overwritten on bind
closes #1651

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-08 14:41:38 +01:00
0abb1f94a4 build(deps): bump @sentry/tracing from 6.14.0 to 6.14.1 in /web (#1746) 2021-11-08 08:30:37 +01:00
c7e299e0bf build(deps): bump eslint from 8.1.0 to 8.2.0 in /web (#1747) 2021-11-08 08:29:44 +01:00
8a6590bac8 build(deps): bump @sentry/browser from 6.14.0 to 6.14.1 in /web (#1748) 2021-11-08 08:29:35 +01:00
ed717dcfa2 build(deps): bump boto3 from 1.19.11 to 1.19.12 (#1749) 2021-11-08 08:29:23 +01:00
b6df42f580 build(deps): bump goauthentik.io/api from 0.2021102.5 to 0.2021102.6 (#1750) 2021-11-08 08:29:16 +01:00
2ea85bd0c4 build(deps): bump celery from 5.1.2 to 5.2.0 (#1751) 2021-11-08 08:28:33 +01:00
68fa8105e1 Merge branch 'master' into version-2021.10 2021-11-07 23:16:53 +01:00
79db0ce4c1 stages/prompt: use initial instead of default
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 22:20:08 +01:00
5e23b11764 stages/prompt: default prompts to the current value of the context
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 21:59:50 +01:00
c4e029ffe2 recovery: add create_admin_group management command
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 21:53:21 +01:00
61b5b36192 core: add command to output full config
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 21:45:52 +01:00
c6cc1b1728 root: fix defaults for EMAIL_USE_TLS
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 21:37:14 +01:00
77dd652160 web: Update Web API Client version (#1744)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
# Conflicts:
#	web/package-lock.json
#	web/package.json
2021-11-07 18:04:27 +01:00
1144944adb stages/identification: only allow limited challenges for login sources
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:35 +01:00
7751be284e stages/identification: use random sleep
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:32 +01:00
74382c6287 cmd/server: improve cleanup on shutdown
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:29 +01:00
011babbbd9 web: fix linting errors by adding a wrapper for next param
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:26 +01:00
3c01a1dd7b ci: keep latest github and scripts folder
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:22 +01:00
6e832be2de core: fix auth_method for tokens
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:19 +01:00
46017f2f86 events: ignore creation/deletion of AuthenticatedSession objects
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:16 +01:00
da50eb0369 web/user: fix redirect after starting configuration flow from user interface
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:13 +01:00
b996e3cee7 ci: lock pipenv to 2021.11.5 for now
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:09 +01:00
12735cc14c admin: improve check to remove version notifications
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-07 18:03:06 +01:00
4d36699b78 outpost/ldap: cleanup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 19:32:11 +01:00
8110d2861b web: Update Web API Client version (#1744)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-06 19:23:25 +01:00
1cc60f572d root: use forked openapi-generator
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 19:10:17 +01:00
90151a13ae stages/identification: only allow limited challenges for login sources
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 14:53:38 +01:00
f958aa6930 stages/identification: use random sleep
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 14:50:35 +01:00
13fbac30a2 cmd/server: improve cleanup on shutdown
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 13:54:59 +01:00
4f4cdf16f1 web: fix linting errors by adding a wrapper for next param
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 13:19:39 +01:00
7d75599627 ci: keep latest github and scripts folder
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 13:06:51 +01:00
924a13e832 core: fix auth_method for tokens
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 13:04:41 +01:00
ae83c35dfd events: ignore creation/deletion of AuthenticatedSession objects
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 13:04:34 +01:00
e9102f4e28 web/user: fix redirect after starting configuration flow from user interface
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 12:57:06 +01:00
9b8c1cbea5 ci: lock pipenv to 2021.11.5 for now
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 12:22:59 +01:00
6424bf98da admin: improve check to remove version notifications
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-06 12:15:05 +01:00
74fb0f9e2a website/docs: Document using Proxmox VE as Provider Integration (#1743) 2021-11-06 00:00:57 +01:00
4380f37a77 web/admin: fix missing values for LDAP Provider form
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 11:42:09 +01:00
17fccd44e6 build(deps): bump goauthentik.io/api from 0.2021102.4 to 0.2021102.5 (#1742)
Bumps [goauthentik.io/api](https://github.com/goauthentik/client-go) from 0.2021102.4 to 0.2021102.5.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v0.2021102.4...v0.2021102.5)

---
updated-dependencies:
- dependency-name: goauthentik.io/api
  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-11-05 10:50:59 +01:00
217a8b5610 web: Update Web API Client version (#1741)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-05 10:42:02 +01:00
2cef220a3e providers/ldap: add/squash migrations
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 10:41:50 +01:00
5a8c66d325 providers/ldap: memory Query (#1681)
* outposts/ldap: modularise ldap outpost, to allow different searchers and binders

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

* outposts/ldap: add basic in-memory searcher

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

* providers/ldap: add search mode field

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

* outpost: add search mode field

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 10:37:30 +01:00
8de13d3f67 build(deps): bump goauthentik.io/api from 0.2021102.2 to 0.2021102.4 (#1738)
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 09:33:26 +01:00
5c22bedbaf build(deps): bump golang from 1.17.2-bullseye to 1.17.3-bullseye (#1737) 2021-11-05 08:29:51 +01:00
8a0f993f0b build(deps): bump boto3 from 1.19.10 to 1.19.11 (#1739) 2021-11-05 08:29:37 +01:00
abcf515a69 web/admin: also show note for SAML provider
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 01:21:10 +01:00
894f704c27 web: Update Web API Client version (#1736)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-05 01:18:13 +01:00
7798292aa8 sources/plex: use exception_to_string in tasks
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 01:16:36 +01:00
3005ca17bd web/admin: show warning on provider when not used with outpost
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 01:15:33 +01:00
909461e533 providers/*: include list of outposts
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 01:06:04 +01:00
df838a4023 web: Update Web API Client version (#1735)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-05 01:01:51 +01:00
0f86b62dd3 website/docs: prepare 2021.10.3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 00:55:31 +01:00
a40c3aeb68 core: make group membership lookup respect parent groups (upwards)
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 00:53:56 +01:00
4080738ded web/elements: fix import
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 00:27:23 +01:00
4a89be3048 core: include parent group name
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-05 00:11:17 +01:00
e587c53e18 web: remove deprecated rollup-plugin-node-resolve
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 22:34:48 +01:00
023b97aa69 sources/ldap: remove deprecated default
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 22:13:47 +01:00
51365dba74 web: Update Web API Client version (#1734)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-04 21:03:09 +01:00
0d3705685e web/admin: show warning on invitation list when no stage exists or is bound
closes #1720

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 21:00:42 +01:00
738e4d5c74 web/admin: only show flows with an invitation stage configured instead of all enrollment flows
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#1720
2021-11-04 20:54:55 +01:00
b14b9cb0dd tests/e2e: fix selector for static token tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 15:55:30 +01:00
2a21ebf7b0 web/flows: fix authenticator_validate not allowing alpha-numeric codes due to empty pattern
closes #1663

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 15:39:10 +01:00
5bc1301043 stages/authenticator_*: add default name for authenticators
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 15:34:51 +01:00
e0e4bf6972 web/user: fix device type for static tokens
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 15:28:55 +01:00
337677ad12 web/flows: improve display of static tokens
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 15:21:04 +01:00
3712d5aee2 web/user: fix empty page when no sources to connect exist
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 15:16:08 +01:00
dd82d55725 outposts: also send outpost type
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 15:08:31 +01:00
8d766efecb root: don't set signal on start when running in ci or dev
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 14:32:21 +01:00
9ac3b29418 outpost: add lightweight, anonymous metrics
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 14:10:43 +01:00
5000c5b061 web/user: fix ak-user-settings-password getting wrong configureUrl
closes #1733

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 13:50:26 +01:00
b362d2af03 lib: fix linting issue
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 13:43:09 +01:00
bcd42fce13 root: further improve detection of environment we're running in
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 13:35:22 +01:00
6deddd038f internal: start embedded outpost directly after backend is healthy instead of waiting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 13:18:04 +01:00
3b47cb64da root: improve compose detection, add anonymous stats
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 13:16:21 +01:00
cf5e70c759 lifecycle: revert to non-h11 worker
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-04 13:16:10 +01:00
20bc38a54b build(deps): bump boto3 from 1.19.9 to 1.19.10 (#1731) 2021-11-04 08:36:15 +01:00
672a4ab1f4 build(deps): bump @sentry/browser from 6.13.3 to 6.14.0 in /web (#1728) 2021-11-04 08:35:53 +01:00
47dd667261 build(deps): bump @trivago/prettier-plugin-sort-imports in /web (#1729) 2021-11-04 08:35:40 +01:00
d1ac69789b build(deps): bump @sentry/tracing from 6.13.3 to 6.14.0 in /web (#1730) 2021-11-04 08:34:36 +01:00
08abf81c6d build(deps): bump goauthentik.io/api from 0.2021101.11 to 0.2021102.2 (#1732) 2021-11-04 08:33:50 +01:00
76bd987e6f web: Update Web API Client version (#1727)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-03 21:11:10 +01:00
5374352411 sources/plex: allow users to connect their plex account without login flow
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-03 21:09:02 +01:00
08eff4cc5d sources/plex: fix missing ordering
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-03 20:21:33 +01:00
c87a9f9489 web: remove debug entry
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-03 20:19:37 +01:00
8f6d700aa8 sources/oauth: set prompt=none for Discord provider
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-03 15:48:59 +01:00
c6843b026c web: Update Web API Client version (#1726)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-03 11:41:57 +01:00
3769c33ef0 Merge branch 'version-2021.10' 2021-11-03 11:39:27 +01:00
8982afaf44 website/docs: add 2021.10.2
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-03 10:20:29 +01:00
58c221e867 release: 2021.10.2 2021-11-03 10:07:28 +01:00
108d3e56e3 build(deps): bump @docusaurus/plugin-client-redirects in /website (#1721) 2021-11-03 09:01:54 +01:00
145b32c480 build(deps): bump lxml from 4.6.3 to 4.6.4 (#1725) 2021-11-03 08:33:42 +01:00
c788504bb0 build(deps): bump boto3 from 1.19.8 to 1.19.9 (#1724) 2021-11-03 08:33:32 +01:00
34782b31e5 build(deps): bump @docusaurus/preset-classic in /website (#1722) 2021-11-03 08:33:10 +01:00
5a3ca13d76 build(deps): bump swagger-spec-validator from 2.7.3 to 2.7.4 (#1723) 2021-11-03 08:33:02 +01:00
5dc0f3b91b website: remove static service account, use helm chart instead
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-03 00:14:01 +01:00
f51515f3de stages/invitation: don't throw 404 error in stage
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-03 00:07:13 +01:00
f978575293 stages/invitation: remove invitation from plan context after deletion
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 23:50:12 +01:00
cb64eed90d web: re-fix lint
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 14:59:35 +01:00
db1f7f0400 Revert "tests/e2e: remove deprecated desired_capabilities"
This reverts commit 2da7a8fede.
2021-11-02 14:53:52 +01:00
0d02dbf55c api: replace django sentry proxy with go proxy to prevent login issues
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 14:44:37 +01:00
6da78b8c32 web/user: fix linting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 13:48:37 +01:00
3a80bc8bda web/user: fix configureUrl not being passed to <ak-user-settings-password>
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 13:21:01 +01:00
1aa9c0f9ca root: move pyright config to toml
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 13:05:11 +01:00
2da7a8fede tests/e2e: remove deprecated desired_capabilities
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 11:04:47 +01:00
89cb402f42 root: fix postgres install on bullseye
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 10:56:39 +01:00
b617fd213f web: replace deprecated commonjs plugin
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 10:38:20 +01:00
97b0f58f25 root: build outposts without CGO, use debug images for basic shell
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-02 10:11:51 +01:00
49a98bb744 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1715) 2021-11-02 08:45:25 +01:00
f93a00d773 build(deps): bump rollup from 2.58.3 to 2.59.0 in /web (#1716) 2021-11-02 08:44:16 +01:00
8de40a8a21 build(deps): bump @typescript-eslint/parser from 5.2.0 to 5.3.0 in /web (#1717) 2021-11-02 08:44:08 +01:00
b9c54e97fa build(deps): bump goauthentik.io/api from 0.2021101.10 to 0.2021101.11 (#1718) 2021-11-02 08:44:00 +01:00
f1c55465f7 build(deps): bump boto3 from 1.19.7 to 1.19.8 (#1719) 2021-11-02 08:43:51 +01:00
40c2b2860b web: Update Web API Client version (#1712)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-11-01 21:08:38 +01:00
a92bce322d web/flows: fix sub_text not rendering for static fields
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-01 20:54:43 +01:00
af83308fd4 stages/prompt: fix type in Prompt not having enum set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-01 20:44:48 +01:00
73d991e75a root: update to buster
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-01 16:31:26 +01:00
1eba3f1334 root: update base images for outposts
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-01 16:29:53 +01:00
b86251255d website/docs: add azure ad docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-11-01 15:58:59 +01:00
ccab41a6ca build(deps): bump packaging from 21.0 to 21.2 (#1708) 2021-11-01 12:32:42 +01:00
0e051031b1 build(deps): bump django-storages from 1.12.2 to 1.12.3 (#1710) 2021-11-01 12:24:06 +01:00
aecbe8c585 build(deps): bump django from 3.2.8 to 3.2.9 (#1711) 2021-11-01 12:19:17 +01:00
da98022704 build(deps): bump boto3 from 1.19.6 to 1.19.7 (#1709) 2021-11-01 12:16:20 +01:00
e13f9c0b38 build(deps-dev): bump coverage from 6.0.2 to 6.1.1 (#1707) 2021-11-01 12:15:57 +01:00
7941fb9d95 build(deps): bump @babel/plugin-proposal-decorators in /web (#1703) 2021-11-01 10:05:47 +01:00
d2392b0881 build(deps): bump @babel/preset-env from 7.15.8 to 7.16.0 in /web (#1704) 2021-11-01 10:05:37 +01:00
b2044d75fb build(deps): bump @babel/core from 7.15.8 to 7.16.0 in /web (#1701) 2021-11-01 10:04:54 +01:00
617b64b7db build(deps): bump @babel/preset-typescript from 7.15.0 to 7.16.0 in /web (#1700) 2021-11-01 10:03:54 +01:00
2bf5f2709a build(deps): bump @patternfly/patternfly from 4.144.5 to 4.151.4 in /web (#1702) 2021-11-01 10:03:42 +01:00
f03325df28 build(deps): bump @babel/plugin-transform-runtime in /web (#1705) 2021-11-01 10:03:22 +01:00
2b71e5bdfd build(deps): bump goauthentik.io/api from 0.2021101.5 to 0.2021101.10 (#1706) 2021-11-01 10:02:52 +01:00
f861737b85 web/admin: fix formatting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-31 23:04:26 +01:00
6036d88392 providers/proxy: allow configuring of additional scope mappings for proxy
closes #1255

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-31 22:25:51 +01:00
bfc8a56a0b *: fix tests for new field show_source_labels
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-31 18:18:21 +01:00
8d995011b8 web: Update Web API Client version (#1699)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-31 18:00:20 +01:00
5646141fe2 stages/identification: add show_source_labels option, to show labels for sources
closes #1679

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-31 17:57:48 +01:00
96b0bc324e web/flows: fix invalid validation for static tokens
closes #1663

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-31 17:32:39 +01:00
335d6edd11 providers/saml: fix error on missing AssertionConsumerServiceURL, fall back to default ACS
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-31 17:21:15 +01:00
5d9bed130a root: fix Detection of S3 settings for backups
closes #1698

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-31 16:54:10 +01:00
0a1ab74707 web: Update Web API Client version (#1697)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-31 12:16:09 +01:00
ef24b94585 Merge branch 'version-2021.10' 2021-10-31 12:13:43 +01:00
77b0438aa4 website/docs: prepare 2021.10.1
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-31 10:57:48 +01:00
2788329880 release: 2021.10.1 2021-10-31 10:56:21 +01:00
15ab11be70 web/user: fix wrong device being selected in user's mfa update form
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-31 00:55:56 +02:00
8d5460a132 outposts: separate websocket re-connection logic to decrease requests on reconnect
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-30 21:33:50 +02:00
5ba2c80813 Merge branch 'update-web-api-client'
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	web/src/user/user-settings/mfa/MFADeviceForm.ts
2021-10-30 15:20:16 +02:00
06766bdb25 web/user: update form to update mfa devices
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-30 15:19:17 +02:00
fdae13316c web: Update Web API Client version
Signed-off-by: GitHub <noreply@github.com>
2021-10-30 13:18:31 +00:00
ae21886e8e web/user: update form to update mfa devices
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-30 15:16:27 +02:00
f5dc81907a core: add created field to source connection
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-30 15:02:41 +02:00
40f8ce3c4c web/user: rework MFA Device UI to support multiple devices
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-30 14:56:14 +02:00
c934915776 web: Update Web API Client version (#1695)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-30 14:53:02 +02:00
d70c8fbcc3 core: add API for all user-source connections
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-30 14:36:54 +02:00
12b26e49ec flows: optimise stage user_settings API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-30 14:16:28 +02:00
0ac548d56e web: Update Web API Client version (#1693)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-29 09:16:08 +02:00
e771e1857f core: add API to list all authenticator devices
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-29 09:08:48 +02:00
479e9750c7 web/user: also search desc and publisher
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-29 09:08:48 +02:00
c5e7801247 build(deps): bump github.com/go-openapi/runtime from 0.20.0 to 0.21.0 (#1691)
Bumps [github.com/go-openapi/runtime](https://github.com/go-openapi/runtime) from 0.20.0 to 0.21.0.
- [Release notes](https://github.com/go-openapi/runtime/releases)
- [Commits](https://github.com/go-openapi/runtime/compare/v0.20.0...v0.21.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-29 09:06:34 +02:00
48ea15a946 build(deps): bump flowchart.js from 1.16.0 to 1.17.0 in /web (#1689) 2021-10-29 08:32:13 +02:00
e4c06f7356 build(deps): bump boto3 from 1.19.5 to 1.19.6 (#1690) 2021-10-29 08:31:58 +02:00
4d7d866e4b build(deps): bump github.com/go-openapi/strfmt from 0.20.3 to 0.21.0 (#1692) 2021-10-29 08:31:34 +02:00
72a93c0959 root: pin node images to v16
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-28 10:29:48 +02:00
73733b20b6 build(deps): bump @trivago/prettier-plugin-sort-imports from 2.0.4 to 3.0.0 in /web (#1684)
* build(deps): bump @trivago/prettier-plugin-sort-imports in /web

Bumps [@trivago/prettier-plugin-sort-imports](https://github.com/trivago/prettier-plugin-sort-imports) from 2.0.4 to 3.0.0.
- [Release notes](https://github.com/trivago/prettier-plugin-sort-imports/releases)
- [Changelog](https://github.com/trivago/prettier-plugin-sort-imports/blob/master/CHANGELOG.md)
- [Commits](https://github.com/trivago/prettier-plugin-sort-imports/commits)

---
updated-dependencies:
- dependency-name: "@trivago/prettier-plugin-sort-imports"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

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

* web: update prettier config

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-10-28 09:48:51 +02:00
3872314931 root: update golang ldap server package
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-28 09:48:31 +02:00
85c6ede448 build(deps): bump goauthentik.io/api from 0.2021101.4 to 0.2021101.5 (#1685) 2021-10-28 08:47:04 +02:00
49c2bee9d6 build(deps): bump boto3 from 1.19.4 to 1.19.5 (#1686) 2021-10-28 08:46:54 +02:00
6b2c9d7c44 web: Update Web API Client version (#1683)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-27 22:32:01 +02:00
381010600f release: 2021.10.1-rc3 2021-10-27 18:57:07 +02:00
2a265f706a website/docs: prepare 2021.10.1-rc3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-27 18:56:52 +02:00
1b21b50b77 providers/oauth2: fallback to uid if UPN was selected but isn't available
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-27 16:11:35 +02:00
fa6324ab1d sources/ldap: prevent key users from being set as this is an M2M relation
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-27 15:43:56 +02:00
9e0daf2bcf sources/ldap: skip values which are of type bytes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-27 15:43:38 +02:00
0273ae16df events: fix error when notification transport doesn't exist anymore
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-27 15:38:41 +02:00
f2f12ef0ba api: fix error when connection to websocket via secret_key
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-27 15:21:52 +02:00
61d3df5f02 outposts: fix docker controller not using object_naming_template
closes #1682

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-27 15:04:59 +02:00
971de4fcb9 core: add USER_ATTRIBUTE_CHANGE_EMAIL
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#1590 and #1677
2021-10-27 13:34:11 +02:00
9c0bc78ca0 build(deps): bump boto3 from 1.19.3 to 1.19.4 (#1678) 2021-10-27 08:30:26 +02:00
92085f1a3c core: add toggle to completely disable backup mechanism
closes #1671

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-26 17:04:33 +02:00
6067406e96 website/docs: add freeipa docs (#1666)
* website/docs: add freeipa docs

Signed-off-by: M. David Bennett <mdavidbennett@syntheticworks.com>

* website/docs: fix freeipa settings screenshot

Signed-off-by: M. David Bennett <mdavidbennett@syntheticworks.com>
2021-10-26 14:29:42 +02:00
9ccd4d69fe build(deps): bump @typescript-eslint/eslint-plugin in /web (#1673) 2021-10-26 13:25:45 +02:00
17ec48332d build(deps): bump rollup from 2.58.0 to 2.58.3 in /web (#1672) 2021-10-26 13:25:01 +02:00
d3f5253a6b build(deps): bump @typescript-eslint/parser from 5.1.0 to 5.2.0 in /web (#1674) 2021-10-26 13:24:38 +02:00
7a70726d57 build(deps): bump kubernetes from v19.15.0b1 to 19.15.0 (#1675) 2021-10-26 13:24:12 +02:00
be303937fb build(deps): bump boto3 from 1.19.2 to 1.19.3 (#1676) 2021-10-26 13:23:59 +02:00
2326fc9ae2 build(deps): bump eslint from 8.0.1 to 8.1.0 in /web (#1669) 2021-10-25 09:58:30 +02:00
9374b0bcf2 build(deps): bump chart.js from 3.5.1 to 3.6.0 in /web (#1668) 2021-10-25 09:58:18 +02:00
47e6028099 build(deps): bump boto3 from 1.19.1 to 1.19.2 (#1670) 2021-10-25 09:57:57 +02:00
24114e8304 Update harbor doc (#1667) 2021-10-24 16:44:04 +02:00
921d9c79a1 build(deps): bump @docusaurus/plugin-client-redirects in /website (#1659) 2021-10-22 07:35:06 +02:00
1119989ab7 build(deps): bump postcss from 8.3.10 to 8.3.11 in /website (#1657) 2021-10-22 07:34:34 +02:00
e17594f0f7 build(deps): bump eslint-plugin-custom-elements in /web (#1658) 2021-10-22 07:34:25 +02:00
5ae3b868d4 build(deps): bump @docusaurus/preset-classic in /website (#1660) 2021-10-22 07:34:11 +02:00
37ee4af5ff build(deps): bump goauthentik.io/api from 0.2021101.2 to 0.2021101.4 (#1661) 2021-10-22 07:33:55 +02:00
829aaca317 build(deps): bump boto3 from 1.19.0 to 1.19.1 (#1662) 2021-10-22 07:33:45 +02:00
8eb4d53810 providers/oauth2: fix events being created from /application/o/authorize/
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-21 22:59:01 +02:00
e60dfc5b3c web: Update Web API Client version (#1656) 2021-10-21 17:06:53 +02:00
cc403d8777 Merge branch 'version-2021.10' 2021-10-21 16:52:18 +02:00
b81e2e69d1 website/docs: prepare 2021.10.1-rc2
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-21 16:49:11 +02:00
731f5d0199 release: 2021.10.1-rc2 2021-10-21 16:38:30 +02:00
a40cb03b44 root: use custom url for discord
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-21 10:40:43 +02:00
f6a85c98c9 website: add redirect for discord
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-21 10:37:53 +02:00
5727f28784 web: Update Web API Client version (#1655)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-21 10:35:15 +02:00
6fc54ed7c6 build(deps): bump postcss from 8.3.9 to 8.3.10 in /website (#1652)
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-21 10:29:48 +02:00
4298900ecc build(deps): bump eslint-plugin-custom-elements in /web (#1653) 2021-10-21 09:03:26 +02:00
f04aa09b72 build(deps): bump boto3 from 1.18.65 to 1.19.0 (#1654) 2021-10-21 09:02:57 +02:00
3647633232 core: cleanup embedded outpost logging, log user for http requests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 22:12:49 +02:00
2e06786869 outpost/ldap: fix logging for mismatched provider
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 19:49:17 +02:00
eba91c6b2b root: add cookie domain setting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 18:26:22 +02:00
ba9f8a5795 lib: add utm_source to default links
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 17:31:27 +02:00
02b4173d30 root: add utm_source
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 16:34:39 +02:00
61fab497cf core: add user flag to prevent users from changing their usernames
closes #1590

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 16:17:19 +02:00
6a95de4e8a website: fix script loading
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 15:37:11 +02:00
621e7f564a flows: also clear cache when deleting bindings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 15:25:38 +02:00
535f2eb27e website: netlify proxy analytics
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 15:24:04 +02:00
0db4716e92 web/flows: show cancel link when choosing authenticator chalenge
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 15:15:31 +02:00
c10ce5c679 web: disable Sentry.showReportDialog
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 11:46:02 +02:00
070438aabe ci: allow manual cleanup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 11:18:23 +02:00
71798b931c ci: only keep images for last week
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 11:17:57 +02:00
8663134c87 build(deps): bump eslint-plugin-lit from 1.6.0 to 1.6.1 in /web (#1648) 2021-10-20 09:13:52 +02:00
6bcbaeec2e build(deps): bump boto3 from 1.18.64 to 1.18.65 (#1649) 2021-10-20 09:13:37 +02:00
17ce113c6b build(deps): bump goauthentik.io/api from 0.202198.6 to 0.2021101.2 (#1650) 2021-10-20 09:13:28 +02:00
ff600cd5b1 web: Update Web API Client version (#1647)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-20 00:19:11 +02:00
2df4322ecf sources/oauth: add choices to oauth provider_type
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-20 00:11:19 +02:00
bb8e0c6f59 web/flow: showing of authentik logo in flow executor
closes #1646

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-19 23:06:23 +02:00
ca682c3ee4 web/flows: fix authenticator device selection not updating
closes #1645

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-19 22:45:09 +02:00
f011e8a61a Merge branch 'version-2021.10' 2021-10-19 22:25:35 +02:00
bfe27d5979 web: Update Web API Client version (#1643)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-19 16:01:03 +02:00
b8aff17d98 web: Update Web API Client version (#1643)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-19 15:52:31 +02:00
3b7e8e3931 website/docs: fix typos
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-19 15:45:15 +02:00
03369e2338 sources/ldap: check for existence of vendor fields before falling back
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#1521
2021-10-19 15:40:40 +02:00
5da7d9a573 release: 2021.10.1-rc1 2021-10-19 15:34:59 +02:00
12110e264d ci: remove pwgen
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-19 15:34:54 +02:00
f5049d3d0f build(deps): bump @typescript-eslint/eslint-plugin in /web (#1639) 2021-10-19 06:59:35 +02:00
b616253444 build(deps): bump flowchart.js from 1.15.0 to 1.16.0 in /web (#1640) 2021-10-19 06:58:04 +02:00
41efe49d27 build(deps): bump @typescript-eslint/parser from 5.0.0 to 5.1.0 in /web (#1641) 2021-10-19 06:57:55 +02:00
86d0e6ce45 build(deps): bump boto3 from 1.18.63 to 1.18.64 (#1642) 2021-10-19 06:57:35 +02:00
89bb27b95c sources/ldap: fix missing arguments?
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 22:04:58 +02:00
9333ffd04f website/docs: fix typo
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 21:48:10 +02:00
2b155964c2 sources/ldap: extract vendor-specific functions
#1521

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 21:44:10 +02:00
c3bd509eb8 website/docs: add matrix docs
closes #1477

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 21:09:26 +02:00
72c0da2bdf build(deps): bump webauthn from 1.0.0 to 1.0.1 (#1638)
Bumps [webauthn](https://github.com/duo-labs/py_webauthn) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/duo-labs/py_webauthn/releases)
- [Changelog](https://github.com/duo-labs/py_webauthn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/duo-labs/py_webauthn/compare/v1.0.0...v1.0.1)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-18 18:04:31 +02:00
151c62733f build(deps): bump goauthentik.io/api from 0.202198.3 to 0.202198.6 (#1637)
Bumps [goauthentik.io/api](https://github.com/goauthentik/client-go) from 0.202198.3 to 0.202198.6.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v0.202198.3...v0.202198.6)

---
updated-dependencies:
- dependency-name: goauthentik.io/api
  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-10-18 18:04:20 +02:00
dbdea24290 website: remove .git suffix for go import
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 17:48:13 +02:00
909c4217bc website/docs: prepare 2021.10
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 17:06:18 +02:00
922fc9b8d5 sources/oauth: add Sign in with Apple (#1635)
* sources/oauth: add apple sign in support

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

* website/docs: apple sign in docs

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

* website/docs: fix missing apple in sidebar

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

* sources/oauth: add fallback values for name and slug

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 16:35:12 +02:00
2c06eed8e7 events: don't prefill task if they already have a state
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 14:48:14 +02:00
a1b3af401d outposts: improve handling of recreate scenarios
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 14:29:37 +02:00
92d38f62b5 outposts: handle k8s 422 response code by recreating objects
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 10:23:11 +02:00
98a56c77e3 providers/proxy: update ingress controller to work with k8s 1.22
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-18 10:00:24 +02:00
e5906a4115 build(deps): bump @docusaurus/plugin-client-redirects in /website (#1629)
Bumps [@docusaurus/plugin-client-redirects](https://github.com/facebook/docusaurus/tree/HEAD/packages/docusaurus-plugin-client-redirects) from 2.0.0-beta.6 to 2.0.0-beta.7.
- [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.7/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-10-18 09:16:44 +02:00
20c6874bb4 build(deps): bump @rollup/plugin-typescript from 8.2.5 to 8.3.0 in /web (#1630)
Bumps [@rollup/plugin-typescript](https://github.com/rollup/plugins/tree/HEAD/packages/typescript) from 8.2.5 to 8.3.0.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/typescript/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/typescript-v8.3.0/packages/typescript)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-18 09:15:35 +02:00
222d3bd358 build(deps): bump @docusaurus/preset-classic in /website (#1631)
Bumps [@docusaurus/preset-classic](https://github.com/facebook/docusaurus/tree/HEAD/packages/docusaurus-preset-classic) from 2.0.0-beta.6 to 2.0.0-beta.7.
- [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.7/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-10-18 09:15:26 +02:00
02c15f7c43 build(deps): bump boto3 from 1.18.62 to 1.18.63 (#1632)
Bumps [boto3](https://github.com/boto/boto3) from 1.18.62 to 1.18.63.
- [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.62...1.18.63)

---
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-10-18 09:15:16 +02:00
ab200eb855 build(deps): bump django-storages from 1.12.1 to 1.12.2 (#1633)
Bumps [django-storages](https://github.com/jschneier/django-storages) from 1.12.1 to 1.12.2.
- [Release notes](https://github.com/jschneier/django-storages/releases)
- [Changelog](https://github.com/jschneier/django-storages/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jschneier/django-storages/compare/1.12.1...1.12.2)

---
updated-dependencies:
- dependency-name: django-storages
  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-10-18 09:15:06 +02:00
9e8ce012e3 build(deps): bump pyjwt from 2.2.0 to 2.3.0 (#1634)
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.2.0 to 2.3.0.
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jpadilla/pyjwt/commits)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-18 09:14:55 +02:00
00dc8f8b1f ci: backoff translation compile ci
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-17 22:15:38 +02:00
ce812e14c7 core: improve detection for s3 settings to trigger backup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-17 15:56:31 +02:00
8d32a53126 outposts: add additional error checking for docker controller
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-17 15:54:57 +02:00
f9b6b1dd3f web/admin: improve visibility of oauth rsa key
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-17 14:15:36 +02:00
9679be39fa lifecycle: bump celery healthcheck to 5s timeout
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#1627
2021-10-16 14:28:05 +02:00
0225bf9c99 stages/authenticator_validate: create a default authenticator validate stage with sensible defaults
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-16 00:28:56 +02:00
8040e2b6e4 build(deps): bump webauthn from 0.4.7 to 1.0.0 (#1625)
* build(deps): bump webauthn from 0.4.7 to 1.0.0

Bumps [webauthn](https://github.com/duo-labs/py_webauthn) from 0.4.7 to 1.0.0.
- [Release notes](https://github.com/duo-labs/py_webauthn/releases)
- [Commits](https://github.com/duo-labs/py_webauthn/compare/v0.4.7...v1.0.0)

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

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

* stages/authenticator_webauthn: migrate to new library version

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

* stages/authenticator_validate: migrate to new version

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

* stages/authenticator_webauthn: add bytes_to_base64url_dict for json encoding

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

* actually don't do that

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

* fix missing response on web

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

* more double json

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

* fix

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

* more base64 stuff

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

* working

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

* ci: always sync

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

* fix

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-15 23:26:29 +02:00
56a56ffdbf web: new default flow background
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-15 23:03:41 +02:00
afedcc0074 build(deps): bump drf-spectacular from 0.20.1 to 0.20.2 (#1624)
Bumps [drf-spectacular](https://github.com/tfranzel/drf-spectacular) from 0.20.1 to 0.20.2.
- [Release notes](https://github.com/tfranzel/drf-spectacular/releases)
- [Changelog](https://github.com/tfranzel/drf-spectacular/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tfranzel/drf-spectacular/compare/0.20.1...0.20.2)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-15 17:48:51 +00:00
4d93e30147 web: Update Web API Client version (#1623)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-15 19:29:44 +02:00
f62786e58b policies: add additional filters to create flow charts on frontend
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-15 18:21:44 +02:00
f76c1a6f93 build(deps): bump @patternfly/patternfly from 4.135.2 to 4.144.5 in /web (#1621) 2021-10-15 08:33:46 +02:00
56871523e7 build(deps): bump boto3 from 1.18.61 to 1.18.62 (#1622) 2021-10-15 08:33:31 +02:00
5f9dda2e58 outposts: rename docker_image_base to container_image_base, since its not docker specific
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 20:28:30 +02:00
0c55eea678 outposts: Adding more flexibility to outposts in Kubernetes. (#1617)
* outposts/ldap: Support hard coded `uidNumber` and `gidNumber`.

* outposts: more options for image + labels

- Set outpost docker image in config.
- Set image pull secrets in outpost config.
- Add additional labels for easier targeting from
  custom services.

* Fix some linting errors.

* outposts: Rename `docker_image` to `container_image
2021-10-14 19:54:56 +02:00
19a343dadb web: fix linting on rollup config
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 19:49:31 +02:00
3ab9798f38 web: prepare for building with external API bases
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 19:45:20 +02:00
dd9dc7e596 root: fix error with sentry proxy
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 19:45:01 +02:00
797e31696a outposts: fix attribute error in docker controller
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 13:37:56 +02:00
9a42c5815d web/admin: add fallback font for doughnut charts
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 12:50:52 +02:00
f341479732 web: make table pagination size user-configurable
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 12:48:52 +02:00
8eddb4b95b admin: check for debug in worker count api
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 12:32:30 +02:00
5c58532121 web/admin: default to warning state for backup task
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 12:31:01 +02:00
4b7399f454 *: add @prefill_task() decorator to "pre-fill" tasks in cache, so they can be executed even before their schedule would do so
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 12:21:28 +02:00
27982a771c web: Update Web API Client version (#1620)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-14 11:52:50 +02:00
8296d0c94c web/admin: fix SMS Authenticator stage not loading state correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 11:49:55 +02:00
9bc9568008 stages/authenticator_sms: make fields non-nullable
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 11:42:11 +02:00
07d619d257 website/docs: add authenticator_sms stage docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 11:33:46 +02:00
6ee7d5bf9c web: Update Web API Client version
Signed-off-by: GitHub <noreply@github.com>
2021-10-14 10:25:13 +02:00
634375c43f stages/authenticator_sms: add generic provider (#1595)
* stages/sms: New SMS provider, aka wrapper for outside API

* web/pages/authenicator_sms: Conditionally show options based on provider.

* stages/authenicator_sms: Fixing up the model.

* Whoops

* stages/authenicator_sms: Adding supported auth types for Generic provider.

* web/pages/stages/authenicator_sms: Added auth type for generic provider

* web/pages/stages/authenicator_sms: Fixing up my generic provider options.

* stages/authenicator/sms: Working version of generic provider.

* stages/authenicator/sms: Cleanup and creating an event on error.

* web/ages/stages/authenicator_sms: Made a default for Auth Type and cleaned up the non-needed name attribute.

* stages/authenicator_validate: Fixing up the migration as it had no SMS.

* stages/authenicator_sms: Removd non-needed migration and better error code handling.

* stages/authenicator_sms: Removd non-needed migration and better error code handling.

* web/pages/stages/authenicator_sms: Provider default is not empty anymore.

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-14 10:24:15 +02:00
10fc33f7d3 build(deps): bump eslint from 8.0.0 to 8.0.1 in /web (#1612) 2021-10-14 08:33:55 +02:00
ee140014e9 build(deps): bump pyyaml from 5.4.1 to 6.0 (#1613) 2021-10-14 08:33:07 +02:00
2d363948b6 build(deps-dev): bump selenium from 3.141.0 to 4.0.0 (#1614) 2021-10-14 08:32:50 +02:00
dcb3ef14d1 build(deps): bump boto3 from 1.18.60 to 1.18.61 (#1615) 2021-10-14 08:32:37 +02:00
a71ef7f36c build(deps): bump django-model-utils from 4.1.1 to 4.2.0 (#1616) 2021-10-14 08:32:28 +02:00
4d51ec906d internal/proxyv2: improve error handling when configuring app
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-13 21:48:11 +02:00
cd42281383 Revert "website: use 302-based proxy for goauthentik.io/v2"
This reverts commit faf706cbec.
2021-10-13 21:27:26 +02:00
faf706cbec website: use 302-based proxy for goauthentik.io/v2
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-13 21:25:12 +02:00
16c05a7bbc tests: migrate to selenium 4 (#1611) 2021-10-13 19:06:19 +02:00
2ad5995332 website/docs: add symlink for latest compose
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-13 17:51:54 +02:00
f73a404fd6 website: make static files available under domain
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-13 17:45:45 +02:00
178e8e7e43 web/user: initial optimisation for smaller screens
see #1610

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-13 11:23:26 +02:00
98907ec889 root: remove structlog.processors.format_exc_info for new structlog version
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-13 09:42:49 +02:00
9dd9ab6da3 build(deps): bump structlog from 21.1.0 to 21.2.0 (#1609)
Bumps [structlog](https://github.com/hynek/structlog) from 21.1.0 to 21.2.0.
- [Release notes](https://github.com/hynek/structlog/releases)
- [Changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/hynek/structlog/compare/21.1.0...21.2.0)

---
updated-dependencies:
- dependency-name: structlog
  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-10-13 09:41:44 +02:00
80c6b8f0c7 build(deps): bump @typescript-eslint/parser from 4.33.0 to 5.0.0 in /web (#1604) 2021-10-13 08:36:09 +02:00
8436814874 build(deps): bump codemirror from 5.63.1 to 5.63.3 in /web (#1606) 2021-10-13 08:34:56 +02:00
3c16bdce45 build(deps): bump typescript from 4.4.3 to 4.4.4 in /web (#1607) 2021-10-13 08:34:34 +02:00
a2bce79796 build(deps): bump boto3 from 1.18.59 to 1.18.60 (#1608) 2021-10-13 08:34:24 +02:00
3e5b05203b Revert "root: handle liveness probe in router"
This reverts commit d39dbc7287.

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 18:44:37 +02:00
57e86582d1 Revert "root: handle liveness probe in router (also keep internal one)"
This reverts commit dd7cb45733.
2021-10-12 18:44:08 +02:00
dd7cb45733 root: handle liveness probe in router (also keep internal one)
This reverts commit d39dbc7287.

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 18:43:39 +02:00
2b09d97522 core: fix squash migrations error when AK_ADMIN_TOKEN is set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 17:45:10 +02:00
d39dbc7287 root: handle liveness probe in router
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 14:54:15 +02:00
48f96ea55f lifecycle: only set prometheus_multiproc_dir in ak wrapper to prevent full disk on worker
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 14:44:32 +02:00
22a7c25526 internal: call GetStore on application to improve logging
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 13:33:20 +02:00
cc69311ec0 stages/authenticator_validate: add new class
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 13:13:31 +02:00
15d7004e25 tests/e2e: use vanity urls
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 12:38:23 +02:00
ddb70a283e managed: don't run managed reconciler in foreground on startup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 12:10:46 +02:00
ecfc3a6d93 *: migrate everything to goauthentik.io docker proxy
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 11:04:47 +02:00
5753182e03 root: migrate docker images to netlify proxy (#1603)
* migrate to netlify proxy

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

* relative forward to func

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

* custom logic for go paths

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

* fix const

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

* missing break

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

* add default for new repos

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-12 10:58:02 +02:00
db79244ba4 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1602)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.33.0 to 5.0.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/v5.0.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  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-10-12 09:26:39 +02:00
3231bcea66 build(deps): bump eslint from 7.32.0 to 8.0.0 in /web (#1596) 2021-10-12 08:34:10 +02:00
5e0299ca82 build(deps): bump @types/codemirror from 5.60.4 to 5.60.5 in /web (#1597) 2021-10-12 08:33:01 +02:00
42e35aace0 build(deps-dev): bump coverage from 6.0.1 to 6.0.2 (#1598) 2021-10-12 08:32:23 +02:00
d96cfc8e30 build(deps): bump goauthentik.io/api from 0.202198.2 to 0.202198.3 (#1599) 2021-10-12 08:32:13 +02:00
36c97afc44 build(deps): bump django-storages from 1.12 to 1.12.1 (#1600) 2021-10-12 08:32:02 +02:00
9c322be8d7 build(deps): bump boto3 from 1.18.58 to 1.18.59 (#1601) 2021-10-12 08:31:51 +02:00
cf09205933 website/docs: fix sidebar
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-11 22:45:24 +02:00
e851a7f294 website/docs: add missing make migrate
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-11 22:33:31 +02:00
e4f141c6c0 *: Squash Migrations (#1593)
* *: first squash pass

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

* sources/saml: squash less

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

* outposts: fix docker controller not correctly checking image

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

* tests/e2e: fix old migration reference

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-11 21:39:35 +02:00
35fa93d9aa ci: fix missing gettext
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-11 17:59:52 +02:00
2bdc0102f9 web: Update Web API Client version (#1592)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-11 17:53:43 +02:00
aef9d27706 stages/authenticator_sms: Add SMS Authenticator Stage (#1577)
* stages/authenticator_sms: initial implementation

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

* web/admin: add initial stage UI

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

* web/elements: clear invalid state when old input was invalid but new input is correct

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

* stages/authenticator_sms: add more logic

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

* web/user: add basic SMS settings

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

* stages/authenticator_sms: initial working version

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

* stages/authenticator_sms: add tests

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

* web/flows: optimise totp password manager entry on authenticator_validation stage

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

* web/elements: add grouping support for table

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

* web/admin: allow sms class in authenticator stage

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

* web/admin: add grouping to more pages

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

* stages/authenticator_validate: add SMS support

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

* api: add throttling for flow executor based on session key and pending user

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

* web: fix style issues

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

* ci: add workflow to compile backend translations

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-11 17:51:49 +02:00
7bf587af24 ci: push dev images to ghcr (#1591)
* ci: push dev images to ghcr

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

* *: use new ghcr images

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

* website/docs: use ghcr proxy

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-11 14:08:34 +02:00
ef1cf7867c Revert "build(deps): bump eslint from 7.32.0 to 8.0.0 in /web (#1584)"
This reverts commit e22b8f5fdc.
2021-10-11 13:43:36 +02:00
da443b443c website: use ghcr proxy for registry
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-11 10:08:21 +02:00
f4322e665a build(deps): bump github.com/go-openapi/strfmt from 0.20.2 to 0.20.3 (#1585)
Bumps [github.com/go-openapi/strfmt](https://github.com/go-openapi/strfmt) from 0.20.2 to 0.20.3.
- [Release notes](https://github.com/go-openapi/strfmt/releases)
- [Commits](https://github.com/go-openapi/strfmt/compare/v0.20.2...v0.20.3)

---
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-10-11 09:20:36 +02:00
e22b8f5fdc build(deps): bump eslint from 7.32.0 to 8.0.0 in /web (#1584) 2021-10-11 08:33:38 +02:00
a18176af56 build(deps): bump react-before-after-slider-component in /website (#1583) 2021-10-11 08:32:48 +02:00
4132fd139c build(deps): bump goauthentik.io/api from 0.202197.2 to 0.202198.2 (#1586) 2021-10-11 08:32:28 +02:00
b077bb8783 build(deps): bump github.com/go-openapi/runtime from 0.19.31 to 0.20.0 (#1587) 2021-10-11 08:32:20 +02:00
69665d9547 build(deps): bump pycryptodome from 3.10.4 to 3.11.0 (#1588) 2021-10-11 08:32:11 +02:00
d0f056357d build(deps): bump boto3 from 1.18.57 to 1.18.58 (#1589) 2021-10-11 08:32:02 +02:00
9ed236f7ab outposts/ldap: Support hard coded uidNumber and gidNumber. (#1582) 2021-10-10 23:43:36 +02:00
83f4830946 website: add netlify config file
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-10 22:26:33 +02:00
e23df99a9e web: Update Web API Client version (#1580)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-10 18:57:23 +02:00
b80ecd4668 stages/prompt: fix wrong field type of field_key
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-10 18:54:56 +02:00
66ca488ea0 web: Update Web API Client version (#1579)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-10 14:43:58 +02:00
d959b7a930 Merge branch 'version-2021.9' 2021-10-10 14:35:40 +02:00
62ae3f1e31 website/docs: prepare 2021.9.8
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-10 13:22:36 +02:00
a1adf382af root: don't compilemessages in build process since it requires redis, do it on startup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 23:38:25 +02:00
834bddd0da root: add AUTHENTIK_SECRET_KEY for compilemessages
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 22:52:32 +02:00
7d9251ce2f root: fix linting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 20:56:49 +02:00
fb13a46252 web: Update Web API Client version (#1576)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-09 20:23:38 +02:00
dfefdbfd7c root: compile messages for backend in docker
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 20:11:51 +02:00
846c971674 root: add translation for backend strings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 20:07:28 +02:00
5b7e1f97e0 stages/authenticator_duo: remove signals
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 19:29:35 +02:00
dff0613b3d crypto: add managed field, prepare managed JWT cert
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 19:14:39 +02:00
0a4343d61b web: Update Web API Client version (#1575)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-09 16:05:02 +02:00
09696207a6 web/user: remove debug
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 16:03:14 +02:00
8965451073 core: add default for user's settings attribute
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 16:01:22 +02:00
994c1c4b6a web: Update Web API Client version (#1574)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-09 16:01:14 +02:00
3ee5a672f1 web/user: load interface settings from user settings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 15:52:36 +02:00
b33ea9cc61 core: add settings serializer to user/me and update_self endpoints, saved in a key in attributes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-09 15:35:18 +02:00
50a623d8ab build(deps): bump golang from 1.17.1 to 1.17.2 (#1566) 2021-10-08 08:34:37 +02:00
cdbf7ae567 build(deps): bump lit from 2.0.0 to 2.0.2 in /web (#1567) 2021-10-08 08:34:21 +02:00
1307a39042 build(deps): bump react-before-after-slider-component in /website (#1569) 2021-10-08 08:33:54 +02:00
dca34cfbd3 build(deps): bump docker from 5.0.2 to 5.0.3 (#1571) 2021-10-08 08:33:39 +02:00
735f7cbd69 build(deps): bump boto3 from 1.18.56 to 1.18.57 (#1570) 2021-10-08 08:33:20 +02:00
728356d420 build(deps): bump goauthentik.io/api from 0.202197.1 to 0.202197.2 (#1572) 2021-10-08 08:32:54 +02:00
a9f6f1563d ci: fix more order
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 22:40:13 +02:00
155c28d7cd ci: prepare variables before checking out stable
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 22:40:13 +02:00
f9a180eb1f ci: fix gh_env
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 22:40:13 +02:00
f32d35b07c policies/password: add extra sub_text field in tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 19:27:24 +02:00
9e936e4436 outposts: fix lint error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 19:15:57 +02:00
649abddea7 outposts: fallback to known-good outpost image if configured image cannot be pulled
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 19:10:39 +02:00
956382b682 ci: set separate variable for container branch name
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 19:06:03 +02:00
67b88595ad stages/prompt: fix sub_text not allowing blank
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 19:00:15 +02:00
b4ee693a5c stages/user_write: allow recursive writing to user.attributes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 18:57:19 +02:00
57e5acaf2f stages/prompt: add sub_text field to add HTML below prompt fields
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 18:34:37 +02:00
050ec99c89 flows: fix inspector history not being cleared when executing from API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 18:29:28 +02:00
10fd1c8120 web/admin: truncate prompt label when too long
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 17:58:07 +02:00
070745e764 Revert "build(deps): bump construct-style-sheets-polyfill in /web (#1531)"
This reverts commit 55259adf38.
2021-10-07 10:48:12 +02:00
cbeee27fc1 build(deps): bump @sentry/tracing from 6.13.2 to 6.13.3 in /web (#1556)
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-07 09:39:44 +02:00
2bc4d0cedb build(deps): bump @babel/core from 7.15.5 to 7.15.8 in /web (#1555) 2021-10-07 08:28:13 +02:00
5105a1c207 build(deps): bump @babel/plugin-transform-runtime in /web (#1557) 2021-10-07 08:28:02 +02:00
64e357ab0e build(deps): bump @babel/preset-env from 7.15.6 to 7.15.8 in /web (#1554) 2021-10-07 08:27:03 +02:00
6ca93525aa build(deps): bump @babel/plugin-proposal-decorators in /web (#1558) 2021-10-07 08:26:21 +02:00
a2c978768c build(deps): bump @sentry/browser from 6.13.2 to 6.13.3 in /web (#1559) 2021-10-07 08:26:11 +02:00
f0c7be7144 build(deps): bump pyjwt from 2.1.0 to 2.2.0 (#1560) 2021-10-07 08:26:00 +02:00
0f96e3e4b3 build(deps): bump django-storages from 1.11.1 to 1.12 (#1561) 2021-10-07 08:25:44 +02:00
d42fc37a88 build(deps): bump goauthentik.io/api from 0.202196.1 to 0.202197.1 (#1562) 2021-10-07 08:25:16 +02:00
4ecd8f5dcf build(deps): bump boto3 from 1.18.55 to 1.18.56 (#1563) 2021-10-07 08:25:06 +02:00
d7a194b512 build(deps-dev): bump coverage from 6.0 to 6.0.1 (#1564) 2021-10-07 08:24:56 +02:00
753f8d38bf web: Update Web API Client version (#1552)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-06 21:09:30 +02:00
118a54517a website/docs: add 2021.9.7 release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-06 21:05:04 +02:00
8c27616d0c Merge branch 'version-2021.9' 2021-10-06 21:04:16 +02:00
097a42bb7b web/admin: fix description for flow import
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-06 20:50:43 +02:00
26f1f47cc1 Revert "build(deps): bump python from 3.9-slim-buster to 3.10.0-slim-buster (#1546)"
This reverts commit 471f9c6d05.
2021-10-06 09:55:44 +02:00
471f9c6d05 build(deps): bump python from 3.9-slim-buster to 3.10.0-slim-buster (#1546)
Bumps python from 3.9-slim-buster to 3.10.0-slim-buster.

---
updated-dependencies:
- dependency-name: python
  dependency-type: direct:production
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-06 09:35:01 +02:00
67d13f19a1 root: fix syntax error in dockerfile healthcheck
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-06 09:18:01 +02:00
1b7c19cf50 build(deps): bump eslint-plugin-lit from 1.5.1 to 1.6.0 in /web (#1547) 2021-10-06 08:29:03 +02:00
b012ae600d build(deps): bump boto3 from 1.18.54 to 1.18.55 (#1548) 2021-10-06 08:28:33 +02:00
1838101d60 build(deps): bump goauthentik.io/api from 0.202195.4 to 0.202196.1 (#1549) 2021-10-06 08:28:23 +02:00
929add4e9c build(deps): bump django from 3.2.7 to 3.2.8 (#1550) 2021-10-06 08:28:15 +02:00
18edaea658 website/docs: fix header of release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-06 00:08:03 +02:00
8030e45d75 web: Update Web API Client version (#1545)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-06 00:07:00 +02:00
d75c63d38b Merge branch 'version-2021.9'
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	web/src/locales/fr_FR.po
2021-10-06 00:04:09 +02:00
52889ffea1 website/docs: add 2021.9.6 release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-06 00:03:29 +02:00
6c603cdf80 internal: add internal healthchecking to prevent websocket errors
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 22:21:14 +02:00
5f4a1417b2 cmd: prevent outposts from panicking when failing to get their config
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 22:19:05 +02:00
e8420957b1 lifecycle: fix syntax error in ak wrapper
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 21:03:54 +02:00
aee58c8d53 root: add docker-native healthcheck for web and celery
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 20:45:18 +02:00
c47ab4f1fc root: remove redundant internal network from compose
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 20:39:27 +02:00
fa6df84de2 admin: clear update notification when notification's version matches current version
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 20:36:38 +02:00
1faa403fe2 root: update security
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 20:08:26 +02:00
7f5feb9451 web: fix strings not being translated at all when matching browser locale not found
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 16:23:40 +02:00
b85aeae5ef web: ensure fallback locale is loaded
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 14:53:02 +02:00
b72b731320 build(deps): bump goauthentik.io/api from 0.202195.3 to 0.202195.4 (#1544)
Bumps [goauthentik.io/api](https://github.com/goauthentik/client-go) from 0.202195.3 to 0.202195.4.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v0.202195.3...v0.202195.4)

---
updated-dependencies:
- dependency-name: goauthentik.io/api
  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-10-05 13:19:20 +02:00
65de4b8cad web: Update Web API Client version (#1543)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-05 13:12:42 +02:00
9e7e22367b core: include group uuids in self serializer
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 13:10:44 +02:00
9301b27e43 build(deps): bump goauthentik.io/api from 0.202195.1 to 0.202195.3 (#1542)
Bumps [goauthentik.io/api](https://github.com/goauthentik/client-go) from 0.202195.1 to 0.202195.3.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v0.202195.1...v0.202195.3)

---
updated-dependencies:
- dependency-name: goauthentik.io/api
  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-10-05 13:00:06 +02:00
7b415a24ee web: Update Web API Client version (#1540)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-05 12:33:50 +02:00
f5761dc70d core: only return group names for user_self
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 12:31:25 +02:00
4f57dfda93 web/flows: adjust message for email stage
closes #1538

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 11:28:11 +02:00
16380b3f7a api: ensure viewsets have default ordering
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 11:26:41 +02:00
b0e416e9f0 web/elements: fix model form always loading when viewport check is disabled
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 11:23:45 +02:00
16f2603130 core: make user's name field fully options
closes #1537

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 11:23:27 +02:00
e742494f3d web: Update Web API Client version (#1539)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-05 11:14:04 +02:00
5fdca722f4 web/admin: only show outpost deployment info when not embedded
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 11:11:44 +02:00
847cfed73f web/user: don't show managed tokens in user interface
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 11:11:34 +02:00
19247accd9 web: fix rendering of token copy button in dark mode
closes #1528

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 11:11:13 +02:00
05b587ae44 outposts: fix error when comparing ports in docker controller when port mapping is disabled
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 10:44:07 +02:00
a515afae0b recovery: handle error when user doesn't exist
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-05 10:40:59 +02:00
8da00585e3 Translate /web/src/locales/en.po in fr_FR (#1536)
translation completed for the source file '/web/src/locales/en.po'
on the 'fr_FR' language.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2021-10-05 10:30:01 +02:00
b70a72f247 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1529) 2021-10-05 07:19:47 +02:00
11160b6e04 build(deps): bump postcss from 8.3.8 to 8.3.9 in /website (#1530) 2021-10-05 07:18:40 +02:00
55259adf38 build(deps): bump construct-style-sheets-polyfill in /web (#1531) 2021-10-05 07:18:28 +02:00
3f308ad48c build(deps): bump @typescript-eslint/parser in /web (#1532) 2021-10-05 07:18:20 +02:00
ee6fd6f609 build(deps): bump react-before-after-slider-component in /website (#1533) 2021-10-05 07:17:38 +02:00
d53d0c353f build(deps): bump goauthentik.io/api from 0.202194.1 to 0.202195.1 (#1534) 2021-10-05 07:17:25 +02:00
1360b76d1b build(deps): bump boto3 from 1.18.53 to 1.18.54 (#1535) 2021-10-05 07:17:13 +02:00
e22a286a6f lifecycle: only lock database when system migrations need to be applied, and during django migrations, and don't double unlock
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 23:14:16 +02:00
62c0f69541 web: Update Web API Client version (#1527)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-04 22:07:00 +02:00
1c340ddbbd Merge branch 'version-2021.9'
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	web/package-lock.json
#	web/package.json
2021-10-04 22:02:56 +02:00
62af5b2dd3 website/docs: add 2021.9.5 release notes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 19:33:11 +02:00
e0859686c4 web: Update Web API Client version (#1526)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-04 18:50:43 +02:00
0692663537 stages/email: add activate_user_on_success flag, add for all example flows
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 18:47:51 +02:00
b5649bdcc4 stages/user_login: add check for user.is_active and tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 18:37:05 +02:00
418e491799 Revert "build(deps): bump construct-style-sheets-polyfill in /web (#1516)"
This reverts commit 0c6237d8c4.
2021-10-04 18:22:21 +02:00
fab9a10487 outposts: don't always build permissions on outpost.user access, only in signals and tasks
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 18:04:19 +02:00
9778050dda lifecycle: switch to h11 uvicorn worker for now
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 18:03:08 +02:00
9ac808ee98 website/docs: add missing pipenv instructions
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 17:54:06 +02:00
0f00b27384 events: add missing migration
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 17:51:31 +02:00
ab5981836d providers/ldap: use RDN when using posixGroup's memberUid attribute (#1514)
Use the RDN instead of the FDN when establishing group memberships based on posixGroup's 'memberUid' attribute.

fixes #1436

Signed-off-by: Steven Armstrong <steven@armstrong.cc>
2021-10-04 10:56:06 +02:00
a4418a83f8 web/admin: fix search group label
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 09:41:16 +02:00
36b23c4624 root: coverage with toml support
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 09:17:31 +02:00
0c6237d8c4 build(deps): bump construct-style-sheets-polyfill in /web (#1516)
Bumps [construct-style-sheets-polyfill](https://github.com/calebdwilliams/adoptedStyleSheets) from 2.4.17 to 3.0.3.
- [Release notes](https://github.com/calebdwilliams/adoptedStyleSheets/releases)
- [Changelog](https://github.com/calebdwilliams/construct-style-sheets/blob/main/CHANGELOG.md)
- [Commits](https://github.com/calebdwilliams/adoptedStyleSheets/commits/v3.0.3)

---
updated-dependencies:
- dependency-name: construct-style-sheets-polyfill
  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>
Co-authored-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-04 09:11:55 +02:00
e546453250 build(deps): bump react-before-after-slider-component in /website (#1517) 2021-10-04 08:33:28 +02:00
5b35d71bb3 build(deps): bump rollup from 2.57.0 to 2.58.0 in /web (#1518) 2021-10-04 08:33:03 +02:00
cddff85e1c build(deps): bump @types/codemirror from 5.60.3 to 5.60.4 in /web (#1519) 2021-10-04 08:32:34 +02:00
c65c6a62cc build(deps): bump boto3 from 1.18.52 to 1.18.53 (#1520) 2021-10-04 08:32:24 +02:00
1bc51adcac build(deps): bump goauthentik.io/api from 0.202193.3 to 0.202194.1 (#1522) 2021-10-04 08:32:11 +02:00
c523b799be build(deps-dev): bump coverage from 5.5 to 6.0 (#1524) 2021-10-04 08:32:00 +02:00
9d0d779f40 build(deps): bump drf-spectacular from 0.19.0 to 0.20.1 (#1523) 2021-10-04 08:31:17 +02:00
8a791c4eac tests/e2e: fallback to gh-master if outpost docker image cannot be found for PR
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-03 23:12:11 +02:00
036a4e86e2 tests/integration: fix tests failing due to incorrect comparison
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-03 22:54:07 +02:00
4715e7bf04 website/docs: fix description for docker outpost settings (#1513)
Changed the first "Kubernetes outpost specific settings" to Docker
2021-10-03 19:43:56 +02:00
83150d9920 outposts: fix circular import in kubernetes controller
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-03 19:25:18 +02:00
d30dcda814 providers/proxy: always check ingress secret in kubernetes controller
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-03 19:14:27 +02:00
c720c9f41b outposts: check ports of deployment in kubernetes outpost controller
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-03 19:09:52 +02:00
62cfb76b39 website/docs: fix order of steps on bookstack integration
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-03 18:46:47 +02:00
1c52836060 web: fix package lock
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-03 01:17:41 +02:00
f3cc1be0f2 Translate /web/src/locales/en.po in fr_FR (#1509)
translation completed updated for the source file '/web/src/locales/en.po'
on the 'fr_FR' language.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2021-10-03 00:32:17 +02:00
8dd77793a0 sources/ldap: fix logic error in Active Directory account disabled status
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-03 00:30:35 +02:00
f6e8dbfb5e outposts/proxy: show full error message when user is authenticated
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-02 22:00:37 +02:00
3c1ac4c7ec outposts/proxy: add new headers with unified naming
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-02 22:00:23 +02:00
52bbf454e3 outpost/proxy: fix missing negation for internal host ssl verification
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-02 21:17:15 +02:00
1252c6b07d web: add locale detection
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-01 14:11:54 +02:00
3493d35af9 web: Translate /web/src/locales/en.po in fr_FR (#1506)
translated updated for the source file '/web/src/locales/en.po'
on the 'fr_FR' language.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-01 14:02:18 +02:00
f8e4ffbc85 web: Update Web API Client version (#1505)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-10-01 12:24:12 +02:00
faca127217 Merge branch 'version-2021.9'
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	Pipfile.lock
2021-10-01 12:19:11 +02:00
f88575cec4 website/docs: prepare 2021.9.4
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-10-01 10:09:54 +02:00
b4eac771c2 build(deps): bump boto3 from 1.18.51 to 1.18.52 (#1503) 2021-10-01 08:49:09 +02:00
84e4ec4406 build(deps): bump channels-redis from 3.3.0 to 3.3.1 (#1504) 2021-10-01 08:48:59 +02:00
53e15bfbca sources/ldap: add support for Active Directory userAccountControl attribute
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-30 19:13:48 +02:00
8bce16e6b4 sources/ldap: don't sync ldap source when no property mappings are set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-30 18:49:18 +02:00
e9bb8c896b web/admin: fix LDAP Source form not exposing syncParentGroup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-30 18:10:56 +02:00
de5455716d build(deps): bump codemirror from 5.63.0 to 5.63.1 in /web (#1500) 2021-09-30 08:40:57 +02:00
1d879400f2 build(deps): bump boto3 from 1.18.49 to 1.18.51 (#1501) 2021-09-30 08:40:48 +02:00
5136ae17f5 build(deps): bump sentry-sdk from 1.4.2 to 1.4.3 (#1502) 2021-09-30 08:40:38 +02:00
4cb8ae760a outposts: allow disabling of docker controller port mapping
closes #1474

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-29 23:55:22 +02:00
e4898f4b92 web/elements: use dedicated button for search clear instead of webkit exclusive one
closes #1499

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-29 21:47:38 +02:00
a2f3c54c2a website/docs: use full paths for forward_auth
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-29 21:36:57 +02:00
c0a0b52fbb web/elements: fix initialLoad not being done when viewportCheck was disabled
closes #1497

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-29 21:36:44 +02:00
cfd4817bb5 root: Use fully qualified names for docker bases base images. (#1490)
Signed-off-by: Steven Armstrong <steven@armstrong.cc>
2021-09-29 09:52:07 +02:00
94ae52b576 web/admin: don't require username nor name for activate/deactivate toggles
closes #1491

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-29 09:42:59 +02:00
be479f2453 build(deps): bump @lingui/core from 3.11.1 to 3.12.1 in /web (#1493) 2021-09-29 09:10:30 +02:00
c5d066577d build(deps): bump @lingui/macro from 3.11.1 to 3.12.1 in /web (#1492) 2021-09-29 08:42:45 +02:00
9ec6eaf4b8 build(deps): bump @lingui/cli from 3.11.1 to 3.12.1 in /web (#1494) 2021-09-29 08:34:38 +02:00
b057120351 build(deps): bump goauthentik.io/api from 0.202193.1 to 0.202193.3 (#1495) 2021-09-29 08:34:27 +02:00
b8082598a1 web: fix linting again
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-28 09:49:22 +02:00
1b5a163f46 web: Update Web API Client version (#1489)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-28 09:40:54 +02:00
1f2f48a7bc web: fix linting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-28 09:39:21 +02:00
f9ad102915 flows: inspector (#1469)
* flows: add initial inspector

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

* flows: change naming a bit

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

* web/flow: add inspector frame

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

* core: don't use shadydom when inspecting

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

* flows: add current stage to api

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

* stages/*: fix imports

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

* flows: deep-copy plan instead of just adding

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

* web/flows: ui

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

* flows: restrict inspector to admin

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

* web/admin: add buttons to launch flow with inspector

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

* web/flows: don't automatically follow redirects when inspector is open

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

* flows: make current_plan optional, only require historry

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

* web/flows: handle error messages in inspector

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

* web/flows: improve UI when flow is done

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

* flows: add is_completed flag to inspector

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

* flows: fix monkeypatches for tests

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

* flows: add inspector tests

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

* ci: re-enable cache

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-28 09:36:48 +02:00
ea4b920264 build(deps): bump @typescript-eslint/parser in /web (#1484) 2021-09-28 09:08:39 +02:00
7d8390ca77 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1485) 2021-09-28 08:32:35 +02:00
7ae551da65 build(deps): bump boto3 from 1.18.48 to 1.18.49 (#1486) 2021-09-28 08:32:25 +02:00
51b26c2ac7 build(deps): bump goauthentik.io/api from 0.202192.5 to 0.202193.1 (#1487) 2021-09-28 08:32:10 +02:00
e4a5f22f9b build(deps): bump sentry-sdk from 1.4.1 to 1.4.2 (#1488) 2021-09-28 08:31:57 +02:00
2462d58135 outposts/proxy: fix duplicate protocol in domain auth mode
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-27 20:49:00 +02:00
44534153a0 website/docs: fix hardcoded name in service-account yaml
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-27 20:18:12 +02:00
facfea035b web: Update Web API Client version (#1483) 2021-09-27 18:52:42 +02:00
626 changed files with 22578 additions and 15084 deletions

View File

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

View File

@ -1 +1,3 @@
keypair
keypairs
hass

View File

@ -133,32 +133,41 @@ jobs:
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: checkout stable
- name: prepare variables
id: ev
run: |
# Copy current, latest config to local
cp authentik/lib/default.yml local.env.yml
git checkout $(git describe --abbrev=0 --match 'version/*')
python ./scripts/gh_env.py
# - id: cache-pipenv
# uses: actions/cache@v2.1.6
# with:
# path: ~/.local/share/virtualenvs
# key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }}
- 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/*')
git checkout ${{ steps.ev.outputs.branchName }} -- .github
git checkout ${{ steps.ev.outputs.branchName }} -- scripts
- name: prepare
# env:
# INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }}
run: scripts/ci_prepare.sh
run: |
scripts/ci_prepare.sh
# Sync anyways since stable will have different dependencies
pipenv sync --dev
- name: run migrations to stable
run: pipenv run python -m lifecycle.migrate
- name: prepare variables
id: ev
run: |
python ./scripts/gh_do_set_branch.py
- name: checkout current code
run: |
set -x
git fetch
git checkout ${{ steps.ev.outputs.branchName }}
pipenv sync --dev
- name: prepare
# env:
# INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }}
run: scripts/ci_prepare.sh
- name: migrate to latest
run: pipenv run python -m lifecycle.migrate
test-unittest:
@ -246,7 +255,7 @@ jobs:
# INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }}
run: |
scripts/ci_prepare.sh
docker-compose -f tests/e2e/ci.docker-compose.yml up -d
docker-compose -f tests/e2e/docker-compose.yml up -d
- id: cache-web
uses: actions/cache@v2.1.6
with:
@ -281,6 +290,7 @@ jobs:
- test-integration
- test-e2e
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v2
- name: Set up Docker Buildx
@ -290,20 +300,20 @@ jobs:
env:
DOCKER_USERNAME: ${{ secrets.HARBOR_USERNAME }}
run: |
python ./scripts/gh_do_set_branch.py
python ./scripts/gh_env.py
- name: Login to Container Registry
uses: docker/login-action@v1
if: ${{ steps.ev.outputs.shouldBuild == 'true' }}
with:
registry: beryju.org
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Building Docker Image
uses: docker/build-push-action@v2
with:
push: ${{ steps.ev.outputs.shouldBuild == 'true' }}
tags: |
beryju.org/authentik/server:gh-${{ steps.ev.outputs.branchName }}
beryju.org/authentik/server:gh-${{ steps.ev.outputs.branchName }}-${{ steps.ev.outputs.timestamp }}-${{ steps.ev.outputs.sha }}
ghcr.io/goauthentik/dev-server:gh-${{ steps.ev.outputs.branchNameContainer }}
ghcr.io/goauthentik/dev-server:gh-${{ steps.ev.outputs.branchNameContainer }}-${{ steps.ev.outputs.timestamp }}-${{ steps.ev.outputs.sha }}
build-args: |
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}

View File

@ -31,6 +31,7 @@ jobs:
golangci/golangci-lint:v1.39.0 \
golangci-lint run -v --timeout 200s
build:
timeout-minutes: 120
needs:
- lint-golint
strategy:
@ -48,22 +49,22 @@ jobs:
env:
DOCKER_USERNAME: ${{ secrets.HARBOR_USERNAME }}
run: |
python ./scripts/gh_do_set_branch.py
python ./scripts/gh_env.py
- name: Login to Container Registry
uses: docker/login-action@v1
if: ${{ steps.ev.outputs.shouldBuild == 'true' }}
with:
registry: beryju.org
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Building Docker Image
uses: docker/build-push-action@v2
with:
push: ${{ steps.ev.outputs.shouldBuild == 'true' }}
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 }}
ghcr.io/goauthentik/dev-${{ matrix.type }}:gh-${{ steps.ev.outputs.branchNameContainer }}
ghcr.io/goauthentik/dev-${{ matrix.type }}:gh-${{ steps.ev.outputs.branchNameContainer }}-${{ steps.ev.outputs.timestamp }}
ghcr.io/goauthentik/dev-${{ matrix.type }}:gh-${{ steps.ev.outputs.sha }}
file: ${{ matrix.type }}.Dockerfile
build-args: |
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}

22
.github/workflows/ghcr-retention.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: ghcr-retention
on:
schedule:
- cron: '0 0 * * *' # every day at midnight
workflow_dispatch:
jobs:
clean-ghcr:
name: Delete old unused container images
runs-on: ubuntu-latest
steps:
- name: Delete 'dev' containers older than a week
uses: sondrelg/container-retention-policy@v1
with:
image-names: dev-server,dev-ldap,dev-proxy
cut-off: One week ago UTC
account-type: org
org-name: goauthentik
untagged-only: false
token: ${{ secrets.GHCR_CLEANUP_TOKEN }}
skip-tags: gh-next,gh-master

View File

@ -3,9 +3,6 @@ name: authentik-on-release
on:
release:
types: [published, created]
push:
branches:
- version-*
jobs:
# Build
@ -33,14 +30,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik:2021.9.8,
beryju/authentik:2021.10.4,
beryju/authentik:latest,
ghcr.io/goauthentik/server:2021.9.8,
ghcr.io/goauthentik/server:2021.10.4,
ghcr.io/goauthentik/server:latest
platforms: linux/amd64,linux/arm64
context: .
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.9.8', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.10.4', 'rc') }}
run: |
docker pull beryju/authentik:latest
docker tag beryju/authentik:latest beryju/authentik:stable
@ -75,14 +72,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-proxy:2021.9.8,
beryju/authentik-proxy:2021.10.4,
beryju/authentik-proxy:latest,
ghcr.io/goauthentik/proxy:2021.9.8,
ghcr.io/goauthentik/proxy:2021.10.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.9.8', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.10.4', 'rc') }}
run: |
docker pull beryju/authentik-proxy:latest
docker tag beryju/authentik-proxy:latest beryju/authentik-proxy:stable
@ -117,14 +114,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-ldap:2021.9.8,
beryju/authentik-ldap:2021.10.4,
beryju/authentik-ldap:latest,
ghcr.io/goauthentik/ldap:2021.9.8,
ghcr.io/goauthentik/ldap:2021.10.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.9.8', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.10.4', 'rc') }}
run: |
docker pull beryju/authentik-ldap:latest
docker tag beryju/authentik-ldap:latest beryju/authentik-ldap:stable
@ -142,15 +139,13 @@ jobs:
- uses: actions/checkout@v2
- name: Run test suite in final docker images
run: |
sudo apt-get install -y pwgen
echo "PG_PASS=$(pwgen 40 1)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(pwgen 50 1)" >> .env
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
docker-compose pull -q
docker-compose up --no-start
docker-compose start postgresql redis
docker-compose run -u root server test
sentry-release:
if: ${{ github.event_name == 'release' }}
needs:
- test-release
runs-on: ubuntu-latest
@ -175,7 +170,7 @@ jobs:
SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org
with:
version: authentik@2021.9.8
version: authentik@2021.10.4
environment: beryjuorg-prod
sourcemaps: './web/dist'
url_prefix: '~/static/dist'

View File

@ -13,15 +13,14 @@ jobs:
- uses: actions/checkout@v2
- name: Pre-release test
run: |
sudo apt-get install -y pwgen
echo "AUTHENTIK_TAG=latest" >> .env
echo "PG_PASS=$(pwgen 40 1)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(pwgen 50 1)" >> .env
docker-compose pull -q
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
docker build \
--no-cache \
-t ghcr.io/goauthentik/server:latest \
-t testing:latest \
-f Dockerfile .
echo "AUTHENTIK_IMAGE=testing" >> .env
echo "AUTHENTIK_TAG=latest" >> .env
docker-compose up --no-start
docker-compose start postgresql redis
docker-compose run -u root server test

View File

@ -0,0 +1,39 @@
name: authentik-backend-translate-compile
on:
push:
branches: [ master ]
paths:
- '/locale/'
schedule:
- cron: "0 */2 * * *"
workflow_dispatch:
env:
POSTGRES_DB: authentik
POSTGRES_USER: authentik
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
jobs:
compile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: prepare
run: |
sudo apt-get update
sudo apt-get install -y gettext
scripts/ci_prepare.sh
- name: run compile
run: pipenv run ./manage.py compilemessages
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: compile-backend-translation
commit-message: "core: compile backend translations"
title: "core: compile backend translations"
delete-branch: true
signoff: true

View File

@ -31,7 +31,7 @@ Basically, don't be a dickhead. This is an open-source non-profit project, that
## 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)
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://goauthentik.io/discord)
## What should I know before I get started?
@ -131,7 +131,7 @@ When you are creating an enhancement suggestion, please fill in [the template](h
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/)
This is documented in the [developer docs](https://goauthentik.io/developer-docs/?utm_source=github)
### Pull Requests

View File

@ -1,5 +1,5 @@
# Stage 1: Lock python dependencies
FROM docker.io/python:3.9-slim-buster as locker
FROM docker.io/python:3.9-slim-bullseye as locker
COPY ./Pipfile /app/
COPY ./Pipfile.lock /app/
@ -11,7 +11,7 @@ RUN pip install pipenv && \
pipenv lock -r --dev-only > requirements-dev.txt
# Stage 2: Build website
FROM docker.io/node as website-builder
FROM docker.io/node:16 as website-builder
COPY ./website /static/
@ -19,7 +19,7 @@ ENV NODE_ENV=production
RUN cd /static && npm i && npm run build-docs-only
# Stage 3: Build webui
FROM docker.io/node as web-builder
FROM docker.io/node:16 as web-builder
COPY ./web /static/
@ -27,7 +27,7 @@ ENV NODE_ENV=production
RUN cd /static && npm i && npm run build
# Stage 4: Build go proxy
FROM docker.io/golang:1.17.1 AS builder
FROM docker.io/golang:1.17.3-bullseye AS builder
WORKDIR /work
@ -47,7 +47,7 @@ COPY ./go.sum /work/go.sum
RUN go build -o /work/authentik ./cmd/server/main.go
# Stage 5: Run
FROM docker.io/python:3.9-slim-buster
FROM docker.io/python:3.9-slim-bullseye
WORKDIR /
COPY --from=locker /app/requirements.txt /
@ -59,7 +59,7 @@ ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
RUN apt-get update && \
apt-get install -y --no-install-recommends curl ca-certificates gnupg git runit && \
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
echo "deb http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
apt-get update && \
apt-get install -y --no-install-recommends libpq-dev postgresql-client build-essential libxmlsec1-dev pkg-config libmaxminddb0 && \
pip install -r /requirements.txt --no-cache-dir && \
@ -83,7 +83,6 @@ USER authentik
ENV TMPDIR /dev/shm/
ENV PYTHONUNBUFFERED 1
ENV prometheus_multiproc_dir /dev/shm/
ENV PATH "/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/lifecycle"
HEALTHCHECK --interval=30s --timeout=30s --start-period=60s --retries=3 CMD [ "/lifecycle/ak", "healthcheck" ]

View File

@ -20,13 +20,23 @@ test:
lint-fix:
isort authentik tests lifecycle
black authentik tests lifecycle
codespell -I .github/codespell-words.txt -S 'web/src/locales/**' -w authentik internal cmd web/src website/src
codespell -I .github/codespell-words.txt -S 'web/src/locales/**' -w \
authentik \
internal \
cmd \
web/src \
website/src \
website/docs \
website/developer-docs
lint:
pyright authentik tests lifecycle
bandit -r authentik tests lifecycle -x node_modules
pylint authentik tests lifecycle
i18n-extract:
./manage.py makemessages --ignore web --ignore internal --ignore web --ignore web-api --ignore website -l en
cd web && npm run extract
gen-build:
./manage.py spectacular --file schema.yml
@ -38,7 +48,7 @@ gen-web:
docker run \
--rm -v ${PWD}:/local \
--user ${UID}:${GID} \
openapitools/openapi-generator-cli generate \
ghcr.io/beryju/openapi-generator generate \
-i /local/schema.yml \
-g typescript-fetch \
-o /local/web-api \
@ -50,18 +60,19 @@ gen-web:
\cp -rfv web-api/* web/node_modules/@goauthentik/api
gen-outpost:
wget https://raw.githubusercontent.com/goauthentik/client-go/main/config.yaml -O config.yaml
mkdir -p templates
wget https://raw.githubusercontent.com/goauthentik/client-go/main/templates/README.mustache -O templates/README.mustache
wget https://raw.githubusercontent.com/goauthentik/client-go/main/templates/go.mod.mustache -O templates/go.mod.mustache
docker run \
--rm -v ${PWD}:/local \
--user ${UID}:${GID} \
openapitools/openapi-generator-cli generate \
--git-host goauthentik.io \
--git-repo-id outpost \
--git-user-id api \
-i /local/schema.yml \
-g go \
-o /local/api \
--additional-properties=packageName=api,enumClassPrefix=true,useOneOfDiscriminatorLookup=true,disallowAdditionalPropertiesIfNotPresent=false
rm -f api/go.mod api/go.sum
-c /local/config.yaml
go mod edit -replace goauthentik.io/api=./api
gen: gen-build gen-clean gen-web
@ -69,4 +80,4 @@ migrate:
python -m lifecycle.migrate
run:
WORKERS=1 go run -v cmd/server/main.go
go run -v cmd/server/main.go

View File

@ -26,9 +26,9 @@ drf-spectacular = "*"
facebook-sdk = "*"
geoip2 = "*"
gunicorn = "*"
kubernetes = "*"
kubernetes = "==v19.15.0"
ldap3 = "*"
lxml = ">=4.6.3"
lxml = "*"
packaging = "*"
psycopg2-binary = "*"
pycryptodome = "*"
@ -52,10 +52,10 @@ codespell = "*"
[dev-packages]
bandit = "*"
black = "==21.5b1"
black = "==21.9b0"
bump2version = "*"
colorama = "*"
coverage = "*"
coverage = {extras = ["toml"],version = "*"}
pylint = "*"
pylint-django = "*"
pytest = "*"

1653
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
---
[![Join Discord](https://img.shields.io/discord/809154715984199690?label=Discord&style=for-the-badge)](https://discord.gg/jg33eMhnj6)
[![Join Discord](https://img.shields.io/discord/809154715984199690?label=Discord&style=for-the-badge)](https://goauthentik.io/discord)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/goauthentik/authentik/authentik-ci-main?label=core%20build&style=for-the-badge)](https://github.com/goauthentik/authentik/actions/workflows/ci-main.yml)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/goauthentik/authentik/authentik-ci-outpost?label=outpost%20build&style=for-the-badge)](https://github.com/goauthentik/authentik/actions/workflows/ci-outpost.yml)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/goauthentik/authentik/authentik-ci-web?label=web%20build&style=for-the-badge)](https://github.com/goauthentik/authentik/actions/workflows/ci-web.yml)
@ -20,9 +20,9 @@ authentik is an open-source Identity Provider focused on flexibility and versati
## Installation
For small/test setups it is recommended to use docker-compose, see the [documentation](https://goauthentik.io/docs/installation/docker-compose/)
For small/test setups it is recommended to use docker-compose, see the [documentation](https://goauthentik.io/docs/installation/docker-compose/?utm_source=github)
For 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/?utm_source=github)
## Screenshots
@ -33,7 +33,7 @@ Light | Dark
## Development
See [Development Documentation](https://goauthentik.io/developer-docs/)
See [Development Documentation](https://goauthentik.io/developer-docs/?utm_source=github)
## Security

View File

@ -6,8 +6,8 @@
| Version | Supported |
| ---------- | ------------------ |
| 2021.7.x | :white_check_mark: |
| 2021.8.x | :white_check_mark: |
| 2021.9.x | :white_check_mark: |
| 2021.10.x | :white_check_mark: |
## Reporting a Vulnerability

View File

@ -1,3 +1,3 @@
"""authentik"""
__version__ = "2021.9.8"
__version__ = "2021.10.4"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -1,4 +1,5 @@
"""authentik administration overview"""
from django.conf import settings
from drf_spectacular.utils import extend_schema, inline_serializer
from prometheus_client import Gauge
from rest_framework.fields import IntegerField
@ -21,4 +22,7 @@ class WorkerView(APIView):
def get(self, request: Request) -> Response:
"""Get currently connected worker count."""
count = len(CELERY_APP.control.ping(timeout=0.5))
# In debug we run with `CELERY_TASK_ALWAYS_EAGER`, so tasks are ran on the main process
if settings.DEBUG:
count += 1
return Response({"count": count})

View File

@ -11,7 +11,12 @@ from structlog.stdlib import get_logger
from authentik import ENV_GIT_HASH_KEY, __version__
from authentik.events.models import Event, EventAction, Notification
from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus
from authentik.events.monitored_tasks import (
MonitoredTask,
TaskResult,
TaskResultStatus,
prefill_task,
)
from authentik.lib.config import CONFIG
from authentik.lib.utils.http import get_http_session
from authentik.root.celery import CELERY_APP
@ -22,6 +27,7 @@ VERSION_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
# Chop of the first ^ because we want to search the entire string
URL_FINDER = URLValidator.regex.pattern[1:]
PROM_INFO = Info("authentik_version", "Currently running authentik version")
LOCAL_VERSION = parse(__version__)
def _set_prom_info():
@ -43,11 +49,12 @@ def clear_update_notifications():
if "new_version" not in notification.event.context:
continue
notification_version = notification.event.context["new_version"]
if notification_version == __version__:
if LOCAL_VERSION >= parse(notification_version):
notification.delete()
@CELERY_APP.task(bind=True, base=MonitoredTask)
@prefill_task()
def update_latest_version(self: MonitoredTask):
"""Update latest version info"""
if CONFIG.y_bool("disable_update_check"):
@ -68,8 +75,7 @@ def update_latest_version(self: MonitoredTask):
_set_prom_info()
# Check if upstream version is newer than what we're running,
# and if no event exists yet, create one.
local_version = parse(__version__)
if local_version < parse(upstream_version):
if LOCAL_VERSION < parse(upstream_version):
# Event has already been created, don't create duplicate
if Event.objects.filter(
action=EventAction.UPDATE_AVAILABLE,

View File

@ -9,6 +9,7 @@ from rest_framework.exceptions import AuthenticationFailed
from rest_framework.request import Request
from structlog.stdlib import get_logger
from authentik.core.middleware import KEY_AUTH_VIA, LOCAL
from authentik.core.models import Token, TokenIntents, User
from authentik.outposts.models import Outpost
@ -44,6 +45,8 @@ def bearer_auth(raw_header: bytes) -> Optional[User]:
if not user:
raise AuthenticationFailed("Token invalid/expired")
return user
if hasattr(LOCAL, "authentik"):
LOCAL.authentik[KEY_AUTH_VIA] = "api_token"
return tokens.first().user
@ -57,7 +60,8 @@ def token_secret_key(value: str) -> Optional[User]:
outposts = Outpost.objects.filter(managed=MANAGED_OUTPOST)
if not outposts:
return None
LOGGER.info("Authenticating via secret_key")
if hasattr(LOCAL, "authentik"):
LOCAL.authentik[KEY_AUTH_VIA] = "secret_key"
outpost = outposts.first()
return outpost.user

View File

@ -1,19 +0,0 @@
"""API tasks"""
from authentik.lib.utils.http import get_http_session
from authentik.root.celery import CELERY_APP
SENTRY_SESSION = get_http_session()
@CELERY_APP.task()
def sentry_proxy(payload: str):
"""Relay data to sentry"""
SENTRY_SESSION.post(
"https://sentry.beryju.org/api/8/envelope/",
data=payload,
headers={
"Content-Type": "application/octet-stream",
},
timeout=10,
)

18
authentik/api/throttle.py Normal file
View File

@ -0,0 +1,18 @@
"""Throttling classes"""
from typing import Type
from django.views import View
from rest_framework.request import Request
from rest_framework.throttling import ScopedRateThrottle
class SessionThrottle(ScopedRateThrottle):
"""Throttle based on session key"""
def allow_request(self, request: Request, view):
if request._request.user.is_superuser:
return True
return super().allow_request(request, view)
def get_cache_key(self, request: Request, view: Type[View]) -> str:
return f"authentik-throttle-session-{request._request.session.session_key}"

View File

@ -4,7 +4,7 @@ from django.urls import include, path
from authentik.api.v3.urls import urlpatterns as v3_urls
urlpatterns = [
# Remove in 2022.1
# TODO: Remove in 2022.1
path("v2beta/", include(v3_urls)),
path("v3/", include(v3_urls)),
]

View File

@ -1,65 +0,0 @@
"""Sentry tunnel"""
from json import loads
from django.conf import settings
from django.http.request import HttpRequest
from django.http.response import HttpResponse
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 structlog.stdlib import get_logger
from authentik.api.tasks import sentry_proxy
from authentik.lib.config import CONFIG
LOGGER = get_logger()
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
if not CONFIG.y_bool("error_reporting.enabled", False):
LOGGER.debug("error reporting disabled")
return HttpResponse(status=400)
# Body is 2 json objects separated by \n
full_body = request.body
lines = full_body.splitlines()
if len(lines) < 1:
return HttpResponse(status=400)
header = loads(lines[0])
# Check that the DSN is what we expect
dsn = header.get("dsn", "")
if dsn != settings.SENTRY_DSN:
LOGGER.debug("Invalid dsn", have=dsn, expected=settings.SENTRY_DSN)
return HttpResponse(status=400)
sentry_proxy.delay(full_body.decode())
return HttpResponse(status=204)

View File

@ -11,14 +11,14 @@ from authentik.admin.api.tasks import TaskViewSet
from authentik.admin.api.version import VersionView
from authentik.admin.api.workers import WorkerView
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
from authentik.core.api.devices import DeviceViewSet
from authentik.core.api.groups import GroupViewSet
from authentik.core.api.propertymappings import PropertyMappingViewSet
from authentik.core.api.providers import ProviderViewSet
from authentik.core.api.sources import SourceViewSet
from authentik.core.api.sources import SourceViewSet, UserSourceConnectionViewSet
from authentik.core.api.tokens import TokenViewSet
from authentik.core.api.users import UserViewSet
from authentik.crypto.api import CertificateKeyPairViewSet
@ -30,7 +30,8 @@ from authentik.events.api.notification_transport import NotificationTransportVie
from authentik.flows.api.bindings import FlowStageBindingViewSet
from authentik.flows.api.flows import FlowViewSet
from authentik.flows.api.stages import StageViewSet
from authentik.flows.views import FlowExecutorView
from authentik.flows.views.executor import FlowExecutorView
from authentik.flows.views.inspector import FlowInspectorView
from authentik.outposts.api.outposts import OutpostViewSet
from authentik.outposts.api.service_connections import (
DockerServiceConnectionViewSet,
@ -67,6 +68,11 @@ from authentik.stages.authenticator_duo.api import (
DuoAdminDeviceViewSet,
DuoDeviceViewSet,
)
from authentik.stages.authenticator_sms.api import (
AuthenticatorSMSStageViewSet,
SMSAdminDeviceViewSet,
SMSDeviceViewSet,
)
from authentik.stages.authenticator_static.api import (
AuthenticatorStaticStageViewSet,
StaticAdminDeviceViewSet,
@ -130,6 +136,7 @@ router.register("events/transports", NotificationTransportViewSet)
router.register("events/rules", NotificationRuleViewSet)
router.register("sources/all", SourceViewSet)
router.register("sources/user_connections/all", UserSourceConnectionViewSet)
router.register("sources/user_connections/oauth", UserOAuthSourceConnectionViewSet)
router.register("sources/user_connections/plex", PlexSourceConnectionViewSet)
router.register("sources/ldap", LDAPSourceViewSet)
@ -163,7 +170,9 @@ router.register("propertymappings/saml", SAMLPropertyMappingViewSet)
router.register("propertymappings/scope", ScopeMappingViewSet)
router.register("propertymappings/notification", NotificationWebhookMappingViewSet)
router.register("authenticators/all", DeviceViewSet, basename="device")
router.register("authenticators/duo", DuoDeviceViewSet)
router.register("authenticators/sms", SMSDeviceViewSet)
router.register("authenticators/static", StaticDeviceViewSet)
router.register("authenticators/totp", TOTPDeviceViewSet)
router.register("authenticators/webauthn", WebAuthnDeviceViewSet)
@ -172,6 +181,11 @@ router.register(
DuoAdminDeviceViewSet,
basename="admin-duodevice",
)
router.register(
"authenticators/admin/sms",
SMSAdminDeviceViewSet,
basename="admin-smsdevice",
)
router.register(
"authenticators/admin/static",
StaticAdminDeviceViewSet,
@ -186,6 +200,7 @@ router.register(
router.register("stages/all", StageViewSet)
router.register("stages/authenticator/duo", AuthenticatorDuoStageViewSet)
router.register("stages/authenticator/sms", AuthenticatorSMSStageViewSet)
router.register("stages/authenticator/static", AuthenticatorStaticStageViewSet)
router.register("stages/authenticator/totp", AuthenticatorTOTPStageViewSet)
router.register("stages/authenticator/validate", AuthenticatorValidateStageViewSet)
@ -228,7 +243,11 @@ urlpatterns = (
FlowExecutorView.as_view(),
name="flow-executor",
),
path("sentry/", SentryTunnelView.as_view(), name="sentry"),
path(
"flows/inspector/<slug:flow_slug>/",
FlowInspectorView.as_view(),
name="flow-inspector",
),
path("schema/", cache_page(86400)(SpectacularAPIView.as_view()), name="schema"),
]
)

View File

@ -0,0 +1,36 @@
"""Authenticator Devices API Views"""
from django_otp import devices_for_user
from django_otp.models import Device
from drf_spectacular.utils import extend_schema
from rest_framework.fields import CharField, IntegerField, SerializerMethodField
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from authentik.core.api.utils import MetaNameSerializer
class DeviceSerializer(MetaNameSerializer):
"""Serializer for Duo authenticator devices"""
pk = IntegerField()
name = CharField()
type = SerializerMethodField()
def get_type(self, instance: Device) -> str:
"""Get type of device"""
return instance._meta.label
class DeviceViewSet(ViewSet):
"""Viewset for authenticator devices"""
serializer_class = DeviceSerializer
permission_classes = [IsAuthenticated]
@extend_schema(responses={200: DeviceSerializer(many=True)})
def list(self, request: Request) -> Response:
"""Get all devices for current user"""
devices = devices_for_user(request.user)
return Response(DeviceSerializer(devices, many=True).data)

View File

@ -42,6 +42,7 @@ class GroupSerializer(ModelSerializer):
users_obj = ListSerializer(
child=GroupMemberSerializer(), read_only=True, source="users", required=False
)
parent_name = CharField(source="parent.name", read_only=True)
class Meta:
@ -51,6 +52,7 @@ class GroupSerializer(ModelSerializer):
"name",
"is_superuser",
"parent",
"parent_name",
"users",
"attributes",
"users_obj",

View File

@ -1,18 +1,21 @@
"""Source API Views"""
from typing import Iterable
from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import extend_schema
from rest_framework import mixins
from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer, SerializerMethodField
from rest_framework.viewsets import GenericViewSet
from structlog.stdlib import get_logger
from authentik.api.authorization import OwnerFilter, OwnerPermissions
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
from authentik.core.models import Source
from authentik.core.models import Source, UserSourceConnection
from authentik.core.types import UserSettingSerializer
from authentik.lib.utils.reflection import all_subclasses
from authentik.policies.engine import PolicyEngine
@ -113,3 +116,39 @@ class SourceViewSet(
LOGGER.warning(source_settings.errors)
matching_sources.append(source_settings.validated_data)
return Response(matching_sources)
class UserSourceConnectionSerializer(SourceSerializer):
"""OAuth Source Serializer"""
source = SourceSerializer(read_only=True)
class Meta:
model = UserSourceConnection
fields = [
"pk",
"user",
"source",
"created",
]
extra_kwargs = {
"user": {"read_only": True},
"created": {"read_only": True},
}
class UserSourceConnectionViewSet(
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
UsedByMixin,
mixins.ListModelMixin,
GenericViewSet,
):
"""User-source connection Viewset"""
queryset = UserSourceConnection.objects.all()
serializer_class = UserSourceConnectionSerializer
permission_classes = [OwnerPermissions]
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
ordering = ["pk"]

View File

@ -22,7 +22,7 @@ from drf_spectacular.utils import (
)
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.fields import CharField, DictField, JSONField, SerializerMethodField
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
@ -45,6 +45,8 @@ 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.models import (
USER_ATTRIBUTE_CHANGE_EMAIL,
USER_ATTRIBUTE_CHANGE_USERNAME,
USER_ATTRIBUTE_SA,
USER_ATTRIBUTE_TOKEN_EXPIRING,
Group,
@ -103,6 +105,7 @@ class UserSelfSerializer(ModelSerializer):
avatar = CharField(read_only=True)
groups = SerializerMethodField()
uid = CharField(read_only=True)
settings = DictField(source="attributes.settings", default=dict)
@extend_schema_field(
ListSerializer(
@ -112,14 +115,30 @@ class UserSelfSerializer(ModelSerializer):
)
)
)
def get_groups(self, user: User):
def get_groups(self, _: User):
"""Return only the group names a user is member of"""
for group in user.ak_groups.all():
for group in self.instance.ak_groups.all():
yield {
"name": group.name,
"pk": group.pk,
}
def validate_email(self, email: str):
"""Check if the user is allowed to change their email"""
if self.instance.group_attributes().get(USER_ATTRIBUTE_CHANGE_EMAIL, True):
return email
if email != self.instance.email:
raise ValidationError("Not allowed to change email.")
return email
def validate_username(self, username: str):
"""Check if the user is allowed to change their username"""
if self.instance.group_attributes().get(USER_ATTRIBUTE_CHANGE_USERNAME, True):
return username
if username != self.instance.username:
raise ValidationError("Not allowed to change username.")
return username
class Meta:
model = User
@ -133,6 +152,7 @@ class UserSelfSerializer(ModelSerializer):
"email",
"avatar",
"uid",
"settings",
]
extra_kwargs = {
"is_active": {"read_only": True},
@ -309,13 +329,14 @@ class UserViewSet(UsedByMixin, ModelViewSet):
# pylint: disable=invalid-name
def me(self, request: Request) -> Response:
"""Get information about current user"""
serializer = SessionUserSerializer(data={"user": UserSelfSerializer(request.user).data})
serializer = SessionUserSerializer(
data={"user": UserSelfSerializer(instance=request.user).data}
)
if SESSION_IMPERSONATE_USER in request._request.session:
serializer.initial_data["original"] = UserSelfSerializer(
request._request.session[SESSION_IMPERSONATE_ORIGINAL_USER]
instance=request._request.session[SESSION_IMPERSONATE_ORIGINAL_USER]
).data
serializer.is_valid()
return Response(serializer.data)
return Response(serializer.initial_data)
@extend_schema(request=UserSelfSerializer, responses={200: SessionUserSerializer(many=False)})
@action(
@ -335,9 +356,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
# 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)
return Response({"user": data.data})
@permission_required("authentik_core.view_user", ["authentik_events.view_event"])
@extend_schema(responses={200: UserMetricsSerializer(many=False)})

View File

@ -8,7 +8,7 @@ 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.flows.views.executor import SESSION_KEY_PLAN
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
@ -55,5 +55,5 @@ class TokenBackend(InbuiltBackend):
if not tokens.exists():
return None
token = tokens.first()
self.set_method("password", request, token=token)
self.set_method("token", request, token=token)
return token.user

View File

View File

@ -0,0 +1,15 @@
"""Output full config"""
from json import dumps
from django.core.management.base import BaseCommand, no_translations
from authentik.lib.config import CONFIG
class Command(BaseCommand): # pragma: no cover
"""Output full config"""
@no_translations
def handle(self, *args, **options):
"""Check permissions for all apps"""
print(dumps(CONFIG.raw, indent=4))

View File

@ -10,6 +10,9 @@ SESSION_IMPERSONATE_USER = "authentik_impersonate_user"
SESSION_IMPERSONATE_ORIGINAL_USER = "authentik_impersonate_original_user"
LOCAL = local()
RESPONSE_HEADER_ID = "X-authentik-id"
KEY_AUTH_VIA = "auth_via"
KEY_USER = "user"
INTERNAL_HEADER_PREFIX = "X-authentik-internal-"
class ImpersonateMiddleware:
@ -50,15 +53,17 @@ class RequestIDMiddleware:
}
response = self.get_response(request)
response[RESPONSE_HEADER_ID] = request.request_id
del LOCAL.authentik["request_id"]
del LOCAL.authentik["host"]
if auth_via := LOCAL.authentik.get(KEY_AUTH_VIA, None):
response[INTERNAL_HEADER_PREFIX + KEY_AUTH_VIA] = auth_via
response[INTERNAL_HEADER_PREFIX + KEY_USER] = request.user.username
for key in list(LOCAL.authentik.keys()):
del LOCAL.authentik[key]
return response
# pylint: disable=unused-argument
def structlog_add_request_id(logger: Logger, method_name: str, event_dict):
def structlog_add_request_id(logger: Logger, method_name: str, event_dict: dict):
"""If threadlocal has authentik defined, add request_id to log"""
if hasattr(LOCAL, "authentik"):
event_dict["request_id"] = LOCAL.authentik.get("request_id", "")
event_dict["host"] = LOCAL.authentik.get("host", "")
event_dict.update(LOCAL.authentik)
return event_dict

View File

@ -0,0 +1,221 @@
# Generated by Django 3.2.8 on 2021-10-10 16:16
from os import environ
import django.db.models.deletion
from django.apps.registry import Apps
from django.conf import settings
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
import authentik.core.models
def create_default_user(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 User
db_alias = schema_editor.connection.alias
akadmin, _ = User.objects.using(db_alias).get_or_create(
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
else:
akadmin.set_unusable_password()
akadmin.save()
def create_default_admin_group(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Group = apps.get_model("authentik_core", "Group")
User = apps.get_model("authentik_core", "User")
# Creates a default admin group
group, _ = Group.objects.using(db_alias).get_or_create(
is_superuser=True,
defaults={
"name": "authentik Admins",
},
)
group.users.set(User.objects.filter(username="akadmin"))
group.save()
class Migration(migrations.Migration):
replaces = [
("authentik_core", "0002_auto_20200523_1133"),
("authentik_core", "0003_default_user"),
("authentik_core", "0004_auto_20200703_2213"),
("authentik_core", "0005_token_intent"),
("authentik_core", "0006_auto_20200709_1608"),
("authentik_core", "0007_auto_20200815_1841"),
("authentik_core", "0008_auto_20200824_1532"),
("authentik_core", "0009_group_is_superuser"),
("authentik_core", "0010_auto_20200917_1021"),
("authentik_core", "0011_provider_name_temp"),
]
dependencies = [
("authentik_core", "0001_initial"),
("authentik_flows", "0003_auto_20200523_1133"),
("auth", "0012_alter_user_first_name_max_length"),
]
operations = [
migrations.RemoveField(
model_name="application",
name="skip_authorization",
),
migrations.AddField(
model_name="source",
name="authentication_flow",
field=models.ForeignKey(
blank=True,
default=None,
help_text="Flow to use when authenticating existing users.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="source_authentication",
to="authentik_flows.flow",
),
),
migrations.AddField(
model_name="source",
name="enrollment_flow",
field=models.ForeignKey(
blank=True,
default=None,
help_text="Flow to use when enrolling new users.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="source_enrollment",
to="authentik_flows.flow",
),
),
migrations.AddField(
model_name="provider",
name="authorization_flow",
field=models.ForeignKey(
help_text="Flow used when authorizing this provider.",
on_delete=django.db.models.deletion.CASCADE,
related_name="provider_authorization",
to="authentik_flows.flow",
),
),
migrations.RemoveField(
model_name="user",
name="is_superuser",
),
migrations.RemoveField(
model_name="user",
name="is_staff",
),
migrations.RunPython(
code=create_default_user,
),
migrations.AddField(
model_name="user",
name="is_superuser",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="user",
name="is_staff",
field=models.BooleanField(default=False),
),
migrations.AlterModelOptions(
name="application",
options={"verbose_name": "Application", "verbose_name_plural": "Applications"},
),
migrations.AlterModelOptions(
name="user",
options={
"permissions": (("reset_user_password", "Reset Password"),),
"verbose_name": "User",
"verbose_name_plural": "Users",
},
),
migrations.AddField(
model_name="token",
name="intent",
field=models.TextField(
choices=[("verification", "Intent Verification"), ("api", "Intent Api")],
default="verification",
),
),
migrations.AlterField(
model_name="source",
name="slug",
field=models.SlugField(help_text="Internal source name, used in URLs.", unique=True),
),
migrations.AlterField(
model_name="user",
name="first_name",
field=models.CharField(blank=True, max_length=150, verbose_name="first name"),
),
migrations.RemoveField(
model_name="user",
name="groups",
),
migrations.AddField(
model_name="user",
name="groups",
field=models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.Group",
verbose_name="groups",
),
),
migrations.RemoveField(
model_name="user",
name="is_superuser",
),
migrations.RemoveField(
model_name="user",
name="is_staff",
),
migrations.AddField(
model_name="user",
name="pb_groups",
field=models.ManyToManyField(related_name="users", to="authentik_core.Group"),
),
migrations.AddField(
model_name="group",
name="is_superuser",
field=models.BooleanField(
default=False, help_text="Users added to this group will be superusers."
),
),
migrations.RunPython(
code=create_default_admin_group,
),
migrations.AlterModelManagers(
name="user",
managers=[
("objects", authentik.core.models.UserManager()),
],
),
migrations.AlterModelOptions(
name="user",
options={
"permissions": (
("reset_user_password", "Reset Password"),
("impersonate", "Can impersonate other users"),
),
"verbose_name": "User",
"verbose_name_plural": "Users",
},
),
migrations.AddField(
model_name="provider",
name="name_temp",
field=models.TextField(default=""),
preserve_default=False,
),
]

View File

@ -0,0 +1,118 @@
# Generated by Django 3.2.8 on 2021-10-12 15:36
from django.apps.registry import Apps
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
import authentik.core.models
def set_default_token_key(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Token = apps.get_model("authentik_core", "Token")
for token in Token.objects.using(db_alias).all():
token.key = token.pk.hex
token.save()
class Migration(migrations.Migration):
replaces = [
("authentik_core", "0012_auto_20201003_1737"),
("authentik_core", "0013_auto_20201003_2132"),
("authentik_core", "0014_auto_20201018_1158"),
("authentik_core", "0015_application_icon"),
("authentik_core", "0016_auto_20201202_2234"),
]
dependencies = [
("authentik_providers_saml", "0006_remove_samlprovider_name"),
("authentik_providers_oauth2", "0006_remove_oauth2provider_name"),
("authentik_core", "0011_provider_name_temp"),
]
operations = [
migrations.RenameField(
model_name="provider",
old_name="name_temp",
new_name="name",
),
migrations.AddField(
model_name="token",
name="identifier",
field=models.TextField(default=""),
preserve_default=False,
),
migrations.AlterField(
model_name="token",
name="intent",
field=models.TextField(
choices=[
("verification", "Intent Verification"),
("api", "Intent Api"),
("recovery", "Intent Recovery"),
],
default="verification",
),
),
migrations.AlterUniqueTogether(
name="token",
unique_together={("identifier", "user")},
),
migrations.AddField(
model_name="token",
name="key",
field=models.TextField(default=authentik.core.models.default_token_key),
),
migrations.AlterUniqueTogether(
name="token",
unique_together=set(),
),
migrations.AlterField(
model_name="token",
name="identifier",
field=models.SlugField(max_length=255),
),
migrations.AddIndex(
model_name="token",
index=models.Index(fields=["key"], name="authentik_co_key_e45007_idx"),
),
migrations.AddIndex(
model_name="token",
index=models.Index(fields=["identifier"], name="authentik_co_identif_1a34a8_idx"),
),
migrations.RunPython(
code=set_default_token_key,
),
migrations.RemoveField(
model_name="application",
name="meta_icon_url",
),
migrations.AddField(
model_name="application",
name="meta_icon",
field=models.FileField(blank=True, default="", upload_to="application-icons/"),
),
migrations.RemoveIndex(
model_name="token",
name="authentik_co_key_e45007_idx",
),
migrations.RemoveIndex(
model_name="token",
name="authentik_co_identif_1a34a8_idx",
),
migrations.RenameField(
model_name="user",
old_name="pb_groups",
new_name="ak_groups",
),
migrations.AddIndex(
model_name="token",
index=models.Index(fields=["identifier"], name="authentik_c_identif_d9d032_idx"),
),
migrations.AddIndex(
model_name="token",
index=models.Index(fields=["key"], name="authentik_c_key_f71355_idx"),
),
]

View File

@ -0,0 +1,210 @@
# Generated by Django 3.2.8 on 2021-10-10 16:12
import uuid
from os import environ
import django.core.validators
import django.db.models.deletion
from django.apps.registry import Apps
from django.conf import settings
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.models import Count
import authentik.core.models
def migrate_sessions(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
from django.contrib.sessions.backends.cache import KEY_PREFIX
from django.core.cache import cache
session_keys = cache.keys(KEY_PREFIX + "*")
cache.delete_many(session_keys)
def fix_duplicates(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Token = apps.get_model("authentik_core", "token")
identifiers = (
Token.objects.using(db_alias)
.values("identifier")
.annotate(identifier_count=Count("identifier"))
.filter(identifier_count__gt=1)
)
for ident in identifiers:
Token.objects.using(db_alias).filter(identifier=ident["identifier"]).delete()
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):
replaces = [
("authentik_core", "0018_auto_20210330_1345"),
("authentik_core", "0019_source_managed"),
("authentik_core", "0020_source_user_matching_mode"),
("authentik_core", "0021_alter_application_slug"),
("authentik_core", "0022_authenticatedsession"),
("authentik_core", "0023_alter_application_meta_launch_url"),
("authentik_core", "0024_alter_token_identifier"),
("authentik_core", "0025_alter_application_meta_icon"),
("authentik_core", "0026_alter_application_meta_icon"),
("authentik_core", "0027_bootstrap_token"),
("authentik_core", "0028_alter_token_intent"),
]
dependencies = [
("authentik_core", "0017_managed"),
]
operations = [
migrations.AlterModelOptions(
name="token",
options={
"permissions": (("view_token_key", "View token's key"),),
"verbose_name": "Token",
"verbose_name_plural": "Tokens",
},
),
migrations.AddField(
model_name="source",
name="managed",
field=models.TextField(
default=None,
help_text="Objects which are managed by authentik. These objects are created and updated automatically. This is flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.",
null=True,
unique=True,
verbose_name="Managed by authentik",
),
),
migrations.AddField(
model_name="source",
name="user_matching_mode",
field=models.TextField(
choices=[
("identifier", "Use the source-specific identifier"),
(
"email_link",
"Link to a user with identical email address. Can have security implications when a source doesn't validate email addresses.",
),
(
"email_deny",
"Use the user's email address, but deny enrollment when the email address already exists.",
),
(
"username_link",
"Link to a user with identical username. Can have security implications when a username is used with another source.",
),
(
"username_deny",
"Use the user's username, but deny enrollment when the username already exists.",
),
],
default="identifier",
help_text="How the source determines if an existing user should be authenticated or a new user enrolled.",
),
),
migrations.AlterField(
model_name="application",
name="slug",
field=models.SlugField(
help_text="Internal application name, used in URLs.", unique=True
),
),
migrations.CreateModel(
name="AuthenticatedSession",
fields=[
(
"expires",
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)),
("session_key", models.CharField(max_length=40)),
("last_ip", models.TextField()),
("last_user_agent", models.TextField(blank=True)),
("last_used", models.DateTimeField(auto_now=True)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
),
),
],
options={
"abstract": False,
},
),
migrations.RunPython(
code=migrate_sessions,
),
migrations.AlterField(
model_name="application",
name="meta_launch_url",
field=models.TextField(
blank=True, default="", validators=[django.core.validators.URLValidator()]
),
),
migrations.RunPython(
code=fix_duplicates,
),
migrations.AlterField(
model_name="token",
name="identifier",
field=models.SlugField(max_length=255, unique=True),
),
migrations.AlterField(
model_name="application",
name="meta_icon",
field=models.FileField(default=None, null=True, upload_to="application-icons/"),
),
migrations.AlterField(
model_name="application",
name="meta_icon",
field=models.FileField(
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",
},
),
migrations.RunPython(
code=create_default_user_token,
),
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

@ -39,6 +39,8 @@ USER_ATTRIBUTE_DEBUG = "goauthentik.io/user/debug"
USER_ATTRIBUTE_SA = "goauthentik.io/user/service-account"
USER_ATTRIBUTE_SOURCES = "goauthentik.io/user/sources"
USER_ATTRIBUTE_TOKEN_EXPIRING = "goauthentik.io/user/token-expires" # nosec
USER_ATTRIBUTE_CHANGE_USERNAME = "goauthentik.io/user/can-change-username"
USER_ATTRIBUTE_CHANGE_EMAIL = "goauthentik.io/user/can-change-email"
USER_ATTRIBUTE_CAN_OVERRIDE_IP = "goauthentik.io/user/override-ips"
GRAVATAR_URL = "https://secure.gravatar.com"
@ -79,6 +81,27 @@ class Group(models.Model):
)
attributes = models.JSONField(default=dict, blank=True)
def is_member(self, user: "User") -> bool:
"""Recursively check if `user` is member of us, or any parent."""
query = """
WITH RECURSIVE parents AS (
SELECT authentik_core_group.*, 0 AS relative_depth
FROM authentik_core_group
WHERE authentik_core_group.group_uuid = %s
UNION ALL
SELECT authentik_core_group.*, parents.relative_depth - 1
FROM authentik_core_group,parents
WHERE authentik_core_group.parent_id = parents.group_uuid
)
SELECT group_uuid
FROM parents
GROUP BY group_uuid;
"""
groups = Group.objects.raw(query, [self.group_uuid])
return user.ak_groups.filter(pk__in=[group.pk for group in groups]).exists()
def __str__(self):
return f"Group {self.name}"
@ -151,7 +174,7 @@ class User(GuardianUserMixin, AbstractUser):
if mode == "none":
return DEFAULT_AVATAR
# gravatar uses md5 for their URLs, so md5 can't be avoided
mail_hash = md5(self.email.encode("utf-8")).hexdigest() # nosec
mail_hash = md5(self.email.lower().encode("utf-8")).hexdigest() # nosec
if mode == "gravatar":
parameters = [
("s", "158"),

View File

@ -22,7 +22,7 @@ from authentik.flows.planner import (
PLAN_CONTEXT_SSO,
FlowPlanner,
)
from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN
from authentik.flows.views.executor 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_INBUILT

View File

@ -6,6 +6,7 @@ from os import environ
from boto3.exceptions import Boto3Error
from botocore.exceptions import BotoCoreError, ClientError
from dbbackup.db.exceptions import CommandConnectorError
from django.conf import settings
from django.contrib.humanize.templatetags.humanize import naturaltime
from django.contrib.sessions.backends.cache import KEY_PREFIX
from django.core import management
@ -15,7 +16,12 @@ from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME
from structlog.stdlib import get_logger
from authentik.core.models import AuthenticatedSession, ExpiringModel
from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus
from authentik.events.monitored_tasks import (
MonitoredTask,
TaskResult,
TaskResultStatus,
prefill_task,
)
from authentik.lib.config import CONFIG
from authentik.root.celery import CELERY_APP
@ -23,6 +29,7 @@ LOGGER = get_logger()
@CELERY_APP.task(bind=True, base=MonitoredTask)
@prefill_task()
def clean_expired_models(self: MonitoredTask):
"""Remove expired objects"""
messages = []
@ -49,23 +56,25 @@ def clean_expired_models(self: MonitoredTask):
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, messages))
def should_backup() -> bool:
"""Check if we should be doing backups"""
if SERVICE_HOST_ENV_NAME in environ and not CONFIG.y("postgresql.s3_backup.bucket"):
LOGGER.info("Running in k8s and s3 backups are not configured, skipping")
return False
if not CONFIG.y_bool("postgresql.backup.enabled"):
return False
if settings.DEBUG:
return False
return True
@CELERY_APP.task(bind=True, base=MonitoredTask)
@prefill_task()
def backup_database(self: MonitoredTask): # pragma: no cover
"""Database backup"""
self.result_timeout_hours = 25
if SERVICE_HOST_ENV_NAME in environ and not CONFIG.y("postgresql.s3_backup"):
LOGGER.info("Running in k8s and s3 backups are not configured, skipping")
self.set_status(
TaskResult(
TaskResultStatus.WARNING,
[
(
"Skipping backup as authentik is running in Kubernetes "
"without S3 backups configured."
),
],
)
)
if not should_backup():
self.set_status(TaskResult(TaskResultStatus.UNKNOWN, ["Backups are not configured."]))
return
try:
start = datetime.now()

View File

@ -4,7 +4,7 @@
{% load i18n %}
{% block head %}
<script src="{% static 'dist/AdminInterface.js' %}" type="module"></script>
<script src="{% static 'dist/admin/AdminInterface.js' %}" type="module"></script>
{% endblock %}
{% block body %}

View File

@ -5,13 +5,13 @@
{% block head_before %}
{{ block.super }}
{% if flow.compatibility_mode %}
{% if flow.compatibility_mode and not inspector %}
<script>ShadyDOM = { force: !navigator.webdriver };</script>
{% endif %}
{% endblock %}
{% block head %}
<script src="{% static 'dist/FlowInterface.js' %}" type="module"></script>
<script src="{% static 'dist/flow/FlowInterface.js' %}" type="module"></script>
<style>
.pf-c-background-image::before {
--ak-flow-background: url("{{ flow.background_url }}");

View File

@ -4,7 +4,7 @@
{% load i18n %}
{% block head %}
<script src="{% static 'dist/UserInterface.js' %}" type="module"></script>
<script src="{% static 'dist/user/UserInterface.js' %}" type="module"></script>
{% endblock %}
{% block body %}

View File

@ -61,7 +61,7 @@
{% endfor %}
{% if tenant.branding_title != "authentik" %}
<li>
<a href="https://goauthentik.io">
<a href="https://goauthentik.io?utm_source=authentik">
{% trans 'Powered by authentik' %}
</a>
</li>

View File

@ -0,0 +1,40 @@
"""group tests"""
from django.test.testcases import TestCase
from authentik.core.models import Group, User
class TestGroups(TestCase):
"""Test group membership"""
def test_group_membership_simple(self):
"""Test simple membership"""
user = User.objects.create(username="user")
user2 = User.objects.create(username="user2")
group = Group.objects.create(name="group")
group.users.add(user)
self.assertTrue(group.is_member(user))
self.assertFalse(group.is_member(user2))
def test_group_membership_parent(self):
"""Test parent membership"""
user = User.objects.create(username="user")
user2 = User.objects.create(username="user2")
first = Group.objects.create(name="first")
second = Group.objects.create(name="second", parent=first)
second.users.add(user)
self.assertTrue(first.is_member(user))
self.assertFalse(first.is_member(user2))
def test_group_membership_parent_extra(self):
"""Test parent membership"""
user = User.objects.create(username="user")
user2 = User.objects.create(username="user2")
first = Group.objects.create(name="first")
second = Group.objects.create(name="second", parent=first)
third = Group.objects.create(name="third", parent=second)
second.users.add(user)
self.assertTrue(first.is_member(user))
self.assertFalse(first.is_member(user2))
self.assertFalse(third.is_member(user))
self.assertFalse(third.is_member(user2))

View File

@ -4,7 +4,7 @@ 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.flows.views.executor import SESSION_KEY_PLAN
from authentik.lib.tests.utils import get_request

View File

@ -2,7 +2,7 @@
from django.urls.base import reverse
from rest_framework.test import APITestCase
from authentik.core.models import User
from authentik.core.models import USER_ATTRIBUTE_CHANGE_EMAIL, USER_ATTRIBUTE_CHANGE_USERNAME, User
from authentik.flows.models import Flow, FlowDesignation
from authentik.stages.email.models import EmailStage
from authentik.tenants.models import Tenant
@ -15,6 +15,34 @@ class TestUsersAPI(APITestCase):
self.admin = User.objects.get(username="akadmin")
self.user = User.objects.create(username="test-user")
def test_update_self(self):
"""Test update_self"""
self.client.force_login(self.admin)
response = self.client.put(
reverse("authentik_api:user-update-self"), data={"username": "foo", "name": "foo"}
)
self.assertEqual(response.status_code, 200)
def test_update_self_username_denied(self):
"""Test update_self"""
self.admin.attributes[USER_ATTRIBUTE_CHANGE_USERNAME] = False
self.admin.save()
self.client.force_login(self.admin)
response = self.client.put(
reverse("authentik_api:user-update-self"), data={"username": "foo", "name": "foo"}
)
self.assertEqual(response.status_code, 400)
def test_update_self_email_denied(self):
"""Test update_self"""
self.admin.attributes[USER_ATTRIBUTE_CHANGE_EMAIL] = False
self.admin.save()
self.client.force_login(self.admin)
response = self.client.put(
reverse("authentik_api:user-update-self"), data={"email": "foo", "name": "foo"}
)
self.assertEqual(response.status_code, 400)
def test_metrics(self):
"""Test user's metrics"""
self.client.force_login(self.admin)

View File

@ -14,4 +14,5 @@ class FlowInterfaceView(TemplateView):
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
kwargs["flow"] = get_object_or_404(Flow, slug=self.kwargs.get("flow_slug"))
kwargs["inspector"] = "inspector" in self.request.GET
return super().get_context_data(**kwargs)

View File

@ -99,6 +99,7 @@ class CertificateKeyPairSerializer(ModelSerializer):
"private_key_available",
"certificate_download_url",
"private_key_download_url",
"managed",
]
extra_kwargs = {
"key_data": {"write_only": True},
@ -134,13 +135,13 @@ class CertificateKeyPairFilter(FilterSet):
class Meta:
model = CertificateKeyPair
fields = ["name"]
fields = ["name", "managed"]
class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
"""CertificateKeyPair Viewset"""
queryset = CertificateKeyPair.objects.all()
queryset = CertificateKeyPair.objects.exclude(managed__isnull=False)
serializer_class = CertificateKeyPairSerializer
filterset_class = CertificateKeyPairFilter

View File

@ -1,4 +1,6 @@
"""authentik crypto app config"""
from importlib import import_module
from django.apps import AppConfig
@ -8,3 +10,6 @@ class AuthentikCryptoConfig(AppConfig):
name = "authentik.crypto"
label = "authentik_crypto"
verbose_name = "authentik Crypto"
def ready(self):
import_module("authentik.crypto.managed")

View File

@ -24,16 +24,17 @@ class CertificateBuilder:
self.__builder = None
self.__certificate = None
self.common_name = "authentik Self-signed Certificate"
self.cert = CertificateKeyPair()
def save(self) -> Optional[CertificateKeyPair]:
"""Save generated certificate as model"""
if not self.__certificate:
raise ValueError("Certificated hasn't been built yet")
return CertificateKeyPair.objects.create(
name=self.common_name,
certificate_data=self.certificate,
key_data=self.private_key,
)
self.cert.name = self.common_name
self.cert.certificate_data = self.certificate
self.cert.key_data = self.private_key
self.cert.save()
return self.cert
def build(
self,

View File

@ -0,0 +1,40 @@
"""Crypto managed objects"""
from datetime import datetime
from typing import Optional
from authentik.crypto.builder import CertificateBuilder
from authentik.crypto.models import CertificateKeyPair
from authentik.managed.manager import ObjectManager
MANAGED_KEY = "goauthentik.io/crypto/jwt-managed"
class CryptoManager(ObjectManager):
"""Crypto managed objects"""
def _create(self, cert: Optional[CertificateKeyPair] = None):
builder = CertificateBuilder()
builder.common_name = "goauthentik.io"
builder.build(
subject_alt_names=["goauthentik.io"],
validity_days=360,
)
if not cert:
cert = CertificateKeyPair()
cert.certificate_data = builder.certificate
cert.key_data = builder.private_key
cert.name = "authentik Internal JWT Certificate"
cert.managed = MANAGED_KEY
cert.save()
def reconcile(self):
certs = CertificateKeyPair.objects.filter(managed=MANAGED_KEY)
if not certs.exists():
self._create()
return []
cert: CertificateKeyPair = certs.first()
now = datetime.now()
if now < cert.certificate.not_valid_before or now > cert.certificate.not_valid_after:
self._create(cert)
return []
return []

View File

@ -0,0 +1,24 @@
# Generated by Django 3.2.8 on 2021-10-09 17:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_crypto", "0002_create_self_signed_kp"),
]
operations = [
migrations.AddField(
model_name="certificatekeypair",
name="managed",
field=models.TextField(
default=None,
help_text="Objects which are managed by authentik. These objects are created and updated automatically. This is flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.",
null=True,
unique=True,
verbose_name="Managed by authentik",
),
),
]

View File

@ -13,9 +13,10 @@ from django.db import models
from django.utils.translation import gettext_lazy as _
from authentik.lib.models import CreatedUpdatedModel
from authentik.managed.models import ManagedModel
class CertificateKeyPair(CreatedUpdatedModel):
class CertificateKeyPair(ManagedModel, CreatedUpdatedModel):
"""CertificateKeyPair that can be used for signing or encrypting if `key_data`
is set, otherwise it can be used to verify remote data."""

View File

@ -7,16 +7,25 @@ from django.core.exceptions import SuspiciousOperation
from django.db.models import Model
from django.db.models.signals import post_save, pre_delete
from django.http import HttpRequest, HttpResponse
from django_otp.plugins.otp_static.models import StaticToken
from guardian.models import UserObjectPermission
from authentik.core.middleware import LOCAL
from authentik.core.models import User
from authentik.core.models import AuthenticatedSession, User
from authentik.events.models import Event, EventAction, Notification
from authentik.events.signals import EventNewThread
from authentik.events.utils import model_to_dict
from authentik.lib.sentry import before_send
from authentik.lib.utils.errors import exception_to_string
IGNORED_MODELS = (
Event,
Notification,
UserObjectPermission,
AuthenticatedSession,
StaticToken,
)
class AuditMiddleware:
"""Register handlers for duration of request-response that log creation/update/deletion
@ -82,7 +91,7 @@ class AuditMiddleware:
user: User, request: HttpRequest, sender, instance: Model, created: bool, **_
):
"""Signal handler for all object's post_save"""
if isinstance(instance, (Event, Notification, UserObjectPermission)):
if isinstance(instance, IGNORED_MODELS):
return
action = EventAction.MODEL_CREATED if created else EventAction.MODEL_UPDATED
@ -92,7 +101,7 @@ class AuditMiddleware:
# pylint: disable=unused-argument
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, IGNORED_MODELS): # pragma: no cover
return
EventNewThread(

View File

@ -0,0 +1,831 @@
# Generated by Django 3.2.8 on 2021-10-10 16:01
import uuid
from datetime import timedelta
from typing import Iterable
import django.core.validators
import django.db.models.deletion
from django.apps.registry import Apps
from django.conf import settings
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
import authentik.events.models
from authentik.events.models import EventAction, NotificationSeverity, TransportMode
def convert_user_to_json(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
Event = apps.get_model("authentik_events", "Event")
db_alias = schema_editor.connection.alias
for event in Event.objects.all():
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._state.adding = True
event.save()
def notify_configuration_error(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")
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()
)
policy, _ = EventMatcherPolicy.objects.using(db_alias).update_or_create(
name="default-match-configuration-error",
defaults={"action": EventAction.CONFIGURATION_ERROR},
)
trigger, _ = NotificationRule.objects.using(db_alias).update_or_create(
name="default-notify-configuration-error",
defaults={"group": admin_group, "severity": NotificationSeverity.ALERT},
)
trigger.transports.set(
NotificationTransport.objects.using(db_alias).filter(name="default-email-transport")
)
trigger.save()
PolicyBinding.objects.using(db_alias).update_or_create(
target=trigger,
policy=policy,
defaults={
"order": 0,
},
)
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")
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()
)
policy, _ = EventMatcherPolicy.objects.using(db_alias).update_or_create(
name="default-match-update",
defaults={"action": EventAction.UPDATE_AVAILABLE},
)
trigger, _ = NotificationRule.objects.using(db_alias).update_or_create(
name="default-notify-update",
defaults={"group": admin_group, "severity": NotificationSeverity.ALERT},
)
trigger.transports.set(
NotificationTransport.objects.using(db_alias).filter(name="default-email-transport")
)
trigger.save()
PolicyBinding.objects.using(db_alias).update_or_create(
target=trigger,
policy=policy,
defaults={
"order": 0,
},
)
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")
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()
)
policy_policy_exc, _ = EventMatcherPolicy.objects.using(db_alias).update_or_create(
name="default-match-policy-exception",
defaults={"action": EventAction.POLICY_EXCEPTION},
)
policy_pm_exc, _ = EventMatcherPolicy.objects.using(db_alias).update_or_create(
name="default-match-property-mapping-exception",
defaults={"action": EventAction.PROPERTY_MAPPING_EXCEPTION},
)
trigger, _ = NotificationRule.objects.using(db_alias).update_or_create(
name="default-notify-exception",
defaults={"group": admin_group, "severity": NotificationSeverity.ALERT},
)
trigger.transports.set(
NotificationTransport.objects.using(db_alias).filter(name="default-email-transport")
)
trigger.save()
PolicyBinding.objects.using(db_alias).update_or_create(
target=trigger,
policy=policy_policy_exc,
defaults={
"order": 0,
},
)
PolicyBinding.objects.using(db_alias).update_or_create(
target=trigger,
policy=policy_pm_exc,
defaults={
"order": 1,
},
)
def transport_email_global(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
NotificationTransport = apps.get_model("authentik_events", "NotificationTransport")
NotificationTransport.objects.using(db_alias).update_or_create(
name="default-email-transport",
defaults={"mode": TransportMode.EMAIL},
)
def token_view_to_secret_view(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
from authentik.events.models import EventAction
db_alias = schema_editor.connection.alias
Event = apps.get_model("authentik_events", "Event")
events = Event.objects.using(db_alias).filter(action="token_view")
for event in events:
event.context["secret"] = event.context.pop("token")
event.action = EventAction.SECRET_VIEW
Event.objects.using(db_alias).bulk_update(events, ["context", "action"])
# Taken from https://stackoverflow.com/questions/3173320/text-progress-bar-in-the-console
def progress_bar(
iterable: Iterable,
prefix="Writing: ",
suffix=" finished",
decimals=1,
length=100,
fill="",
print_end="\r",
):
"""
Call in a loop to create terminal progress bar
@params:
iteration - Required : current iteration (Int)
total - Required : total iterations (Int)
prefix - Optional : prefix string (Str)
suffix - Optional : suffix string (Str)
decimals - Optional : positive number of decimals in percent complete (Int)
length - Optional : character length of bar (Int)
fill - Optional : bar fill character (Str)
print_end - Optional : end character (e.g. "\r", "\r\n") (Str)
"""
total = len(iterable)
if total < 1:
return
def print_progress_bar(iteration):
"""Progress Bar Printing Function"""
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)
# Initial Call
print_progress_bar(0)
# Update Progress Bar
for i, item in enumerate(iterable):
yield item
print_progress_bar(i + 1)
# Print New Line on Complete
print()
def update_expires(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Event = apps.get_model("authentik_events", "event")
all_events = Event.objects.using(db_alias).all()
if all_events.count() < 1:
return
print("\nAdding expiry to events, this might take a couple of minutes...")
for event in progress_bar(all_events):
event.expires = event.created + timedelta(days=365)
event.save()
class Migration(migrations.Migration):
replaces = [
("authentik_events", "0001_initial"),
("authentik_events", "0002_auto_20200918_2116"),
("authentik_events", "0003_auto_20200917_1155"),
("authentik_events", "0004_auto_20200921_1829"),
("authentik_events", "0005_auto_20201005_2139"),
("authentik_events", "0006_auto_20201017_2024"),
("authentik_events", "0007_auto_20201215_0939"),
("authentik_events", "0008_auto_20201220_1651"),
("authentik_events", "0009_auto_20201227_1210"),
("authentik_events", "0010_notification_notificationtransport_notificationrule"),
("authentik_events", "0011_notification_rules_default_v1"),
("authentik_events", "0012_auto_20210202_1821"),
("authentik_events", "0013_auto_20210209_1657"),
("authentik_events", "0014_expiry"),
("authentik_events", "0015_alter_event_action"),
("authentik_events", "0016_add_tenant"),
("authentik_events", "0017_alter_event_action"),
("authentik_events", "0018_auto_20210911_2217"),
("authentik_events", "0019_alter_notificationtransport_webhook_url"),
]
initial = True
dependencies = [
("authentik_policies", "0004_policy_execution_logging"),
("authentik_core", "0016_auto_20201202_2234"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("authentik_policies_event_matcher", "0003_auto_20210110_1907"),
("authentik_core", "0028_alter_token_intent"),
]
operations = [
migrations.CreateModel(
name="Event",
fields=[
(
"event_uuid",
models.UUIDField(
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
),
),
(
"action",
models.TextField(
choices=[
("LOGIN", "login"),
("LOGIN_FAILED", "login_failed"),
("LOGOUT", "logout"),
("AUTHORIZE_APPLICATION", "authorize_application"),
("SUSPICIOUS_REQUEST", "suspicious_request"),
("SIGN_UP", "sign_up"),
("PASSWORD_RESET", "password_reset"),
("INVITE_CREATED", "invitation_created"),
("INVITE_USED", "invitation_used"),
("IMPERSONATION_STARTED", "impersonation_started"),
("IMPERSONATION_ENDED", "impersonation_ended"),
("CUSTOM", "custom"),
]
),
),
("date", models.DateTimeField(auto_now_add=True)),
("app", models.TextField()),
("context", models.JSONField(blank=True, default=dict)),
("client_ip", models.GenericIPAddressField(null=True)),
("created", models.DateTimeField(auto_now_add=True)),
(
"user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
),
),
("user_json", models.JSONField(default=dict)),
],
options={
"verbose_name": "Event",
"verbose_name_plural": "Events",
},
),
migrations.RunPython(
code=convert_user_to_json,
),
migrations.RemoveField(
model_name="event",
name="user",
),
migrations.RenameField(
model_name="event",
old_name="user_json",
new_name="user",
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("sign_up", "Sign Up"),
("authorize_application", "Authorize Application"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("invitation_created", "Invite Created"),
("invitation_used", "Invite Used"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("custom_", "Custom Prefix"),
]
),
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("invitation_created", "Invite Created"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("custom_", "Custom Prefix"),
]
),
),
migrations.RemoveField(
model_name="event",
name="date",
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("token_view", "Token View"),
("invitation_created", "Invite Created"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("custom_", "Custom Prefix"),
]
),
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("token_view", "Token View"),
("invitation_created", "Invite Created"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("custom_", "Custom Prefix"),
]
),
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("token_view", "Token View"),
("invitation_created", "Invite Created"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
]
),
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("token_view", "Token View"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("configuration_error", "Configuration Error"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
]
),
),
migrations.CreateModel(
name="NotificationTransport",
fields=[
(
"uuid",
models.UUIDField(
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
),
),
("name", models.TextField(unique=True)),
(
"mode",
models.TextField(
choices=[
("webhook", "Generic Webhook"),
("webhook_slack", "Slack Webhook (Slack/Discord)"),
("email", "Email"),
]
),
),
("webhook_url", models.TextField(blank=True)),
],
options={
"verbose_name": "Notification Transport",
"verbose_name_plural": "Notification Transports",
},
),
migrations.CreateModel(
name="NotificationRule",
fields=[
(
"policybindingmodel_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_policies.policybindingmodel",
),
),
("name", models.TextField(unique=True)),
(
"severity",
models.TextField(
choices=[("notice", "Notice"), ("warning", "Warning"), ("alert", "Alert")],
default="notice",
help_text="Controls which severity level the created notifications will have.",
),
),
(
"group",
models.ForeignKey(
blank=True,
help_text="Define which group of users this notification should be sent and shown to. If left empty, Notification won't ben sent.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="authentik_core.group",
),
),
(
"transports",
models.ManyToManyField(
help_text="Select which transports should be used to notify the user. If none are selected, the notification will only be shown in the authentik UI.",
to="authentik_events.NotificationTransport",
),
),
],
options={
"verbose_name": "Notification Rule",
"verbose_name_plural": "Notification Rules",
},
bases=("authentik_policies.policybindingmodel",),
),
migrations.CreateModel(
name="Notification",
fields=[
(
"uuid",
models.UUIDField(
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
),
),
(
"severity",
models.TextField(
choices=[("notice", "Notice"), ("warning", "Warning"), ("alert", "Alert")]
),
),
("body", models.TextField()),
("created", models.DateTimeField(auto_now_add=True)),
("seen", models.BooleanField(default=False)),
(
"event",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="authentik_events.event",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
),
),
],
options={
"verbose_name": "Notification",
"verbose_name_plural": "Notifications",
},
),
migrations.RunPython(
code=transport_email_global,
),
migrations.RunPython(
code=notify_configuration_error,
),
migrations.RunPython(
code=notify_update,
),
migrations.RunPython(
code=notify_exception,
),
migrations.AddField(
model_name="notificationtransport",
name="send_once",
field=models.BooleanField(
default=False,
help_text="Only send notification once, for example when sending a webhook into a chat channel.",
),
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("token_view", "Token View"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("system_task_execution", "System Task Execution"),
("system_task_exception", "System Task Exception"),
("configuration_error", "Configuration Error"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
]
),
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("secret_view", "Secret View"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("system_task_execution", "System Task Execution"),
("system_task_exception", "System Task Exception"),
("configuration_error", "Configuration Error"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
]
),
),
migrations.RunPython(
code=token_view_to_secret_view,
),
migrations.AddField(
model_name="event",
name="expires",
field=models.DateTimeField(default=authentik.events.models.default_event_duration),
),
migrations.AddField(
model_name="event",
name="expiring",
field=models.BooleanField(default=True),
),
migrations.RunPython(
code=update_expires,
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("secret_view", "Secret View"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("system_task_execution", "System Task Execution"),
("system_task_exception", "System Task Exception"),
("configuration_error", "Configuration Error"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("email_sent", "Email Sent"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
]
),
),
migrations.AddField(
model_name="event",
name="tenant",
field=models.JSONField(blank=True, default=authentik.events.models.default_tenant),
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("secret_view", "Secret View"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("system_task_execution", "System Task Execution"),
("system_task_exception", "System Task Exception"),
("system_exception", "System Exception"),
("configuration_error", "Configuration Error"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("email_sent", "Email Sent"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
]
),
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("secret_view", "Secret View"),
("secret_rotate", "Secret Rotate"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("system_task_execution", "System Task Execution"),
("system_task_exception", "System Task Exception"),
("system_exception", "System Exception"),
("configuration_error", "Configuration Error"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("email_sent", "Email Sent"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
]
),
),
migrations.CreateModel(
name="NotificationWebhookMapping",
fields=[
(
"propertymapping_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_core.propertymapping",
),
),
],
options={
"verbose_name": "Notification Webhook Mapping",
"verbose_name_plural": "Notification Webhook Mappings",
},
bases=("authentik_core.propertymapping",),
),
migrations.AddField(
model_name="notificationtransport",
name="webhook_mapping",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
to="authentik_events.notificationwebhookmapping",
),
),
migrations.AlterField(
model_name="notificationtransport",
name="webhook_url",
field=models.TextField(blank=True, validators=[django.core.validators.URLValidator()]),
),
]

View File

@ -7,7 +7,9 @@ from typing import Any, Optional
from celery import Task
from django.core.cache import cache
from django.utils.translation import gettext_lazy as _
from prometheus_client import Gauge
from structlog.stdlib import get_logger
from authentik.events.models import Event, EventAction
from authentik.lib.utils.errors import exception_to_string
@ -18,6 +20,8 @@ GAUGE_TASKS = Gauge(
["task_name", "task_uid", "status"],
)
LOGGER = get_logger()
class TaskResultStatus(Enum):
"""Possible states of tasks"""
@ -25,6 +29,7 @@ class TaskResultStatus(Enum):
SUCCESSFUL = 1
WARNING = 2
ERROR = 4
UNKNOWN = 8
@dataclass
@ -76,7 +81,7 @@ class TaskInfo:
@staticmethod
def by_name(name: str) -> Optional["TaskInfo"]:
"""Get TaskInfo Object by name"""
return cache.get(f"task_{name}")
return cache.get(f"task_{name}", None)
def delete(self):
"""Delete task info from cache"""
@ -107,6 +112,30 @@ class TaskInfo:
cache.set(key, self, timeout=timeout_hours * 60 * 60)
def prefill_task():
"""Ensure a task's details are always in cache, so it can always be triggered via API"""
def inner_wrap(func):
status = TaskInfo.by_name(func.__name__)
if status:
return func
TaskInfo(
task_name=func.__name__,
task_description=func.__doc__,
result=TaskResult(TaskResultStatus.UNKNOWN, messages=[_("Task has not been run yet.")]),
task_call_module=func.__module__,
task_call_func=func.__name__,
# We don't have real values for these attributes but they cannot be null
start_timestamp=default_timer(),
finish_timestamp=default_timer(),
finish_time=datetime.now(),
).save(86400)
LOGGER.debug("prefilled task", task_name=func.__name__)
return func
return inner_wrap
class MonitoredTask(Task):
"""Task which can save its state to the cache"""

View File

@ -12,7 +12,7 @@ from authentik.core.signals import password_changed
from authentik.events.models import Event, EventAction
from authentik.events.tasks import event_notification_handler
from authentik.flows.planner import PLAN_CONTEXT_SOURCE, FlowPlan
from authentik.flows.views import SESSION_KEY_PLAN
from authentik.flows.views.executor 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

View File

@ -98,7 +98,9 @@ def notification_transport(self: MonitoredTask, notification_pk: int, transport_
notification: Notification = Notification.objects.filter(pk=notification_pk).first()
if not notification:
return
transport: NotificationTransport = NotificationTransport.objects.get(pk=transport_pk)
transport = NotificationTransport.objects.filter(pk=transport_pk).first()
if not transport:
return
transport.send(notification)
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL))
except NotificationTransportError as exc:

View File

@ -32,7 +32,7 @@ from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner, cach
from authentik.flows.transfer.common import DataclassEncoder
from authentik.flows.transfer.exporter import FlowExporter
from authentik.flows.transfer.importer import FlowImporter
from authentik.flows.views import SESSION_KEY_PLAN
from authentik.flows.views.executor import SESSION_KEY_HISTORY, SESSION_KEY_PLAN
from authentik.lib.views import bad_request_message
LOGGER = get_logger()
@ -334,6 +334,9 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
# pylint: disable=unused-argument
def execute(self, request: Request, slug: str):
"""Execute flow for current user"""
# Because we pre-plan the flow here, and not in the planner, we need to manually clear
# the history of the inspector
request.session[SESSION_KEY_HISTORY] = []
flow: Flow = self.get_object()
planner = FlowPlanner(flow)
planner.use_cache = False

View File

@ -1,6 +1,4 @@
"""Flow Stage API Views"""
from typing import Iterable
from django.urls.base import reverse
from drf_spectacular.utils import extend_schema
from rest_framework import mixins
@ -15,7 +13,7 @@ from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
from authentik.core.types import UserSettingSerializer
from authentik.flows.api.flows import FlowSerializer
from authentik.flows.models import Stage
from authentik.flows.models import ConfigurableStage, Stage
from authentik.lib.utils.reflection import all_subclasses
LOGGER = get_logger()
@ -86,9 +84,11 @@ class StageViewSet(
@action(detail=False, pagination_class=None, filter_backends=[])
def user_settings(self, request: Request) -> Response:
"""Get all stages the user can configure"""
_all_stages: Iterable[Stage] = Stage.objects.all().select_subclasses().order_by("name")
stages = []
for configurable_stage in all_subclasses(ConfigurableStage):
stages += list(configurable_stage.objects.all().order_by("name"))
matching_stages: list[dict] = []
for stage in _all_stages:
for stage in stages:
user_settings = stage.ui_user_settings
if not user_settings:
continue

View File

@ -0,0 +1,180 @@
# Generated by Django 3.2.8 on 2021-10-10 16:08
import uuid
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
replaces = [
("authentik_flows", "0001_initial"),
("authentik_flows", "0003_auto_20200523_1133"),
("authentik_flows", "0006_auto_20200629_0857"),
("authentik_flows", "0007_auto_20200703_2059"),
]
initial = True
dependencies = [
("authentik_policies", "0001_initial"),
("authentik_policies", "0002_auto_20200528_1647"),
]
operations = [
migrations.CreateModel(
name="Flow",
fields=[
(
"flow_uuid",
models.UUIDField(
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
),
),
("name", models.TextField()),
("slug", models.SlugField(unique=True)),
(
"designation",
models.CharField(
choices=[
("authentication", "Authentication"),
("invalidation", "Invalidation"),
("enrollment", "Enrollment"),
("unenrollment", "Unrenollment"),
("recovery", "Recovery"),
("password_change", "Password Change"),
],
max_length=100,
),
),
(
"pbm",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
related_name="+",
to="authentik_policies.policybindingmodel",
),
),
],
options={
"verbose_name": "Flow",
"verbose_name_plural": "Flows",
},
bases=("authentik_policies.policybindingmodel",),
),
migrations.CreateModel(
name="Stage",
fields=[
(
"stage_uuid",
models.UUIDField(
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
),
),
("name", models.TextField()),
],
),
migrations.CreateModel(
name="FlowStageBinding",
fields=[
(
"policybindingmodel_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
to="authentik_policies.policybindingmodel",
),
),
(
"fsb_uuid",
models.UUIDField(
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
),
),
(
"re_evaluate_policies",
models.BooleanField(
default=False,
help_text="When this option is enabled, the planner will re-evaluate policies bound to this.",
),
),
("order", models.IntegerField()),
(
"target",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="authentik_flows.flow"
),
),
(
"stage",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="authentik_flows.stage"
),
),
],
options={
"verbose_name": "Flow Stage Binding",
"verbose_name_plural": "Flow Stage Bindings",
"ordering": ["order", "target"],
"unique_together": {("target", "stage", "order")},
},
bases=("authentik_policies.policybindingmodel",),
),
migrations.AddField(
model_name="flow",
name="stages",
field=models.ManyToManyField(
blank=True, through="authentik_flows.FlowStageBinding", to="authentik_flows.Stage"
),
),
migrations.AlterField(
model_name="flow",
name="designation",
field=models.CharField(
choices=[
("authentication", "Authentication"),
("authorization", "Authorization"),
("invalidation", "Invalidation"),
("enrollment", "Enrollment"),
("unenrollment", "Unrenollment"),
("recovery", "Recovery"),
("password_change", "Password Change"),
],
max_length=100,
),
),
migrations.AlterField(
model_name="flow",
name="designation",
field=models.CharField(
choices=[
("authentication", "Authentication"),
("authorization", "Authorization"),
("invalidation", "Invalidation"),
("enrollment", "Enrollment"),
("unenrollment", "Unrenollment"),
("recovery", "Recovery"),
("stage_setup", "Stage Setup"),
],
max_length=100,
),
),
migrations.RenameField(
model_name="flow",
old_name="pbm",
new_name="policybindingmodel_ptr",
),
migrations.AlterField(
model_name="flow",
name="policybindingmodel_ptr",
field=models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
to="authentik_policies.policybindingmodel",
),
),
]

View File

@ -0,0 +1,171 @@
# Generated by Django 3.2.8 on 2021-10-10 16:08
import django.db.models.deletion
from django.apps.registry import Apps
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
import authentik.lib.models
from authentik.flows.models import FlowDesignation
def update_flow_designation(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
Flow = apps.get_model("authentik_flows", "Flow")
db_alias = schema_editor.connection.alias
for flow in Flow.objects.using(db_alias).all():
if flow.designation == "stage_setup":
flow.designation = FlowDesignation.STAGE_CONFIGURATION
flow.save()
# First stage for default-source-enrollment flow (prompt stage)
# needs to have its policy re-evaluated
def update_default_source_enrollment_flow_binding(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
Flow = apps.get_model("authentik_flows", "Flow")
FlowStageBinding = apps.get_model("authentik_flows", "FlowStageBinding")
db_alias = schema_editor.connection.alias
flows = Flow.objects.using(db_alias).filter(slug="default-source-enrollment")
if not flows.exists():
return
flow = flows.first()
binding = FlowStageBinding.objects.get(target=flow, order=0)
binding.re_evaluate_policies = True
binding.save()
class Migration(migrations.Migration):
replaces = [
("authentik_flows", "0012_auto_20200908_1542"),
("authentik_flows", "0013_auto_20200924_1605"),
("authentik_flows", "0014_auto_20200925_2332"),
("authentik_flows", "0015_flowstagebinding_evaluate_on_plan"),
("authentik_flows", "0016_auto_20201202_1307"),
("authentik_flows", "0017_auto_20210329_1334"),
]
dependencies = [
("authentik_flows", "0011_flow_title"),
]
operations = [
migrations.AlterField(
model_name="flowstagebinding",
name="stage",
field=authentik.lib.models.InheritanceForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="authentik_flows.stage"
),
),
migrations.AlterField(
model_name="stage",
name="name",
field=models.TextField(unique=True),
),
migrations.AlterField(
model_name="flow",
name="designation",
field=models.CharField(
choices=[
("authentication", "Authentication"),
("authorization", "Authorization"),
("invalidation", "Invalidation"),
("enrollment", "Enrollment"),
("unenrollment", "Unrenollment"),
("recovery", "Recovery"),
("stage_configuration", "Stage Configuration"),
],
max_length=100,
),
),
migrations.RunPython(
code=update_flow_designation,
),
migrations.AlterModelOptions(
name="flowstagebinding",
options={
"ordering": ["target", "order"],
"verbose_name": "Flow Stage Binding",
"verbose_name_plural": "Flow Stage Bindings",
},
),
migrations.AlterField(
model_name="flowstagebinding",
name="re_evaluate_policies",
field=models.BooleanField(
default=False,
help_text="When this option is enabled, the planner will re-evaluate policies bound to this binding.",
),
),
migrations.RunPython(
code=update_default_source_enrollment_flow_binding,
),
migrations.AlterField(
model_name="flowstagebinding",
name="re_evaluate_policies",
field=models.BooleanField(
default=False, help_text="Evaluate policies when the Stage is present to the user."
),
),
migrations.AddField(
model_name="flowstagebinding",
name="evaluate_on_plan",
field=models.BooleanField(
default=True,
help_text="Evaluate policies during the Flow planning process. Disable this for input-based policies.",
),
),
migrations.AddField(
model_name="flow",
name="background",
field=models.FileField(
blank=True,
default="../static/dist/assets/images/flow_background.jpg",
help_text="Background shown during execution",
upload_to="flow-backgrounds/",
),
),
migrations.AlterField(
model_name="flow",
name="designation",
field=models.CharField(
choices=[
("authentication", "Authentication"),
("authorization", "Authorization"),
("invalidation", "Invalidation"),
("enrollment", "Enrollment"),
("unenrollment", "Unrenollment"),
("recovery", "Recovery"),
("stage_configuration", "Stage Configuration"),
],
help_text="Decides what this Flow is used for. For example, the Authentication flow is redirect to when an un-authenticated user visits authentik.",
max_length=100,
),
),
migrations.AlterField(
model_name="flow",
name="slug",
field=models.SlugField(help_text="Visible in the URL.", unique=True),
),
migrations.AlterField(
model_name="flow",
name="title",
field=models.TextField(help_text="Shown as the Title in Flow pages."),
),
migrations.AlterModelOptions(
name="flow",
options={
"permissions": [
("export_flow", "Can export a Flow"),
("view_flow_cache", "View Flow's cache metrics"),
("clear_flow_cache", "Clear Flow's cache metrics"),
],
"verbose_name": "Flow",
"verbose_name_plural": "Flows",
},
),
]

View File

@ -0,0 +1,64 @@
# Generated by Django 3.2.8 on 2021-10-10 16:10
from django.db import migrations, models
class Migration(migrations.Migration):
replaces = [
("authentik_flows", "0019_alter_flow_background"),
("authentik_flows", "0020_flow_compatibility_mode"),
("authentik_flows", "0021_flowstagebinding_invalid_response_action"),
("authentik_flows", "0022_alter_flowstagebinding_invalid_response_action"),
("authentik_flows", "0023_alter_flow_background"),
("authentik_flows", "0024_alter_flow_compatibility_mode"),
]
dependencies = [
("authentik_flows", "0018_oob_flows"),
]
operations = [
migrations.AlterField(
model_name="flow",
name="background",
field=models.FileField(
default=None,
help_text="Background shown during execution",
null=True,
upload_to="flow-backgrounds/",
),
),
migrations.AddField(
model_name="flowstagebinding",
name="invalid_response_action",
field=models.TextField(
choices=[
("retry", "Retry"),
("restart", "Restart"),
("restart_with_context", "Restart With Context"),
],
default="retry",
help_text="Configure how the flow executor should handle an invalid response to a challenge. RETRY returns the error message and a similar challenge to the executor. RESTART restarts the flow from the beginning, and RESTART_WITH_CONTEXT restarts the flow while keeping the current context.",
),
),
migrations.AlterField(
model_name="flow",
name="background",
field=models.FileField(
default=None,
help_text="Background shown during execution",
max_length=500,
null=True,
upload_to="flow-backgrounds/",
),
),
migrations.AddField(
model_name="flow",
name="compatibility_mode",
field=models.BooleanField(
default=False,
help_text="Enable compatibility mode, increases compatibility with password managers on mobile devices.",
),
),
]

View File

@ -1,6 +1,6 @@
"""authentik flow signals"""
from django.core.cache import cache
from django.db.models.signals import post_save
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
from structlog.stdlib import get_logger
@ -15,6 +15,7 @@ def delete_cache_prefix(prefix: str) -> int:
@receiver(post_save)
@receiver(pre_delete)
# pylint: disable=unused-argument
def invalidate_flow_cache(sender, instance, **_):
"""Invalidate flow cache when flow is updated"""

View File

@ -18,7 +18,7 @@ from authentik.flows.challenge import (
)
from authentik.flows.models import InvalidResponseAction
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_PENDING_USER
from authentik.flows.views import FlowExecutorView
from authentik.flows.views.executor import FlowExecutorView
PLAN_CONTEXT_PENDING_USER_IDENTIFIER = "pending_user_identifier"
LOGGER = get_logger()

View File

@ -14,7 +14,7 @@ from authentik.flows.markers import ReevaluateMarker, StageMarker
from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding, InvalidResponseAction
from authentik.flows.planner import FlowPlan, FlowPlanner
from authentik.flows.stage import PLAN_CONTEXT_PENDING_USER_IDENTIFIER, StageView
from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_PLAN, FlowExecutorView
from authentik.flows.views.executor import NEXT_ARG_NAME, SESSION_KEY_PLAN, FlowExecutorView
from authentik.lib.config import CONFIG
from authentik.policies.dummy.models import DummyPolicy
from authentik.policies.models import PolicyBinding
@ -38,13 +38,13 @@ TO_STAGE_RESPONSE_MOCK = MagicMock(side_effect=to_stage_response)
class TestFlowExecutor(APITestCase):
"""Test views logic"""
"""Test executor"""
def setUp(self):
self.request_factory = RequestFactory()
@patch(
"authentik.flows.views.to_stage_response",
"authentik.flows.views.executor.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
)
def test_existing_plan_diff_flow(self):
@ -62,7 +62,7 @@ class TestFlowExecutor(APITestCase):
session.save()
cancel_mock = MagicMock()
with patch("authentik.flows.views.FlowExecutorView.cancel", cancel_mock):
with patch("authentik.flows.views.executor.FlowExecutorView.cancel", cancel_mock):
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
@ -70,7 +70,7 @@ class TestFlowExecutor(APITestCase):
self.assertEqual(cancel_mock.call_count, 2)
@patch(
"authentik.flows.views.to_stage_response",
"authentik.flows.views.executor.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
)
@patch(
@ -105,7 +105,7 @@ class TestFlowExecutor(APITestCase):
)
@patch(
"authentik.flows.views.to_stage_response",
"authentik.flows.views.executor.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
)
def test_invalid_empty_flow(self):
@ -124,7 +124,7 @@ class TestFlowExecutor(APITestCase):
self.assertEqual(response.url, reverse("authentik_core:root-redirect"))
@patch(
"authentik.flows.views.to_stage_response",
"authentik.flows.views.executor.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
)
def test_invalid_flow_redirect(self):
@ -175,7 +175,7 @@ class TestFlowExecutor(APITestCase):
self.assertEqual(len(plan.bindings), 1)
@patch(
"authentik.flows.views.to_stage_response",
"authentik.flows.views.executor.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
)
def test_reevaluate_remove_last(self):
@ -545,6 +545,7 @@ class TestFlowExecutor(APITestCase):
"password_fields": False,
"primary_action": "Log in",
"sources": [],
"show_source_labels": False,
"user_fields": [UserFields.E_MAIL],
},
)

View File

@ -0,0 +1,93 @@
"""Flow inspector tests"""
from json import loads
from django.test.client import RequestFactory
from django.urls.base import reverse
from rest_framework.test import APITestCase
from authentik.core.models import User
from authentik.flows.challenge import ChallengeTypes
from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding, InvalidResponseAction
from authentik.stages.dummy.models import DummyStage
from authentik.stages.identification.models import IdentificationStage, UserFields
class TestFlowInspector(APITestCase):
"""Test inspector"""
def setUp(self):
self.request_factory = RequestFactory()
self.admin = User.objects.get(username="akadmin")
self.client.force_login(self.admin)
def test(self):
"""test inspector"""
flow = Flow.objects.create(
name="test-full",
slug="test-full",
designation=FlowDesignation.AUTHENTICATION,
)
# Stage 1 is an identification stage
ident_stage = IdentificationStage.objects.create(
name="ident",
user_fields=[UserFields.USERNAME],
)
FlowStageBinding.objects.create(
target=flow,
stage=ident_stage,
order=1,
invalid_response_action=InvalidResponseAction.RESTART_WITH_CONTEXT,
)
FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name="dummy2"), order=1
)
res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
self.assertJSONEqual(
res.content,
{
"component": "ak-stage-identification",
"flow_info": {
"background": flow.background_url,
"cancel_url": reverse("authentik_flows:cancel"),
"title": "",
},
"type": ChallengeTypes.NATIVE.value,
"password_fields": False,
"primary_action": "Log in",
"sources": [],
"show_source_labels": False,
"user_fields": ["username"],
},
)
ins = self.client.get(
reverse("authentik_api:flow-inspector", kwargs={"flow_slug": flow.slug}),
)
content = loads(ins.content)
self.assertEqual(content["is_completed"], False)
self.assertEqual(content["current_plan"]["current_stage"]["stage_obj"]["name"], "ident")
self.assertEqual(
content["current_plan"]["next_planned_stage"]["stage_obj"]["name"], "dummy2"
)
self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
{"uid_field": "akadmin"},
follow=True,
)
ins = self.client.get(
reverse("authentik_api:flow-inspector", kwargs={"flow_slug": flow.slug}),
)
content = loads(ins.content)
self.assertEqual(content["is_completed"], False)
self.assertEqual(content["plans"][0]["current_stage"]["stage_obj"]["name"], "ident")
self.assertEqual(content["current_plan"]["current_stage"]["stage_obj"]["name"], "dummy2")
self.assertEqual(
content["current_plan"]["plan_context"]["pending_user"]["username"], "akadmin"
)

View File

@ -4,7 +4,7 @@ from typing import Callable, Type
from django.test import RequestFactory, TestCase
from authentik.flows.stage import StageView
from authentik.flows.views import FlowExecutorView
from authentik.flows.views.executor import FlowExecutorView
from authentik.lib.utils.reflection import all_subclasses

View File

@ -4,7 +4,7 @@ from django.urls import reverse
from authentik.flows.models import Flow, FlowDesignation
from authentik.flows.planner import FlowPlan
from authentik.flows.views import SESSION_KEY_PLAN
from authentik.flows.views.executor import SESSION_KEY_PLAN
class TestHelperView(TestCase):

View File

@ -2,7 +2,7 @@
from django.urls import path
from authentik.flows.models import FlowDesignation
from authentik.flows.views import CancelView, ConfigureFlowInitView, ToDefaultFlow
from authentik.flows.views.executor import CancelView, ConfigureFlowInitView, ToDefaultFlow
urlpatterns = [
path(

View File

View File

@ -1,4 +1,5 @@
"""authentik multi-stage authentication engine"""
from copy import deepcopy
from traceback import format_tb
from typing import Any, Optional
@ -52,6 +53,7 @@ NEXT_ARG_NAME = "next"
SESSION_KEY_PLAN = "authentik_flows_plan"
SESSION_KEY_APPLICATION_PRE = "authentik_flows_application_pre"
SESSION_KEY_GET = "authentik_flows_get"
SESSION_KEY_HISTORY = "authentik_flows_history"
def challenge_types():
@ -140,6 +142,7 @@ class FlowExecutorView(APIView):
# Don't check session again as we've either already loaded the plan or we need to plan
if not self.plan:
request.session[SESSION_KEY_HISTORY] = []
self._logger.debug("f(exec): No active Plan found, initiating planner")
try:
self.plan = self._initiate_plan()
@ -321,6 +324,7 @@ class FlowExecutorView(APIView):
"f(exec): Stage ok",
stage_class=class_to_path(self.current_stage_view.__class__),
)
self.request.session.get(SESSION_KEY_HISTORY, []).append(deepcopy(self.plan))
self.plan.pop()
self.request.session[SESSION_KEY_PLAN] = self.plan
if self.plan.bindings:
@ -368,6 +372,10 @@ class FlowExecutorView(APIView):
SESSION_KEY_APPLICATION_PRE,
SESSION_KEY_PLAN,
SESSION_KEY_GET,
# We don't delete the history on purpose, as a user might
# still be inspecting it.
# It's only deleted on a fresh executions
# SESSION_KEY_HISTORY,
]
for key in keys_to_delete:
if key in self.request.session:

View File

@ -0,0 +1,119 @@
"""Flow Inspector"""
from hashlib import sha256
from typing import Any
from django.conf import settings
from django.http.request import HttpRequest
from django.http.response import HttpResponse
from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
from django.views.decorators.clickjacking import xframe_options_sameorigin
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.fields import BooleanField, ListField, SerializerMethodField
from rest_framework.permissions import IsAdminUser
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from structlog.stdlib import BoundLogger, get_logger
from authentik.core.api.utils import PassiveSerializer
from authentik.events.utils import sanitize_dict
from authentik.flows.api.bindings import FlowStageBindingSerializer
from authentik.flows.models import Flow
from authentik.flows.planner import FlowPlan
from authentik.flows.views.executor import SESSION_KEY_HISTORY, SESSION_KEY_PLAN
class FlowInspectorPlanSerializer(PassiveSerializer):
"""Serializer for an active FlowPlan"""
current_stage = SerializerMethodField()
next_planned_stage = SerializerMethodField(required=False)
plan_context = SerializerMethodField()
session_id = SerializerMethodField()
def get_current_stage(self, plan: FlowPlan) -> FlowStageBindingSerializer:
"""Get the current stage"""
return FlowStageBindingSerializer(instance=plan.bindings[0]).data
def get_next_planned_stage(self, plan: FlowPlan) -> FlowStageBindingSerializer:
"""Get the next planned stage"""
if len(plan.bindings) < 2:
return FlowStageBindingSerializer().data
return FlowStageBindingSerializer(instance=plan.bindings[1]).data
def get_plan_context(self, plan: FlowPlan) -> dict[str, Any]:
"""Get the plan's context, sanitized"""
return sanitize_dict(plan.context)
# pylint: disable=unused-argument
def get_session_id(self, plan: FlowPlan) -> str:
"""Get a unique session ID"""
request: Request = self.context["request"]
return sha256(
f"{request._request.session.session_key}-{settings.SECRET_KEY}".encode("ascii")
).hexdigest()
class FlowInspectionSerializer(PassiveSerializer):
"""Serializer for inspect endpoint"""
plans = ListField(child=FlowInspectorPlanSerializer())
current_plan = FlowInspectorPlanSerializer(required=False)
is_completed = BooleanField()
@method_decorator(xframe_options_sameorigin, name="dispatch")
class FlowInspectorView(APIView):
"""Flow inspector API"""
permission_classes = [IsAdminUser]
flow: Flow
_logger: BoundLogger
def setup(self, request: HttpRequest, flow_slug: str):
super().setup(request, flow_slug=flow_slug)
self.flow = get_object_or_404(Flow.objects.select_related(), slug=flow_slug)
self._logger = get_logger().bind(flow_slug=flow_slug)
# pylint: disable=unused-argument, too-many-return-statements
def dispatch(self, request: HttpRequest, flow_slug: str) -> HttpResponse:
if SESSION_KEY_HISTORY not in self.request.session:
return HttpResponse(status=400)
return super().dispatch(request, flow_slug=flow_slug)
@extend_schema(
responses={
200: FlowInspectionSerializer(),
400: OpenApiResponse(
description="No flow plan in session."
), # This error can be raised by the email stage
},
request=OpenApiTypes.NONE,
operation_id="flows_inspector_get",
)
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""Get current flow state and record it"""
plans = []
for plan in request.session[SESSION_KEY_HISTORY]:
plan_serializer = FlowInspectorPlanSerializer(
instance=plan, context={"request": request}
)
plans.append(plan_serializer.data)
is_completed = False
if SESSION_KEY_PLAN in request.session:
current_plan: FlowPlan = request.session[SESSION_KEY_PLAN]
else:
current_plan = request.session[SESSION_KEY_HISTORY][-1]
is_completed = True
current_serializer = FlowInspectorPlanSerializer(
instance=current_plan, context={"request": request}
)
response = {
"plans": plans,
"current_plan": current_serializer.data,
"is_completed": is_completed,
}
return Response(response)

View File

@ -5,6 +5,16 @@ postgresql:
user: authentik
port: 5432
password: 'env://POSTGRES_PASSWORD'
backup:
enabled: true
s3_backup:
access_key: ""
secret_key: ""
bucket: ""
region: eu-central-1
host: ""
location: ""
insecure_skip_verify: false
web:
listen: 0.0.0.0:9000
@ -54,15 +64,17 @@ outposts:
# %(type)s: Outpost type; proxy, ldap, etc
# %(version)s: Current version; 2021.4.1
# %(build_hash)s: Build hash if you're running a beta version
docker_image_base: "ghcr.io/goauthentik/%(type)s:%(version)s"
container_image_base: env://AUTHENTIK_OUTPOSTS__DOCKER_IMAGE_BASE?goauthentik.io/%(type)s:%(version)s
cookie_domain: null
disable_update_check: false
disable_startup_analytics: false
avatars: env://AUTHENTIK_AUTHENTIK__AVATARS?gravatar
geoip: "./GeoLite2-City.mmdb"
# Can't currently be configured via environment variables, only yaml
footer_links:
- name: Documentation
href: https://goauthentik.io/docs/
href: https://goauthentik.io/docs/?utm_source=authentik
- name: authentik Website
href: https://goauthentik.io/
href: https://goauthentik.io/?utm_source=authentik

View File

@ -13,6 +13,7 @@ from django.db import InternalError, OperationalError, ProgrammingError
from django.http.response import Http404
from django_redis.exceptions import ConnectionInterrupted
from docker.errors import DockerException
from h11 import LocalProtocolError
from ldap3.core.exceptions import LDAPException
from redis.exceptions import ConnectionError as RedisConnectionError
from redis.exceptions import RedisError, ResponseError
@ -72,6 +73,7 @@ def before_send(event: dict, hint: dict) -> Optional[dict]:
# websocket errors
ChannelFull,
WebSocketException,
LocalProtocolError,
# rest_framework error
APIException,
# celery errors

View File

@ -1,8 +1,13 @@
"""authentik lib reflection utilities"""
import os
from importlib import import_module
from pathlib import Path
from typing import Union
from django.conf import settings
from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME
from authentik.lib.config import CONFIG
def all_subclasses(cls, sort=True):
@ -42,3 +47,16 @@ def get_apps():
for _app in apps.get_app_configs():
if _app.name.startswith("authentik"):
yield _app
def get_env() -> str:
"""Get environment in which authentik is currently running"""
if SERVICE_HOST_ENV_NAME in os.environ:
return "kubernetes"
if "CI" in os.environ:
return "ci"
if Path("/tmp/authentik-mode").exists(): # nosec
return "compose"
if CONFIG.y_bool("debug"):
return "dev"
return "custom"

View File

@ -13,4 +13,4 @@ class AuthentikManagedConfig(AppConfig):
from authentik.managed.tasks import managed_reconcile
# pyright: reportGeneralTypeIssues=false
managed_reconcile() # pylint: disable=no-value-for-parameter
managed_reconcile.delay() # pylint: disable=no-value-for-parameter

View File

@ -2,11 +2,17 @@
from django.db import DatabaseError
from authentik.core.tasks import CELERY_APP
from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus
from authentik.events.monitored_tasks import (
MonitoredTask,
TaskResult,
TaskResultStatus,
prefill_task,
)
from authentik.managed.manager import ObjectManager
@CELERY_APP.task(bind=True, base=MonitoredTask)
@prefill_task()
def managed_reconcile(self: MonitoredTask):
"""Run ObjectManager to ensure objects are up-to-date"""
try:

View File

@ -69,7 +69,10 @@ class BaseController:
def get_container_image(self) -> str:
"""Get container image to use for this outpost"""
image_name_template: str = CONFIG.y("outposts.docker_image_base")
if self.outpost.config.container_image is not None:
return self.outpost.config.container_image
image_name_template: str = CONFIG.y("outposts.container_image_base")
return image_name_template % {
"type": self.outpost.type,
"version": __version__,

View File

@ -2,6 +2,7 @@
from time import sleep
from django.conf import settings
from django.utils.text import slugify
from docker import DockerClient
from docker.errors import DockerException, NotFound
from docker.models.containers import Container
@ -28,6 +29,17 @@ class DockerController(BaseController):
except ServiceConnectionInvalid as exc:
raise ControllerException from exc
@property
def name(self) -> str:
"""Get the name of the object this reconciler manages"""
return (
self.outpost.config.object_naming_template
% {
"name": slugify(self.outpost.name),
"uuid": self.outpost.uuid.hex,
}
).lower()
def _get_labels(self) -> dict[str, str]:
return {
"io.goauthentik.outpost-uuid": self.outpost.pk.hex,
@ -81,7 +93,7 @@ class DockerController(BaseController):
return False
for port in self.deployment_ports:
key = f"{port.inner_port or port.port}/{port.protocol.lower()}"
if key not in container.ports:
if not container.ports.get(key, None):
return True
host_matching = False
for host_port in container.ports[key]:
@ -90,17 +102,26 @@ class DockerController(BaseController):
return True
return False
def _get_container(self) -> tuple[Container, bool]:
container_name = f"authentik-proxy-{self.outpost.uuid.hex}"
def try_pull_image(self):
"""Try to pull the image needed for this outpost based on the CONFIG
`outposts.container_image_base`, but fall back to known-good images"""
image = self.get_container_image()
try:
return self.client.containers.get(container_name), False
self.client.images.pull(image)
except DockerException:
image = f"goauthentik.io/{self.outpost.type}:latest"
self.client.images.pull(image)
return image
def _get_container(self) -> tuple[Container, bool]:
try:
return self.client.containers.get(self.name), False
except NotFound:
self.logger.info("(Re-)creating container...")
image_name = self.get_container_image()
self.client.images.pull(image_name)
image_name = self.try_pull_image()
container_args = {
"image": image_name,
"name": container_name,
"name": self.name,
"detach": True,
"environment": self._get_env(),
"labels": self._get_labels(),
@ -121,12 +142,23 @@ class DockerController(BaseController):
True,
)
def _migrate_container_name(self):
"""Migrate 2021.9 to 2021.10+"""
old_name = f"authentik-proxy-{self.outpost.uuid.hex}"
try:
old_container: Container = self.client.containers.get(old_name)
old_container.kill()
old_container.remove()
except NotFound:
return
# pylint: disable=too-many-return-statements
def up(self, depth=1):
if self.outpost.managed == MANAGED_OUTPOST:
return None
if depth >= 10:
raise ControllerException("Giving up since we exceeded recursion limit.")
self._migrate_container_name()
try:
container, has_been_created = self._get_container()
if has_been_created:
@ -134,12 +166,12 @@ class DockerController(BaseController):
return None
# Check if the container is out of date, delete it and retry
if len(container.image.tags) > 0:
tag: str = container.image.tags[0]
if tag != self.get_container_image():
should_image = self.try_pull_image()
if should_image not in container.image.tags:
self.logger.info(
"Container has mismatched image, re-creating...",
has=tag,
should=self.get_container_image(),
has=container.image.tags,
should=should_image,
)
self.down()
return self.up(depth + 1)

View File

@ -1,5 +1,5 @@
"""Base Kubernetes Reconciler"""
from typing import TYPE_CHECKING, Generic, TypeVar
from typing import TYPE_CHECKING, Generic, Optional, TypeVar
from django.utils.text import slugify
from kubernetes.client import V1ObjectMeta
@ -70,21 +70,34 @@ class KubernetesObjectReconciler(Generic[T]):
raise exc
else:
self.reconcile(current, reference)
except NeedsRecreate:
self.logger.debug("Recreate requested")
if current:
self.logger.debug("Deleted old")
self.delete(current)
else:
self.logger.debug("No old found, creating")
self.logger.debug("Creating")
self.create(reference)
except NeedsUpdate:
self.logger.debug("Updating")
self.update(current, reference)
try:
self.update(current, reference)
self.logger.debug("Updating")
except (OpenApiException, HTTPError) as exc:
# pylint: disable=no-member
if isinstance(exc, ApiException) and exc.status == 422:
self.logger.debug("Failed to update current, triggering re-create")
self._recreate(current=current, reference=reference)
return
self.logger.debug("Other unhandled error", exc=exc)
raise exc
except NeedsRecreate:
self._recreate(current=current, reference=reference)
else:
self.logger.debug("Object is up-to-date.")
def _recreate(self, reference: T, current: Optional[T] = None):
"""Recreate object"""
self.logger.debug("Recreate requested")
if current:
self.logger.debug("Deleted old")
self.delete(current)
else:
self.logger.debug("No old found, creating")
self.logger.debug("Creating")
self.create(reference)
def down(self):
"""Delete object if found"""
if self.noop:
@ -138,6 +151,8 @@ class KubernetesObjectReconciler(Generic[T]):
"app.kubernetes.io/version": __version__,
"app.kubernetes.io/managed-by": "goauthentik.io",
"goauthentik.io/outpost-uuid": self.controller.outpost.uuid.hex,
"goauthentik.io/outpost-type": str(self.controller.outpost.type),
"goauthentik.io/outpost-name": slugify(self.controller.outpost.name),
},
**kwargs,
)

View File

@ -1,6 +1,7 @@
"""Kubernetes Deployment Reconciler"""
from typing import TYPE_CHECKING
from django.utils.text import slugify
from kubernetes.client import (
AppsV1Api,
V1Container,
@ -11,6 +12,7 @@ from kubernetes.client import (
V1EnvVarSource,
V1LabelSelector,
V1ObjectMeta,
V1ObjectReference,
V1PodSpec,
V1PodTemplateSpec,
V1SecretKeySelector,
@ -56,6 +58,8 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
"app.kubernetes.io/name": "authentik-outpost",
"app.kubernetes.io/managed-by": "goauthentik.io",
"goauthentik.io/outpost-uuid": self.controller.outpost.uuid.hex,
"goauthentik.io/outpost-name": slugify(self.controller.outpost.name),
"goauthentik.io/outpost-type": str(self.controller.outpost.type),
}
def get_reference_object(self) -> V1Deployment:
@ -72,6 +76,7 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
)
meta = self.get_object_meta(name=self.name)
image_name = self.controller.get_container_image()
image_pull_secrets = self.outpost.config.kubernetes_image_pull_secrets
return V1Deployment(
metadata=meta,
spec=V1DeploymentSpec(
@ -80,6 +85,9 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
template=V1PodTemplateSpec(
metadata=V1ObjectMeta(labels=self.get_pod_meta()),
spec=V1PodSpec(
image_pull_secrets=[
V1ObjectReference(name=secret) for secret in image_pull_secrets
],
containers=[
V1Container(
name=str(self.outpost.type),
@ -124,7 +132,7 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
),
],
)
]
],
),
),
),

View File

@ -0,0 +1,340 @@
# Generated by Django 3.2.8 on 2021-10-10 16:18
import uuid
import django.db.models.deletion
from django.apps.registry import Apps
from django.core.exceptions import FieldError
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
import authentik.lib.models
import authentik.outposts.models
def fix_missing_token_identifier(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
User = apps.get_model("authentik_core", "User")
Token = apps.get_model("authentik_core", "Token")
from authentik.outposts.models import Outpost
for outpost in Outpost.objects.using(schema_editor.connection.alias).all().only("pk"):
user_identifier = outpost.user_identifier
users = User.objects.filter(username=user_identifier)
if not users.exists():
continue
tokens = Token.objects.filter(user=users.first())
for token in tokens:
if token.identifier != outpost.token_identifier:
token.identifier = outpost.token_identifier
token.save()
def migrate_to_service_connection(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Outpost = apps.get_model("authentik_outposts", "Outpost")
DockerServiceConnection = apps.get_model("authentik_outposts", "DockerServiceConnection")
KubernetesServiceConnection = apps.get_model(
"authentik_outposts", "KubernetesServiceConnection"
)
docker = DockerServiceConnection.objects.filter(local=True).first()
k8s = KubernetesServiceConnection.objects.filter(local=True).first()
try:
for outpost in Outpost.objects.using(db_alias).all().exclude(deployment_type="custom"):
if outpost.deployment_type == "kubernetes":
outpost.service_connection = k8s
elif outpost.deployment_type == "docker":
outpost.service_connection = docker
outpost.save()
except FieldError:
# This is triggered during e2e tests when this function is called on an already-upgraded
# schema
pass
def remove_pb_prefix_users(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
alias = schema_editor.connection.alias
User = apps.get_model("authentik_core", "User")
Outpost = apps.get_model("authentik_outposts", "Outpost")
for outpost in Outpost.objects.using(alias).all():
matching = User.objects.using(alias).filter(username=f"pb-outpost-{outpost.uuid.hex}")
if matching.exists():
matching.delete()
def update_config_prefix(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
alias = schema_editor.connection.alias
Outpost = apps.get_model("authentik_outposts", "Outpost")
for outpost in Outpost.objects.using(alias).all():
config = outpost._config
for key in list(config):
if "passbook" in key:
new_key = key.replace("passbook", "authentik")
config[new_key] = config[key]
del config[key]
outpost._config = config
outpost.save()
class Migration(migrations.Migration):
replaces = [
("authentik_outposts", "0001_initial"),
("authentik_outposts", "0002_auto_20200826_1306"),
("authentik_outposts", "0003_auto_20200827_2108"),
("authentik_outposts", "0004_auto_20200830_1056"),
("authentik_outposts", "0005_auto_20200909_1733"),
("authentik_outposts", "0006_auto_20201003_2239"),
("authentik_outposts", "0007_remove_outpost_channels"),
("authentik_outposts", "0008_auto_20201014_1547"),
("authentik_outposts", "0009_fix_missing_token_identifier"),
("authentik_outposts", "0010_service_connection"),
("authentik_outposts", "0011_docker_tls_auth"),
("authentik_outposts", "0012_service_connection_non_unique"),
("authentik_outposts", "0013_auto_20201203_2009"),
("authentik_outposts", "0014_auto_20201213_1407"),
("authentik_outposts", "0015_auto_20201224_1206"),
("authentik_outposts", "0016_alter_outpost_type"),
("authentik_outposts", "0017_outpost_managed"),
]
initial = True
dependencies = [
("authentik_core", "0014_auto_20201018_1158"),
("authentik_core", "0016_auto_20201202_2234"),
("authentik_crypto", "0002_create_self_signed_kp"),
("authentik_core", "0008_auto_20200824_1532"),
]
operations = [
migrations.CreateModel(
name="Outpost",
fields=[
(
"uuid",
models.UUIDField(
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
),
),
("name", models.TextField()),
("providers", models.ManyToManyField(to="authentik_core.Provider")),
(
"_config",
models.JSONField(default=authentik.outposts.models.default_outpost_config),
),
("type", models.TextField(choices=[("proxy", "Proxy")], default="proxy")),
(
"deployment_type",
models.TextField(
choices=[
("kubernetes", "Kubernetes"),
("docker", "Docker"),
("custom", "Custom"),
],
default="custom",
help_text="Select between authentik-managed deployment types or a custom deployment.",
),
),
],
),
migrations.RunPython(
code=fix_missing_token_identifier,
),
migrations.CreateModel(
name="OutpostServiceConnection",
fields=[
(
"uuid",
models.UUIDField(
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
),
),
("name", models.TextField()),
(
"local",
models.BooleanField(
default=False,
help_text="If enabled, use the local connection. Required Docker socket/Kubernetes Integration",
unique=True,
),
),
],
),
migrations.CreateModel(
name="DockerServiceConnection",
fields=[
(
"outpostserviceconnection_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_outposts.outpostserviceconnection",
),
),
("url", models.TextField()),
("tls", models.BooleanField()),
],
bases=("authentik_outposts.outpostserviceconnection",),
),
migrations.CreateModel(
name="KubernetesServiceConnection",
fields=[
(
"outpostserviceconnection_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_outposts.outpostserviceconnection",
),
),
("kubeconfig", models.JSONField()),
],
bases=("authentik_outposts.outpostserviceconnection",),
),
migrations.AddField(
model_name="outpost",
name="service_connection",
field=models.ForeignKey(
blank=True,
default=None,
help_text="Select Service-Connection authentik should use to manage this outpost. Leave empty if authentik should not handle the deployment.",
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
to="authentik_outposts.outpostserviceconnection",
),
),
migrations.RunPython(
code=migrate_to_service_connection,
),
migrations.RemoveField(
model_name="outpost",
name="deployment_type",
),
migrations.AlterModelOptions(
name="dockerserviceconnection",
options={
"verbose_name": "Docker Service-Connection",
"verbose_name_plural": "Docker Service-Connections",
},
),
migrations.AlterModelOptions(
name="kubernetesserviceconnection",
options={
"verbose_name": "Kubernetes Service-Connection",
"verbose_name_plural": "Kubernetes Service-Connections",
},
),
migrations.AlterField(
model_name="outpost",
name="service_connection",
field=authentik.lib.models.InheritanceForeignKey(
blank=True,
default=None,
help_text="Select Service-Connection authentik should use to manage this outpost. Leave empty if authentik should not handle the deployment.",
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
to="authentik_outposts.outpostserviceconnection",
),
),
migrations.AlterModelOptions(
name="outpostserviceconnection",
options={
"verbose_name": "Outpost Service-Connection",
"verbose_name_plural": "Outpost Service-Connections",
},
),
migrations.AlterField(
model_name="kubernetesserviceconnection",
name="kubeconfig",
field=models.JSONField(
default=None,
help_text="Paste your kubeconfig here. authentik will automatically use the currently selected context.",
),
preserve_default=False,
),
migrations.RemoveField(
model_name="dockerserviceconnection",
name="tls",
),
migrations.AddField(
model_name="dockerserviceconnection",
name="tls_authentication",
field=models.ForeignKey(
blank=True,
default=None,
help_text="Certificate/Key used for authentication. Can be left empty for no authentication.",
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
related_name="+",
to="authentik_crypto.certificatekeypair",
),
),
migrations.AddField(
model_name="dockerserviceconnection",
name="tls_verification",
field=models.ForeignKey(
blank=True,
default=None,
help_text="CA which the endpoint's Certificate is verified against. Can be left empty for no validation.",
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
related_name="+",
to="authentik_crypto.certificatekeypair",
),
),
migrations.AlterField(
model_name="outpostserviceconnection",
name="local",
field=models.BooleanField(
default=False,
help_text="If enabled, use the local connection. Required Docker socket/Kubernetes Integration",
),
),
migrations.RunPython(
code=remove_pb_prefix_users,
),
migrations.RunPython(
code=update_config_prefix,
),
migrations.AlterField(
model_name="dockerserviceconnection",
name="url",
field=models.TextField(
help_text="Can be in the format of 'unix://<path>' when connecting to a local docker daemon, or 'https://<hostname>:2376' when connecting to a remote system."
),
),
migrations.AlterField(
model_name="kubernetesserviceconnection",
name="kubeconfig",
field=models.JSONField(
blank=True,
help_text="Paste your kubeconfig here. authentik will automatically use the currently selected context.",
),
),
migrations.AlterField(
model_name="outpost",
name="type",
field=models.TextField(choices=[("proxy", "Proxy"), ("ldap", "Ldap")], default="proxy"),
),
migrations.AddField(
model_name="outpost",
name="managed",
field=models.TextField(
default=None,
help_text="Objects which are managed by authentik. These objects are created and updated automatically. This is flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update.",
null=True,
unique=True,
verbose_name="Managed by authentik",
),
),
]

View File

@ -74,12 +74,15 @@ class OutpostConfig:
docker_network: Optional[str] = field(default=None)
docker_map_ports: bool = field(default=True)
container_image: Optional[str] = field(default=None)
kubernetes_replicas: int = field(default=1)
kubernetes_namespace: str = field(default_factory=get_namespace)
kubernetes_ingress_annotations: dict[str, str] = field(default_factory=dict)
kubernetes_ingress_secret_name: str = field(default="authentik-outpost-tls")
kubernetes_service_type: str = field(default="ClusterIP")
kubernetes_disabled_components: list[str] = field(default_factory=list)
kubernetes_image_pull_secrets: Optional[list[str]] = field(default_factory=list)
class OutpostModel(Model):

View File

@ -17,7 +17,12 @@ from kubernetes.config.incluster_config import SERVICE_TOKEN_FILENAME
from kubernetes.config.kube_config import KUBE_CONFIG_DEFAULT_LOCATION
from structlog.stdlib import get_logger
from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus
from authentik.events.monitored_tasks import (
MonitoredTask,
TaskResult,
TaskResultStatus,
prefill_task,
)
from authentik.lib.utils.reflection import path_to_class
from authentik.outposts.controllers.base import BaseController, ControllerException
from authentik.outposts.models import (
@ -71,6 +76,7 @@ def outpost_service_connection_state(connection_pk: Any):
@CELERY_APP.task(bind=True, base=MonitoredTask)
@prefill_task()
def outpost_service_connection_monitor(self: MonitoredTask):
"""Regularly check the state of Outpost Service Connections"""
connections = OutpostServiceConnection.objects.all()
@ -120,6 +126,7 @@ def outpost_controller(
@CELERY_APP.task(bind=True, base=MonitoredTask)
@prefill_task()
def outpost_token_ensurer(self: MonitoredTask):
"""Periodically ensure that all Outposts have valid Service Accounts
and Tokens"""

View File

@ -2,6 +2,8 @@
from typing import OrderedDict
from django.core.exceptions import ObjectDoesNotExist
from django_filters.filters import BooleanFilter, ModelMultipleChoiceFilter
from django_filters.filterset import FilterSet
from rest_framework.serializers import ModelSerializer, PrimaryKeyRelatedField, ValidationError
from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger
@ -96,6 +98,22 @@ class PolicyBindingSerializer(ModelSerializer):
return attrs
class PolicyBindingFilter(FilterSet):
"""Filter for PolicyBindings"""
target_in = ModelMultipleChoiceFilter(
field_name="target__pbm_uuid",
to_field_name="pbm_uuid",
queryset=PolicyBindingModel.objects.select_subclasses(),
)
policy__isnull = BooleanFilter("policy", "isnull")
class Meta:
model = PolicyBinding
fields = ["policy", "policy__isnull", "target", "target_in", "enabled", "order", "timeout"]
class PolicyBindingViewSet(UsedByMixin, ModelViewSet):
"""PolicyBinding Viewset"""
@ -105,5 +123,6 @@ class PolicyBindingViewSet(UsedByMixin, ModelViewSet):
.prefetch_related("policy")
) # prefetching policy so we resolve the subclass
serializer_class = PolicyBindingSerializer
filterset_fields = ["policy", "target", "enabled", "order", "timeout"]
search_fields = ["policy__name"]
filterset_class = PolicyBindingFilter
ordering = ["target", "order"]

View File

@ -0,0 +1,173 @@
# Generated by Django 3.2.8 on 2021-10-10 16:11
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
replaces = [
("authentik_policies_event_matcher", "0001_initial"),
("authentik_policies_event_matcher", "0002_auto_20201230_2046"),
("authentik_policies_event_matcher", "0003_auto_20210110_1907"),
("authentik_policies_event_matcher", "0004_auto_20210112_2158"),
("authentik_policies_event_matcher", "0005_auto_20210202_1821"),
("authentik_policies_event_matcher", "0006_auto_20210203_1134"),
("authentik_policies_event_matcher", "0007_auto_20210209_1657"),
("authentik_policies_event_matcher", "0008_auto_20210213_1640"),
("authentik_policies_event_matcher", "0009_auto_20210215_2159"),
("authentik_policies_event_matcher", "0010_auto_20210222_1821"),
("authentik_policies_event_matcher", "0011_auto_20210302_0856"),
("authentik_policies_event_matcher", "0012_auto_20210323_1339"),
("authentik_policies_event_matcher", "0013_alter_eventmatcherpolicy_app"),
("authentik_policies_event_matcher", "0014_alter_eventmatcherpolicy_app"),
("authentik_policies_event_matcher", "0015_alter_eventmatcherpolicy_app"),
("authentik_policies_event_matcher", "0016_alter_eventmatcherpolicy_action"),
("authentik_policies_event_matcher", "0017_alter_eventmatcherpolicy_action"),
("authentik_policies_event_matcher", "0018_alter_eventmatcherpolicy_action"),
]
initial = True
dependencies = [
("authentik_policies", "0004_policy_execution_logging"),
]
operations = [
migrations.CreateModel(
name="EventMatcherPolicy",
fields=[
(
"policy_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_policies.policy",
),
),
(
"action",
models.TextField(
blank=True,
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("secret_view", "Secret View"),
("secret_rotate", "Secret Rotate"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("system_task_execution", "System Task Execution"),
("system_task_exception", "System Task Exception"),
("system_exception", "System Exception"),
("configuration_error", "Configuration Error"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("email_sent", "Email Sent"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
],
help_text="Match created events with this action type. When left empty, all action types will be matched.",
),
),
(
"client_ip",
models.TextField(
blank=True,
help_text="Matches Event's Client IP (strict matching, for network matching use an Expression Policy)",
),
),
(
"app",
models.TextField(
blank=True,
choices=[
("authentik.admin", "authentik Admin"),
("authentik.api", "authentik API"),
("authentik.events", "authentik Events"),
("authentik.crypto", "authentik Crypto"),
("authentik.flows", "authentik Flows"),
("authentik.outposts", "authentik Outpost"),
("authentik.lib", "authentik lib"),
("authentik.policies", "authentik Policies"),
("authentik.policies.dummy", "authentik Policies.Dummy"),
(
"authentik.policies.event_matcher",
"authentik Policies.Event Matcher",
),
("authentik.policies.expiry", "authentik Policies.Expiry"),
("authentik.policies.expression", "authentik Policies.Expression"),
("authentik.policies.hibp", "authentik Policies.HaveIBeenPwned"),
("authentik.policies.password", "authentik Policies.Password"),
("authentik.policies.reputation", "authentik Policies.Reputation"),
("authentik.providers.proxy", "authentik Providers.Proxy"),
("authentik.providers.ldap", "authentik Providers.LDAP"),
("authentik.providers.oauth2", "authentik Providers.OAuth2"),
("authentik.providers.saml", "authentik Providers.SAML"),
("authentik.recovery", "authentik Recovery"),
("authentik.sources.ldap", "authentik Sources.LDAP"),
("authentik.sources.oauth", "authentik Sources.OAuth"),
("authentik.sources.plex", "authentik Sources.Plex"),
("authentik.sources.saml", "authentik Sources.SAML"),
(
"authentik.stages.authenticator_duo",
"authentik Stages.Authenticator.Duo",
),
(
"authentik.stages.authenticator_static",
"authentik Stages.Authenticator.Static",
),
(
"authentik.stages.authenticator_totp",
"authentik Stages.Authenticator.TOTP",
),
(
"authentik.stages.authenticator_validate",
"authentik Stages.Authenticator.Validate",
),
(
"authentik.stages.authenticator_webauthn",
"authentik Stages.Authenticator.WebAuthn",
),
("authentik.stages.captcha", "authentik Stages.Captcha"),
("authentik.stages.consent", "authentik Stages.Consent"),
("authentik.stages.deny", "authentik Stages.Deny"),
("authentik.stages.dummy", "authentik Stages.Dummy"),
("authentik.stages.email", "authentik Stages.Email"),
("authentik.stages.identification", "authentik Stages.Identification"),
("authentik.stages.invitation", "authentik Stages.User Invitation"),
("authentik.stages.password", "authentik Stages.Password"),
("authentik.stages.prompt", "authentik Stages.Prompt"),
("authentik.stages.user_delete", "authentik Stages.User Delete"),
("authentik.stages.user_login", "authentik Stages.User Login"),
("authentik.stages.user_logout", "authentik Stages.User Logout"),
("authentik.stages.user_write", "authentik Stages.User Write"),
("authentik.tenants", "authentik Tenants"),
("authentik.core", "authentik Core"),
("authentik.managed", "authentik Managed"),
],
default="",
help_text="Match events created by selected application. When left empty, all applications are matched.",
),
),
],
options={
"verbose_name": "Event Matcher Policy",
"verbose_name_plural": "Event Matcher Policies",
},
bases=("authentik_policies.policy",),
),
]

View File

@ -0,0 +1,79 @@
# Generated by Django 3.2.8 on 2021-10-09 17:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_policies_event_matcher", "0018_alter_eventmatcherpolicy_action"),
]
operations = [
migrations.AlterField(
model_name="eventmatcherpolicy",
name="app",
field=models.TextField(
blank=True,
choices=[
("authentik.admin", "authentik Admin"),
("authentik.api", "authentik API"),
("authentik.crypto", "authentik Crypto"),
("authentik.events", "authentik Events"),
("authentik.flows", "authentik Flows"),
("authentik.lib", "authentik lib"),
("authentik.outposts", "authentik Outpost"),
("authentik.policies.dummy", "authentik Policies.Dummy"),
("authentik.policies.event_matcher", "authentik Policies.Event Matcher"),
("authentik.policies.expiry", "authentik Policies.Expiry"),
("authentik.policies.expression", "authentik Policies.Expression"),
("authentik.policies.hibp", "authentik Policies.HaveIBeenPwned"),
("authentik.policies.password", "authentik Policies.Password"),
("authentik.policies.reputation", "authentik Policies.Reputation"),
("authentik.policies", "authentik Policies"),
("authentik.providers.ldap", "authentik Providers.LDAP"),
("authentik.providers.oauth2", "authentik Providers.OAuth2"),
("authentik.providers.proxy", "authentik Providers.Proxy"),
("authentik.providers.saml", "authentik Providers.SAML"),
("authentik.recovery", "authentik Recovery"),
("authentik.sources.ldap", "authentik Sources.LDAP"),
("authentik.sources.oauth", "authentik Sources.OAuth"),
("authentik.sources.plex", "authentik Sources.Plex"),
("authentik.sources.saml", "authentik Sources.SAML"),
("authentik.stages.authenticator_duo", "authentik Stages.Authenticator.Duo"),
("authentik.stages.authenticator_sms", "authentik Stages.Authenticator.SMS"),
(
"authentik.stages.authenticator_static",
"authentik Stages.Authenticator.Static",
),
("authentik.stages.authenticator_totp", "authentik Stages.Authenticator.TOTP"),
(
"authentik.stages.authenticator_validate",
"authentik Stages.Authenticator.Validate",
),
(
"authentik.stages.authenticator_webauthn",
"authentik Stages.Authenticator.WebAuthn",
),
("authentik.stages.captcha", "authentik Stages.Captcha"),
("authentik.stages.consent", "authentik Stages.Consent"),
("authentik.stages.deny", "authentik Stages.Deny"),
("authentik.stages.dummy", "authentik Stages.Dummy"),
("authentik.stages.email", "authentik Stages.Email"),
("authentik.stages.identification", "authentik Stages.Identification"),
("authentik.stages.invitation", "authentik Stages.User Invitation"),
("authentik.stages.password", "authentik Stages.Password"),
("authentik.stages.prompt", "authentik Stages.Prompt"),
("authentik.stages.user_delete", "authentik Stages.User Delete"),
("authentik.stages.user_login", "authentik Stages.User Login"),
("authentik.stages.user_logout", "authentik Stages.User Logout"),
("authentik.stages.user_write", "authentik Stages.User Write"),
("authentik.tenants", "authentik Tenants"),
("authentik.core", "authentik Core"),
("authentik.managed", "authentik Managed"),
],
default="",
help_text="Match events created by selected application. When left empty, all applications are matched.",
),
),
]

View File

@ -65,14 +65,14 @@ class PolicyBinding(SerializerModel):
# This is quite an ugly hack to prevent pylint from trying
# to resolve authentik_core.models.Group
# as python import path
"authentik_core." + "Group",
"authentik_core.Group",
on_delete=models.CASCADE,
default=None,
null=True,
blank=True,
)
user = models.ForeignKey(
"authentik_core." + "User",
"authentik_core.User",
on_delete=models.CASCADE,
default=None,
null=True,
@ -96,7 +96,7 @@ class PolicyBinding(SerializerModel):
self.policy: Policy
return self.policy.passes(request)
if self.group:
return PolicyResult(self.group.users.filter(pk=request.user.pk).exists())
return PolicyResult(self.group.is_member(request.user))
if self.user:
return PolicyResult(request.user == self.user)
return PolicyResult(False)

View File

@ -65,6 +65,7 @@ class TestPasswordPolicyFlow(APITestCase):
"placeholder": "PASSWORD_PLACEHOLDER",
"required": True,
"type": "password",
"sub_text": "",
}
],
"flow_info": {

View File

@ -2,7 +2,12 @@
from django.core.cache import cache
from structlog.stdlib import get_logger
from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus
from authentik.events.monitored_tasks import (
MonitoredTask,
TaskResult,
TaskResultStatus,
prefill_task,
)
from authentik.policies.reputation.models import IPReputation, UserReputation
from authentik.policies.reputation.signals import CACHE_KEY_IP_PREFIX, CACHE_KEY_USER_PREFIX
from authentik.root.celery import CELERY_APP
@ -11,6 +16,7 @@ LOGGER = get_logger()
@CELERY_APP.task(bind=True, base=MonitoredTask)
@prefill_task()
def save_ip_reputation(self: MonitoredTask):
"""Save currently cached reputation to database"""
objects_to_update = []
@ -24,6 +30,7 @@ def save_ip_reputation(self: MonitoredTask):
@CELERY_APP.task(bind=True, base=MonitoredTask)
@prefill_task()
def save_user_reputation(self: MonitoredTask):
"""Save currently cached reputation to database"""
objects_to_update = []

View File

@ -10,7 +10,7 @@ from django.views.generic.base import View
from structlog.stdlib import get_logger
from authentik.core.models import Application, Provider, User
from authentik.flows.views import SESSION_KEY_APPLICATION_PRE
from authentik.flows.views.executor import SESSION_KEY_APPLICATION_PRE
from authentik.lib.sentry import SentryIgnoredException
from authentik.policies.denied import AccessDeniedResponse
from authentik.policies.engine import PolicyEngine

View File

@ -1,5 +1,5 @@
"""LDAPProvider API Views"""
from rest_framework.fields import CharField
from rest_framework.fields import CharField, ListField
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
@ -11,6 +11,8 @@ from authentik.providers.ldap.models import LDAPProvider
class LDAPProviderSerializer(ProviderSerializer):
"""LDAPProvider Serializer"""
outpost_set = ListField(child=CharField(), read_only=True, source="outpost_set.all")
class Meta:
model = LDAPProvider
@ -21,6 +23,8 @@ class LDAPProviderSerializer(ProviderSerializer):
"tls_server_name",
"uid_start_number",
"gid_start_number",
"outpost_set",
"search_mode",
]
@ -65,6 +69,7 @@ class LDAPOutpostConfigSerializer(ModelSerializer):
"tls_server_name",
"uid_start_number",
"gid_start_number",
"search_mode",
]

View File

@ -0,0 +1,93 @@
# Generated by Django 3.2.8 on 2021-11-05 09:41
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
replaces = [
("authentik_providers_ldap", "0001_initial"),
("authentik_providers_ldap", "0002_ldapprovider_search_group"),
("authentik_providers_ldap", "0003_auto_20210713_1138"),
("authentik_providers_ldap", "0004_auto_20210713_2115"),
("authentik_providers_ldap", "0005_ldapprovider_search_mode"),
]
initial = True
dependencies = [
("authentik_core", "0019_source_managed"),
("authentik_crypto", "0002_create_self_signed_kp"),
]
operations = [
migrations.CreateModel(
name="LDAPProvider",
fields=[
(
"provider_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_core.provider",
),
),
(
"base_dn",
models.TextField(
default="DC=ldap,DC=goauthentik,DC=io",
help_text="DN under which objects are accessible.",
),
),
(
"search_group",
models.ForeignKey(
default=None,
help_text="Users in this group can do search queries. If not set, every user can execute search queries.",
null=True,
on_delete=django.db.models.deletion.SET_DEFAULT,
to="authentik_core.group",
),
),
(
"certificate",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="authentik_crypto.certificatekeypair",
),
),
("tls_server_name", models.TextField(blank=True, default="")),
(
"gid_start_number",
models.IntegerField(
default=4000,
help_text="The start for gidNumbers, this number is added to a number generated from the group.Pk to make sure that the numbers aren't too low for POSIX groups. Default is 4000 to ensure that we don't collide with local groups or users primary groups gidNumber",
),
),
(
"uid_start_number",
models.IntegerField(
default=2000,
help_text="The start for uidNumbers, this number is added to the user.Pk to make sure that the numbers aren't too low for POSIX users. Default is 2000 to ensure that we don't collide with local users uidNumber",
),
),
(
"search_mode",
models.TextField(
choices=[("direct", "Direct"), ("cached", "Cached")], default="direct"
),
),
],
options={
"verbose_name": "LDAP Provider",
"verbose_name_plural": "LDAP Providers",
},
bases=("authentik_core.provider", models.Model),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.8 on 2021-11-05 09:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_ldap", "0004_auto_20210713_2115"),
]
operations = [
migrations.AddField(
model_name="ldapprovider",
name="search_mode",
field=models.TextField(
choices=[("direct", "Direct"), ("cached", "Cached")], default="direct"
),
),
]

View File

@ -10,6 +10,13 @@ from authentik.crypto.models import CertificateKeyPair
from authentik.outposts.models import OutpostModel
class SearchModes(models.TextChoices):
"""Search modes"""
DIRECT = "direct"
CACHED = "cached"
class LDAPProvider(OutpostModel, Provider):
"""Allow applications to authenticate against authentik's users using LDAP."""
@ -59,6 +66,8 @@ class LDAPProvider(OutpostModel, Provider):
),
)
search_mode = models.TextField(default=SearchModes.DIRECT, choices=SearchModes.choices)
@property
def launch_url(self) -> Optional[str]:
"""LDAP never has a launch URL"""

View File

@ -0,0 +1,128 @@
# Generated by Django 3.2.8 on 2021-10-10 16:24
import django.db.models.deletion
from django.apps.registry import Apps
from django.db import migrations, models
import authentik.lib.utils.time
scope_uid_map = {
"openid": "goauthentik.io/providers/oauth2/scope-openid",
"email": "goauthentik.io/providers/oauth2/scope-email",
"profile": "goauthentik.io/providers/oauth2/scope-profile",
"ak_proxy": "goauthentik.io/providers/proxy/scope-proxy",
}
def set_managed_flag(apps: Apps, schema_editor):
ScopeMapping = apps.get_model("authentik_providers_oauth2", "ScopeMapping")
db_alias = schema_editor.connection.alias
for mapping in ScopeMapping.objects.using(db_alias).filter(name__startswith="Autogenerated "):
mapping.managed = scope_uid_map[mapping.scope_name]
mapping.save()
class Migration(migrations.Migration):
replaces = [
("authentik_providers_oauth2", "0007_auto_20201016_1107"),
("authentik_providers_oauth2", "0008_oauth2provider_issuer_mode"),
("authentik_providers_oauth2", "0009_remove_oauth2provider_response_type"),
("authentik_providers_oauth2", "0010_auto_20201227_1804"),
("authentik_providers_oauth2", "0011_managed"),
("authentik_providers_oauth2", "0012_oauth2provider_access_code_validity"),
("authentik_providers_oauth2", "0013_alter_authorizationcode_nonce"),
("authentik_providers_oauth2", "0014_alter_oauth2provider_rsa_key"),
("authentik_providers_oauth2", "0015_auto_20210703_1313"),
("authentik_providers_oauth2", "0016_alter_authorizationcode_nonce"),
("authentik_providers_oauth2", "0017_alter_oauth2provider_token_validity"),
]
dependencies = [
("authentik_core", "0017_managed"),
("authentik_crypto", "0002_create_self_signed_kp"),
("authentik_providers_oauth2", "0006_remove_oauth2provider_name"),
]
operations = [
migrations.AlterModelOptions(
name="refreshtoken",
options={"verbose_name": "OAuth2 Token", "verbose_name_plural": "OAuth2 Tokens"},
),
migrations.AddField(
model_name="oauth2provider",
name="issuer_mode",
field=models.TextField(
choices=[
("global", "Same identifier is used for all providers"),
(
"per_provider",
"Each provider has a different issuer, based on the application slug.",
),
],
default="per_provider",
help_text="Configure how the issuer field of the ID Token should be filled.",
),
),
migrations.RemoveField(
model_name="oauth2provider",
name="response_type",
),
migrations.AlterField(
model_name="refreshtoken",
name="access_token",
field=models.TextField(verbose_name="Access Token"),
),
migrations.RunPython(
code=set_managed_flag,
),
migrations.AddField(
model_name="oauth2provider",
name="access_code_validity",
field=models.TextField(
default="minutes=1",
help_text="Access codes not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).",
validators=[authentik.lib.utils.time.timedelta_string_validator],
),
),
migrations.AlterField(
model_name="authorizationcode",
name="nonce",
field=models.TextField(blank=True, default="", verbose_name="Nonce"),
),
migrations.AlterField(
model_name="oauth2provider",
name="rsa_key",
field=models.ForeignKey(
help_text="Key used to sign the tokens. Only required when JWT Algorithm is set to RS256.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="authentik_crypto.certificatekeypair",
verbose_name="RSA Key",
),
),
migrations.AddField(
model_name="authorizationcode",
name="revoked",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="refreshtoken",
name="revoked",
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name="authorizationcode",
name="nonce",
field=models.TextField(default=None, null=True, verbose_name="Nonce"),
),
migrations.AlterField(
model_name="oauth2provider",
name="token_validity",
field=models.TextField(
default="days=30",
help_text="Tokens not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).",
validators=[authentik.lib.utils.time.timedelta_string_validator],
),
),
]

View File

@ -448,7 +448,7 @@ class RefreshToken(ExpiringModel, BaseGrantModel):
elif self.provider.sub_mode == SubModes.USER_USERNAME:
sub = user.username
elif self.provider.sub_mode == SubModes.USER_UPN:
sub = user.attributes["upn"]
sub = user.attributes.get("upn", user.uid)
else:
raise ValueError(
(

View File

@ -23,7 +23,7 @@ from authentik.flows.planner import (
FlowPlanner,
)
from authentik.flows.stage import StageView
from authentik.flows.views import SESSION_KEY_PLAN
from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.lib.utils.time import timedelta_from_string
from authentik.lib.utils.urls import redirect_with_qs
from authentik.lib.views import bad_request_message
@ -386,6 +386,9 @@ class AuthorizationFlowInitView(PolicyAccessView):
def pre_permission_check(self):
"""Check prompt parameter before checking permission/authentication,
see https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.6"""
# Quick sanity check at the beginning to prevent event spamming
if len(self.request.GET) < 1:
raise Http404
try:
self.params = OAuthAuthorizationParams.from_request(self.request)
except AuthorizeError as error:

View File

@ -11,6 +11,7 @@ from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer
from authentik.lib.utils.time import timedelta_from_string
from authentik.providers.oauth2.models import ScopeMapping
from authentik.providers.oauth2.views.provider import ProviderInfoView
from authentik.providers.proxy.models import ProxyMode, ProxyProvider
@ -36,6 +37,7 @@ class ProxyProviderSerializer(ProviderSerializer):
"""ProxyProvider Serializer"""
redirect_uris = CharField(read_only=True)
outpost_set = ListField(child=CharField(), read_only=True, source="outpost_set.all")
def validate(self, attrs) -> dict[Any, str]:
"""Check that internal_host is set when mode is Proxy"""
@ -74,6 +76,7 @@ class ProxyProviderSerializer(ProviderSerializer):
"redirect_uris",
"cookie_domain",
"token_validity",
"outpost_set",
]
@ -108,6 +111,7 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
oidc_configuration = SerializerMethodField()
token_validity = SerializerMethodField()
scopes_to_request = SerializerMethodField()
@extend_schema_field(OpenIDConnectConfigurationSerializer)
def get_oidc_configuration(self, obj: ProxyProvider):
@ -118,6 +122,14 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
"""Get token validity as second count"""
return timedelta_from_string(obj.token_validity).total_seconds()
def get_scopes_to_request(self, obj: ProxyProvider) -> list[str]:
"""Get all the scope names the outpost should request,
including custom-defined ones"""
scope_names = set(
ScopeMapping.objects.filter(provider__in=[obj]).values_list("scope_name", flat=True)
)
return list(scope_names)
class Meta:
model = ProxyProvider
@ -139,6 +151,7 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
"mode",
"cookie_domain",
"token_validity",
"scopes_to_request",
]

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