Compare commits

...

112 Commits

Author SHA1 Message Date
941bc61b31 release: 2021.9.3 2021-09-27 17:31:50 +02:00
282b364606 stages/prompt: fix inconsistent policy context for validation policies
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-27 17:05:26 +02:00
ad4bc4083d website/docs: update dev docs
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-27 16:04:41 +02:00
ebe282eb1a web/admin: fix user_write form not writing group
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-27 10:12:45 +02:00
830c26ca25 tests/e2e: fix linting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-27 09:52:47 +02:00
ed3b4a3d4a build(deps): bump rapidoc from 9.1.2 to 9.1.3 in /website (#1478)
Bumps [rapidoc](https://github.com/mrin9/RapiDoc) from 9.1.2 to 9.1.3.
- [Release notes](https://github.com/mrin9/RapiDoc/releases)
- [Commits](https://github.com/mrin9/RapiDoc/compare/v9.1.2...v9.1.3)

---
updated-dependencies:
- dependency-name: rapidoc
  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-09-27 09:24:43 +02:00
975c4ddc04 build(deps): bump postcss from 8.3.7 to 8.3.8 in /website (#1479)
Bumps [postcss](https://github.com/postcss/postcss) from 8.3.7 to 8.3.8.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.3.7...8.3.8)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-27 09:22:49 +02:00
7e2896298a build(deps): bump rapidoc from 9.1.2 to 9.1.3 in /web (#1480)
Bumps [rapidoc](https://github.com/mrin9/RapiDoc) from 9.1.2 to 9.1.3.
- [Release notes](https://github.com/mrin9/RapiDoc/releases)
- [Commits](https://github.com/mrin9/RapiDoc/compare/v9.1.2...v9.1.3)

---
updated-dependencies:
- dependency-name: rapidoc
  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-09-27 09:22:31 +02:00
cba9cf8361 build(deps): bump actions/github-script from 4.1 to 5 (#1481)
Bumps [actions/github-script](https://github.com/actions/github-script) from 4.1 to 5.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v4.1...v5)

---
updated-dependencies:
- dependency-name: actions/github-script
  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-09-27 09:22:21 +02:00
bf12580f64 build(deps): bump pycryptodome from 3.10.3 to 3.10.4 (#1482)
Bumps [pycryptodome](https://github.com/Legrandin/pycryptodome) from 3.10.3 to 3.10.4.
- [Release notes](https://github.com/Legrandin/pycryptodome/releases)
- [Changelog](https://github.com/Legrandin/pycryptodome/blob/master/Changelog.rst)
- [Commits](https://github.com/Legrandin/pycryptodome/commits/v3.10.4)

---
updated-dependencies:
- dependency-name: pycryptodome
  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-09-27 09:22:03 +02:00
75ef4ce596 tests/e2e: add new ldap object classes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 14:57:42 +02:00
c2f3ce11b0 outposts/ldap: fix potential panic when converting attributes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 14:52:25 +02:00
3c256fecc6 outposts/ldap: add groupofuniquenames
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 14:49:11 +02:00
0285b84133 outposts/ldap: add query support for all supported object classes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 14:42:26 +02:00
99a371a02c web/elements: fix token copy button not working on chrome...
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 14:34:28 +02:00
c7e6eb8896 outposts/ldap: add support for base scope and domain info
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 14:01:22 +02:00
674bd9e05c web/admin: Fix typo 'username address' -> 'username' (#1473) 2021-09-26 12:53:37 +02:00
b79901df87 website/docs: prepare 2021.9.3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 12:03:10 +02:00
b248f450dd outposts: make AUTHENTIK_HOST_BROWSER configurable from central config
closes #1471

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 12:00:51 +02:00
05db9e5c40 web/admin: handle error correctly when creating user recovery link
closes #1472

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 11:49:40 +02:00
234a5e2b66 outposts: fix outposts not correctly updating central state
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-26 11:40:21 +02:00
aea1736f70 outposts/proxy: Fix failing traefik healtcheck (#1470) 2021-09-26 11:33:18 +02:00
9f4a4449f5 outposts/proxy: ensure cookies only last as long as tokens
closes #1462

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-25 16:12:59 +02:00
b6b55e2336 build(deps): bump goauthentik.io/api from 0.202192.3 to 0.202192.5 (#1468)
Bumps [goauthentik.io/api](https://github.com/goauthentik/client-go) from 0.202192.3 to 0.202192.5.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v0.202192.3...v0.202192.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-09-25 16:06:10 +02:00
8f2805e05b web: Update Web API Client version (#1467)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-25 16:04:07 +02:00
4f3583cd7e providers/proxy: make token_validity float and optional for backwards compat
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-25 15:54:32 +02:00
617e90dca3 web: Update Web API Client version (#1465)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-25 15:48:05 +02:00
f7408626a8 providers/proxy: return token_validity as total seconds instead of expression
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-25 15:44:16 +02:00
4dcb15af46 build(deps): bump goauthentik.io/api from 0.202192.1 to 0.202192.3 (#1464)
Bumps [goauthentik.io/api](https://github.com/goauthentik/client-go) from 0.202192.1 to 0.202192.3.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v0.202192.1...v0.202192.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-09-25 15:11:08 +02:00
89beb7a9f7 web: Update Web API Client version (#1463)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-25 15:02:33 +02:00
28eeb4798e providers/proxy: add token_validity field for outpost configuration
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#1462
2021-09-25 15:00:06 +02:00
79b92e764e *: fix typos in code
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-25 00:01:11 +02:00
919336a519 outposts: ensure service is always re-created with mismatching ports
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-24 23:45:15 +02:00
27e04589c1 outposts/proxyv2: fix routing not working correctly for domain auth
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-24 23:32:16 +02:00
ba44fbdac8 website/docs: fix typos and grammar (#1459) 2021-09-24 15:37:54 +02:00
0e093a8917 web: Update Web API Client version (#1458) 2021-09-24 12:23:14 +02:00
d0bfb99859 web/elements: improve error handling on forms
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-24 12:19:56 +02:00
93bdea3769 core: fix api return code for user self-update
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-24 11:51:03 +02:00
e681654af7 web/admin: add notice for recovery
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-24 11:50:52 +02:00
cab7593dca web/user: fix brand not being shown in safari
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-24 11:50:46 +02:00
cf92f9aefc web/elements: fix token copy error in safari
closes #1219

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-24 10:44:28 +02:00
8d72b3498d internal: fix typo
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-24 10:44:28 +02:00
42ab858c50 build(deps): bump goauthentik.io/api from 0.202191.4 to 0.202192.1 (#1455)
Bumps [goauthentik.io/api](https://github.com/goauthentik/client-go) from 0.202191.4 to 0.202192.1.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v0.202191.4...v0.202192.1)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-24 09:34:10 +02:00
a1abae9ab1 build(deps): bump boto3 from 1.18.46 to 1.18.47 (#1456)
Bumps [boto3](https://github.com/boto/boto3) from 1.18.46 to 1.18.47.
- [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.46...1.18.47)

---
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-09-24 09:34:01 +02:00
8f36b49061 web/user: search apps when user typed before apps have loaded
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-23 16:34:11 +02:00
64b4e851ce events: add additional validation for event transport
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-23 16:29:58 +02:00
40a62ac1e5 web/admin: fix Transport Form not loading mode correctly on edit
closes #1453

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-23 16:16:38 +02:00
5df60e4d87 web/admin: fix NotificationWebhookMapping not loading correctly
closes #1452

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-23 16:13:58 +02:00
50ebc8522d web: Update Web API Client version (#1454)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-23 14:21:49 +02:00
eddca478dc release: 2021.9.2 2021-09-23 12:34:02 +02:00
99a7fca08e website/docs: prepare 2021.9.2
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-23 12:33:42 +02:00
a7e3602908 web: fix import order of polyfills causing shadydom to not work on firefox and safari
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-23 10:16:49 +02:00
74169860cf api: add logging to sentry proxy
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-23 09:57:42 +02:00
52bb774f73 internal: add asset paths for user interface
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-23 09:57:24 +02:00
f26fcaf825 website/docs: add warning for example flows (#1444) 2021-09-23 08:34:40 +02:00
b8e92e2f11 build(deps): bump postcss from 8.3.6 to 8.3.7 in /website (#1445) 2021-09-23 08:33:27 +02:00
08adfc94d6 build(deps): bump rollup from 2.56.3 to 2.57.0 in /web (#1446) 2021-09-23 08:33:18 +02:00
236fafb735 build(deps): bump boto3 from 1.18.45 to 1.18.46 (#1447) 2021-09-23 08:33:10 +02:00
5ad9ddee3c build(deps): bump goauthentik.io/api from 0.202191.3 to 0.202191.4 (#1449) 2021-09-23 08:33:01 +02:00
24d220ff49 build(deps): bump urllib3 from 1.26.6 to 1.26.7 (#1448) 2021-09-23 08:32:53 +02:00
3364c195b7 build(deps): bump sentry-sdk from 1.4.0 to 1.4.1 (#1450) 2021-09-23 08:32:43 +02:00
50aa87d141 web/user: enable sentry
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-22 22:35:52 +02:00
72b375023d web: Update Web API Client version (#1443)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-22 20:53:25 +02:00
77ba186818 website/docs: add notice for guacamole token length
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-22 20:02:30 +02:00
2fe6de0505 release: 2021.9.1 2021-09-22 19:11:20 +02:00
bf9e969b53 website/docs: prepare 2021.9.1
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-22 18:58:52 +02:00
184f119b16 website: set use_global_settings to true for example flows with email stages
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-22 18:52:55 +02:00
ebc06f1abe outposts/ldap: fix logic error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-22 13:19:50 +02:00
0f8880ab0a outposts: fix typo
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-22 13:14:28 +02:00
ee56da5092 build(deps): bump @sentry/tracing from 6.13.1 to 6.13.2 in /web (#1438) 2021-09-22 07:32:40 +02:00
2152004502 build(deps): bump @types/codemirror from 5.60.2 to 5.60.3 in /web (#1437) 2021-09-22 07:30:35 +02:00
45d0b80d02 build(deps): bump @sentry/browser from 6.13.1 to 6.13.2 in /web (#1439) 2021-09-22 07:30:27 +02:00
96065eb942 build(deps): bump boto3 from 1.18.44 to 1.18.45 (#1441) 2021-09-22 07:30:01 +02:00
ac944fee8b build(deps): bump drf-spectacular from 0.18.2 to 0.19.0 (#1442) 2021-09-22 07:29:52 +02:00
1d0e5fc353 build(deps): bump sentry-sdk from 1.3.1 to 1.4.0 (#1440) 2021-09-22 07:28:48 +02:00
1f97420207 outposts/ldap: allow custom attributes to shadow built-in attributes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-21 21:59:39 +02:00
ae07f13a87 outposts: don't map port 9300 on docker, only expose port
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-21 21:40:08 +02:00
0aec504170 website/docs: add ssl port for ldap
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-21 15:44:05 +02:00
3b4c9bcc57 root: use tagged go client version
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-21 15:42:07 +02:00
5182a6741e root: format pyproject
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-21 13:32:28 +02:00
da7635ae5c web: sort imports
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-21 11:33:51 +02:00
a92a0fb60a web: migrate to lit 2
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-21 11:19:26 +02:00
cb10c1753b build(deps): bump lit-html from 1.4.1 to 2.0.0 in /web (#1427) 2021-09-21 08:35:36 +02:00
ae654bd4c8 build(deps): bump lit-element from 2.5.1 to 3.0.0 in /web (#1433) 2021-09-21 08:32:15 +02:00
28192655ec build(deps): bump @typescript-eslint/eslint-plugin in /web (#1426) 2021-09-21 08:32:00 +02:00
9582294eb8 build(deps): bump @sentry/tracing from 6.12.0 to 6.13.1 in /web (#1428) 2021-09-21 08:31:48 +02:00
0172430d7d build(deps): bump @patternfly/patternfly from 4.132.2 to 4.135.2 in /web (#1429) 2021-09-21 08:30:44 +02:00
1454b65933 build(deps): bump @typescript-eslint/parser in /web (#1430) 2021-09-21 08:30:36 +02:00
432a7792e2 build(deps): bump @sentry/browser from 6.12.0 to 6.13.1 in /web (#1431) 2021-09-21 08:30:28 +02:00
54069618b4 build(deps): bump codemirror from 5.62.3 to 5.63.0 in /web (#1432) 2021-09-21 08:30:20 +02:00
81feb313df build(deps): bump geoip2 from 4.2.0 to 4.3.0 (#1434) 2021-09-21 08:29:33 +02:00
e6b275add3 stages/invitation: fix linting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 20:41:05 +02:00
27016a5527 stages/invitation: fix tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 20:30:51 +02:00
4c29d517f0 stages/email: use different query arguments for email and invitation tokens
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 19:55:53 +02:00
180d27cc37 outposts: don't restart container when health checks are starting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 19:46:05 +02:00
5a8b356dc7 web: fix css for dark mode
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 19:38:25 +02:00
3195640776 stages/email: slugify token identifier
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 19:26:25 +02:00
f463296d47 web: Update Web API Client version (#1421)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-20 19:22:46 +02:00
adf4b23c01 website/docs: add /akprox for nginx auth_request (#1420) 2021-09-20 19:21:30 +02:00
d900a2b6a9 *: fix lookup_fields
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 19:19:36 +02:00
95a2fddfa8 policies/expression: add ak_user_has_authenticator
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 19:13:41 +02:00
8f7d21b692 stages/email: don't throw 404 when token can't be found
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 19:01:25 +02:00
3f84abec2f core: fix token identifier not being slugified when created with user-controller input
closes #1390

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 13:43:25 +02:00
b5c857aff4 api: add explicit lookup_value_regex, disable include_format_suffixes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 13:42:56 +02:00
f8dee09107 web/user: allow customisable background colour
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 12:49:17 +02:00
84a800583c web/user: make search configurable
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-20 12:15:53 +02:00
88de94f014 build(deps): bump rapidoc from 9.1.0 to 9.1.2 in /website (#1418)
Bumps [rapidoc](https://github.com/mrin9/RapiDoc) from 9.1.0 to 9.1.2.
- [Release notes](https://github.com/mrin9/RapiDoc/releases)
- [Commits](https://github.com/mrin9/RapiDoc/compare/v9.1.0...v9.1.2)

---
updated-dependencies:
- dependency-name: rapidoc
  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-09-20 11:50:38 +02:00
25549ec339 build(deps): bump rapidoc from 9.1.0 to 9.1.2 in /web (#1419)
Bumps [rapidoc](https://github.com/mrin9/RapiDoc) from 9.1.0 to 9.1.2.
- [Release notes](https://github.com/mrin9/RapiDoc/releases)
- [Commits](https://github.com/mrin9/RapiDoc/compare/v9.1.0...v9.1.2)

---
updated-dependencies:
- dependency-name: rapidoc
  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-09-20 11:50:27 +02:00
fe4923bff6 build(deps): bump boto3 from 1.18.43 to 1.18.44 (#1417)
Bumps [boto3](https://github.com/boto/boto3) from 1.18.43 to 1.18.44.
- [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.43...1.18.44)

---
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-09-20 09:09:22 +02:00
bb1a0b6bd2 web: Update Web API Client version (#1416)
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2021-09-19 22:32:38 +02:00
879b5ead71 web: fix notification badge not refreshing after clearing notifications
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-19 21:58:59 +02:00
1670ec9167 website/docs: update 2021.9.1-rc3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-09-19 21:55:21 +02:00
338 changed files with 3951 additions and 2650 deletions

View File

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

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

@ -0,0 +1 @@
keypair

View File

@ -33,14 +33,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik:2021.9.1-rc3,
beryju/authentik:2021.9.3,
beryju/authentik:latest,
ghcr.io/goauthentik/server:2021.9.1-rc3,
ghcr.io/goauthentik/server:2021.9.3,
ghcr.io/goauthentik/server:latest
platforms: linux/amd64,linux/arm64
context: .
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.9.1-rc3', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.9.3', 'rc') }}
run: |
docker pull beryju/authentik:latest
docker tag beryju/authentik:latest beryju/authentik:stable
@ -75,14 +75,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-proxy:2021.9.1-rc3,
beryju/authentik-proxy:2021.9.3,
beryju/authentik-proxy:latest,
ghcr.io/goauthentik/proxy:2021.9.1-rc3,
ghcr.io/goauthentik/proxy:2021.9.3,
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.1-rc3', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.9.3', 'rc') }}
run: |
docker pull beryju/authentik-proxy:latest
docker tag beryju/authentik-proxy:latest beryju/authentik-proxy:stable
@ -117,14 +117,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-ldap:2021.9.1-rc3,
beryju/authentik-ldap:2021.9.3,
beryju/authentik-ldap:latest,
ghcr.io/goauthentik/ldap:2021.9.1-rc3,
ghcr.io/goauthentik/ldap:2021.9.3,
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.1-rc3', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.9.3', 'rc') }}
run: |
docker pull beryju/authentik-ldap:latest
docker tag beryju/authentik-ldap:latest beryju/authentik-ldap:stable
@ -175,7 +175,7 @@ jobs:
SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org
with:
version: authentik@2021.9.1-rc3
version: authentik@2021.9.3
environment: beryjuorg-prod
sourcemaps: './web/dist'
url_prefix: '~/static/dist'

View File

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

View File

@ -20,6 +20,11 @@ test:
lint-fix:
isort authentik tests lifecycle
black authentik tests lifecycle
codespell -I .github/codespell-words.txt -w authentik
codespell -I .github/codespell-words.txt -w internal
codespell -I .github/codespell-words.txt -w cmd
codespell -I .github/codespell-words.txt -w web/src
codespell -I .github/codespell-words.txt -w website/src
lint:
pyright authentik tests lifecycle

View File

@ -48,6 +48,7 @@ duo-client = "*"
ua-parser = "*"
deepmerge = "*"
colorama = "*"
codespell = "*"
[dev-packages]
bandit = "*"

236
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "19d5324fd1a4af125ed57a683030ca14ee2d3648117748e4b32656875484728e"
"sha256": "babb6061c555f8f239f00210b2a0356763bdaaca2f3d704cf3444891b84db84d"
},
"pipfile-spec": 6,
"requires": {},
@ -120,19 +120,19 @@
},
"boto3": {
"hashes": [
"sha256:9b6679e3c54f8c32c09872948450ece87473cbc830cfd6c84dad58eb014329ba",
"sha256:caa96b7c2be2168b6efc25ab1fb61c996174bcfbcab21b5f642608185daa6403"
"sha256:7b45b224442c479de4bc6e6e9cb0557b642fc7a77edc8702e393ccaa2e0aa128",
"sha256:c388da7dc1a596755f39de990a72e05cee558d098e81de63de55bd9598cc5134"
],
"index": "pypi",
"version": "==1.18.43"
"version": "==1.18.48"
},
"botocore": {
"hashes": [
"sha256:b74d0a5fe0f7b73fa4b5670eaa9ff456b0bce70966d478dcd631c91458916eb6",
"sha256:de7bf9c9098578d386b785b5b6eab954acccd3f79fe3e2eb971da608c967082b"
"sha256:2c25a76f09223b2f00ad578df34492b7b84cd4828fc90c08ccbdd1d70abbd7eb",
"sha256:9d5b70be2f417d0aa30788049fd20473ad27218eccd05e71f545b4b4e09c79a0"
],
"markers": "python_version >= '3.6'",
"version": "==1.21.43"
"version": "==1.21.48"
},
"cachetools": {
"hashes": [
@ -252,11 +252,11 @@
},
"charset-normalizer": {
"hashes": [
"sha256:7098e7e862f6370a2a8d1a6398cd359815c45d12626267652c3f13dec58e2367",
"sha256:fa471a601dfea0f492e4f4fca035cd82155e65dc45c9b83bf4322dfab63755dd"
"sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6",
"sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"
],
"markers": "python_version >= '3'",
"version": "==2.0.5"
"version": "==2.0.6"
},
"click": {
"hashes": [
@ -286,6 +286,14 @@
],
"version": "==0.2.0"
},
"codespell": {
"hashes": [
"sha256:19d3fe5644fef3425777e66f225a8c82d39059dcfe9edb3349a8a2cf48383ee5",
"sha256:b864c7d917316316ac24272ee992d7937c3519be4569209c5b60035ac5d569b5"
],
"index": "pypi",
"version": "==2.1.0"
},
"colorama": {
"hashes": [
"sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b",
@ -308,8 +316,10 @@
"sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7",
"sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085",
"sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc",
"sha256:3c4129fc3fdc0fa8e40861b5ac0c673315b3c902bbdc05fc176764815b43dd1d",
"sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a",
"sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498",
"sha256:695104a9223a7239d155d7627ad912953b540929ef97ae0c34c7b8bf30857e89",
"sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9",
"sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c",
"sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7",
@ -369,11 +379,11 @@
},
"django-filter": {
"hashes": [
"sha256:84e9d5bb93f237e451db814ed422a3a625751cbc9968b484ecc74964a8696b06",
"sha256:e00d32cebdb3d54273c48f4f878f898dced8d5dfaad009438fe61ebdf535ace1"
"sha256:632a251fa8f1aadb4b8cceff932bb52fe2f826dd7dfe7f3eac40e5c463d6836e",
"sha256:f4a6737a30104c98d2e2a5fb93043f36dd7978e0c7ddc92f5998e85433ea5063"
],
"index": "pypi",
"version": "==2.4.0"
"version": "==21.1"
},
"django-guardian": {
"hashes": [
@ -449,11 +459,11 @@
},
"drf-spectacular": {
"hashes": [
"sha256:47ef6ec8ff48ac8aede6ec12450a55fee381cf84de969ef1724dcde5a93de6b8",
"sha256:d746b936cb4cddec380ea95bf91de6a6721777dfc42e0eea53b83c61a625e94e"
"sha256:65df818226477cdfa629947ea52bc0cc13eb40550b192eeccec64a6b782651fd",
"sha256:f71205da3645d770545abeaf48e8a15afd6ee9a76e57c03df4592e51be1059bf"
],
"index": "pypi",
"version": "==0.18.2"
"version": "==0.19.0"
},
"duo-client": {
"hashes": [
@ -480,11 +490,11 @@
},
"geoip2": {
"hashes": [
"sha256:906a1dbf15a179a1af3522970e8420ab15bb3e0afc526942cc179e12146d9c1d",
"sha256:b97b44031fdc463e84eb1316b4f19edd978cb1d78703465fcb1e36dc5a822ba6"
"sha256:f150bed3190d543712a17467208388d31bd8ddb49b2226fba53db8aaedb8ba89",
"sha256:f9172cdfb2a5f9225ace5e30dd7426413ad28798a5f474cd1538780686bd6a87"
],
"index": "pypi",
"version": "==4.2.0"
"version": "==4.4.0"
},
"google-auth": {
"hashes": [
@ -704,10 +714,10 @@
},
"maxminddb": {
"hashes": [
"sha256:47e86a084dd814fac88c99ea34ba3278a74bc9de5a25f4b815b608798747c7dc"
"sha256:e37707ec4fab115804670e0fb7aedb4b57075a8b6f80052bdc648d3c005184e5"
],
"markers": "python_version >= '3.6'",
"version": "==2.0.3"
"version": "==2.2.0"
},
"msgpack": {
"hashes": [
@ -898,39 +908,39 @@
},
"pycryptodome": {
"hashes": [
"sha256:09c1555a3fa450e7eaca41ea11cd00afe7c91fef52353488e65663777d8524e0",
"sha256:12222a5edc9ca4a29de15fbd5339099c4c26c56e13c2ceddf0b920794f26165d",
"sha256:1723ebee5561628ce96748501cdaa7afaa67329d753933296321f0be55358dce",
"sha256:1c5e1ca507de2ad93474be5cfe2bfa76b7cf039a1a32fc196f40935944871a06",
"sha256:2603c98ae04aac675fefcf71a6c87dc4bb74a75e9071ae3923bbc91a59f08d35",
"sha256:2dea65df54349cdfa43d6b2e8edb83f5f8d6861e5cf7b1fbc3e34c5694c85e27",
"sha256:31c1df17b3dc5f39600a4057d7db53ac372f492c955b9b75dd439f5d8b460129",
"sha256:38661348ecb71476037f1e1f553159b80d256c00f6c0b00502acac891f7116d9",
"sha256:3e2e3a06580c5f190df843cdb90ea28d61099cf4924334d5297a995de68e4673",
"sha256:3f840c49d38986f6e17dbc0673d37947c88bc9d2d9dba1c01b979b36f8447db1",
"sha256:501ab36aae360e31d0ec370cf5ce8ace6cb4112060d099b993bc02b36ac83fb6",
"sha256:60386d1d4cfaad299803b45a5bc2089696eaf6cdd56f9fc17479a6f89595cfc8",
"sha256:6260e24d41149268122dd39d4ebd5941e9d107f49463f7e071fd397e29923b0c",
"sha256:6bbf7fee7b7948b29d7e71fcacf48bac0c57fb41332007061a933f2d996f9713",
"sha256:6d2df5223b12437e644ce0a3be7809471ffa71de44ccd28b02180401982594a6",
"sha256:758949ca62690b1540dfb24ad773c6da9cd0e425189e83e39c038bbd52b8e438",
"sha256:77997519d8eb8a4adcd9a47b9cec18f9b323e296986528186c0e9a7a15d6a07e",
"sha256:7fd519b89585abf57bf47d90166903ec7b43af4fe23c92273ea09e6336af5c07",
"sha256:98213ac2b18dc1969a47bc65a79a8fca02a414249d0c8635abb081c7f38c91b6",
"sha256:99b2f3fc51d308286071d0953f92055504a6ffe829a832a9fc7a04318a7683dd",
"sha256:9b6f711b25e01931f1c61ce0115245a23cdc8b80bf8539ac0363bdcf27d649b6",
"sha256:a3105a0eb63eacf98c2ecb0eb4aa03f77f40fbac2bdde22020bb8a536b226bb8",
"sha256:a8eb8b6ea09ec1c2535bf39914377bc8abcab2c7d30fa9225eb4fe412024e427",
"sha256:a92d5c414e8ee1249e850789052608f582416e82422502dc0ac8c577808a9067",
"sha256:d3d6958d53ad307df5e8469cc44474a75393a434addf20ecd451f38a72fe29b8",
"sha256:e0a4d5933a88a2c98bbe19c0c722f5483dc628d7a38338ac2cb64a7dbd34064b",
"sha256:e3bf558c6aeb49afa9f0c06cee7fb5947ee5a1ff3bd794b653d39926b49077fa",
"sha256:e61e363d9a5d7916f3a4ce984a929514c0df3daf3b1b2eb5e6edbb131ee771cf",
"sha256:f977cdf725b20f6b8229b0c87acb98c7717e742ef9f46b113985303ae12a99da",
"sha256:fc7489a50323a0df02378bc2fff86eb69d94cc5639914346c736be981c6a02e7"
"sha256:04e14c732c3693d2830839feed5129286ce47ffa8bfe90e4ae042c773e51c677",
"sha256:11d3164fb49fdee000fde05baecce103c0c698168ef1a18d9c7429dd66f0f5bb",
"sha256:217dcc0c92503f7dd4b3d3b7d974331a4419f97f555c99a845c3b366fed7056b",
"sha256:24c1b7705d19d8ae3e7255431efd2e526006855df62620118dd7b5374c6372f6",
"sha256:309529d2526f3fb47102aeef376b3459110a6af7efb162e860b32e3a17a46f06",
"sha256:3a153658d97258ca20bf18f7fe31c09cc7c558b6f8974a6ec74e19f6c634bd64",
"sha256:3f9fb499e267039262569d08658132c9cd8b136bf1d8c56b72f70ed05551e526",
"sha256:3faa6ebd35c61718f3f8862569c1f38450c24f3ededb213e1a64806f02f584bc",
"sha256:40083b0d7f277452c7f2dd4841801f058cc12a74c219ee4110d65774c6a58bef",
"sha256:49e54f2245befb0193848c8c8031d8d1358ed4af5a1ae8d0a3ba669a5cdd3a72",
"sha256:4e8fc4c48365ce8a542fe48bf1360da05bb2851df12f64fc94d751705e7cdbe7",
"sha256:54d4e4d45f349d8c4e2f31c2734637ff62a844af391b833f789da88e43a8f338",
"sha256:66301e4c42dee43ee2da256625d3fe81ef98cc9924c2bd535008cc3ad8ded77b",
"sha256:6b45fcace5a5d9c57ba87cf804b161adc62aa826295ce7f7acbcbdc0df74ed37",
"sha256:7efec2418e9746ec48e264eea431f8e422d931f71c57b1c96ee202b117f58fa9",
"sha256:851e6d4930b160417235955322db44adbdb19589918670d63f4acd5d92959ac0",
"sha256:8e82524e7c354033508891405574d12e612cc4fdd3b55d2c238fc1a3e300b606",
"sha256:8ec154ec445412df31acf0096e7f715e30e167c8f2318b8f5b1ab7c28f4c82f7",
"sha256:91ba4215a1f37d0f371fe43bc88c5ff49c274849f3868321c889313787de7672",
"sha256:97e7df67a4da2e3f60612bbfd6c3f243a63a15d8f4797dd275e1d7b44a65cb12",
"sha256:9a2312440057bf29b9582f72f14d79692044e63bfbc4b4bbea8559355f44f3dd",
"sha256:a7471646d8cd1a58bb696d667dcb3853e5c9b341b68dcf3c3cc0893d0f98ca5f",
"sha256:ac3012c36633564b2b5539bb7c6d9175f31d2ce74844e9abe654c428f02d0fd8",
"sha256:b1daf251395af7336ddde6a0015ba5e632c18fe646ba930ef87402537358e3b4",
"sha256:b217b4525e60e1af552d62bec01b4685095436d4de5ecde0f05d75b2f95ba6d4",
"sha256:c61ea053bd5d4c12a063d7e704fbe1c45abb5d2510dab55bd95d166ba661604f",
"sha256:c6469d1453f5864e3321a172b0aa671b938d753cbf2376b99fa2ab8841539bb8",
"sha256:cefe6b267b8e5c3c72e11adec35a9c7285b62e8ea141b63e87055e9a9e5f2f8c",
"sha256:d713dc0910e5ded07852a05e9b75f1dd9d3a31895eebee0668f612779b2a748c",
"sha256:db15fa07d2a4c00beeb5e9acdfdbc1c79f9ccfbdc1a8f36c82c4aa44951b33c9"
],
"index": "pypi",
"version": "==3.10.1"
"version": "==3.10.4"
},
"pyjwt": {
"hashes": [
@ -1082,11 +1092,11 @@
},
"sentry-sdk": {
"hashes": [
"sha256:ebe99144fa9618d4b0e7617e7929b75acd905d258c3c779edcd34c0adfffe26c",
"sha256:f33d34c886d0ba24c75ea8885a8b3a172358853c7cbde05979fc99c29ef7bc52"
"sha256:4297555ddc37c7136740e6b547b7d68f5bca0b4832f94ac097e5d531a4c77528",
"sha256:ea04bc3be6eb082f34ff3f8f6380ea9c691766592298f3f975a435dafac6bf6a"
],
"index": "pypi",
"version": "==1.3.1"
"version": "==1.4.1"
},
"service-identity": {
"hashes": [
@ -1176,11 +1186,11 @@
"secure"
],
"hashes": [
"sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4",
"sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
"sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
"sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
],
"index": "pypi",
"version": "==1.26.6"
"version": "==1.26.7"
},
"uvicorn": {
"extras": [
@ -1457,11 +1467,11 @@
},
"charset-normalizer": {
"hashes": [
"sha256:7098e7e862f6370a2a8d1a6398cd359815c45d12626267652c3f13dec58e2367",
"sha256:fa471a601dfea0f492e4f4fca035cd82155e65dc45c9b83bf4322dfab63755dd"
"sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6",
"sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"
],
"markers": "python_version >= '3'",
"version": "==2.0.5"
"version": "==2.0.6"
},
"click": {
"hashes": [
@ -1547,11 +1557,11 @@
},
"gitpython": {
"hashes": [
"sha256:b838a895977b45ab6f0cc926a9045c8d1c44e2b653c1fcc39fe91f42c6e8f05b",
"sha256:fce760879cd2aebd2991b3542876dc5c4a909b30c9d69dfc488e504a8db37ee8"
"sha256:dc0a7f2f697657acc8d7f89033e8b1ea94dd90356b2983bca89dc8d2ab3cc647",
"sha256:df83fdf5e684fef7c6ee2c02fc68a5ceb7e7e759d08b694088d0cacb4eba59e5"
],
"markers": "python_version >= '3.6'",
"version": "==3.1.18"
"markers": "python_version >= '3.7'",
"version": "==3.1.24"
},
"idna": {
"hashes": [
@ -1642,11 +1652,11 @@
},
"platformdirs": {
"hashes": [
"sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f",
"sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"
"sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2",
"sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"
],
"markers": "python_version >= '3.6'",
"version": "==2.3.0"
"version": "==2.4.0"
},
"pluggy": {
"hashes": [
@ -1748,49 +1758,49 @@
},
"regex": {
"hashes": [
"sha256:04f6b9749e335bb0d2f68c707f23bb1773c3fb6ecd10edf0f04df12a8920d468",
"sha256:08d74bfaa4c7731b8dac0a992c63673a2782758f7cfad34cf9c1b9184f911354",
"sha256:0fc1f8f06977c2d4f5e3d3f0d4a08089be783973fc6b6e278bde01f0544ff308",
"sha256:121f4b3185feaade3f85f70294aef3f777199e9b5c0c0245c774ae884b110a2d",
"sha256:1413b5022ed6ac0d504ba425ef02549a57d0f4276de58e3ab7e82437892704fc",
"sha256:1743345e30917e8c574f273f51679c294effba6ad372db1967852f12c76759d8",
"sha256:28fc475f560d8f67cc8767b94db4c9440210f6958495aeae70fac8faec631797",
"sha256:31a99a4796bf5aefc8351e98507b09e1b09115574f7c9dbb9cf2111f7220d2e2",
"sha256:328a1fad67445550b982caa2a2a850da5989fd6595e858f02d04636e7f8b0b13",
"sha256:473858730ef6d6ff7f7d5f19452184cd0caa062a20047f6d6f3e135a4648865d",
"sha256:4cde065ab33bcaab774d84096fae266d9301d1a2f5519d7bd58fc55274afbf7a",
"sha256:5f6a808044faae658f546dd5f525e921de9fa409de7a5570865467f03a626fc0",
"sha256:610b690b406653c84b7cb6091facb3033500ee81089867ee7d59e675f9ca2b73",
"sha256:66256b6391c057305e5ae9209941ef63c33a476b73772ca967d4a2df70520ec1",
"sha256:6eebf512aa90751d5ef6a7c2ac9d60113f32e86e5687326a50d7686e309f66ed",
"sha256:79aef6b5cd41feff359acaf98e040844613ff5298d0d19c455b3d9ae0bc8c35a",
"sha256:808ee5834e06f57978da3e003ad9d6292de69d2bf6263662a1a8ae30788e080b",
"sha256:8e44769068d33e0ea6ccdf4b84d80c5afffe5207aa4d1881a629cf0ef3ec398f",
"sha256:999ad08220467b6ad4bd3dd34e65329dd5d0df9b31e47106105e407954965256",
"sha256:9b006628fe43aa69259ec04ca258d88ed19b64791693df59c422b607b6ece8bb",
"sha256:9d05ad5367c90814099000442b2125535e9d77581855b9bee8780f1b41f2b1a2",
"sha256:a577a21de2ef8059b58f79ff76a4da81c45a75fe0bfb09bc8b7bb4293fa18983",
"sha256:a617593aeacc7a691cc4af4a4410031654f2909053bd8c8e7db837f179a630eb",
"sha256:abb48494d88e8a82601af905143e0de838c776c1241d92021e9256d5515b3645",
"sha256:ac88856a8cbccfc14f1b2d0b829af354cc1743cb375e7f04251ae73b2af6adf8",
"sha256:b4c220a1fe0d2c622493b0a1fd48f8f991998fb447d3cd368033a4b86cf1127a",
"sha256:b844fb09bd9936ed158ff9df0ab601e2045b316b17aa8b931857365ea8586906",
"sha256:bdc178caebd0f338d57ae445ef8e9b737ddf8fbc3ea187603f65aec5b041248f",
"sha256:c206587c83e795d417ed3adc8453a791f6d36b67c81416676cad053b4104152c",
"sha256:c61dcc1cf9fd165127a2853e2c31eb4fb961a4f26b394ac9fe5669c7a6592892",
"sha256:c7cb4c512d2d3b0870e00fbbac2f291d4b4bf2634d59a31176a87afe2777c6f0",
"sha256:d4a332404baa6665b54e5d283b4262f41f2103c255897084ec8f5487ce7b9e8e",
"sha256:d5111d4c843d80202e62b4fdbb4920db1dcee4f9366d6b03294f45ed7b18b42e",
"sha256:e1e8406b895aba6caa63d9fd1b6b1700d7e4825f78ccb1e5260551d168db38ed",
"sha256:e8690ed94481f219a7a967c118abaf71ccc440f69acd583cab721b90eeedb77c",
"sha256:ed283ab3a01d8b53de3a05bfdf4473ae24e43caee7dcb5584e86f3f3e5ab4374",
"sha256:ed4b50355b066796dacdd1cf538f2ce57275d001838f9b132fab80b75e8c84dd",
"sha256:ee329d0387b5b41a5dddbb6243a21cb7896587a651bebb957e2d2bb8b63c0791",
"sha256:f3bf1bc02bc421047bfec3343729c4bbbea42605bcfd6d6bfe2c07ade8b12d2a",
"sha256:f585cbbeecb35f35609edccb95efd95a3e35824cd7752b586503f7e6087303f1",
"sha256:f60667673ff9c249709160529ab39667d1ae9fd38634e006bec95611f632e759"
"sha256:0628ed7d6334e8f896f882a5c1240de8c4d9b0dd7c7fb8e9f4692f5684b7d656",
"sha256:09eb62654030f39f3ba46bc6726bea464069c29d00a9709e28c9ee9623a8da4a",
"sha256:0bba1f6df4eafe79db2ecf38835c2626dbd47911e0516f6962c806f83e7a99ae",
"sha256:10a7a9cbe30bd90b7d9a1b4749ef20e13a3528e4215a2852be35784b6bd070f0",
"sha256:17310b181902e0bb42b29c700e2c2346b8d81f26e900b1328f642e225c88bce1",
"sha256:1e8d1898d4fb817120a5f684363b30108d7b0b46c7261264b100d14ec90a70e7",
"sha256:2054dea683f1bda3a804fcfdb0c1c74821acb968093d0be16233873190d459e3",
"sha256:29385c4dbb3f8b3a55ce13de6a97a3d21bd00de66acd7cdfc0b49cb2f08c906c",
"sha256:295bc8a13554a25ad31e44c4bedabd3c3e28bba027e4feeb9bb157647a2344a7",
"sha256:2cdb3789736f91d0b3333ac54d12a7e4f9efbc98f53cb905d3496259a893a8b3",
"sha256:3baf3eaa41044d4ced2463fd5d23bf7bd4b03d68739c6c99a59ce1f95599a673",
"sha256:4e61100200fa6ab7c99b61476f9f9653962ae71b931391d0264acfb4d9527d9c",
"sha256:6266fde576e12357b25096351aac2b4b880b0066263e7bc7a9a1b4307991bb0e",
"sha256:650c4f1fc4273f4e783e1d8e8b51a3e2311c2488ba0fcae6425b1e2c248a189d",
"sha256:658e3477676009083422042c4bac2bdad77b696e932a3de001c42cc046f8eda2",
"sha256:6adc1bd68f81968c9d249aab8c09cdc2cbe384bf2d2cb7f190f56875000cdc72",
"sha256:6c4d83d21d23dd854ffbc8154cf293f4e43ba630aa9bd2539c899343d7f59da3",
"sha256:6f74b6d8f59f3cfb8237e25c532b11f794b96f5c89a6f4a25857d85f84fbef11",
"sha256:7783d89bd5413d183a38761fbc68279b984b9afcfbb39fa89d91f63763fbfb90",
"sha256:7e3536f305f42ad6d31fc86636c54c7dafce8d634e56fef790fbacb59d499dd5",
"sha256:821e10b73e0898544807a0692a276e539e5bafe0a055506a6882814b6a02c3ec",
"sha256:835962f432bce92dc9bf22903d46c50003c8d11b1dc64084c8fae63bca98564a",
"sha256:85c61bee5957e2d7be390392feac7e1d7abd3a49cbaed0c8cee1541b784c8561",
"sha256:86f9931eb92e521809d4b64ec8514f18faa8e11e97d6c2d1afa1bcf6c20a8eab",
"sha256:8a5c2250c0a74428fd5507ae8853706fdde0f23bfb62ee1ec9418eeacf216078",
"sha256:8aec4b4da165c4a64ea80443c16e49e3b15df0f56c124ac5f2f8708a65a0eddc",
"sha256:8c268e78d175798cd71d29114b0a1f1391c7d011995267d3b62319ec1a4ecaa1",
"sha256:8d80087320632457aefc73f686f66139801959bf5b066b4419b92be85be3543c",
"sha256:95e89a8558c8c48626dcffdf9c8abac26b7c251d352688e7ab9baf351e1c7da6",
"sha256:9c371dd326289d85906c27ec2bc1dcdedd9d0be12b543d16e37bad35754bde48",
"sha256:9c7cb25adba814d5f419733fe565f3289d6fa629ab9e0b78f6dff5fa94ab0456",
"sha256:a731552729ee8ae9c546fb1c651c97bf5f759018fdd40d0e9b4d129e1e3a44c8",
"sha256:aea4006b73b555fc5bdb650a8b92cf486d678afa168cf9b38402bb60bf0f9c18",
"sha256:b0e3f59d3c772f2c3baaef2db425e6fc4149d35a052d874bb95ccfca10a1b9f4",
"sha256:b15dc34273aefe522df25096d5d087abc626e388a28a28ac75a4404bb7668736",
"sha256:c000635fd78400a558bd7a3c2981bb2a430005ebaa909d31e6e300719739a949",
"sha256:c31f35a984caffb75f00a86852951a337540b44e4a22171354fb760cefa09346",
"sha256:c50a6379763c733562b1fee877372234d271e5c78cd13ade5f25978aa06744db",
"sha256:c94722bf403b8da744b7d0bb87e1f2529383003ceec92e754f768ef9323f69ad",
"sha256:dcbbc9cfa147d55a577d285fd479b43103188855074552708df7acc31a476dd9",
"sha256:fb9f5844db480e2ef9fce3a72e71122dd010ab7b2920f777966ba25f7eb63819"
],
"version": "==2021.8.28"
"version": "==2021.9.24"
},
"requests": {
"hashes": [
@ -1861,11 +1871,11 @@
"secure"
],
"hashes": [
"sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4",
"sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"
"sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
"sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
],
"index": "pypi",
"version": "==1.26.6"
"version": "==1.26.7"
},
"wrapt": {
"hashes": [

View File

@ -1,3 +1,3 @@
"""authentik"""
__version__ = "2021.9.1-rc3"
__version__ = "2021.9.3"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -84,7 +84,7 @@ class SystemSerializer(PassiveSerializer):
return now()
def get_embedded_outpost_host(self, request: Request) -> str:
"""Get the FQDN configured on the embeddded outpost"""
"""Get the FQDN configured on the embedded outpost"""
outposts = Outpost.objects.filter(managed=MANAGED_OUTPOST)
if not outposts.exists():
return ""

View File

@ -40,7 +40,6 @@ def bearer_auth(raw_header: bytes) -> Optional[User]:
raise AuthenticationFailed("Malformed header")
tokens = Token.filter_not_expired(key=password, intent=TokenIntents.INTENT_API)
if not tokens.exists():
LOGGER.info("Authenticating via secret_key")
user = token_secret_key(password)
if not user:
raise AuthenticationFailed("Token invalid/expired")
@ -58,6 +57,7 @@ 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")
outpost = outposts.first()
return outpost.user

View File

@ -11,7 +11,7 @@ from drf_spectacular.types import OpenApiTypes
def build_standard_type(obj, **kwargs):
"""Build a basic type with optional add ons."""
"""Build a basic type with optional add owns."""
schema = build_basic_type(obj)
schema.update(kwargs)
return schema

View File

@ -63,7 +63,7 @@ class ConfigView(APIView):
@extend_schema(responses={200: ConfigSerializer(many=False)})
def get(self, request: Request) -> Response:
"""Retrive public configuration options"""
"""Retrieve public configuration options"""
config = ConfigSerializer(
{
"error_reporting_enabled": CONFIG.y("error_reporting.enabled"),

View File

@ -10,10 +10,13 @@ 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."""
@ -45,6 +48,7 @@ class SentryTunnelView(APIView):
"""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
@ -55,6 +59,7 @@ class SentryTunnelView(APIView):
# 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

@ -99,6 +99,7 @@ from authentik.stages.user_write.api import UserWriteStageViewSet
from authentik.tenants.api import TenantViewSet
router = routers.DefaultRouter()
router.include_format_suffixes = False
router.register("admin/system_tasks", TaskViewSet, basename="admin_system_tasks")
router.register("admin/apps", AppsViewSet, basename="apps")

View File

@ -8,6 +8,7 @@ from django.db.transaction import atomic
from django.db.utils import IntegrityError
from django.urls import reverse_lazy
from django.utils.http import urlencode
from django.utils.text import slugify
from django.utils.timezone import now
from django.utils.translation import gettext as _
from django_filters.filters import BooleanFilter, CharFilter, ModelMultipleChoiceFilter
@ -273,7 +274,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
)
group.users.add(user)
token = Token.objects.create(
identifier=f"service-account-{username}-password",
identifier=slugify(f"service-account-{username}-password"),
intent=TokenIntents.INTENT_APP_PASSWORD,
user=user,
expires=now() + timedelta(days=360),
@ -307,7 +308,7 @@ class UserViewSet(UsedByMixin, ModelViewSet):
"""Allow users to change information on their own profile"""
data = UserSelfSerializer(instance=User.objects.get(pk=request.user.pk), data=request.data)
if not data.is_valid():
return Response(data.errors)
return Response(data.errors, status=400)
new_user = data.save()
# If we're impersonating, we need to update that user object
# since it caches the full object

View File

@ -26,7 +26,7 @@ class Migration(migrations.Migration):
),
(
"username_link",
"Link to a user with identical username address. Can have security implications when a username is used with another source.",
"Link to a user with identical username. Can have security implications when a username is used with another source.",
),
(
"username_deny",

View File

@ -283,7 +283,7 @@ class SourceUserMatchingModes(models.TextChoices):
)
USERNAME_LINK = "username_link", _(
(
"Link to a user with identical username address. Can have security implications "
"Link to a user with identical username. Can have security implications "
"when a username is used with another source."
)
)

View File

@ -1,7 +1,10 @@
"""NotificationTransport API Views"""
from typing import Any
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, ListField, SerializerMethodField
from rest_framework.request import Request
from rest_framework.response import Response
@ -29,6 +32,14 @@ class NotificationTransportSerializer(ModelSerializer):
"""Return selected mode with a UI Label"""
return TransportMode(instance.mode).label
def validate(self, attrs: dict[Any, str]) -> dict[Any, str]:
"""Ensure the required fields are set."""
mode = attrs.get("mode")
if mode in [TransportMode.WEBHOOK, TransportMode.WEBHOOK_SLACK]:
if "webhook_url" not in attrs or attrs.get("webhook_url", "") == "":
raise ValidationError("Webhook URL may not be empty.")
return attrs
class Meta:
model = NotificationTransport

View File

@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Optional, Type, Union
from uuid import uuid4
from django.conf import settings
from django.core.validators import URLValidator
from django.db import models
from django.http import HttpRequest
from django.http.request import QueryDict
@ -223,7 +224,7 @@ class NotificationTransport(models.Model):
name = models.TextField(unique=True)
mode = models.TextField(choices=TransportMode.choices)
webhook_url = models.TextField(blank=True)
webhook_url = models.TextField(blank=True, validators=[URLValidator()])
webhook_mapping = models.ForeignKey(
"NotificationWebhookMapping", on_delete=models.SET_DEFAULT, null=True, default=None
)

View File

@ -4,7 +4,13 @@ from django.urls import reverse
from rest_framework.test import APITestCase
from authentik.core.models import User
from authentik.events.models import Event, EventAction, Notification, NotificationSeverity
from authentik.events.models import (
Event,
EventAction,
Notification,
NotificationSeverity,
TransportMode,
)
class TestEventsAPI(APITestCase):
@ -41,3 +47,23 @@ class TestEventsAPI(APITestCase):
)
notification.refresh_from_db()
self.assertTrue(notification.seen)
def test_transport(self):
"""Test transport API"""
response = self.client.post(
reverse("authentik_api:notificationtransport-list"),
data={
"name": "foo-with",
"mode": TransportMode.WEBHOOK,
"webhook_url": "http://foo.com",
},
)
self.assertEqual(response.status_code, 201)
response = self.client.post(
reverse("authentik_api:notificationtransport-list"),
data={
"name": "foo-without",
"mode": TransportMode.WEBHOOK,
},
)
self.assertEqual(response.status_code, 400)

View File

@ -77,7 +77,7 @@ def sanitize_dict(source: dict[Any, Any]) -> dict[Any, Any]:
final_dict = {}
for key, value in source.items():
if is_dataclass(value):
# Because asdict calls `copy.deepcopy(obj)` on everything thats not tuple/dict,
# Because asdict calls `copy.deepcopy(obj)` on everything that's not tuple/dict,
# and deepcopy doesn't work with HttpRequests (neither django nor rest_framework).
# Currently, the only dataclass that actually holds an http request is a PolicyRequest
if isinstance(value, PolicyRequest):

View File

@ -57,11 +57,11 @@ class FlowPlan:
markers: list[StageMarker] = field(default_factory=list)
def append_stage(self, stage: Stage, marker: Optional[StageMarker] = None):
"""Append `stage` to all stages, optionall with stage marker"""
"""Append `stage` to all stages, optionally with stage marker"""
return self.append(FlowStageBinding(stage=stage), marker)
def append(self, binding: FlowStageBinding, marker: Optional[StageMarker] = None):
"""Append `stage` to all stages, optionall with stage marker"""
"""Append `stage` to all stages, optionally with stage marker"""
self.bindings.append(binding)
self.markers.append(marker or StageMarker())

View File

@ -438,7 +438,7 @@ class TestFlowExecutor(APITestCase):
# third request, this should trigger the re-evaluate
# A get request will evaluate the policies and this will return stage 4
# but it won't save it, hence we cant' check the plan
# but it won't save it, hence we can't check the plan
response = self.client.get(exec_url)
self.assertEqual(response.status_code, 200)
self.assertJSONEqual(

View File

@ -11,7 +11,7 @@ from authentik.lib.sentry import SentryIgnoredException
def get_attrs(obj: SerializerModel) -> dict[str, Any]:
"""Get object's attributes via their serializer, and covert it to a normal dict"""
"""Get object's attributes via their serializer, and convert it to a normal dict"""
data = dict(obj.serializer(obj).data)
to_remove = (
"policies",

View File

@ -14,12 +14,7 @@ from django.utils.decorators import method_decorator
from django.views.decorators.clickjacking import xframe_options_sameorigin
from django.views.generic import View
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import (
OpenApiParameter,
OpenApiResponse,
PolymorphicProxySerializer,
extend_schema,
)
from drf_spectacular.utils import OpenApiParameter, PolymorphicProxySerializer, extend_schema
from rest_framework.permissions import AllowAny
from rest_framework.views import APIView
from sentry_sdk import capture_exception
@ -131,12 +126,12 @@ class FlowExecutorView(APIView):
# pylint: disable=unused-argument, too-many-return-statements
def dispatch(self, request: HttpRequest, flow_slug: str) -> HttpResponse:
# Early check if theres an active Plan for the current session
# Early check if there's an active Plan for the current session
if SESSION_KEY_PLAN in self.request.session:
self.plan = self.request.session[SESSION_KEY_PLAN]
if self.plan.flow_pk != self.flow.pk.hex:
self._logger.warning(
"f(exec): Found existing plan for other flow, deleteing plan",
"f(exec): Found existing plan for other flow, deleting plan",
)
# Existing plan is deleted from session and instance
self.plan = None
@ -213,9 +208,6 @@ class FlowExecutorView(APIView):
serializers=challenge_types(),
resource_type_field_name="component",
),
404: OpenApiResponse(
description="No Token found"
), # This error can be raised by the email stage
},
request=OpenApiTypes.NONE,
parameters=[
@ -441,7 +433,7 @@ class ToDefaultFlow(View):
plan: FlowPlan = self.request.session[SESSION_KEY_PLAN]
if plan.flow_pk != flow.pk.hex:
LOGGER.warning(
"f(def): Found existing plan for other flow, deleteing plan",
"f(def): Found existing plan for other flow, deleting plan",
flow_slug=flow.slug,
)
del self.request.session[SESSION_KEY_PLAN]

View File

@ -32,7 +32,7 @@ class TestConfig(TestCase):
config = ConfigLoader()
environ["foo"] = "bar"
self.assertEqual(config.parse_uri("env://foo"), "bar")
self.assertEqual(config.parse_uri("env://fo?bar"), "bar")
self.assertEqual(config.parse_uri("env://foo?bar"), "bar")
def test_uri_file(self):
"""Test URI parsing (file load)"""

View File

@ -27,7 +27,7 @@ class TestHTTP(TestCase):
token = Token.objects.create(
identifier="test", user=self.user, intent=TokenIntents.INTENT_API
)
# Invalid, non-existant token
# Invalid, non-existent token
request = self.factory.get(
"/",
**{
@ -36,7 +36,7 @@ class TestHTTP(TestCase):
},
)
self.assertEqual(get_client_ip(request), "127.0.0.1")
# Invalid, user doesn't have permisions
# Invalid, user doesn't have permissions
request = self.factory.get(
"/",
**{

View File

@ -104,7 +104,7 @@ class OutpostConsumer(AuthJsonConsumer):
expected=self.outpost.config.kubernetes_replicas,
).inc()
LOGGER.debug(
"added outpost instace to cache",
"added outpost instance to cache",
outpost=self.outpost,
instance_uuid=self.last_uid,
)

View File

@ -38,6 +38,7 @@ class DockerController(BaseController):
"AUTHENTIK_HOST": self.outpost.config.authentik_host.lower(),
"AUTHENTIK_INSECURE": str(self.outpost.config.authentik_host_insecure).lower(),
"AUTHENTIK_TOKEN": self.outpost.token.key,
"AUTHENTIK_HOST_BROWSER": self.outpost.config.authentik_host_browser,
}
def _comp_env(self, container: Container) -> bool:
@ -164,11 +165,9 @@ class DockerController(BaseController):
self.down()
return self.up(depth + 1)
# Check that container is healthy
if (
container.status == "running"
and container.attrs.get("State", {}).get("Health", {}).get("Status", "")
!= "healthy"
):
if container.status == "running" and container.attrs.get("State", {}).get(
"Health", {}
).get("Status", "") not in ["healthy", "starting"]:
# At this point we know the config is correct, but the container isn't healthy,
# so we just restart it with the same config
if has_been_created:
@ -217,6 +216,7 @@ class DockerController(BaseController):
"AUTHENTIK_HOST": self.outpost.config.authentik_host,
"AUTHENTIK_INSECURE": str(self.outpost.config.authentik_host_insecure),
"AUTHENTIK_TOKEN": self.outpost.token.key,
"AUTHENTIK_HOST_BROWSER": self.outpost.config.authentik_host_browser,
},
"labels": self._get_labels(),
}

View File

@ -109,7 +109,7 @@ class KubernetesObjectReconciler(Generic[T]):
except (OpenApiException, HTTPError) as exc:
# pylint: disable=no-member
if isinstance(exc, ApiException) and exc.status == 404:
self.logger.debug("Failed to get current, assuming non-existant")
self.logger.debug("Failed to get current, assuming non-existent")
return
self.logger.debug("Other unhandled error", exc=exc)
raise exc
@ -129,7 +129,7 @@ class KubernetesObjectReconciler(Generic[T]):
raise NotImplementedError
def retrieve(self) -> T:
"""API Wrapper to retrive object"""
"""API Wrapper to retrieve object"""
raise NotImplementedError
def delete(self, reference: T):

View File

@ -89,6 +89,15 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
)
),
),
V1EnvVar(
name="AUTHENTIK_HOST_BROWSER",
value_from=V1EnvVarSource(
secret_key_ref=V1SecretKeySelector(
name=self.name,
key="authentik_host_browser",
)
),
),
V1EnvVar(
name="AUTHENTIK_TOKEN",
value_from=V1EnvVarSource(

View File

@ -26,7 +26,7 @@ class SecretReconciler(KubernetesObjectReconciler[V1Secret]):
def reconcile(self, current: V1Secret, reference: V1Secret):
super().reconcile(current, reference)
for key in reference.data.keys():
if current.data[key] != reference.data[key]:
if key not in current.data or current.data[key] != reference.data[key]:
raise NeedsUpdate()
def get_reference_object(self) -> V1Secret:
@ -40,6 +40,9 @@ class SecretReconciler(KubernetesObjectReconciler[V1Secret]):
str(self.controller.outpost.config.authentik_host_insecure)
),
"token": b64string(self.controller.outpost.token.key),
"authentik_host_browser": b64string(
self.controller.outpost.config.authentik_host_browser
),
},
)

View File

@ -19,12 +19,16 @@ class ServiceReconciler(KubernetesObjectReconciler[V1Service]):
self.api = CoreV1Api(controller.client)
def reconcile(self, current: V1Service, reference: V1Service):
super().reconcile(current, reference)
if len(current.spec.ports) != len(reference.spec.ports):
raise NeedsRecreate()
for port in reference.spec.ports:
if port not in current.spec.ports:
raise NeedsRecreate()
# run the base reconcile last, as that will probably raise NeedsUpdate
# after an authentik update. However the ports might have also changed during
# the update, so this causes the service to be re-created with higher
# priority than being updated.
super().reconcile(current, reference)
def get_reference_object(self) -> V1Service:
"""Get deployment object for outpost"""

View File

@ -30,7 +30,7 @@ class DockerInlineTLS:
return str(path)
def write(self) -> TLSConfig:
"""Create TLSConfig with Certificate Keypairs"""
"""Create TLSConfig with Certificate Key pairs"""
# So yes, this is quite ugly. But sadly, there is no clean way to pass
# docker-py (which is using requests (which is using urllib3)) a certificate
# for verification or authentication as string.

View File

@ -64,6 +64,7 @@ class OutpostConfig:
authentik_host: str = ""
authentik_host_insecure: bool = False
authentik_host_browser: str = ""
log_level: str = CONFIG.y("log_level")
error_reporting_enabled: bool = CONFIG.y_bool("error_reporting.enabled")

View File

@ -181,7 +181,7 @@ def outpost_post_save(model_class: str, model_pk: Any):
def outpost_send_update(model_instace: Model):
"""Send outpost update to all registered outposts, irregardless to which authentik
"""Send outpost update to all registered outposts, regardless to which authentik
instance they are connected"""
channel_layer = get_channel_layer()
if isinstance(model_instace, OutpostModel):
@ -208,7 +208,7 @@ def _outpost_single_update(outpost: Outpost, layer=None):
@CELERY_APP.task()
def outpost_local_connection():
"""Checks the local environment and create Service connections."""
# Explicitly check against token filename, as thats
# Explicitly check against token filename, as that's
# only present when the integration is enabled
if Path(SERVICE_TOKEN_FILENAME).exists():
LOGGER.debug("Detected in-cluster Kubernetes Config")

View File

@ -3,8 +3,10 @@ from ipaddress import ip_address, ip_network
from typing import TYPE_CHECKING, Optional
from django.http import HttpRequest
from django_otp import devices_for_user
from structlog.stdlib import get_logger
from authentik.core.models import User
from authentik.flows.planner import PLAN_CONTEXT_SSO
from authentik.lib.expression.evaluator import BaseEvaluator
from authentik.lib.utils.http import get_client_ip
@ -28,6 +30,7 @@ class PolicyEvaluator(BaseEvaluator):
self._messages = []
self._context["ak_logger"] = get_logger(policy_name)
self._context["ak_message"] = self.expr_func_message
self._context["ak_user_has_authenticator"] = self.expr_func_user_has_authenticator
self._context["ip_address"] = ip_address
self._context["ip_network"] = ip_network
self._filename = policy_name or "PolicyEvaluator"
@ -36,6 +39,19 @@ class PolicyEvaluator(BaseEvaluator):
"""Wrapper to append to messages list, which is returned with PolicyResult"""
self._messages.append(message)
def expr_func_user_has_authenticator(
self, user: User, device_type: Optional[str] = None
) -> bool:
"""Check if a user has any authenticator devices, optionally matching *device_type*"""
user_devices = devices_for_user(user)
if device_type:
for device in user_devices:
device_class = device.__class__.__name__.lower().replace("device", "")
if device_class == device_type:
return True
return False
return len(user_devices) > 0
def set_policy_request(self, request: PolicyRequest):
"""Update context based on policy request (if http request is given, update that too)"""
# update website/docs/expressions/_objects.md

View File

@ -46,7 +46,7 @@ def cache_key(binding: PolicyBinding, request: PolicyRequest) -> str:
class PolicyProcess(PROCESS_CLASS):
"""Evaluate a single policy within a seprate process"""
"""Evaluate a single policy within a separate process"""
connection: Connection
binding: PolicyBinding

View File

@ -34,7 +34,7 @@ def update_score(request: HttpRequest, username: str, amount: int):
@receiver(user_login_failed)
# pylint: disable=unused-argument
def handle_failed_login(sender, request, credentials, **_):
"""Lower Score for failed loging attempts"""
"""Lower Score for failed login attempts"""
if "username" in credentials:
update_score(request, credentials.get("username"), -1)

View File

@ -14,7 +14,7 @@ from authentik.policies.types import PolicyRequest
def clear_policy_cache():
"""Ensure no policy-related keys are stil cached"""
"""Ensure no policy-related keys are still cached"""
keys = cache.keys("policy_*")
cache.delete(keys)

View File

@ -1,16 +1,15 @@
"""LDAP Provider Docker Contoller"""
"""LDAP Provider Docker Controller"""
from authentik.outposts.controllers.base import DeploymentPort
from authentik.outposts.controllers.docker import DockerController
from authentik.outposts.models import DockerServiceConnection, Outpost
class LDAPDockerController(DockerController):
"""LDAP Provider Docker Contoller"""
"""LDAP Provider Docker Controller"""
def __init__(self, outpost: Outpost, connection: DockerServiceConnection):
super().__init__(outpost, connection)
self.deployment_ports = [
DeploymentPort(389, "ldap", "tcp", 3389),
DeploymentPort(636, "ldaps", "tcp", 6636),
DeploymentPort(9300, "http-metrics", "tcp", 9300),
]

View File

@ -1,11 +1,11 @@
"""LDAP Provider Kubernetes Contoller"""
"""LDAP Provider Kubernetes Controller"""
from authentik.outposts.controllers.base import DeploymentPort
from authentik.outposts.controllers.kubernetes import KubernetesController
from authentik.outposts.models import KubernetesServiceConnection, Outpost
class LDAPKubernetesController(KubernetesController):
"""LDAP Provider Kubernetes Contoller"""
"""LDAP Provider Kubernetes Controller"""
def __init__(self, outpost: Outpost, connection: KubernetesServiceConnection):
super().__init__(outpost, connection)

View File

@ -153,7 +153,7 @@ def protected_resource_view(scopes: list[str]):
if not set(scopes).issubset(set(token.scope)):
LOGGER.warning(
"Scope missmatch.",
"Scope mismatch.",
required=set(scopes),
token_has=set(token.scope),
)

View File

@ -33,7 +33,7 @@ class UserInfoView(View):
for scope in ScopeMapping.objects.filter(scope_name__in=scopes).order_by("scope_name"):
if scope.description != "":
scope_descriptions.append({"id": scope.scope_name, "name": scope.description})
# GitHub Compatibility Scopes are handeled differently, since they required custom paths
# GitHub Compatibility Scopes are handled differently, since they required custom paths
# Hence they don't exist as Scope objects
github_scope_map = {
SCOPE_GITHUB_USER: ("GitHub Compatibility: Access your User Information"),

View File

@ -1,5 +1,5 @@
"""ProxyProvider API Views"""
from typing import Any
from typing import Any, Optional
from drf_spectacular.utils import extend_schema_field
from rest_framework.exceptions import ValidationError
@ -10,6 +10,7 @@ from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
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.views.provider import ProviderInfoView
from authentik.providers.proxy.models import ProxyMode, ProxyProvider
@ -106,6 +107,16 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
"""Proxy provider serializer for outposts"""
oidc_configuration = SerializerMethodField()
token_validity = SerializerMethodField()
@extend_schema_field(OpenIDConnectConfigurationSerializer)
def get_oidc_configuration(self, obj: ProxyProvider):
"""Embed OpenID Connect provider information"""
return ProviderInfoView(request=self.context["request"]._request).get_info(obj)
def get_token_validity(self, obj: ProxyProvider) -> Optional[float]:
"""Get token validity as second count"""
return timedelta_from_string(obj.token_validity).total_seconds()
class Meta:
@ -127,13 +138,9 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
"basic_auth_user_attribute",
"mode",
"cookie_domain",
"token_validity",
]
@extend_schema_field(OpenIDConnectConfigurationSerializer)
def get_oidc_configuration(self, obj: ProxyProvider):
"""Embed OpenID Connect provider information"""
return ProviderInfoView(request=self.context["request"]._request).get_info(obj)
class ProxyOutpostConfigViewSet(ReadOnlyModelViewSet):
"""ProxyProvider Viewset"""

View File

@ -1,4 +1,4 @@
"""Proxy Provider Docker Contoller"""
"""Proxy Provider Docker Controller"""
from urllib.parse import urlparse
from authentik.outposts.controllers.base import DeploymentPort
@ -8,13 +8,12 @@ from authentik.providers.proxy.models import ProxyProvider
class ProxyDockerController(DockerController):
"""Proxy Provider Docker Contoller"""
"""Proxy Provider Docker Controller"""
def __init__(self, outpost: Outpost, connection: DockerServiceConnection):
super().__init__(outpost, connection)
self.deployment_ports = [
DeploymentPort(9000, "http", "tcp"),
DeploymentPort(9300, "http-metrics", "tcp"),
DeploymentPort(9443, "https", "tcp"),
]
@ -30,6 +29,11 @@ class ProxyDockerController(DockerController):
labels[f"traefik.http.routers.{traefik_name}-router.rule"] = f"Host({','.join(hosts)})"
labels[f"traefik.http.routers.{traefik_name}-router.tls"] = "true"
labels[f"traefik.http.routers.{traefik_name}-router.service"] = f"{traefik_name}-service"
labels[f"traefik.http.services.{traefik_name}-service.loadbalancer.healthcheck.path"] = "/"
labels[
f"traefik.http.services.{traefik_name}-service.loadbalancer.healthcheck.path"
] = "/akprox/ping"
labels[
f"traefik.http.services.{traefik_name}-service.loadbalancer.healthcheck.port"
] = "9300"
labels[f"traefik.http.services.{traefik_name}-service.loadbalancer.server.port"] = "9000"
return labels

View File

@ -1,4 +1,4 @@
"""Proxy Provider Kubernetes Contoller"""
"""Proxy Provider Kubernetes Controller"""
from authentik.outposts.controllers.base import DeploymentPort
from authentik.outposts.controllers.kubernetes import KubernetesController
from authentik.outposts.models import KubernetesServiceConnection, Outpost
@ -7,7 +7,7 @@ from authentik.providers.proxy.controllers.k8s.traefik import TraefikMiddlewareR
class ProxyKubernetesController(KubernetesController):
"""Proxy Provider Kubernetes Contoller"""
"""Proxy Provider Kubernetes Controller"""
def __init__(self, outpost: Outpost, connection: KubernetesServiceConnection):
super().__init__(outpost, connection)

View File

@ -4,6 +4,7 @@ from getpass import getuser
from django.core.management.base import BaseCommand
from django.urls import reverse
from django.utils.text import slugify
from django.utils.timezone import now
from django.utils.translation import gettext as _
from structlog.stdlib import get_logger
@ -42,7 +43,7 @@ class Command(BaseCommand):
user=user,
intent=TokenIntents.INTENT_RECOVERY,
description=f"Recovery Token generated by {getuser()} on {_now}",
identifier=f"ak-recovery-{user}-{_now}",
identifier=slugify(f"ak-recovery-{user}-{_now}"),
)
self.stdout.write(
(f"Store this link safely, as it will allow" f" anyone to access authentik as {user}.")

View File

@ -119,7 +119,7 @@ class LDAPPasswordChanger:
return True
def ad_password_complexity(self, password: str, user: Optional[User] = None) -> bool:
"""Check if password matches Active direcotry password policies
"""Check if password matches Active directory password policies
https://docs.microsoft.com/en-us/windows/security/threat-protection/
security-policy-settings/password-must-meet-complexity-requirements

View File

@ -48,7 +48,7 @@ def ldap_password_validate(sender, password: str, plan_context: dict[str, Any],
password, plan_context.get(PLAN_CONTEXT_PENDING_USER, None)
)
if not passing:
raise ValidationError(_("Password does not match Active Direcory Complexity."))
raise ValidationError(_("Password does not match Active Directory Complexity."))
@receiver(password_changed)

View File

@ -46,9 +46,9 @@ class OAuthSourceSerializer(SourceSerializer):
type = SerializerMethodField()
@extend_schema_field(SourceTypeSerializer)
def get_type(self, instace: OAuthSource) -> SourceTypeSerializer:
def get_type(self, instance: OAuthSource) -> SourceTypeSerializer:
"""Get source's type configuration"""
return SourceTypeSerializer(instace.type).data
return SourceTypeSerializer(instance.type).data
def validate(self, attrs: dict) -> dict:
provider_type = MANAGER.find_type(attrs.get("provider_type", ""))

View File

@ -14,7 +14,7 @@ class Migration(migrations.Migration):
model_name="oauthsource",
name="access_token_url",
field=models.CharField(
help_text="URL used by authentik to retrive tokens.",
help_text="URL used by authentik to retrieve tokens.",
max_length=255,
verbose_name="Access Token URL",
),

View File

@ -15,7 +15,7 @@ class Migration(migrations.Migration):
name="access_token_url",
field=models.CharField(
blank=True,
help_text="URL used by authentik to retrive tokens.",
help_text="URL used by authentik to retrieve tokens.",
max_length=255,
verbose_name="Access Token URL",
),

View File

@ -39,7 +39,7 @@ class Migration(migrations.Migration):
model_name="oauthsource",
name="access_token_url",
field=models.CharField(
help_text="URL used by authentik to retrive tokens.",
help_text="URL used by authentik to retrieve tokens.",
max_length=255,
null=True,
verbose_name="Access Token URL",

View File

@ -37,7 +37,7 @@ class OAuthSource(Source):
max_length=255,
null=True,
verbose_name=_("Access Token URL"),
help_text=_("URL used by authentik to retrive tokens."),
help_text=_("URL used by authentik to retrieve tokens."),
)
profile_url = models.CharField(
max_length=255,

View File

@ -24,7 +24,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name="plexsource",
name="plex_token",
field=models.TextField(default="", help_text="Plex token used to check firends"),
field=models.TextField(default="", help_text="Plex token used to check friends"),
),
migrations.AlterField(
model_name="plexsource",

View File

@ -13,6 +13,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name="plexsource",
name="plex_token",
field=models.TextField(help_text="Plex token used to check firends"),
field=models.TextField(help_text="Plex token used to check friends"),
),
]

View File

@ -50,7 +50,7 @@ class PlexSource(Source):
default=True,
help_text=_("Allow friends to authenticate, even if you don't share a server."),
)
plex_token = models.TextField(help_text=_("Plex token used to check firends"))
plex_token = models.TextField(help_text=_("Plex token used to check friends"))
@property
def component(self) -> str:

View File

@ -54,7 +54,7 @@ class CaptchaChallengeResponse(ChallengeResponse):
class CaptchaStageView(ChallengeStageView):
"""Simple captcha checker, logic is handeled in django-captcha module"""
"""Simple captcha checker, logic is handled in django-captcha module"""
response_class = CaptchaChallengeResponse

View File

@ -3,9 +3,9 @@ from datetime import timedelta
from django.contrib import messages
from django.http import HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.utils.http import urlencode
from django.utils.text import slugify
from django.utils.timezone import now
from django.utils.translation import gettext as _
from rest_framework.fields import CharField
@ -22,7 +22,7 @@ from authentik.stages.email.tasks import send_mails
from authentik.stages.email.utils import TemplateEmailMessage
LOGGER = get_logger()
QS_KEY_TOKEN = "token" # nosec
QS_KEY_TOKEN = "etoken" # nosec
PLAN_CONTEXT_EMAIL_SENT = "email_sent"
@ -65,7 +65,7 @@ class EmailStageView(ChallengeStageView):
) # + 1 because django timesince always rounds down
token_filters = {
"user": pending_user,
"identifier": f"ak-email-stage-{current_stage.name}-{pending_user}",
"identifier": slugify(f"ak-email-stage-{current_stage.name}-{pending_user}"),
}
# Don't check for validity here, we only care if the token exists
tokens = Token.objects.filter(**token_filters)
@ -99,7 +99,10 @@ class EmailStageView(ChallengeStageView):
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
# Check if the user came back from the email link to verify
if QS_KEY_TOKEN in request.session.get(SESSION_KEY_GET, {}):
token = get_object_or_404(Token, key=request.session[SESSION_KEY_GET][QS_KEY_TOKEN])
tokens = Token.filter_not_expired(key=request.session[SESSION_KEY_GET][QS_KEY_TOKEN])
if not tokens.exists():
return self.executor.stage_invalid(_("Invalid token"))
token = tokens.first()
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = token.user
token.delete()
messages.success(request, _("Successfully verified Email."))
@ -118,7 +121,7 @@ class EmailStageView(ChallengeStageView):
challenge = EmailChallenge(
data={
"type": ChallengeTypes.NATIVE.value,
"title": "Email sent.",
"title": _("Email sent."),
}
)
return challenge

View File

@ -15,7 +15,8 @@ from authentik.stages.invitation.signals import invitation_used
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
LOGGER = get_logger()
INVITATION_TOKEN_KEY = "token" # nosec
INVITATION_TOKEN_KEY_CONTEXT = "token" # nosec
INVITATION_TOKEN_KEY = "itoken" # nosec
INVITATION_IN_EFFECT = "invitation_in_effect"
INVITATION = "invitation"
@ -29,10 +30,14 @@ class InvitationStageView(StageView):
def get_token(self) -> Optional[str]:
"""Get token from saved get-arguments or prompt_data"""
# Check for ?token= and ?itoken=
if INVITATION_TOKEN_KEY in self.request.session.get(SESSION_KEY_GET, {}):
return self.request.session[SESSION_KEY_GET][INVITATION_TOKEN_KEY]
if INVITATION_TOKEN_KEY in self.executor.plan.context.get(PLAN_CONTEXT_PROMPT, {}):
return self.executor.plan.context[PLAN_CONTEXT_PROMPT][INVITATION_TOKEN_KEY]
if INVITATION_TOKEN_KEY_CONTEXT in self.request.session.get(SESSION_KEY_GET, {}):
return self.request.session[SESSION_KEY_GET][INVITATION_TOKEN_KEY_CONTEXT]
# Check for {'token': ''} in the context
if INVITATION_TOKEN_KEY_CONTEXT in self.executor.plan.context.get(PLAN_CONTEXT_PROMPT, {}):
return self.executor.plan.context[PLAN_CONTEXT_PROMPT][INVITATION_TOKEN_KEY_CONTEXT]
return None
def get(self, request: HttpRequest) -> HttpResponse:

View File

@ -15,7 +15,11 @@ from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
from authentik.flows.tests.test_views import TO_STAGE_RESPONSE_MOCK
from authentik.flows.views import SESSION_KEY_PLAN
from authentik.stages.invitation.models import Invitation, InvitationStage
from authentik.stages.invitation.stage import INVITATION_TOKEN_KEY, PLAN_CONTEXT_PROMPT
from authentik.stages.invitation.stage import (
INVITATION_TOKEN_KEY,
INVITATION_TOKEN_KEY_CONTEXT,
PLAN_CONTEXT_PROMPT,
)
from authentik.stages.password import BACKEND_INBUILT
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
@ -131,7 +135,7 @@ class TestUserLoginStage(APITestCase):
)
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
plan.context[PLAN_CONTEXT_PROMPT] = {INVITATION_TOKEN_KEY: invite.pk.hex}
plan.context[PLAN_CONTEXT_PROMPT] = {INVITATION_TOKEN_KEY_CONTEXT: invite.pk.hex}
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()

View File

@ -53,9 +53,11 @@ class PromptChallengeResponse(ChallengeResponse):
def __init__(self, *args, **kwargs):
stage: PromptStage = kwargs.pop("stage", None)
plan: FlowPlan = kwargs.pop("plan", None)
request: HttpRequest = kwargs.pop("request", None)
super().__init__(*args, **kwargs)
self.stage = stage
self.plan = plan
self.request = request
if not self.stage:
return
# list() is called so we only load the fields once
@ -104,8 +106,9 @@ class PromptChallengeResponse(ChallengeResponse):
self._validate_password_fields(*[field.field_key for field in password_fields])
user = self.plan.context.get(PLAN_CONTEXT_PENDING_USER, get_anonymous_user())
engine = ListPolicyEngine(self.stage.validation_policies.all(), user)
engine.request.context = attrs
engine = ListPolicyEngine(self.stage.validation_policies.all(), user, self.request)
engine.request.context[PLAN_CONTEXT_PROMPT] = attrs
engine.request.context.update(attrs)
engine.build()
result = engine.result
if not result.passing:
@ -173,6 +176,7 @@ class PromptStageView(ChallengeStageView):
return PromptChallengeResponse(
instance=None,
data=data,
request=self.request,
stage=self.executor.current_stage,
plan=self.executor.plan,
)

View File

@ -21,7 +21,7 @@ services:
networks:
- internal
server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.9.1-rc3}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.9.3}
restart: unless-stopped
command: server
environment:
@ -44,7 +44,7 @@ services:
- "0.0.0.0:9000:9000"
- "0.0.0.0:9443:9443"
worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.9.1-rc3}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.9.3}
restart: unless-stopped
command: worker
networks:

2
go.mod
View File

@ -34,7 +34,7 @@ require (
github.com/recws-org/recws v1.3.1
github.com/sirupsen/logrus v1.8.1
go.mongodb.org/mongo-driver v1.5.2 // indirect
goauthentik.io/api v0.0.0-20210913161416-2242c65afb14
goauthentik.io/api v0.202192.5
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558

4
go.sum
View File

@ -554,8 +554,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
goauthentik.io/api v0.0.0-20210913161416-2242c65afb14 h1:sOyZZNbhj6LquWGcGfw0muSbGJcAqRkcvIaGPJkB9I0=
goauthentik.io/api v0.0.0-20210913161416-2242c65afb14/go.mod h1:SPObiI/v8m5cjhj+bGvzb4Nm1w5gmlil5zHQx10sfjE=
goauthentik.io/api v0.202192.5 h1:BS4E71K2uZXy1vAdGVFLJJU0KwvAkkqKg42cYv46ud0=
goauthentik.io/api v0.202192.5/go.mod h1:02nnD4FRd8lu8A1+ZuzqownBgvAhdCKzqkKX8v7JMTE=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

View File

@ -17,4 +17,4 @@ func OutpostUserAgent() string {
return fmt.Sprintf("authentik-outpost@%s (build=%s)", VERSION, BUILD())
}
const VERSION = "2021.9.1-rc3"
const VERSION = "2021.9.3"

View File

@ -116,10 +116,9 @@ func (a *APIController) OnRefresh() error {
log.WithError(err).Error("Failed to fetch outpost configuration")
return err
}
outpost := outposts.Results[0]
doGlobalSetup(outpost.Config)
a.Outpost = outposts.Results[0]
log.WithField("name", outpost.Name).Debug("Fetched outpost configuration")
log.WithField("name", a.Outpost.Name).Debug("Fetched outpost configuration")
return a.Server.Refresh()
}

View File

@ -128,6 +128,7 @@ func (ac *APIController) startWSHealth() {
if err != nil {
ac.logger.WithField("loop", "ws-health").WithError(err).Warning("ws write error, reconnecting")
ac.wsConn.CloseAndReconnect()
time.Sleep(time.Second * 5)
continue
} else {
ConnectionStatus.With(prometheus.Labels{

View File

@ -79,6 +79,11 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult,
}).Inc()
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied")
}
if req.SearchRequest.Scope == ldap.ScopeBaseObject {
pi.log.Debug("base scope, showing domain info")
return pi.SearchBase(req, flags.CanSearch)
}
if !flags.CanSearch {
pi.log.Debug("User can't search, showing info about user")
return pi.SearchMe(req, flags)
@ -111,6 +116,12 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult,
"client": utils.GetIP(req.conn.RemoteAddr()),
}).Inc()
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, req.Filter)
case "groupOfUniqueNames":
fallthrough
case "goauthentik.io/ldap/group":
fallthrough
case "goauthentik.io/ldap/virtual-group":
fallthrough
case GroupObjectClass:
wg := sync.WaitGroup{}
wg.Add(2)
@ -160,7 +171,15 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult,
}()
wg.Wait()
entries = append(gEntries, uEntries...)
case UserObjectClass, "":
case "":
fallthrough
case "organizationalPerson":
fallthrough
case "inetOrgPerson":
fallthrough
case "goauthentik.io/ldap/user":
fallthrough
case UserObjectClass:
uapisp := sentry.StartSpan(req.ctx, "authentik.providers.ldap.search.api_user")
searchReq, skip := parseFilterForUser(c.CoreApi.CoreUsersList(uapisp.Context()), parsedFilter, false)
if skip {
@ -181,99 +200,45 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult,
}
func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry {
attrs := []*ldap.EntryAttribute{
{
Name: "cn",
Values: []string{u.Username},
},
{
Name: "sAMAccountName",
Values: []string{u.Username},
},
{
Name: "uid",
Values: []string{u.Uid},
},
{
Name: "name",
Values: []string{u.Name},
},
{
Name: "displayName",
Values: []string{u.Name},
},
{
Name: "mail",
Values: []string{*u.Email},
},
{
Name: "objectClass",
Values: []string{UserObjectClass, "organizationalPerson", "goauthentik.io/ldap/user"},
},
{
Name: "uidNumber",
Values: []string{pi.GetUidNumber(u)},
},
{
Name: "gidNumber",
Values: []string{pi.GetUidNumber(u)},
},
}
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: pi.GroupsForUser(u)})
// Old fields for backwards compatibility
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{BoolToString(*u.IsActive)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "superuser", Values: []string{BoolToString(u.IsSuperuser)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "goauthentik.io/ldap/active", Values: []string{BoolToString(*u.IsActive)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "goauthentik.io/ldap/superuser", Values: []string{BoolToString(u.IsSuperuser)}})
attrs = append(attrs, AKAttrsToLDAP(u.Attributes)...)
dn := pi.GetUserDN(u.Username)
attrs := AKAttrsToLDAP(u.Attributes)
attrs = pi.ensureAttributes(attrs, map[string][]string{
"memberOf": pi.GroupsForUser(u),
// Old fields for backwards compatibility
"accountStatus": {BoolToString(*u.IsActive)},
"superuser": {BoolToString(u.IsSuperuser)},
"goauthentik.io/ldap/active": {BoolToString(*u.IsActive)},
"goauthentik.io/ldap/superuser": {BoolToString(u.IsSuperuser)},
"cn": {u.Username},
"sAMAccountName": {u.Username},
"uid": {u.Uid},
"name": {u.Name},
"displayName": {u.Name},
"mail": {*u.Email},
"objectClass": {UserObjectClass, "organizationalPerson", "inetOrgPerson", "goauthentik.io/ldap/user"},
"uidNumber": {pi.GetUidNumber(u)},
"gidNumber": {pi.GetUidNumber(u)},
})
return &ldap.Entry{DN: dn, Attributes: attrs}
}
func (pi *ProviderInstance) GroupEntry(g LDAPGroup) *ldap.Entry {
attrs := []*ldap.EntryAttribute{
{
Name: "cn",
Values: []string{g.cn},
},
{
Name: "uid",
Values: []string{g.uid},
},
{
Name: "sAMAccountName",
Values: []string{g.cn},
},
{
Name: "gidNumber",
Values: []string{g.gidNumber},
},
}
attrs := AKAttrsToLDAP(g.akAttributes)
objectClass := []string{GroupObjectClass, "groupOfUniqueNames", "goauthentik.io/ldap/group"}
if g.isVirtualGroup {
attrs = append(attrs, &ldap.EntryAttribute{
Name: "objectClass",
Values: []string{GroupObjectClass, "goauthentik.io/ldap/group", "goauthentik.io/ldap/virtual-group"},
})
} else {
attrs = append(attrs, &ldap.EntryAttribute{
Name: "objectClass",
Values: []string{GroupObjectClass, "goauthentik.io/ldap/group"},
})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: "member", Values: g.member})
attrs = append(attrs, &ldap.EntryAttribute{Name: "goauthentik.io/ldap/superuser", Values: []string{BoolToString(g.isSuperuser)}})
if g.akAttributes != nil {
attrs = append(attrs, AKAttrsToLDAP(g.akAttributes)...)
objectClass = append(objectClass, "goauthentik.io/ldap/virtual-group")
}
attrs = pi.ensureAttributes(attrs, map[string][]string{
"objectClass": objectClass,
"member": g.member,
"goauthentik.io/ldap/superuser": {BoolToString(g.isSuperuser)},
"cn": {g.cn},
"uid": {g.uid},
"sAMAccountName": {g.cn},
"gidNumber": {g.gidNumber},
})
return &ldap.Entry{DN: g.dn, Attributes: attrs}
}

View File

@ -0,0 +1,53 @@
package ldap
import (
"fmt"
"github.com/nmcclain/ldap"
"goauthentik.io/internal/constants"
)
func (pi *ProviderInstance) SearchBase(req SearchRequest, authz bool) (ldap.ServerSearchResult, error) {
dn := ""
if authz {
dn = req.SearchRequest.BaseDN
}
return ldap.ServerSearchResult{
Entries: []*ldap.Entry{
{
DN: dn,
Attributes: []*ldap.EntryAttribute{
{
Name: "distinguishedName",
Values: []string{pi.BaseDN},
},
{
Name: "objectClass",
Values: []string{"top", "domain"},
},
{
Name: "supportedLDAPVersion",
Values: []string{"3"},
},
{
Name: "namingContexts",
Values: []string{
pi.BaseDN,
pi.GroupDN,
pi.UserDN,
},
},
{
Name: "vendorName",
Values: []string{"goauthentik.io"},
},
{
Name: "vendorVersion",
Values: []string{fmt.Sprintf("authentik LDAP Outpost Version %s (build %s)", constants.VERSION, constants.BUILD())},
},
},
},
},
Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess,
}, nil
}

View File

@ -38,7 +38,7 @@ func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn n
SearchRequest: searchReq,
BindDN: bindDN,
conn: conn,
log: ls.log.WithField("bindDN", bindDN).WithField("requestId", rid).WithField("client", utils.GetIP(conn.RemoteAddr())).WithField("filter", searchReq.Filter).WithField("baseDN", searchReq.BaseDN),
log: ls.log.WithField("bindDN", bindDN).WithField("requestId", rid).WithField("scope", ldap.ScopeMap[searchReq.Scope]).WithField("client", utils.GetIP(conn.RemoteAddr())).WithField("filter", searchReq.Filter).WithField("baseDN", searchReq.BaseDN),
id: rid,
ctx: span.Context(),
}
@ -60,7 +60,7 @@ func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn n
if err == nil {
return
}
log.WithError(err.(error)).Error("recover in serach request")
log.WithError(err.(error)).Error("recover in search request")
sentry.CaptureException(err.(error))
}()
@ -74,7 +74,7 @@ func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn n
}
for _, provider := range ls.providers {
providerBase, _ := goldap.ParseDN(provider.BaseDN)
if providerBase.AncestorOf(bd) {
if providerBase.AncestorOf(bd) || providerBase.Equal(bd) {
return provider.Search(req)
}
}

View File

@ -39,6 +39,9 @@ func ldapResolveTypeSingle(in interface{}) *string {
func AKAttrsToLDAP(attrs interface{}) []*ldap.EntryAttribute {
attrList := []*ldap.EntryAttribute{}
if attrs == nil {
return attrList
}
a := attrs.(*map[string]interface{})
for attrKey, attrValue := range *a {
entry := &ldap.EntryAttribute{Name: attrKey}
@ -140,3 +143,26 @@ func (pi *ProviderInstance) GetRIDForGroup(uid string) int32 {
return int32(gid)
}
func (pi *ProviderInstance) ensureAttributes(attrs []*ldap.EntryAttribute, shouldHave map[string][]string) []*ldap.EntryAttribute {
for name, values := range shouldHave {
attrs = pi.mustHaveAttribute(attrs, name, values)
}
return attrs
}
func (pi *ProviderInstance) mustHaveAttribute(attrs []*ldap.EntryAttribute, name string, value []string) []*ldap.EntryAttribute {
shouldSet := true
for _, attr := range attrs {
if attr.Name == name {
shouldSet = false
}
}
if shouldSet {
return append(attrs, &ldap.EntryAttribute{
Name: name,
Values: value,
})
}
return attrs
}

View File

@ -18,7 +18,7 @@ type OIDCEndpoint struct {
func GetOIDCEndpoint(p api.ProxyOutpostConfig, authentikHost string) OIDCEndpoint {
authUrl := p.OidcConfiguration.AuthorizationEndpoint
endUrl := p.OidcConfiguration.EndSessionEndpoint
if browserHost, found := os.LookupEnv("AUTHENTIK_HOST_BROWSER"); found {
if browserHost, found := os.LookupEnv("AUTHENTIK_HOST_BROWSER"); found && browserHost != "" {
host := os.Getenv("AUTHENTIK_HOST")
authUrl = strings.ReplaceAll(authUrl, host, browserHost)
endUrl = strings.ReplaceAll(endUrl, host, browserHost)

View File

@ -18,12 +18,22 @@ func GetStore(p api.ProxyOutpostConfig) sessions.Store {
if err != nil {
panic(err)
}
if p.TokenValidity.IsSet() {
t := p.TokenValidity.Get()
// Add one to the validity to ensure we don't have a session with indefinite length
rs.Options.MaxAge = int(*t) + 1
}
rs.Options.Domain = *p.CookieDomain
log.Info("using redis session backend")
store = rs
} else {
cs := sessions.NewCookieStore([]byte(*p.CookieSecret))
cs.Options.Domain = *p.CookieDomain
if p.TokenValidity.IsSet() {
t := p.TokenValidity.Get()
// Add one to the validity to ensure we don't have a session with indefinite length
cs.Options.MaxAge = int(*t) + 1
}
log.Info("using cookie session backend")
store = cs
}

View File

@ -45,6 +45,15 @@ func (ps *ProxyServer) Handle(rw http.ResponseWriter, r *http.Request) {
host := web.GetHost(r)
a, ok := ps.apps[host]
if !ok {
// If we only have one handler, host name switching doesn't matter
if len(ps.apps) == 1 {
ps.log.WithField("host", host).Warning("passing to single app mux")
for k := range ps.apps {
ps.apps[k].ServeHTTP(rw, r)
return
}
}
ps.log.WithField("host", host).Warning("no app for hostname")
rw.WriteHeader(400)
return

View File

@ -36,13 +36,15 @@ func (ws *WebServer) configureStatic() {
}
statRouter.PathPrefix("/static/dist/").Handler(distHandler)
statRouter.PathPrefix("/static/authentik/").Handler(authentikHandler)
// Prevent font-loading issues on safari, which loads fonts relatively to the URL the browser is on
statRouter.PathPrefix("/if/flow/{flow_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
http.StripPrefix(fmt.Sprintf("/if/flow/%s", vars["flow_slug"]), distFs).ServeHTTP(rw, r)
disableIndex(http.StripPrefix(fmt.Sprintf("/if/flow/%s", vars["flow_slug"]), distFs)).ServeHTTP(rw, r)
})
statRouter.PathPrefix("/if/admin/assets").Handler(http.StripPrefix("/if/admin", distFs))
statRouter.PathPrefix("/if/admin/assets").Handler(disableIndex(http.StripPrefix("/if/admin", distFs)))
statRouter.PathPrefix("/if/user/assets").Handler(disableIndex(http.StripPrefix("/if/user", distFs)))
statRouter.PathPrefix("/media/").Handler(http.StripPrefix("/media", fs))

View File

@ -17,4 +17,6 @@ COPY --from=builder /go/ldap /
HEALTHCHECK CMD [ "wget", "--spider", "http://localhost:9300/akprox/ping" ]
EXPOSE 3389 6636 9300
ENTRYPOINT ["/ldap"]

View File

@ -29,4 +29,6 @@ COPY --from=builder /go/proxy /
HEALTHCHECK CMD [ "wget", "--spider", "http://localhost:9300/akprox/ping" ]
EXPOSE 9000 9300 9443
ENTRYPOINT ["/proxy"]

View File

@ -15,13 +15,7 @@ force_to_top = "*"
[tool.coverage.run]
source = ["authentik"]
relative_files = true
omit = [
"*/asgi.py",
"manage.py",
"*/migrations/*",
"*/apps.py",
"website/",
]
omit = ["*/asgi.py", "manage.py", "*/migrations/*", "*/apps.py", "website/"]
[tool.coverage.report]
sort = "Cover"
@ -45,35 +39,36 @@ exclude_lines = [
show_missing = true
[tool.pylint.master]
disable =[
"arguments-differ",
"no-self-use",
"fixme",
"locally-disabled",
"too-many-ancestors",
"too-few-public-methods",
"import-outside-toplevel",
"bad-continuation",
"signature-differs",
"similarities",
"cyclic-import",
"protected-access",
"raise-missing-from",
# To preverse django's translation function we need to use %-formatting
"consider-using-f-string",]
disable = [
"arguments-differ",
"no-self-use",
"fixme",
"locally-disabled",
"too-many-ancestors",
"too-few-public-methods",
"import-outside-toplevel",
"bad-continuation",
"signature-differs",
"similarities",
"cyclic-import",
"protected-access",
"raise-missing-from",
# To preverse django's translation function we need to use %-formatting
"consider-using-f-string",
]
load-plugins=["pylint_django","pylint.extensions.bad_builtin"]
django-settings-module="authentik.root.settings"
extension-pkg-whitelist=["lxml","xmlsec"]
load-plugins = ["pylint_django", "pylint.extensions.bad_builtin"]
django-settings-module = "authentik.root.settings"
extension-pkg-whitelist = ["lxml", "xmlsec"]
# Allow constants to be shorter than normal (and lowercase, for settings.py)
const-rgx="[a-zA-Z0-9_]{1,40}$"
const-rgx = "[a-zA-Z0-9_]{1,40}$"
ignored-modules=["django-otp","binascii", "socket", "zlib"]
generated-members=["xmlsec.constants.*","xmlsec.tree.*","xmlsec.template.*"]
ignore="migrations"
max-attributes=12
max-branches=20
ignored-modules = ["django-otp", "binascii", "socket", "zlib"]
generated-members = ["xmlsec.constants.*", "xmlsec.tree.*", "xmlsec.template.*"]
ignore = "migrations"
max-attributes = 12
max-branches = 20
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "authentik.root.settings"

View File

@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: authentik
version: 2021.9.1-rc3
version: 2021.9.3
description: Making authentication simple.
contact:
email: hello@beryju.org
@ -4702,8 +4702,6 @@ paths:
schema:
$ref: '#/components/schemas/ChallengeTypes'
description: ''
'404':
description: No Token found
'400':
$ref: '#/components/schemas/ValidationError'
'403':
@ -11397,7 +11395,7 @@ paths:
/root/config/:
get:
operationId: root_config_retrieve
description: Retrive public configuration options
description: Retrieve public configuration options
tags:
- root
security:
@ -21582,6 +21580,7 @@ components:
readOnly: true
webhook_url:
type: string
format: uri
webhook_mapping:
type: string
format: uuid
@ -21611,6 +21610,7 @@ components:
$ref: '#/components/schemas/NotificationTransportModeEnum'
webhook_url:
type: string
format: uri
webhook_mapping:
type: string
format: uuid
@ -21908,7 +21908,7 @@ components:
access_token_url:
type: string
nullable: true
description: URL used by authentik to retrive tokens.
description: URL used by authentik to retrieve tokens.
maxLength: 255
profile_url:
type: string
@ -21983,7 +21983,7 @@ components:
access_token_url:
type: string
nullable: true
description: URL used by authentik to retrive tokens.
description: URL used by authentik to retrieve tokens.
maxLength: 255
profile_url:
type: string
@ -25810,6 +25810,7 @@ components:
$ref: '#/components/schemas/NotificationTransportModeEnum'
webhook_url:
type: string
format: uri
webhook_mapping:
type: string
format: uuid
@ -25936,7 +25937,7 @@ components:
access_token_url:
type: string
nullable: true
description: URL used by authentik to retrive tokens.
description: URL used by authentik to retrieve tokens.
maxLength: 255
profile_url:
type: string
@ -26114,7 +26115,7 @@ components:
description: Allow friends to authenticate, even if you don't share a server.
plex_token:
type: string
description: Plex token used to check firends
description: Plex token used to check friends
PatchedPolicyBindingRequest:
type: object
description: PolicyBinding Serializer
@ -26747,7 +26748,7 @@ components:
description: Allow friends to authenticate, even if you don't share a server.
plex_token:
type: string
description: Plex token used to check firends
description: Plex token used to check friends
required:
- component
- name
@ -26842,7 +26843,7 @@ components:
description: Allow friends to authenticate, even if you don't share a server.
plex_token:
type: string
description: Plex token used to check firends
description: Plex token used to check friends
required:
- name
- plex_token
@ -27377,11 +27378,17 @@ components:
Exclusive with internal_host.
cookie_domain:
type: string
token_validity:
type: number
format: float
nullable: true
readOnly: true
required:
- external_host
- name
- oidc_configuration
- pk
- token_validity
ProxyProvider:
type: object
description: ProxyProvider Serializer

View File

@ -217,6 +217,7 @@ class TestProviderLDAP(SeleniumTestCase):
"objectClass": [
"user",
"organizationalPerson",
"inetOrgPerson",
"goauthentik.io/ldap/user",
],
"uidNumber": [str(2000 + outpost_user.pk)],
@ -243,6 +244,7 @@ class TestProviderLDAP(SeleniumTestCase):
"objectClass": [
"user",
"organizationalPerson",
"inetOrgPerson",
"goauthentik.io/ldap/user",
],
"uidNumber": [str(2000 + embedded_account.pk)],
@ -269,6 +271,7 @@ class TestProviderLDAP(SeleniumTestCase):
"objectClass": [
"user",
"organizationalPerson",
"inetOrgPerson",
"goauthentik.io/ldap/user",
],
"uidNumber": [str(2000 + USER().pk)],

View File

@ -6,3 +6,5 @@ dist
coverage
# don't lint generated code
api/
# Import order matters
poly.ts

View File

@ -14,5 +14,7 @@
"tabWidth": 4,
"trailingComma": "all",
"useTabs": false,
"vueIndentScriptAndStyle": false
"vueIndentScriptAndStyle": false,
"importOrder": ["^@lingui/(.*)$", "^lit(.*)$", "\\.css$", "^@goauthentik/api$", "^[./]"],
"importOrderSeparation": true
}

680
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -47,30 +47,31 @@
"@babel/preset-env": "^7.15.6",
"@babel/preset-typescript": "^7.15.0",
"@fortawesome/fontawesome-free": "^5.15.4",
"@goauthentik/api": "^2021.9.1-rc2-1631875394",
"@goauthentik/api": "^2021.9.2-1632578262",
"@lingui/cli": "^3.11.1",
"@lingui/core": "^3.11.1",
"@lingui/macro": "^3.11.1",
"@patternfly/patternfly": "^4.132.2",
"@patternfly/patternfly": "^4.135.2",
"@polymer/iron-form": "^3.0.1",
"@polymer/paper-input": "^3.2.1",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-replace": "^3.0.0",
"@rollup/plugin-typescript": "^8.2.5",
"@sentry/browser": "^6.12.0",
"@sentry/tracing": "^6.12.0",
"@sentry/browser": "^6.13.2",
"@sentry/tracing": "^6.13.2",
"@squoosh/cli": "^0.7.2",
"@trivago/prettier-plugin-sort-imports": "^2.0.4",
"@types/chart.js": "^2.9.34",
"@types/codemirror": "5.60.2",
"@types/codemirror": "5.60.3",
"@types/grecaptcha": "^3.0.3",
"@typescript-eslint/eslint-plugin": "^4.31.1",
"@typescript-eslint/parser": "^4.31.1",
"@typescript-eslint/eslint-plugin": "^4.31.2",
"@typescript-eslint/parser": "^4.31.2",
"@webcomponents/webcomponentsjs": "^2.6.0",
"babel-plugin-macros": "^3.1.0",
"base64-js": "^1.5.1",
"chart.js": "^3.5.1",
"chartjs-adapter-moment": "^1.0.0",
"codemirror": "^5.62.3",
"codemirror": "^5.63.0",
"construct-style-sheets-polyfill": "^2.4.16",
"eslint": "^7.32.0",
"eslint-config-google": "^0.14.0",
@ -78,12 +79,11 @@
"eslint-plugin-lit": "^1.5.1",
"flowchart.js": "^1.15.0",
"fuse.js": "^6.4.6",
"lit-element": "^2.5.1",
"lit-html": "^1.4.1",
"lit": "^2.0.0",
"moment": "^2.29.1",
"prettier": "^2.4.1",
"rapidoc": "^9.1.0",
"rollup": "^2.56.2",
"rapidoc": "^9.1.3",
"rollup": "^2.57.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-cssimport": "^1.0.2",

View File

@ -2,3 +2,4 @@
window["polymerSkipLoadingFontRoboto"] = true;
import "construct-style-sheets-polyfill";
import "@webcomponents/webcomponentsjs";
import "lit/polyfill-support";

View File

@ -1,11 +1,11 @@
import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import { terser } from "rollup-plugin-terser";
import sourcemaps from "rollup-plugin-sourcemaps";
import cssimport from "rollup-plugin-cssimport";
import copy from "rollup-plugin-copy";
import babel from "@rollup/plugin-babel";
import replace from "@rollup/plugin-replace";
import commonjs from "rollup-plugin-commonjs";
import copy from "rollup-plugin-copy";
import cssimport from "rollup-plugin-cssimport";
import resolve from "rollup-plugin-node-resolve";
import sourcemaps from "rollup-plugin-sourcemaps";
import { terser } from "rollup-plugin-terser";
const extensions = [".js", ".jsx", ".ts", ".tsx"];

View File

@ -1,4 +1,5 @@
import { t } from "@lingui/macro";
import { EVENT_WS_MESSAGE } from "../constants";
import { MessageLevel } from "../elements/messages/Message";
import { showMessage } from "../elements/messages/MessageContainer";

View File

@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
export const ERROR_CLASS = "pf-m-danger";
export const PROGRESS_CLASS = "pf-m-in-progress";
export const CURRENT_CLASS = "pf-m-current";
export const VERSION = "2021.9.1-rc3";
export const VERSION = "2021.9.3";
export const PAGE_SIZE = 20;
export const TITLE_DEFAULT = "authentik";
export const ROUTE_SEPARATOR = ";";

View File

@ -1,29 +1,23 @@
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
import CodeMirror from "codemirror";
import "codemirror/addon/dialog/dialog";
import "codemirror/addon/display/autorefresh";
import "codemirror/addon/hint/show-hint";
import "codemirror/addon/search/search";
import "codemirror/addon/search/searchcursor";
import "codemirror/addon/dialog/dialog";
import "codemirror/addon/hint/show-hint";
import "codemirror/mode/xml/xml.js";
import "codemirror/mode/yaml/yaml.js";
import "codemirror/mode/javascript/javascript.js";
import "codemirror/mode/python/python.js";
import CodeMirrorStyle from "codemirror/lib/codemirror.css";
import CodeMirrorTheme from "codemirror/theme/monokai.css";
import "codemirror/mode/xml/xml.js";
import "codemirror/mode/yaml/yaml.js";
import YAML from "yaml";
import { css, CSSResult, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import CodeMirrorDialogStyle from "codemirror/addon/dialog/dialog.css";
import CodeMirrorShowHintStyle from "codemirror/addon/hint/show-hint.css";
import { ifDefined } from "lit-html/directives/if-defined";
import YAML from "yaml";
import CodeMirrorStyle from "codemirror/lib/codemirror.css";
import CodeMirrorTheme from "codemirror/theme/monokai.css";
@customElement("ak-codemirror")
export class CodeMirrorTextarea extends LitElement {

View File

@ -1,6 +1,8 @@
import { css, CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { css, CSSResult, html, LitElement, TemplateResult } from "lit";
import { customElement } from "lit/decorators";
import AKGlobal from "../authentik.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
@customElement("ak-divider")
export class Divider extends LitElement {

View File

@ -1,8 +1,10 @@
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import PFEmptyState from "@patternfly/patternfly/components/EmptyState/empty-state.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import { CSSResult, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import AKGlobal from "../authentik.css";
import PFEmptyState from "@patternfly/patternfly/components/EmptyState/empty-state.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { PFSize } from "./Spinner";

View File

@ -1,5 +1,8 @@
import { t } from "@lingui/macro";
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { CSSResult, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import PFExpandableSection from "../../node_modules/@patternfly/patternfly/components/ExpandableSection/expandable-section.css";
@customElement("ak-expand")

View File

@ -1,7 +1,9 @@
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFLabel from "@patternfly/patternfly/components/Label/label.css";
import { CSSResult, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import AKGlobal from "../authentik.css";
import PFLabel from "@patternfly/patternfly/components/Label/label.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
export enum PFColor {
Green = "pf-m-green",

View File

@ -1,13 +1,8 @@
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
import { css, CSSResult, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { PFSize } from "./Spinner";
@customElement("ak-loading-overlay")

View File

@ -1,25 +1,22 @@
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
import { css, CSSResult, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import AKGlobal from "../authentik.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { EventsApi } from "@goauthentik/api";
import { DEFAULT_CONFIG, tenant } from "../api/Config";
import {
EVENT_API_DRAWER_TOGGLE,
EVENT_NOTIFICATION_DRAWER_TOGGLE,
EVENT_REFRESH,
EVENT_SIDEBAR_TOGGLE,
TITLE_DEFAULT,
} from "../constants";
import { DEFAULT_CONFIG, tenant } from "../api/Config";
import { EventsApi } from "@goauthentik/api";
@customElement("ak-page-header")
export class PageHeader extends LitElement {
@ -90,14 +87,11 @@ export class PageHeader extends LitElement {
];
}
renderIcon(): TemplateResult {
if (this.icon) {
if (this.iconImage) {
return html`<img class="pf-icon" src="${this.icon}" />&nbsp;`;
}
return html`<i class=${this.icon}></i>&nbsp;`;
}
return html``;
constructor() {
super();
window.addEventListener(EVENT_REFRESH, () => {
this.firstUpdated();
});
}
firstUpdated(): void {
@ -112,6 +106,16 @@ export class PageHeader extends LitElement {
});
}
renderIcon(): TemplateResult {
if (this.icon) {
if (this.iconImage) {
return html`<img class="pf-icon" src="${this.icon}" />&nbsp;`;
}
return html`<i class=${this.icon}></i>&nbsp;`;
}
return html``;
}
render(): TemplateResult {
return html`<button
class="sidebar-trigger pf-c-button pf-m-plain"

View File

@ -1,5 +1,8 @@
import { t } from "@lingui/macro";
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { CSSResult, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import PFSpinner from "@patternfly/patternfly/components/Spinner/spinner.css";
export enum PFSize {

View File

@ -1,18 +1,14 @@
import {
LitElement,
html,
customElement,
property,
CSSResult,
TemplateResult,
css,
} from "lit-element";
import { ifDefined } from "lit-html/directives/if-defined";
import { t } from "@lingui/macro";
import { LitElement, html, CSSResult, TemplateResult, css } from "lit";
import { customElement, property } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import AKGlobal from "../authentik.css";
import PFTabs from "@patternfly/patternfly/components/Tabs/tabs.css";
import PFGlobal from "@patternfly/patternfly/patternfly-base.css";
import AKGlobal from "../authentik.css";
import { CURRENT_CLASS, ROUTE_SEPARATOR } from "../constants";
import { t } from "@lingui/macro";
@customElement("ak-tabs")
export class Tabs extends LitElement {

View File

@ -1,17 +1,17 @@
import { customElement, property } from "lit-element";
import { SpinnerButton } from "./SpinnerButton";
import { showMessage } from "../messages/MessageContainer";
import { customElement, property } from "lit/decorators";
import { MessageLevel } from "../messages/Message";
import { showMessage } from "../messages/MessageContainer";
import { SpinnerButton } from "./SpinnerButton";
@customElement("ak-action-button")
export class ActionButton extends SpinnerButton {
@property({ attribute: false })
// eslint-disable-next-line @typescript-eslint/no-explicit-any
apiRequest: () => Promise<any> = () => {
apiRequest: () => Promise<unknown> = () => {
throw new Error();
};
callAction = (): Promise<void> => {
callAction = (): Promise<unknown> => {
this.setLoading();
return this.apiRequest().catch((e: Error | Response) => {
if (e instanceof Error) {

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