Compare commits

..

70 Commits

Author SHA1 Message Date
e0f48a30b7 release: 2021.6.1-rc6 2021-06-15 21:18:33 +02:00
973f14d911 ci: only build stable images when non-rc version
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-15 18:41:26 +02:00
e8978adc1b outpost: fix syntax error when creating an outpost with connection
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-15 18:39:51 +02:00
3ca8d9c968 ci: build and push stable tag when rc not in release name
closes #1023

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-15 17:34:23 +02:00
42636142fa build(deps): bump @typescript-eslint/parser in /web (#1021)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 4.26.1 to 4.27.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.27.0/packages/parser)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-15 09:29:14 +02:00
57c459348f build(deps): bump @sentry/tracing from 6.6.0 to 6.7.0 in /web (#1020)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 6.6.0 to 6.7.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/6.6.0...6.7.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-15 09:28:55 +02:00
493b34cf0d build(deps): bump boto3 from 1.17.93 to 1.17.94 (#1022) 2021-06-15 08:55:32 +02:00
f0493f418b build(deps): bump @sentry/browser from 6.6.0 to 6.7.0 in /web (#1019) 2021-06-15 08:55:05 +02:00
d45a292652 build(deps): bump @babel/core from 7.14.5 to 7.14.6 in /web (#1018) 2021-06-15 08:54:44 +02:00
b21ea360db build(deps): bump @lingui/core from 3.10.2 to 3.10.3 in /web (#1016) 2021-06-15 08:54:36 +02:00
6816f8b851 build(deps): bump postcss from 8.3.2 to 8.3.4 in /website (#1015) 2021-06-15 08:54:18 +02:00
de714f0390 build(deps): bump @typescript-eslint/eslint-plugin in /web (#1017) 2021-06-15 08:54:10 +02:00
800df332b5 stages/authenticator_duo: don't create default duo stage
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 22:55:37 +02:00
16c194d2dc core: fix upload api not checking clear properly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 22:34:47 +02:00
53100a72fe stages/identification: fix challenges not being annotated correctly and API client not loading data correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 22:28:11 +02:00
ec4c3f44cb events: don't create system exception event in debug
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 22:16:27 +02:00
f10bd432b3 policies/reputation: fix race condition in tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 20:40:40 +02:00
4de927ba5b web/admin: fix link for github issue creation
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 18:55:43 +02:00
74e578c2bf events: add tenant to event
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 18:43:29 +02:00
e584fd1344 events: catch unhandled exceptions from request as event, add button to open github issue
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 17:22:58 +02:00
0e02925a3d stages/authenticator_validate: add tests for authenticator validation
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 16:32:36 +02:00
5b837c3ccc providers/saml: improve error handling for signature errors
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 12:51:42 +02:00
2580371f94 outposts: fix error when getting component for base service connection
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 12:38:29 +02:00
4e9be85353 website/docs: add docs for outpost configuration
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-14 09:21:35 +02:00
79508e1965 core: fix linting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 23:41:50 +02:00
3a88dde545 web: fix declaration of Intl
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 23:13:43 +02:00
31fc4d1cb9 web: migrate banner to sidebar
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 22:55:41 +02:00
09cd8f8f63 web/admin: fix ak-application-check-access-form for get api
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 22:40:51 +02:00
d824b09365 outposts/ldap: improve responses for unsuccessful binds
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 22:00:05 +02:00
cabbd18880 core: revert check_access API to get to prevent CSRF errors
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 21:47:49 +02:00
c9dda17c68 web/admin: select service connection by default when only one exists
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 20:12:01 +02:00
bb8559ee18 web: remove base interface
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 19:54:27 +02:00
5ae32e525c web/flows: improve display of allowed fields for identification stage
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 16:30:03 +02:00
0832145a01 web: fix fields for new api schema
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 15:36:25 +02:00
4167276c8f root: fix references to helm chart
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 14:30:44 +02:00
afb84c7bc5 flows: fix error clearing flow background when no files have been uploaded
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 14:14:41 +02:00
82b2c7e3f0 web: add capabilities to sentry event
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 14:08:39 +02:00
fc8004db2b outposts: fix integrity error with tokens
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 13:36:54 +02:00
ddfc943bba root: fix build_hash being set incorrectly for tagged versions
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 13:32:18 +02:00
8c0c12292e build(deps): bump tslib from 2.2.0 to 2.3.0 in /web (#1011)
Bumps [tslib](https://github.com/Microsoft/tslib) from 2.2.0 to 2.3.0.
- [Release notes](https://github.com/Microsoft/tslib/releases)
- [Commits](https://github.com/Microsoft/tslib/compare/2.2.0...2.3.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-13 13:08:50 +02:00
803490d98b build(deps): bump rollup from 2.51.1 to 2.51.2 in /web (#1012)
Bumps [rollup](https://github.com/rollup/rollup) from 2.51.1 to 2.51.2.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v2.51.1...v2.51.2)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-13 13:08:38 +02:00
16835ab478 build(deps): bump boto3 from 1.17.92 to 1.17.93 (#1013)
Bumps [boto3](https://github.com/boto/boto3) from 1.17.92 to 1.17.93.
- [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.17.92...1.17.93)

---
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-06-13 13:08:27 +02:00
572b8d87b5 api: fix import error
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 12:59:28 +02:00
31d2ea65fd provider/proxy: mark forward_auth flag as deprecated
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 12:39:25 +02:00
f4ac2f50e2 sources/saml: check sessions before deleting user
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 12:39:10 +02:00
969a3f0ddd build(deps): bump drf-spectacular from 0.17.0 to 0.17.1 (#1014)
Bumps [drf-spectacular](https://github.com/tfranzel/drf-spectacular) from 0.17.0 to 0.17.1.
- [Release notes](https://github.com/tfranzel/drf-spectacular/releases)
- [Changelog](https://github.com/tfranzel/drf-spectacular/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tfranzel/drf-spectacular/compare/0.17.0...0.17.1)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-13 12:28:24 +02:00
4e18f47f28 web/flows: fix expiry not shown on consent stage when loading
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-13 12:21:11 +02:00
f10286edf8 Merge branch 'version-2021.6' into next 2021-06-12 20:43:12 +02:00
d789dcc28f core: fix impersonation not working with inactive users
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-12 20:41:02 +02:00
715a71427e web/admin: fix user enable/disable modal not matching other modals
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-12 20:31:02 +02:00
84c21d16cf website: fix duplicate plugin ID
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-12 20:15:35 +02:00
2e4e17adb7 web/flows: fix IdentificationStage's label not matching fields
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-12 18:49:50 +02:00
00cbaaf672 web/flows: improve display of errors
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-12 18:18:36 +02:00
74e4e8f6aa core: delete real session when AuthenticatedSession is deleted
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-12 17:37:32 +02:00
d78fda990a release: 2021.6.1-rc5 2021-06-12 15:19:24 +02:00
10d949f7a9 stages/password: add constants for password backends
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-12 12:14:55 +02:00
6661af032d build(deps): bump @sentry/tracing from 6.5.1 to 6.6.0 in /web (#1007)
Bumps [@sentry/tracing](https://github.com/getsentry/sentry-javascript) from 6.5.1 to 6.6.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/6.5.1...6.6.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-11 09:28:58 +02:00
fb5e4a3af8 build(deps): bump postcss from 8.3.1 to 8.3.2 in /website (#1006) 2021-06-11 08:25:06 +02:00
1dfad83a34 build(deps): bump @sentry/browser from 6.5.1 to 6.6.0 in /web (#1008) 2021-06-11 08:24:48 +02:00
70025c648c build(deps): bump boto3 from 1.17.91 to 1.17.92 (#1009) 2021-06-11 08:24:24 +02:00
676b77aa7c stages/identification: add UPN
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-10 22:48:39 +02:00
e35e096266 stages/authenticator_webauthn: use tenant title as RP_NAME
closes #1004

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-10 22:17:25 +02:00
7af12d4fec stages/authenticator_totp: set TOTP issuer based on slug'd tenant title
closes #1004

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-10 22:16:37 +02:00
8d6db0fabf flows: fix configuration URL being set when no flow is configure
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-10 22:07:26 +02:00
8ddcf99bf7 web: fix flow download link
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-10 21:47:40 +02:00
e25f6aea8c release: 2021.6.1-rc4 2021-06-10 18:59:00 +02:00
b1a9eda1d3 ci: fix release test using wrong docker image
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-10 18:58:30 +02:00
2c15ab9995 release: 2021.6.1-rc3 2021-06-10 18:04:59 +02:00
b3c51e426d web: fix styling for toggle group on dark mode
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-10 18:02:27 +02:00
71578af47f ci: fix testing for release tag
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-06-10 17:41:54 +02:00
109 changed files with 1394 additions and 788 deletions

View File

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

View File

@ -1,5 +1,4 @@
env
helm
static
htmlcov
*.env.yml

View File

@ -33,12 +33,22 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik:2021.6.1-rc2,
beryju/authentik:2021.6.1-rc6,
beryju/authentik:latest,
ghcr.io/goauthentik/server:2021.6.1-rc2,
ghcr.io/goauthentik/server:2021.6.1-rc6,
ghcr.io/goauthentik/server:latest
platforms: linux/amd64,linux/arm64
context: .
- name: Building Docker Image (stable)
uses: docker/build-push-action@v2
if: ${{ github.event_name == 'release' && !contains('2021.6.1-rc6', 'rc') }}
with:
push: true
tags: |
beryju/authentik:stable,
ghcr.io/goauthentik/server:stable
platforms: linux/amd64,linux/arm64
context: .
build-proxy:
runs-on: ubuntu-latest
steps:
@ -66,12 +76,22 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-proxy:2021.6.1-rc2,
beryju/authentik-proxy:2021.6.1-rc6,
beryju/authentik-proxy:latest,
ghcr.io/goauthentik/proxy:2021.6.1-rc2,
ghcr.io/goauthentik/proxy:2021.6.1-rc6,
ghcr.io/goauthentik/proxy:latest
file: outpost/proxy.Dockerfile
platforms: linux/amd64,linux/arm64
- name: Building Docker Image (stable)
uses: docker/build-push-action@v2
if: ${{ github.event_name == 'release' && !contains('2021.6.1-rc6', 'rc') }}
with:
push: true
tags: |
beryju/authentik-proxy:stable,
ghcr.io/goauthentik/proxy:stable
platforms: linux/amd64,linux/arm64
context: .
build-ldap:
runs-on: ubuntu-latest
steps:
@ -99,12 +119,22 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-ldap:2021.6.1-rc2,
beryju/authentik-ldap:2021.6.1-rc6,
beryju/authentik-ldap:latest,
ghcr.io/goauthentik/ldap:2021.6.1-rc2,
ghcr.io/goauthentik/ldap:2021.6.1-rc6,
ghcr.io/goauthentik/ldap:latest
file: outpost/ldap.Dockerfile
platforms: linux/amd64,linux/arm64
- name: Building Docker Image (stable)
uses: docker/build-push-action@v2
if: ${{ github.event_name == 'release' && !contains('2021.6.1-rc6', 'rc') }}
with:
push: true
tags: |
beryju/authentik-ldap:stable,
ghcr.io/goauthentik/ldap:stable
platforms: linux/amd64,linux/arm64
context: .
test-release:
if: ${{ github.event_name == 'release' }}
needs:
@ -138,5 +168,5 @@ jobs:
SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org
with:
version: authentik@2021.6.1-rc2
version: authentik@2021.6.1-rc6
environment: beryjuorg-prod

View File

@ -20,11 +20,11 @@ jobs:
docker-compose pull -q
docker build \
--no-cache \
-t beryju/authentik:latest \
-t ghcr.io/goauthentik/server:latest \
-f Dockerfile .
docker-compose up --no-start
docker-compose start postgresql redis
docker-compose run -u root --entrypoint /bin/bash server -c "apt-get update && apt-get install -y --no-install-recommends git && pip install --no-cache -r requirements-dev.txt && ./manage.py test authentik"
docker-compose run -u root server test
- name: Extract version number
id: get_version
uses: actions/github-script@v4.0.2

4
.gitignore vendored
View File

@ -193,10 +193,6 @@ pip-selfcheck.json
local.env.yml
.vscode/
### Helm ###
# Chart dependencies
**/charts/*.tgz
# Selenium Screenshots
selenium_screenshots/
backups/

111
Pipfile.lock generated
View File

@ -56,6 +56,7 @@
"sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a",
"sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"
],
"markers": "python_version >= '3.6'",
"version": "==3.7.4.post0"
},
"aioredis": {
@ -70,6 +71,7 @@
"sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2",
"sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb"
],
"markers": "python_version >= '3.6'",
"version": "==5.0.6"
},
"asgiref": {
@ -77,6 +79,7 @@
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
],
"markers": "python_version >= '3.6'",
"version": "==3.3.4"
},
"async-timeout": {
@ -84,6 +87,7 @@
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
],
"markers": "python_full_version >= '3.5.3'",
"version": "==3.0.1"
},
"attrs": {
@ -91,6 +95,7 @@
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==21.2.0"
},
"autobahn": {
@ -98,6 +103,7 @@
"sha256:9195df8af03b0ff29ccd4b7f5abbde957ee90273465942205f9a1bad6c3f07ac",
"sha256:e126c1f583e872fb59e79d36977cfa1f2d0a8a79f90ae31f406faae7664b8e03"
],
"markers": "python_version >= '3.7'",
"version": "==21.3.1"
},
"automat": {
@ -116,23 +122,26 @@
},
"boto3": {
"hashes": [
"sha256:4cfab400cd9ca9b27b7dffb43f5675525ea5d36c81223d64d15542fdb16cdf7e",
"sha256:b0808a58c54c595b6cc6271cbc14a09bb89f0951ca9e8b105d1e94bef3ed24a0"
"sha256:6180272094030bda3ee5c242881892cd3d9d19c05cb513945f530e396c7de1e4",
"sha256:95d814d16fe55ae55e1e4a3db248596f9647a0c42f4796c6e05be0bfaffb1830"
],
"index": "pypi",
"version": "==1.17.91"
"version": "==1.17.94"
},
"botocore": {
"hashes": [
"sha256:462e75419e6537efb2709b7eb5b8c7ade007d30209416f0476bd7c51a2ddc78d"
"sha256:60a382a5b2f7d77b1b575d54fba819097526e3fdd0f3004f4d1142d50af0d642",
"sha256:ba8a7951be535e25219a82dea15c30d7bdf0c51e7c1623c3306248493c1616ac"
],
"version": "==1.20.91"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.20.94"
},
"cachetools": {
"hashes": [
"sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001",
"sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"
],
"markers": "python_version ~= '3.5'",
"version": "==4.2.2"
},
"cbor2": {
@ -151,6 +160,7 @@
"sha256:ce6219986385778b1ab7f9b542f160bb4d3558f52975e914a27b774e47016fb7",
"sha256:d562b2773e14ee1d65ea5b85351a83a64d4f3fd011bc2b4c70a6e813e78203ce"
],
"markers": "python_version >= '3.6'",
"version": "==5.4.0"
},
"celery": {
@ -243,6 +253,7 @@
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0"
},
"click": {
@ -250,6 +261,7 @@
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==7.1.2"
},
"click-didyoumean": {
@ -309,6 +321,7 @@
"sha256:76ffae916ba3aa66b46996c14fa713e46004788167a4873d647544e750e0e99f",
"sha256:a9af943c79717bc52fe64a3c236ae5d3adccc8b5be19c881b442d2c3db233393"
],
"markers": "python_version >= '3.6'",
"version": "==3.0.2"
},
"defusedxml": {
@ -413,11 +426,11 @@
},
"drf-spectacular": {
"hashes": [
"sha256:4d35e890b8139e1c056588c5529a2f2066615635482563f0840b96d3b879d7d2",
"sha256:f552476dfde647963c21615249672e7f4f9ece3788036b5ee5c6cc5ad50748ab"
"sha256:146e8c21dc806a20c84c687811c30163970fbf620213ab87280f7403469d80bb",
"sha256:8a028d251a6d0b39739ebdec487fd43ee4ecba244d8ffaaac43ff06430728dd8"
],
"index": "pypi",
"version": "==0.17.0"
"version": "==0.17.1"
},
"duo-client": {
"hashes": [
@ -439,6 +452,7 @@
"hashes": [
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.18.2"
},
"geoip2": {
@ -451,10 +465,11 @@
},
"google-auth": {
"hashes": [
"sha256:9b235dbc876e49454cbedc52ae0abd540ef705ebccdf4fbe93553bb13f26b1a4",
"sha256:eb017521276a75492282c6ca4b718f26de112ed3bcbeaeeb02c1b82de425f909"
"sha256:154f7889c5d679a6f626f36adb12afbd4dbb0a9a04ec575d989d6ba79c4fd65e",
"sha256:6d47c79b5d09fbc7e8355fd9594cc4cf65fdde5d401c63951eaac4baa1ba2ae1"
],
"version": "==1.30.2"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.31.0"
},
"gunicorn": {
"hashes": [
@ -469,6 +484,7 @@
"sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6",
"sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"
],
"markers": "python_version >= '3.6'",
"version": "==0.12.0"
},
"hiredis": {
@ -515,6 +531,7 @@
"sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0",
"sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a"
],
"markers": "python_version >= '3.6'",
"version": "==2.0.0"
},
"httptools": {
@ -563,6 +580,7 @@
"sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417",
"sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"
],
"markers": "python_version >= '3.5'",
"version": "==0.5.1"
},
"jmespath": {
@ -570,6 +588,7 @@
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.0"
},
"jsonschema": {
@ -584,6 +603,7 @@
"sha256:01481d99f4606f6939cdc9b637264ed353ee9e3e4f62cfb582324142c41a572d",
"sha256:e2dedd8a86c9077c350555153825a31e456a0dc20c15d5751f00137ec9c75f0a"
],
"markers": "python_version >= '3.6'",
"version": "==5.1.0"
},
"kubernetes": {
@ -597,6 +617,9 @@
"ldap3": {
"hashes": [
"sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91",
"sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59",
"sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c",
"sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056",
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57"
],
"index": "pypi",
@ -658,6 +681,7 @@
"hashes": [
"sha256:47e86a084dd814fac88c99ea34ba3278a74bc9de5a25f4b815b608798747c7dc"
],
"markers": "python_version >= '3.6'",
"version": "==2.0.3"
},
"msgpack": {
@ -733,6 +757,7 @@
"sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281",
"sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"
],
"markers": "python_version >= '3.6'",
"version": "==5.1.0"
},
"oauthlib": {
@ -740,6 +765,7 @@
"sha256:42bf6354c2ed8c6acb54d971fce6f88193d97297e18602a3a886603f9d7730cc",
"sha256:8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3"
],
"markers": "python_version >= '3.6'",
"version": "==3.1.1"
},
"packaging": {
@ -755,6 +781,7 @@
"sha256:3a8baade6cb80bcfe43297e33e7623f3118d660d41387593758e2fb1ea173a86",
"sha256:b014bc76815eb1399da8ce5fc84b7717a3e63652b0c0f8804092c9363acab1b2"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.11.0"
},
"prompt-toolkit": {
@ -762,6 +789,7 @@
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
],
"markers": "python_full_version >= '3.6.1'",
"version": "==3.0.18"
},
"psycopg2-binary": {
@ -807,15 +835,37 @@
},
"pyasn1": {
"hashes": [
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
"sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"
"sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2",
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"
],
"version": "==0.4.8"
},
"pyasn1-modules": {
"hashes": [
"sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
"sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
"sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
"sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
"sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
"sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
"sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
"sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
],
"version": "==0.2.8"
},
@ -824,6 +874,7 @@
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.20"
},
"pycryptodome": {
@ -867,6 +918,7 @@
"sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316",
"sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29"
],
"markers": "python_version >= '3.5'",
"version": "==2.0.2"
},
"pyjwt": {
@ -889,12 +941,14 @@
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.7"
},
"pyrsistent": {
"hashes": [
"sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"
],
"markers": "python_version >= '3.5'",
"version": "==0.17.3"
},
"python-dateutil": {
@ -902,6 +956,7 @@
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.8.1"
},
"python-dotenv": {
@ -958,6 +1013,7 @@
"sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",
"sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==3.5.3"
},
"requests": {
@ -965,12 +1021,14 @@
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.25.1"
},
"requests-oauthlib": {
"hashes": [
"sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a",
"sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"
],
"index": "pypi",
"version": "==1.3.0"
@ -1011,6 +1069,7 @@
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"sqlparse": {
@ -1018,6 +1077,7 @@
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
],
"markers": "python_version >= '3.5'",
"version": "==0.4.1"
},
"structlog": {
@ -1073,6 +1133,7 @@
"sha256:7d6f89745680233f1c4db9ddb748df5e88d2a7a37962be174c0fd04c8dba1dc8",
"sha256:c16b55f9a67b2419cfdf8846576e2ec9ba94fe6978a83080c352a80db31c93fb"
],
"markers": "python_version >= '3.6'",
"version": "==21.2.1"
},
"typing-extensions": {
@ -1096,6 +1157,7 @@
"sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f",
"sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==3.0.1"
},
"urllib3": {
@ -1140,6 +1202,7 @@
"sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30",
"sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"
],
"markers": "python_version >= '3.6'",
"version": "==5.0.0"
},
"watchgod": {
@ -1169,6 +1232,7 @@
"sha256:b68e4959d704768fa20e35c9d508c8dc2bbc041fd8d267c0d7345cffe2824568",
"sha256:e5c333bfa9fa739538b652b6f8c8fc2559f1d364243c8a689d7c0e1d41c2e611"
],
"markers": "python_version >= '3.6'",
"version": "==1.1.0"
},
"websockets": {
@ -1266,6 +1330,7 @@
"sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a",
"sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"
],
"markers": "python_version >= '3.6'",
"version": "==1.6.3"
},
"zope.interface": {
@ -1322,6 +1387,7 @@
"sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4",
"sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==5.4.0"
}
},
@ -1338,6 +1404,7 @@
"sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e",
"sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"
],
"markers": "python_version ~= '3.6'",
"version": "==2.5.6"
},
"attrs": {
@ -1345,6 +1412,7 @@
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==21.2.0"
},
"bandit": {
@ -1383,6 +1451,7 @@
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0"
},
"click": {
@ -1390,6 +1459,7 @@
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==7.1.2"
},
"colorama": {
@ -1463,6 +1533,7 @@
"sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0",
"sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"
],
"markers": "python_version >= '3.4'",
"version": "==4.0.7"
},
"gitpython": {
@ -1470,6 +1541,7 @@
"sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135",
"sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e"
],
"markers": "python_version >= '3.5'",
"version": "==3.1.17"
},
"idna": {
@ -1491,6 +1563,7 @@
"sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
"sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
],
"markers": "python_version >= '3.6' and python_version < '4'",
"version": "==5.8.0"
},
"lazy-object-proxy": {
@ -1518,6 +1591,7 @@
"sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
"sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.6.0"
},
"mccabe": {
@ -1554,6 +1628,7 @@
"sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd",
"sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"
],
"markers": "python_version >= '2.6'",
"version": "==5.6.0"
},
"pluggy": {
@ -1561,6 +1636,7 @@
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.13.1"
},
"py": {
@ -1568,6 +1644,7 @@
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.10.0"
},
"pylint": {
@ -1598,6 +1675,7 @@
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.7"
},
"pytest": {
@ -1702,6 +1780,7 @@
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.25.1"
},
"requests-mock": {
@ -1725,6 +1804,7 @@
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"smmap": {
@ -1732,6 +1812,7 @@
"sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182",
"sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"
],
"markers": "python_version >= '3.5'",
"version": "==4.0.0"
},
"stevedore": {
@ -1739,6 +1820,7 @@
"sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee",
"sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"
],
"markers": "python_version >= '3.6'",
"version": "==3.3.0"
},
"toml": {
@ -1746,6 +1828,7 @@
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"urllib3": {

View File

@ -21,7 +21,7 @@ authentik is an open-source Identity Provider focused on flexibility and versati
For small/test setups it is recommended to use docker-compose, see the [documentation](https://goauthentik.io/docs/installation/docker-compose/)
For bigger setups, there is a Helm Chart in the `helm/` directory. This is documented [here](https://goauthentik.io/docs/installation/kubernetes/)
For bigger setups, there is a Helm Chart [here])(https://github.com/goauthentik/helm). This is documented [here](https://goauthentik.io/docs/installation/kubernetes/)
## Screenshots

View File

@ -1,3 +1,3 @@
"""authentik"""
__version__ = "2021.6.1-rc2"
__version__ = "2021.6.1-rc6"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -10,3 +10,25 @@ class AuthentikAPIConfig(AppConfig):
label = "authentik_api"
mountpoint = "api/"
verbose_name = "authentik API"
def ready(self) -> None:
from drf_spectacular.extensions import OpenApiAuthenticationExtension
from authentik.api.authentication import TokenAuthentication
# Class is defined here as it needs to be created early enough that drf-spectacular will
# find it, but also won't cause any import issues
# pylint: disable=unused-variable
class TokenSchema(OpenApiAuthenticationExtension):
"""Auth schema"""
target_class = TokenAuthentication
name = "authentik"
def get_security_definition(self, auto_schema):
"""Auth schema"""
return {
"type": "apiKey",
"in": "header",
"name": "Authorization",
}

View File

@ -3,7 +3,6 @@ from base64 import b64decode
from binascii import Error
from typing import Any, Optional, Union
from drf_spectacular.authentication import OpenApiAuthenticationExtension
from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.request import Request
@ -56,18 +55,3 @@ class TokenAuthentication(BaseAuthentication):
return None
return (token.user, None) # pragma: no cover
class TokenSchema(OpenApiAuthenticationExtension):
"""Auth schema"""
target_class = TokenAuthentication
name = "authentik"
def get_security_definition(self, auto_schema):
"""Auth schema"""
return {
"type": "apiKey",
"in": "header",
"name": "Authorization",
}

View File

@ -11,13 +11,7 @@ from drf_spectacular.utils import (
inline_serializer,
)
from rest_framework.decorators import action
from rest_framework.fields import (
BooleanField,
CharField,
FileField,
IntegerField,
ReadOnlyField,
)
from rest_framework.fields import BooleanField, CharField, FileField, ReadOnlyField
from rest_framework.parsers import MultiPartParser
from rest_framework.request import Request
from rest_framework.response import Response
@ -107,15 +101,19 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
return applications
@extend_schema(
request=inline_serializer(
"CheckAccessRequest", fields={"for_user": IntegerField(required=False)}
),
parameters=[
OpenApiParameter(
name="for_user",
location=OpenApiParameter.QUERY,
type=OpenApiTypes.INT,
)
],
responses={
200: PolicyTestResultSerializer(),
404: OpenApiResponse(description="for_user user not found"),
},
)
@action(detail=True, methods=["POST"])
@action(detail=True, methods=["GET"])
# pylint: disable=unused-argument
def check_access(self, request: Request, slug: str) -> Response:
"""Check access to a single application by slug"""
@ -204,7 +202,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
"""Set application icon"""
app: Application = self.get_object()
icon = request.FILES.get("file", None)
clear = request.data.get("clear", False)
clear = request.data.get("clear", "false").lower() == "true"
if clear:
# .delete() saves the model by default
app.meta_icon.delete()

View File

@ -26,6 +26,8 @@ class ImpersonateMiddleware:
if SESSION_IMPERSONATE_USER in request.session:
request.user = request.session[SESSION_IMPERSONATE_USER]
# Ensure that the user is active, otherwise nothing will work
request.user.is_active = True
return self.get_response(request)

View File

@ -1,11 +1,12 @@
"""authentik core signals"""
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Type
from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.contrib.sessions.backends.cache import KEY_PREFIX
from django.core.cache import cache
from django.core.signals import Signal
from django.db.models import Model
from django.db.models.signals import post_save
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
from django.http.request import HttpRequest
from prometheus_client import Gauge
@ -18,7 +19,7 @@ GAUGE_MODELS = Gauge(
)
if TYPE_CHECKING:
from authentik.core.models import User
from authentik.core.models import AuthenticatedSession, User
@receiver(post_save)
@ -60,3 +61,17 @@ def user_logged_out_session(sender, request: HttpRequest, user: "User", **_):
AuthenticatedSession.objects.filter(
session_key=request.session.session_key
).delete()
@receiver(pre_delete)
def authenticated_session_delete(
sender: Type[Model], instance: "AuthenticatedSession", **_
):
"""Delete session when authenticated session is deleted"""
from authentik.core.models import AuthenticatedSession
if sender != AuthenticatedSession:
return
cache_key = f"{KEY_PREFIX}{instance.session_key}"
cache.delete(cache_key)

View File

@ -33,6 +33,7 @@ from authentik.flows.planner import (
from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN
from authentik.lib.utils.urls import redirect_with_qs
from authentik.policies.utils import delete_none_keys
from authentik.stages.password import BACKEND_DJANGO
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
@ -198,7 +199,7 @@ class SourceFlowManager:
kwargs.update(
{
# Since we authenticate the user by their token, they have no backend set
PLAN_CONTEXT_AUTHENTICATION_BACKEND: "django.contrib.auth.backends.ModelBackend",
PLAN_CONTEXT_AUTHENTICATION_BACKEND: BACKEND_DJANGO,
PLAN_CONTEXT_SSO: True,
PLAN_CONTEXT_SOURCE: self.source,
PLAN_CONTEXT_REDIRECT: final_redirect,

View File

@ -3,16 +3,6 @@
{% load static %}
{% load i18n %}
{% block head %}
{{ block.super }}
<style>
.pf-c-background-image::before {
background-image: url("{% static 'dist/assets/images/flow_background.jpg' %}");
background-position: center;
}
</style>
{% endblock %}
{% block title %}
{% trans 'End session' %} - {{ tenant.branding_title }}
{% endblock %}

View File

@ -26,7 +26,7 @@ class TestApplicationsAPI(APITestCase):
def test_check_access(self):
"""Test check_access operation"""
self.client.force_login(self.user)
response = self.client.post(
response = self.client.get(
reverse(
"authentik_api:application-check-access",
kwargs={"slug": self.allowed.slug},
@ -36,7 +36,7 @@ class TestApplicationsAPI(APITestCase):
self.assertJSONEqual(
force_str(response.content), {"messages": [], "passing": True}
)
response = self.client.post(
response = self.client.get(
reverse(
"authentik_api:application-check-access",
kwargs={"slug": self.denied.slug},

View File

@ -17,6 +17,9 @@ class TestImpersonation(TestCase):
def test_impersonate_simple(self):
"""test simple impersonation and un-impersonation"""
# test with an inactive user to ensure that still works
self.other_user.is_active = False
self.other_user.save()
self.client.force_login(self.akadmin)
self.client.get(

View File

@ -2,7 +2,7 @@
from dataclasses import dataclass
from typing import Optional
from rest_framework.fields import CharField, DictField
from rest_framework.fields import CharField
from authentik.core.api.utils import PassiveSerializer
from authentik.flows.challenge import Challenge
@ -22,18 +22,10 @@ class UILoginButton:
icon_url: Optional[str] = None
class UILoginButtonSerializer(PassiveSerializer):
"""Serializer for Login buttons of sources"""
name = CharField()
challenge = DictField()
icon_url = CharField(required=False, allow_null=True)
class UserSettingSerializer(PassiveSerializer):
"""Serializer for User settings for stages and sources"""
object_uid = CharField()
component = CharField()
title = CharField()
configure_url = CharField()
configure_url = CharField(required=False)

View File

@ -36,6 +36,7 @@ class EventSerializer(ModelSerializer):
"client_ip",
"created",
"expires",
"tenant",
]
@ -76,6 +77,11 @@ class EventsFilter(django_filters.FilterSet):
field_name="action",
lookup_expr="icontains",
)
tenant_name = django_filters.CharFilter(
field_name="tenant",
lookup_expr="name",
label="Tenant name",
)
# pylint: disable=unused-argument
def filter_context_model_pk(self, queryset, name, value):

View File

@ -40,9 +40,9 @@ class GeoIPReader:
return
try:
reader = Reader(path)
LOGGER.info("Loaded GeoIP database")
self.__reader = reader
self.__last_mtime = stat(path).st_mtime
LOGGER.info("Loaded GeoIP database", last_write=self.__last_mtime)
except OSError as exc:
LOGGER.warning("Failed to load GeoIP database", exc=exc)

View File

@ -2,6 +2,7 @@
from functools import partial
from typing import Callable
from django.conf import settings
from django.db.models import Model
from django.db.models.signals import post_save, pre_delete
from django.http import HttpRequest, HttpResponse
@ -12,6 +13,7 @@ from authentik.core.models import User
from authentik.events.models import Event, EventAction, Notification
from authentik.events.signals import EventNewThread
from authentik.events.utils import model_to_dict
from authentik.lib.utils.errors import exception_to_string
class AuditMiddleware:
@ -54,10 +56,19 @@ class AuditMiddleware:
# pylint: disable=unused-argument
def process_exception(self, request: HttpRequest, exception: Exception):
"""Unregister handlers in case of exception"""
"""Disconnect handlers in case of exception"""
post_save.disconnect(dispatch_uid=LOCAL.authentik["request_id"])
pre_delete.disconnect(dispatch_uid=LOCAL.authentik["request_id"])
if settings.DEBUG:
return
thread = EventNewThread(
EventAction.SYSTEM_EXCEPTION,
request,
message=exception_to_string(exception),
)
thread.run()
@staticmethod
# pylint: disable=unused-argument
def post_save_handler(

View File

@ -0,0 +1,55 @@
# Generated by Django 3.2.4 on 2021-06-14 15:33
from django.db import migrations, models
import authentik.events.models
class Migration(migrations.Migration):
dependencies = [
("authentik_events", "0015_alter_event_action"),
]
operations = [
migrations.AddField(
model_name="event",
name="tenant",
field=models.JSONField(
blank=True, default=authentik.events.models.default_tenant
),
),
migrations.AlterField(
model_name="event",
name="action",
field=models.TextField(
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("secret_view", "Secret View"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("system_task_execution", "System Task Execution"),
("system_task_exception", "System Task Exception"),
("system_exception", "System Exception"),
("configuration_error", "Configuration Error"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("email_sent", "Email Sent"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
]
),
),
]

View File

@ -21,11 +21,12 @@ from authentik.core.middleware import (
)
from authentik.core.models import ExpiringModel, Group, User
from authentik.events.geo import GEOIP_READER
from authentik.events.utils import cleanse_dict, get_user, sanitize_dict
from authentik.events.utils import cleanse_dict, get_user, model_to_dict, sanitize_dict
from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.http import get_client_ip
from authentik.policies.models import PolicyBindingModel
from authentik.stages.email.utils import TemplateEmailMessage
from authentik.tenants.utils import DEFAULT_TENANT
LOGGER = get_logger("authentik.events")
GAUGE_EVENTS = Gauge(
@ -40,6 +41,11 @@ def default_event_duration():
return now() + timedelta(days=365)
def default_tenant():
"""Get a default value for tenant"""
return sanitize_dict(model_to_dict(DEFAULT_TENANT))
class NotificationTransportError(SentryIgnoredException):
"""Error raised when a notification fails to be delivered"""
@ -71,6 +77,7 @@ class EventAction(models.TextChoices):
SYSTEM_TASK_EXECUTION = "system_task_execution"
SYSTEM_TASK_EXCEPTION = "system_task_exception"
SYSTEM_EXCEPTION = "system_exception"
CONFIGURATION_ERROR = "configuration_error"
@ -94,6 +101,7 @@ class Event(ExpiringModel):
context = models.JSONField(default=dict, blank=True)
client_ip = models.GenericIPAddressField(null=True)
created = models.DateTimeField(auto_now_add=True)
tenant = models.JSONField(default=default_tenant, blank=True)
# Shadow the expires attribute from ExpiringModel to override the default duration
expires = models.DateTimeField(default=default_event_duration)
@ -132,6 +140,13 @@ class Event(ExpiringModel):
"""Add data from a Django-HttpRequest, allowing the creation of
Events independently from requests.
`user` arguments optionally overrides user from requests."""
if request:
self.context["http_request"] = {
"path": request.get_full_path(),
"method": request.method,
}
if hasattr(request, "tenant"):
self.tenant = sanitize_dict(model_to_dict(request.tenant))
if hasattr(request, "user"):
original_user = None
if hasattr(request, "session"):

View File

@ -301,10 +301,14 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
"""Set Flow background"""
flow: Flow = self.get_object()
background = request.FILES.get("file", None)
clear = request.data.get("clear", False)
clear = request.data.get("clear", "false").lower() == "true"
if clear:
# .delete() saves the model by default
flow.background.delete()
if flow.background_url.startswith("/media"):
# .delete() saves the model by default
flow.background.delete()
else:
flow.background = None
flow.save()
return Response({})
if background:
flow.background = background

View File

@ -93,7 +93,7 @@ class StageViewSet(
if not user_settings:
continue
user_settings.initial_data["object_uid"] = str(stage.pk)
if hasattr(stage, "configure_flow"):
if hasattr(stage, "configure_flow") and stage.configure_flow:
user_settings.initial_data["configure_url"] = reverse(
"authentik_flows:configure",
kwargs={"stage_uuid": stage.pk},

View File

@ -6,6 +6,7 @@ from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from authentik.flows.models import FlowDesignation
from authentik.stages.identification.models import UserFields
from authentik.stages.password import BACKEND_DJANGO, BACKEND_LDAP
def create_default_authentication_flow(
@ -31,7 +32,7 @@ def create_default_authentication_flow(
password_stage, _ = PasswordStage.objects.using(db_alias).update_or_create(
name="default-authentication-password",
defaults={"backends": ["django.contrib.auth.backends.ModelBackend"]},
defaults={"backends": [BACKEND_DJANGO, BACKEND_LDAP]},
)
login_stage, _ = UserLoginStage.objects.using(db_alias).update_or_create(

View File

@ -15,9 +15,6 @@ PREFILL_POLICY_EXPRESSION = """# This policy sets the user for the currently run
# by injecting "pending_user"
akadmin = ak_user_by(username="akadmin")
context["pending_user"] = akadmin
# We're also setting the backend for the user, so we can
# directly login without having to identify again
context["user_backend"] = "django.contrib.auth.backends.ModelBackend"
return True"""

View File

@ -174,7 +174,7 @@ class FlowExecutorView(APIView):
@extend_schema(
responses={
200: PolymorphicProxySerializer(
component_name="FlowChallengeRequest",
component_name="ChallengeTypes",
serializers=challenge_types(),
resource_type_field_name="component",
),
@ -214,7 +214,7 @@ class FlowExecutorView(APIView):
@extend_schema(
responses={
200: PolymorphicProxySerializer(
component_name="FlowChallengeRequest",
component_name="ChallengeTypes",
serializers=challenge_types(),
resource_type_field_name="component",
),

View File

@ -0,0 +1,10 @@
"""error utils"""
from traceback import format_tb
TRACEBACK_HEADER = "Traceback (most recent call last):\n"
def exception_to_string(exc: Exception) -> str:
"""Convert exception to string stackrace"""
# Either use passed original exception or whatever we have
return TRACEBACK_HEADER + "".join(format_tb(exc.__traceback__)) + str(exc)

View File

@ -33,6 +33,13 @@ class ServiceConnectionSerializer(ModelSerializer, MetaNameSerializer):
component = ReadOnlyField()
def get_component(self, obj: OutpostServiceConnection) -> str:
"""Get object type so that we know how to edit the object"""
# pyright: reportGeneralTypeIssues=false
if obj.__class__ == OutpostServiceConnection:
return ""
return obj.component
class Meta:
model = OutpostServiceConnection

View File

@ -63,7 +63,7 @@ class DockerController(BaseController):
self.client.images.pull(image_name)
container_args = {
"image": image_name,
"name": f"authentik-proxy-{self.outpost.uuid.hex}",
"name": container_name,
"detach": True,
"ports": {
f"{port.port}/{port.protocol.lower()}": port.inner_port or port.port

View File

@ -8,7 +8,7 @@ from uuid import uuid4
from dacite import from_dict
from django.contrib.auth.models import Permission
from django.core.cache import cache
from django.db import models, transaction
from django.db import IntegrityError, models, transaction
from django.db.models.base import Model
from django.utils.translation import gettext_lazy as _
from docker.client import DockerClient
@ -50,6 +50,8 @@ class ServiceConnectionInvalid(SentryIgnoredException):
class OutpostConfig:
"""Configuration an outpost uses to configure it self"""
# update website/docs/outposts/outposts.md
authentik_host: str
authentik_host_insecure: bool = False
@ -141,7 +143,9 @@ class OutpostServiceConnection(models.Model):
@property
def component(self) -> str:
"""Return component used to edit this object"""
raise NotImplementedError
# This is called when creating an outpost with a service connection
# since the response doesn't use the correct inheritance
return ""
class Meta:
@ -380,21 +384,24 @@ class Outpost(models.Model):
tokens = Token.filter_not_expired(
identifier=self.token_identifier,
intent=TokenIntents.INTENT_API,
)
if tokens.exists():
token = tokens.first()
if not token.managed:
token.managed = managed
token.save()
return token
return Token.objects.create(
user=self.user,
identifier=self.token_identifier,
intent=TokenIntents.INTENT_API,
description=f"Autogenerated by authentik for Outpost {self.name}",
expiring=False,
managed=managed,
)
if tokens.exists():
return tokens.first()
try:
return Token.objects.create(
user=self.user,
identifier=self.token_identifier,
intent=TokenIntents.INTENT_API,
description=f"Autogenerated by authentik for Outpost {self.name}",
expiring=False,
managed=managed,
)
except IntegrityError:
# Integrity error happens mostly when managed is re-used
Token.objects.filter(managed=managed).delete()
Token.objects.filter(identifier=self.token_identifier).delete()
return self.token
def get_required_objects(self) -> Iterable[Union[models.Model, str]]:
"""Get an iterator of all objects the user needs read access to"""

View File

@ -0,0 +1,48 @@
# Generated by Django 3.2.4 on 2021-06-14 15:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_policies_event_matcher", "0016_alter_eventmatcherpolicy_action"),
]
operations = [
migrations.AlterField(
model_name="eventmatcherpolicy",
name="action",
field=models.TextField(
blank=True,
choices=[
("login", "Login"),
("login_failed", "Login Failed"),
("logout", "Logout"),
("user_write", "User Write"),
("suspicious_request", "Suspicious Request"),
("password_set", "Password Set"),
("secret_view", "Secret View"),
("invitation_used", "Invite Used"),
("authorize_application", "Authorize Application"),
("source_linked", "Source Linked"),
("impersonation_started", "Impersonation Started"),
("impersonation_ended", "Impersonation Ended"),
("policy_execution", "Policy Execution"),
("policy_exception", "Policy Exception"),
("property_mapping_exception", "Property Mapping Exception"),
("system_task_execution", "System Task Execution"),
("system_task_exception", "System Task Exception"),
("system_exception", "System Exception"),
("configuration_error", "Configuration Error"),
("model_created", "Model Created"),
("model_updated", "Model Updated"),
("model_deleted", "Model Deleted"),
("email_sent", "Email Sent"),
("update_available", "Update Available"),
("custom_", "Custom Prefix"),
],
help_text="Match created events with this action type. When left empty, all action types will be matched.",
),
),
]

View File

@ -1,7 +1,6 @@
"""authentik policy task"""
from multiprocessing import get_context
from multiprocessing.connection import Connection
from traceback import format_tb
from typing import Optional
from django.core.cache import cache
@ -11,12 +10,12 @@ from sentry_sdk.tracing import Span
from structlog.stdlib import get_logger
from authentik.events.models import Event, EventAction
from authentik.lib.utils.errors import exception_to_string
from authentik.policies.exceptions import PolicyException
from authentik.policies.models import PolicyBinding
from authentik.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger()
TRACEBACK_HEADER = "Traceback (most recent call last):\n"
FORK_CTX = get_context("fork")
PROCESS_CLASS = FORK_CTX.Process
@ -106,11 +105,7 @@ class PolicyProcess(PROCESS_CLASS):
except PolicyException as exc:
# Either use passed original exception or whatever we have
src_exc = exc.src_exc if exc.src_exc else exc
error_string = (
TRACEBACK_HEADER
+ "".join(format_tb(src_exc.__traceback__))
+ str(src_exc)
)
error_string = exception_to_string(src_exc)
# Create policy exception event, only when we're not debugging
if not self.request.debug:
self.create_event(EventAction.POLICY_EXCEPTION, message=error_string)

View File

@ -3,11 +3,13 @@ from django.core.cache import cache
from django.db import models
from django.utils.translation import gettext as _
from rest_framework.serializers import BaseSerializer
from structlog import get_logger
from authentik.lib.utils.http import get_client_ip
from authentik.policies.models import Policy
from authentik.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger()
CACHE_KEY_IP_PREFIX = "authentik_reputation_ip_"
CACHE_KEY_USER_PREFIX = "authentik_reputation_user_"
@ -35,9 +37,16 @@ class ReputationPolicy(Policy):
if self.check_ip:
score = cache.get_or_set(CACHE_KEY_IP_PREFIX + remote_ip, 0)
passing = passing and score <= self.threshold
LOGGER.debug("Score for IP", ip=remote_ip, score=score, passing=passing)
if self.check_username:
score = cache.get_or_set(CACHE_KEY_USER_PREFIX + request.user.username, 0)
passing = passing and score <= self.threshold
LOGGER.debug(
"Score for Username",
username=request.user.username,
score=score,
passing=passing,
)
return PolicyResult(passing)
class Meta:

View File

@ -1,9 +1,10 @@
"""test reputation signals and policy"""
from django.contrib.auth import authenticate
from django.core.cache import cache
from django.test import TestCase
from django.test import RequestFactory, TestCase
from authentik.core.models import User
from authentik.lib.utils.http import DEFAULT_IP
from authentik.policies.reputation.models import (
CACHE_KEY_IP_PREFIX,
CACHE_KEY_USER_PREFIX,
@ -19,9 +20,12 @@ class TestReputationPolicy(TestCase):
"""test reputation signals and policy"""
def setUp(self):
self.test_ip = "255.255.255.255"
self.request_factory = RequestFactory()
self.request = self.request_factory.get("/")
self.test_ip = "127.0.0.1"
self.test_username = "test"
cache.delete(CACHE_KEY_IP_PREFIX + self.test_ip)
cache.delete(CACHE_KEY_IP_PREFIX + DEFAULT_IP)
cache.delete(CACHE_KEY_USER_PREFIX + self.test_username)
# We need a user for the one-to-one in userreputation
self.user = User.objects.create(username=self.test_username)
@ -29,7 +33,9 @@ class TestReputationPolicy(TestCase):
def test_ip_reputation(self):
"""test IP reputation"""
# Trigger negative reputation
authenticate(None, username=self.test_username, password=self.test_username)
authenticate(
self.request, username=self.test_username, password=self.test_username
)
# Test value in cache
self.assertEqual(cache.get(CACHE_KEY_IP_PREFIX + self.test_ip), -1)
# Save cache and check db values
@ -39,7 +45,9 @@ class TestReputationPolicy(TestCase):
def test_user_reputation(self):
"""test User reputation"""
# Trigger negative reputation
authenticate(None, username=self.test_username, password=self.test_username)
authenticate(
self.request, username=self.test_username, password=self.test_username
)
# Test value in cache
self.assertEqual(cache.get(CACHE_KEY_USER_PREFIX + self.test_username), -1)
# Save cache and check db values

View File

@ -1,7 +1,7 @@
"""ProxyProvider API Views"""
from typing import Any
from drf_spectacular.utils import extend_schema_field
from drf_spectacular.utils import extend_schema_field, extend_schema_serializer
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, ListField, SerializerMethodField
from rest_framework.serializers import ModelSerializer
@ -85,6 +85,7 @@ class ProxyProviderViewSet(UsedByMixin, ModelViewSet):
ordering = ["name"]
@extend_schema_serializer(deprecate_fields=["forward_auth_mode"])
class ProxyOutpostConfigSerializer(ModelSerializer):
"""Proxy provider serializer for outposts"""

View File

@ -120,7 +120,7 @@ class ServiceProviderMetadataParser:
)
ctx.key = key
ctx.verify(signature_node)
except xmlsec.VerificationError as exc:
except xmlsec.Error as exc:
raise ValueError("Failed to verify Metadata signature") from exc
def parse(self, raw_xml: str) -> ServiceProviderMetadata:

View File

@ -108,7 +108,7 @@ class AuthNRequestParser:
)
ctx.key = key
ctx.verify(signature_node)
except xmlsec.VerificationError as exc:
except xmlsec.Error as exc:
raise CannotHandleAssertion(ERROR_FAILED_TO_VERIFY) from exc
return self._parse_xml(decoded_xml, relay_state)
@ -160,7 +160,7 @@ class AuthNRequestParser:
sign_algorithm_transform,
b64decode(signature),
)
except xmlsec.VerificationError as exc:
except xmlsec.Error as exc:
raise CannotHandleAssertion(ERROR_FAILED_TO_VERIFY) from exc
return self._parse_xml(decoded_xml, relay_state)

View File

@ -2,12 +2,13 @@
from base64 import b64encode
from django.contrib.sessions.middleware import SessionMiddleware
from django.http.request import HttpRequest, QueryDict
from django.http.request import QueryDict
from django.test import RequestFactory, TestCase
from guardian.utils import get_anonymous_user
from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow
from authentik.flows.tests.test_planner import dummy_get_response
from authentik.providers.saml.models import SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.assertion import AssertionProcessor
from authentik.providers.saml.processors.request_parser import AuthNRequestParser
@ -58,11 +59,6 @@ qNAZMq1DqpibfCBg
-----END CERTIFICATE-----"""
def dummy_get_response(request: HttpRequest): # pragma: no cover
"""Dummy get_response for SessionMiddleware"""
return None
class TestAuthNRequest(TestCase):
"""Test AuthN Request generator and parser"""

View File

@ -7,6 +7,7 @@ from django.utils.translation import gettext as _
from django.views import View
from authentik.core.models import Token, TokenIntents
from authentik.stages.password import BACKEND_DJANGO
class UseTokenView(View):
@ -18,7 +19,7 @@ class UseTokenView(View):
if not tokens.exists():
raise Http404
token = tokens.first()
login(request, token.user, backend="django.contrib.auth.backends.ModelBackend")
login(request, token.user, backend=BACKEND_DJANGO)
token.delete()
messages.warning(request, _("Used recovery-link to authenticate."))
return redirect("authentik_core:if-admin")

View File

@ -375,7 +375,11 @@ if _ERROR_REPORTING:
environment=CONFIG.y("error_reporting.environment", "customer"),
send_default_pii=CONFIG.y_bool("error_reporting.send_pii", False),
)
set_tag("authentik.build_hash", os.environ.get(ENV_GIT_HASH_KEY, "tagged"))
# Default to empty string as that is what docker has
build_hash = os.environ.get(ENV_GIT_HASH_KEY, "")
if build_hash == "":
build_hash = "tagged"
set_tag("authentik.build_hash", build_hash)
set_tag(
"authentik.env", "kubernetes" if "KUBERNETES_PORT" in os.environ else "compose"
)

View File

@ -39,7 +39,7 @@ from authentik.sources.saml.processors.constants import (
from authentik.sources.saml.processors.request import SESSION_REQUEST_ID
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
from authentik.stages.user_login.stage import DEFAULT_BACKEND
from authentik.stages.user_login.stage import BACKEND_DJANGO
LOGGER = get_logger()
if TYPE_CHECKING:
@ -141,7 +141,7 @@ class ResponseProcessor:
self._source.authentication_flow,
**{
PLAN_CONTEXT_PENDING_USER: user,
PLAN_CONTEXT_AUTHENTICATION_BACKEND: DEFAULT_BACKEND,
PLAN_CONTEXT_AUTHENTICATION_BACKEND: BACKEND_DJANGO,
},
)
@ -204,7 +204,7 @@ class ResponseProcessor:
self._source.authentication_flow,
**{
PLAN_CONTEXT_PENDING_USER: matching_users.first(),
PLAN_CONTEXT_AUTHENTICATION_BACKEND: DEFAULT_BACKEND,
PLAN_CONTEXT_AUTHENTICATION_BACKEND: BACKEND_DJANGO,
PLAN_CONTEXT_REDIRECT: final_redirect,
},
)

View File

@ -2,7 +2,7 @@
from django.utils.timezone import now
from structlog.stdlib import get_logger
from authentik.core.models import User
from authentik.core.models import AuthenticatedSession, User
from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus
from authentik.lib.utils.time import timedelta_from_string
from authentik.root.celery import CELERY_APP
@ -31,11 +31,13 @@ def clean_temporary_users(self: MonitoredTask):
continue
source = sources.first()
source_delta = timedelta_from_string(source.temporary_user_delete_after)
if _now - user.last_login >= source_delta:
if (
_now - user.last_login >= source_delta
and not AuthenticatedSession.objects.filter(user=user).exists()
):
LOGGER.debug(
"User is expired and will be deleted.", user=user, delta=source_delta
)
# TODO: Check if user is signed in anywhere?
user.delete()
deleted_users += 1
messages.append(f"Successfully deleted {deleted_users} users.")

View File

@ -1,44 +1,6 @@
# Generated by Django 3.1.1 on 2020-09-25 14:32
from django.apps.registry import Apps
from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from authentik.flows.models import FlowDesignation
def create_default_setup_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
Flow = apps.get_model("authentik_flows", "Flow")
FlowStageBinding = apps.get_model("authentik_flows", "FlowStageBinding")
AuthenticatorDuoStage = apps.get_model(
"authentik_stages_authenticator_duo", "AuthenticatorDuoStage"
)
db_alias = schema_editor.connection.alias
flow, _ = Flow.objects.using(db_alias).update_or_create(
slug="default-authenticator-duo-setup",
designation=FlowDesignation.STAGE_CONFIGURATION,
defaults={
"name": "default-authenticator-duo-setup",
"title": "Setup Duo",
},
)
stage, _ = AuthenticatorDuoStage.objects.using(db_alias).update_or_create(
name="default-authenticator-duo-setup"
)
FlowStageBinding.objects.using(db_alias).update_or_create(
target=flow, stage=stage, defaults={"order": 0}
)
for stage in AuthenticatorDuoStage.objects.using(db_alias).filter(
configure_flow=None
):
stage.configure_flow = flow
stage.save()
class Migration(migrations.Migration):
@ -50,6 +12,4 @@ class Migration(migrations.Migration):
),
]
operations = [
migrations.RunPython(create_default_setup_flow),
]
operations = []

View File

@ -3,4 +3,4 @@
INSTALLED_APPS = [
"django_otp.plugins.otp_totp",
]
OTP_TOTP_ISSUER = "authentik"
OTP_TOTP_ISSUER = "__to_replace__"

View File

@ -1,6 +1,7 @@
"""TOTP Setup stage"""
from django.http import HttpRequest, HttpResponse
from django.http.request import QueryDict
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from django_otp.plugins.otp_totp.models import TOTPDevice
from rest_framework.fields import CharField, IntegerField
@ -16,6 +17,7 @@ from authentik.flows.challenge import (
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
from authentik.flows.stage import ChallengeStageView
from authentik.stages.authenticator_totp.models import AuthenticatorTOTPStage
from authentik.stages.authenticator_totp.settings import OTP_TOTP_ISSUER
LOGGER = get_logger()
SESSION_TOTP_DEVICE = "totp_device"
@ -54,7 +56,9 @@ class AuthenticatorTOTPStageView(ChallengeStageView):
return AuthenticatorTOTPChallenge(
data={
"type": ChallengeTypes.NATIVE.value,
"config_url": device.config_url,
"config_url": device.config_url.replace(
OTP_TOTP_ISSUER, slugify(self.request.tenant.branding_title)
),
}
)

View File

@ -0,0 +1,127 @@
"""Test validator stage"""
from unittest.mock import MagicMock, patch
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import TestCase
from django.test.client import RequestFactory
from django_otp.plugins.otp_totp.models import TOTPDevice
from rest_framework.exceptions import ValidationError
from authentik.core.models import User
from authentik.flows.models import NotConfiguredAction
from authentik.flows.tests.test_planner import dummy_get_response
from authentik.providers.oauth2.generators import (
generate_client_id,
generate_client_secret,
)
from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice
from authentik.stages.authenticator_validate.api import (
AuthenticatorValidateStageSerializer,
)
from authentik.stages.authenticator_validate.challenge import (
get_challenge_for_device,
validate_challenge_code,
validate_challenge_duo,
validate_challenge_webauthn,
)
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
class AuthenticatorValidateStageTests(TestCase):
"""Test validator stage"""
def setUp(self) -> None:
self.user = User.objects.get(username="akadmin")
self.request_factory = RequestFactory()
def test_stage_validation(self):
"""Test serializer validation"""
self.client.force_login(self.user)
serializer = AuthenticatorValidateStageSerializer(
data={"name": "foo", "not_configured_action": NotConfiguredAction.CONFIGURE}
)
self.assertFalse(serializer.is_valid())
self.assertIn("not_configured_action", serializer.errors)
def test_device_challenge_totp(self):
"""Test device challenge"""
request = self.request_factory.get("/")
totp_device = TOTPDevice.objects.create(
user=self.user, confirmed=True, digits=6
)
self.assertEqual(get_challenge_for_device(request, totp_device), {})
with self.assertRaises(ValidationError):
validate_challenge_code("1234", request, self.user)
def test_device_challenge_webauthn(self):
"""Test webauthn"""
request = self.request_factory.get("/")
request.user = self.user
middleware = SessionMiddleware(dummy_get_response)
middleware.process_request(request)
request.session.save()
webauthn_device = WebAuthnDevice.objects.create(
user=self.user,
public_key="qwerqwerqre",
credential_id="foobarbaz",
sign_count=0,
rp_id="foo",
)
challenge = get_challenge_for_device(request, webauthn_device)
del challenge["challenge"]
self.assertEqual(
challenge,
{
"allowCredentials": [
{
"id": "foobarbaz",
"transports": ["usb", "nfc", "ble", "internal"],
"type": "public-key",
}
],
"rpId": "foo",
"timeout": 60000,
"userVerification": "discouraged",
},
)
with self.assertRaises(ValidationError):
validate_challenge_webauthn({}, request, self.user)
def test_device_challenge_duo(self):
"""Test duo"""
request = self.request_factory.get("/")
stage = AuthenticatorDuoStage.objects.create(
name="test",
client_id=generate_client_id(),
client_secret=generate_client_secret(),
api_hostname="",
)
duo_device = DuoDevice.objects.create(
user=self.user,
stage=stage,
)
duo_mock = MagicMock(
auth=MagicMock(
return_value={
"result": "allow",
"status": "allow",
"status_msg": "Success. Logging you in...",
}
)
)
failed_duo_mock = MagicMock(auth=MagicMock(return_value={"result": "deny"}))
with patch(
"authentik.stages.authenticator_duo.models.AuthenticatorDuoStage.client",
duo_mock,
):
self.assertEqual(
duo_device.pk, validate_challenge_duo(duo_device.pk, request, self.user)
)
with patch(
"authentik.stages.authenticator_duo.models.AuthenticatorDuoStage.client",
failed_duo_mock,
):
with self.assertRaises(ValidationError):
validate_challenge_duo(duo_device.pk, request, self.user)

View File

@ -28,8 +28,6 @@ from authentik.stages.authenticator_webauthn.utils import (
get_rp_id,
)
RP_NAME = "authentik"
LOGGER = get_logger()
SESSION_KEY_WEBAUTHN_AUTHENTICATED = (
@ -119,7 +117,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
user = self.get_pending_user()
make_credential_options = WebAuthnMakeCredentialOptions(
challenge,
RP_NAME,
self.request.tenant.branding_title,
get_rp_id(self.request),
user.uid,
user.username,

View File

@ -0,0 +1,31 @@
# Generated by Django 3.2.4 on 2021-06-14 15:32
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_stages_identification", "0010_identificationstage_password_stage"),
]
operations = [
migrations.AlterField(
model_name="identificationstage",
name="user_fields",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(
choices=[
("email", "E Mail"),
("username", "Username"),
("upn", "Upn"),
],
max_length=100,
),
blank=True,
help_text="Fields of the user object to match against. (Hold shift to select multiple options)",
size=None,
),
),
]

View File

@ -17,6 +17,7 @@ class UserFields(models.TextChoices):
E_MAIL = "email"
USERNAME = "username"
UPN = "upn"
class IdentificationStage(Stage):

View File

@ -8,19 +8,20 @@ from django.db.models import Q
from django.http import HttpResponse
from django.urls import reverse
from django.utils.translation import gettext as _
from rest_framework.fields import BooleanField, CharField, ListField
from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field
from rest_framework.fields import BooleanField, CharField, DictField, ListField
from rest_framework.serializers import ValidationError
from structlog.stdlib import get_logger
from authentik.core.api.utils import PassiveSerializer
from authentik.core.models import Application, Source, User
from authentik.core.types import UILoginButtonSerializer
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
from authentik.flows.stage import (
PLAN_CONTEXT_PENDING_USER_IDENTIFIER,
ChallengeStageView,
)
from authentik.flows.views import SESSION_KEY_APPLICATION_PRE
from authentik.flows.views import SESSION_KEY_APPLICATION_PRE, challenge_types
from authentik.stages.identification.models import IdentificationStage
from authentik.stages.identification.signals import identification_failed
from authentik.stages.password.stage import authenticate
@ -28,6 +29,26 @@ from authentik.stages.password.stage import authenticate
LOGGER = get_logger()
@extend_schema_field(
PolymorphicProxySerializer(
component_name="ChallengeTypes",
serializers=challenge_types(),
resource_type_field_name="component",
)
)
class ChallengeDictWrapper(DictField):
"""Wrapper around DictField that annotates itself as challenge proxy"""
class LoginSourceSerializer(PassiveSerializer):
"""Serializer for Login buttons of sources"""
name = CharField()
icon_url = CharField(required=False, allow_null=True)
challenge = ChallengeDictWrapper()
class IdentificationChallenge(Challenge):
"""Identification challenges with all UI elements"""
@ -38,7 +59,7 @@ class IdentificationChallenge(Challenge):
enroll_url = CharField(required=False)
recovery_url = CharField(required=False)
primary_action = CharField()
sources = UILoginButtonSerializer(many=True, required=False)
sources = LoginSourceSerializer(many=True, required=False)
component = CharField(default="ak-stage-identification")
@ -96,7 +117,11 @@ class IdentificationStageView(ChallengeStageView):
current_stage: IdentificationStage = self.executor.current_stage
query = Q()
for search_field in current_stage.user_fields:
model_field = search_field
model_field = {
"email": "email",
"username": "username",
"upn": "attributes__upn",
}[search_field]
if current_stage.case_insensitive_matching:
model_field += "__iexact"
else:
@ -150,6 +175,7 @@ class IdentificationStageView(ChallengeStageView):
button = asdict(ui_login_button)
button["challenge"] = ui_login_button.challenge.data
ui_sources.append(button)
print(ui_sources)
challenge.initial_data["sources"] = ui_sources
return challenge

View File

@ -9,6 +9,7 @@ from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding
from authentik.providers.oauth2.generators import generate_client_secret
from authentik.sources.oauth.models import OAuthSource
from authentik.stages.identification.models import IdentificationStage, UserFields
from authentik.stages.password import BACKEND_DJANGO
from authentik.stages.password.models import PasswordStage
@ -70,7 +71,7 @@ class TestIdentificationStage(TestCase):
def test_valid_with_password(self):
"""Test with valid email and password in single step"""
pw_stage = PasswordStage.objects.create(
name="password", backends=["django.contrib.auth.backends.ModelBackend"]
name="password", backends=[BACKEND_DJANGO]
)
self.stage.password_stage = pw_stage
self.stage.save()
@ -92,7 +93,7 @@ class TestIdentificationStage(TestCase):
def test_invalid_with_password(self):
"""Test with valid email and invalid password in single step"""
pw_stage = PasswordStage.objects.create(
name="password", backends=["django.contrib.auth.backends.ModelBackend"]
name="password", backends=[BACKEND_DJANGO]
)
self.stage.password_stage = pw_stage
self.stage.save()

View File

@ -17,6 +17,7 @@ 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.password import BACKEND_DJANGO
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
@ -46,9 +47,7 @@ class TestUserLoginStage(TestCase):
flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()]
)
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
plan.context[
PLAN_CONTEXT_AUTHENTICATION_BACKEND
] = "django.contrib.auth.backends.ModelBackend"
plan.context[PLAN_CONTEXT_AUTHENTICATION_BACKEND] = BACKEND_DJANGO
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
@ -79,9 +78,7 @@ class TestUserLoginStage(TestCase):
flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()]
)
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
plan.context[
PLAN_CONTEXT_AUTHENTICATION_BACKEND
] = "django.contrib.auth.backends.ModelBackend"
plan.context[PLAN_CONTEXT_AUTHENTICATION_BACKEND] = BACKEND_DJANGO
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()

View File

@ -0,0 +1,3 @@
"""Backend paths"""
BACKEND_DJANGO = "django.contrib.auth.backends.ModelBackend"
BACKEND_LDAP = "authentik.sources.ldap.auth.LDAPBackend"

View File

@ -9,17 +9,18 @@ from rest_framework.serializers import BaseSerializer
from authentik.core.types import UserSettingSerializer
from authentik.flows.models import ConfigurableStage, Stage
from authentik.stages.password import BACKEND_DJANGO, BACKEND_LDAP
def get_authentication_backends():
"""Return all available authentication backends as tuple set"""
return [
(
"django.contrib.auth.backends.ModelBackend",
BACKEND_DJANGO,
_("authentik-internal Userdatabase"),
),
(
"authentik.sources.ldap.auth.LDAPBackend",
BACKEND_LDAP,
_("authentik LDAP"),
),
]

View File

@ -14,6 +14,7 @@ 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.providers.oauth2.generators import generate_client_secret
from authentik.stages.password import BACKEND_DJANGO
from authentik.stages.password.models import PasswordStage
MOCK_BACKEND_AUTHENTICATE = MagicMock(side_effect=PermissionDenied("test"))
@ -36,7 +37,7 @@ class TestPasswordStage(TestCase):
designation=FlowDesignation.AUTHENTICATION,
)
self.stage = PasswordStage.objects.create(
name="password", backends=["django.contrib.auth.backends.ModelBackend"]
name="password", backends=[BACKEND_DJANGO]
)
FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)

View File

@ -8,10 +8,10 @@ from structlog.stdlib import get_logger
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
from authentik.flows.stage import StageView
from authentik.lib.utils.time import timedelta_from_string
from authentik.stages.password import BACKEND_DJANGO
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
LOGGER = get_logger()
DEFAULT_BACKEND = "django.contrib.auth.backends.ModelBackend"
USER_LOGIN_AUTHENTICATED = "user_login_authenticated"
@ -26,7 +26,7 @@ class UserLoginStageView(StageView):
LOGGER.debug(message)
return self.executor.stage_invalid()
backend = self.executor.plan.context.get(
PLAN_CONTEXT_AUTHENTICATION_BACKEND, DEFAULT_BACKEND
PLAN_CONTEXT_AUTHENTICATION_BACKEND, BACKEND_DJANGO
)
login(
self.request,

View File

@ -9,6 +9,7 @@ from authentik.flows.markers import StageMarker
from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
from authentik.flows.views import SESSION_KEY_PLAN
from authentik.stages.password import BACKEND_DJANGO
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
from authentik.stages.user_logout.models import UserLogoutStage
@ -35,9 +36,7 @@ class TestUserLogoutStage(TestCase):
flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()]
)
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
plan.context[
PLAN_CONTEXT_AUTHENTICATION_BACKEND
] = "django.contrib.auth.backends.ModelBackend"
plan.context[PLAN_CONTEXT_AUTHENTICATION_BACKEND] = BACKEND_DJANGO
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()

View File

@ -9,6 +9,7 @@ from authentik.lib.config import CONFIG
from authentik.tenants.models import Tenant
_q_default = Q(default=True)
DEFAULT_TENANT = Tenant(domain="fallback")
def get_tenant_for_request(request: HttpRequest) -> Tenant:
@ -17,13 +18,13 @@ def get_tenant_for_request(request: HttpRequest) -> Tenant:
Q(domain__iendswith=request.get_host()) | _q_default
)
if not db_tenants.exists():
return Tenant(domain="fallback")
return DEFAULT_TENANT
return db_tenants.first()
def context_processor(request: HttpRequest) -> dict[str, Any]:
"""Context Processor that injects tenant object into every template"""
tenant = getattr(request, "tenant", Tenant(domain="fallback"))
tenant = getattr(request, "tenant", DEFAULT_TENANT)
return {
"tenant": tenant,
"ak_version": __version__,

View File

@ -21,7 +21,7 @@ services:
networks:
- internal
server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.1-rc2}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.1-rc6}
restart: unless-stopped
command: server
environment:
@ -52,7 +52,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.6.1-rc2}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.1-rc6}
restart: unless-stopped
command: worker
networks:

View File

@ -1,3 +1,3 @@
package constants
const VERSION = "2021.6.1-rc2"
const VERSION = "2021.6.1-rc6"

View File

@ -3,7 +3,6 @@ package ldap
import (
"context"
"errors"
"fmt"
"net"
"net/http"
"net/http/cookiejar"
@ -66,15 +65,15 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne
params := url.Values{}
params.Add("goauthentik.io/outpost/ldap", "true")
passed, err := pi.solveFlowChallenge(username, bindPW, apiClient, params.Encode(), 1)
if err != nil {
passed, rerr := pi.solveFlowChallenge(username, bindPW, apiClient, params.Encode(), 1)
if rerr != ldap.LDAPResultSuccess {
pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to solve challenge")
return ldap.LDAPResultOperationsError, nil
return rerr, nil
}
if !passed {
return ldap.LDAPResultInvalidCredentials, nil
}
p, _, err := apiClient.CoreApi.CoreApplicationsCheckAccessCreate(context.Background(), pi.appSlug).Execute()
p, _, err := apiClient.CoreApi.CoreApplicationsCheckAccessRetrieve(context.Background(), pi.appSlug).Execute()
if !p.Passing {
pi.log.WithField("bindDN", bindDN).Info("Access denied for user")
return ldap.LDAPResultInsufficientAccessRights, nil
@ -138,12 +137,12 @@ type ChallengeInt interface {
GetResponseErrors() map[string][]api.ErrorDetail
}
func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, client *api.APIClient, urlParams string, depth int) (bool, error) {
func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, client *api.APIClient, urlParams string, depth int) (bool, ldap.LDAPResultCode) {
req := client.FlowsApi.FlowsExecutorGet(context.Background(), pi.flowSlug).Query(urlParams)
challenge, _, err := req.Execute()
if err != nil {
pi.log.WithError(err).Warning("Failed to get challenge")
return false, err
return false, ldap.LDAPResultOperationsError
}
ch := challenge.GetActualInstance().(ChallengeInt)
pi.log.WithField("component", ch.GetComponent()).WithField("type", ch.GetType()).Debug("Got challenge")
@ -162,45 +161,51 @@ func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, c
}
}
if deviceChallenge == nil {
return false, errors.New("got ak-stage-authenticator-validate without duo")
pi.log.Warning("got ak-stage-authenticator-validate without duo")
return false, ldap.LDAPResultOperationsError
}
devId, err := strconv.Atoi(deviceChallenge.DeviceUid)
if err != nil {
return false, errors.New("failed to convert duo device id to int")
pi.log.Warning("failed to convert duo device id to int")
return false, ldap.LDAPResultOperationsError
}
devId32 := int32(devId)
inner := api.NewAuthenticatorValidationChallengeResponseRequest()
inner.Duo = &devId32
responseReq = responseReq.FlowChallengeResponseRequest(api.AuthenticatorValidationChallengeResponseRequestAsFlowChallengeResponseRequest(inner))
case "ak-stage-access-denied":
return false, errors.New("got ak-stage-access-denied")
pi.log.Info("got ak-stage-access-denied")
return false, ldap.LDAPResultInsufficientAccessRights
default:
return false, fmt.Errorf("unsupported challenge type: %s", ch.GetComponent())
pi.log.WithField("component", ch.GetComponent()).Warning("unsupported challenge type")
return false, ldap.LDAPResultOperationsError
}
response, _, err := responseReq.Execute()
ch = response.GetActualInstance().(ChallengeInt)
pi.log.WithField("component", ch.GetComponent()).WithField("type", ch.GetType()).Debug("Got response")
switch ch.GetComponent() {
case "ak-stage-access-denied":
return false, errors.New("got ak-stage-access-denied")
pi.log.Info("got ak-stage-access-denied")
return false, ldap.LDAPResultInsufficientAccessRights
}
if ch.GetType() == "redirect" {
return true, nil
return true, ldap.LDAPResultSuccess
}
if err != nil {
pi.log.WithError(err).Warning("Failed to submit challenge")
return false, err
return false, ldap.LDAPResultOperationsError
}
if len(ch.GetResponseErrors()) > 0 {
for key, errs := range ch.GetResponseErrors() {
for _, err := range errs {
pi.log.WithField("key", key).WithField("code", err.Code).WithField("msg", err.String).Warning("Flow error")
return false, nil
return false, ldap.LDAPResultInsufficientAccessRights
}
}
}
if depth >= 10 {
return false, errors.New("exceeded stage recursion depth")
pi.log.Warning("exceeded stage recursion depth")
return false, ldap.LDAPResultOperationsError
}
return pi.solveFlowChallenge(bindDN, password, client, urlParams, depth+1)
}

View File

@ -5,7 +5,7 @@ import (
"os"
)
const VERSION = "2021.6.1-rc2"
const VERSION = "2021.6.1-rc6"
func BUILD() string {
build := os.Getenv("GIT_BUILD_HASH")

View File

@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: authentik
version: 2021.6.1-rc1
version: 2021.6.1-rc5
description: Making authentication simple.
contact:
email: hello@beryju.org
@ -1504,10 +1504,14 @@ paths:
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/core/applications/{slug}/check_access/:
post:
operationId: core_applications_check_access_create
get:
operationId: core_applications_check_access_retrieve
description: Check access to a single application by slug
parameters:
- in: query
name: for_user
schema:
type: integer
- in: path
name: slug
schema:
@ -1516,17 +1520,6 @@ paths:
required: true
tags:
- core
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CheckAccessRequestRequest'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/CheckAccessRequestRequest'
multipart/form-data:
schema:
$ref: '#/components/schemas/CheckAccessRequestRequest'
security:
- authentik: []
- cookieAuth: []
@ -2717,14 +2710,10 @@ paths:
name: is_active
schema:
type: boolean
title: Active
description: Designates whether this user should be treated as active. Unselect
this instead of deleting accounts.
- in: query
name: is_superuser
schema:
type: string
format: uuid
type: boolean
- in: query
name: name
schema:
@ -3041,7 +3030,7 @@ paths:
- in: query
name: has_key
schema:
type: string
type: boolean
description: Only return certificate-key pairs with keys
- in: query
name: name
@ -3429,6 +3418,11 @@ paths:
description: A search term.
schema:
type: string
- in: query
name: tenant_name
schema:
type: string
description: Tenant name
- in: query
name: username
schema:
@ -3545,6 +3539,11 @@ paths:
description: A search term.
schema:
type: string
- in: query
name: tenant_name
schema:
type: string
description: Tenant name
- in: query
name: top_n
schema:
@ -4609,7 +4608,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/FlowChallengeRequest'
$ref: '#/components/schemas/ChallengeTypes'
description: ''
'404':
description: No Token found
@ -4655,7 +4654,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/FlowChallengeRequest'
$ref: '#/components/schemas/ChallengeTypes'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
@ -18413,17 +18412,75 @@ components:
required:
- certificate_data
- name
ChallT:
type: object
description: |-
Challenge that gets sent to the client based on which stage
is currently active
properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
flow_info:
$ref: '#/components/schemas/ContextualFlowInfo'
component:
type: string
default: ''
response_errors:
type: object
additionalProperties:
type: array
items:
$ref: '#/components/schemas/ErrorDetail'
required:
- type
ChallengeChoices:
enum:
- native
- shell
- redirect
type: string
CheckAccessRequestRequest:
type: object
properties:
for_user:
type: integer
ChallengeTypes:
oneOf:
- $ref: '#/components/schemas/AccessDeniedChallenge'
- $ref: '#/components/schemas/AuthenticatorDuoChallenge'
- $ref: '#/components/schemas/AuthenticatorStaticChallenge'
- $ref: '#/components/schemas/AuthenticatorTOTPChallenge'
- $ref: '#/components/schemas/AuthenticatorValidationChallenge'
- $ref: '#/components/schemas/AuthenticatorWebAuthnChallenge'
- $ref: '#/components/schemas/AutosubmitChallenge'
- $ref: '#/components/schemas/CaptchaChallenge'
- $ref: '#/components/schemas/ChallT'
- $ref: '#/components/schemas/ConsentChallenge'
- $ref: '#/components/schemas/DummyChallenge'
- $ref: '#/components/schemas/EmailChallenge'
- $ref: '#/components/schemas/IdentificationChallenge'
- $ref: '#/components/schemas/PasswordChallenge'
- $ref: '#/components/schemas/PlexAuthenticationChallenge'
- $ref: '#/components/schemas/PromptChallenge'
- $ref: '#/components/schemas/RedirectChallenge'
- $ref: '#/components/schemas/ShellChallenge'
discriminator:
propertyName: component
mapping:
ak-stage-access-denied: '#/components/schemas/AccessDeniedChallenge'
ak-stage-authenticator-duo: '#/components/schemas/AuthenticatorDuoChallenge'
ak-stage-authenticator-static: '#/components/schemas/AuthenticatorStaticChallenge'
ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallenge'
ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallenge'
ak-stage-authenticator-webauthn: '#/components/schemas/AuthenticatorWebAuthnChallenge'
ak-stage-autosubmit: '#/components/schemas/AutosubmitChallenge'
ak-stage-captcha: '#/components/schemas/CaptchaChallenge'
? ''
: '#/components/schemas/ChallT'
ak-stage-consent: '#/components/schemas/ConsentChallenge'
ak-stage-dummy: '#/components/schemas/DummyChallenge'
ak-stage-email: '#/components/schemas/EmailChallenge'
ak-stage-identification: '#/components/schemas/IdentificationChallenge'
ak-stage-password: '#/components/schemas/PasswordChallenge'
ak-flow-sources-plex: '#/components/schemas/PlexAuthenticationChallenge'
ak-stage-prompt: '#/components/schemas/PromptChallenge'
xak-flow-redirect: '#/components/schemas/RedirectChallenge'
xak-flow-shell: '#/components/schemas/ShellChallenge'
ClientTypeEnum:
enum:
- confidential
@ -19097,6 +19154,9 @@ components:
expires:
type: string
format: date-time
tenant:
type: object
additionalProperties: {}
required:
- action
- app
@ -19169,6 +19229,7 @@ components:
- property_mapping_exception
- system_task_execution
- system_task_exception
- system_exception
- configuration_error
- model_created
- model_updated
@ -19222,6 +19283,9 @@ components:
expires:
type: string
format: date-time
tenant:
type: object
additionalProperties: {}
required:
- action
- app
@ -19387,45 +19451,6 @@ components:
- slug
- stages
- title
FlowChallengeRequest:
oneOf:
- $ref: '#/components/schemas/AccessDeniedChallenge'
- $ref: '#/components/schemas/AuthenticatorDuoChallenge'
- $ref: '#/components/schemas/AuthenticatorStaticChallenge'
- $ref: '#/components/schemas/AuthenticatorTOTPChallenge'
- $ref: '#/components/schemas/AuthenticatorValidationChallenge'
- $ref: '#/components/schemas/AuthenticatorWebAuthnChallenge'
- $ref: '#/components/schemas/AutosubmitChallenge'
- $ref: '#/components/schemas/CaptchaChallenge'
- $ref: '#/components/schemas/ConsentChallenge'
- $ref: '#/components/schemas/DummyChallenge'
- $ref: '#/components/schemas/EmailChallenge'
- $ref: '#/components/schemas/IdentificationChallenge'
- $ref: '#/components/schemas/PasswordChallenge'
- $ref: '#/components/schemas/PlexAuthenticationChallenge'
- $ref: '#/components/schemas/PromptChallenge'
- $ref: '#/components/schemas/RedirectChallenge'
- $ref: '#/components/schemas/ShellChallenge'
discriminator:
propertyName: component
mapping:
ak-stage-access-denied: '#/components/schemas/AccessDeniedChallenge'
ak-stage-authenticator-duo: '#/components/schemas/AuthenticatorDuoChallenge'
ak-stage-authenticator-static: '#/components/schemas/AuthenticatorStaticChallenge'
ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallenge'
ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallenge'
ak-stage-authenticator-webauthn: '#/components/schemas/AuthenticatorWebAuthnChallenge'
ak-stage-autosubmit: '#/components/schemas/AutosubmitChallenge'
ak-stage-captcha: '#/components/schemas/CaptchaChallenge'
ak-stage-consent: '#/components/schemas/ConsentChallenge'
ak-stage-dummy: '#/components/schemas/DummyChallenge'
ak-stage-email: '#/components/schemas/EmailChallenge'
ak-stage-identification: '#/components/schemas/IdentificationChallenge'
ak-stage-password: '#/components/schemas/PasswordChallenge'
ak-flow-sources-plex: '#/components/schemas/PlexAuthenticationChallenge'
ak-stage-prompt: '#/components/schemas/PromptChallenge'
xak-flow-redirect: '#/components/schemas/RedirectChallenge'
xak-flow-shell: '#/components/schemas/ShellChallenge'
FlowChallengeResponseRequest:
oneOf:
- $ref: '#/components/schemas/AuthenticatorDuoChallengeResponseRequest'
@ -19775,7 +19800,7 @@ components:
sources:
type: array
items:
$ref: '#/components/schemas/UILoginButton'
$ref: '#/components/schemas/LoginSource'
required:
- password_fields
- primary_action
@ -20471,6 +20496,20 @@ components:
required:
- logins_failed_per_1h
- logins_per_1h
LoginSource:
type: object
description: Serializer for Login buttons of sources
properties:
name:
type: string
icon_url:
type: string
nullable: true
challenge:
$ref: '#/components/schemas/ChallengeTypes'
required:
- challenge
- name
NameIdPolicyEnum:
enum:
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
@ -26137,6 +26176,7 @@ components:
forward_auth_mode:
type: boolean
readOnly: true
deprecated: true
required:
- external_host
- forward_auth_mode
@ -27524,21 +27564,6 @@ components:
- description
- model_name
- name
UILoginButton:
type: object
description: Serializer for Login buttons of sources
properties:
name:
type: string
challenge:
type: object
additionalProperties: {}
icon_url:
type: string
nullable: true
required:
- challenge
- name
UsedBy:
type: object
description: A list of all objects referencing the queried object
@ -27687,6 +27712,7 @@ components:
enum:
- email
- username
- upn
type: string
UserLoginStage:
type: object
@ -27917,7 +27943,6 @@ components:
type: string
required:
- component
- configure_url
- object_uid
- title
UserWriteStage:

View File

@ -1,5 +1,4 @@
env
helm
static
htmlcov
*.env.yml

380
web/package-lock.json generated
View File

@ -9,14 +9,14 @@
"version": "0.0.0",
"license": "GNU GPLv3",
"dependencies": {
"@babel/core": "^7.14.5",
"@babel/core": "^7.14.6",
"@babel/plugin-proposal-decorators": "^7.14.5",
"@babel/plugin-transform-runtime": "^7.14.5",
"@babel/preset-env": "^7.14.5",
"@babel/preset-typescript": "^7.14.5",
"@fortawesome/fontawesome-free": "^5.15.3",
"@lingui/cli": "^3.10.2",
"@lingui/core": "^3.10.2",
"@lingui/core": "^3.10.3",
"@lingui/macro": "^3.10.2",
"@patternfly/patternfly": "^4.108.2",
"@polymer/iron-form": "^3.0.1",
@ -24,13 +24,13 @@
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-replace": "^2.4.2",
"@rollup/plugin-typescript": "^8.2.1",
"@sentry/browser": "^6.5.1",
"@sentry/tracing": "^6.5.1",
"@sentry/browser": "^6.7.0",
"@sentry/tracing": "^6.7.0",
"@types/chart.js": "^2.9.32",
"@types/codemirror": "5.60.0",
"@types/grecaptcha": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^4.26.1",
"@typescript-eslint/parser": "^4.26.1",
"@typescript-eslint/eslint-plugin": "^4.27.0",
"@typescript-eslint/parser": "^4.27.0",
"@webcomponents/webcomponentsjs": "^2.5.0",
"authentik-api": "file:api",
"babel-plugin-macros": "^3.1.0",
@ -48,7 +48,7 @@
"lit-html": "^1.4.1",
"moment": "^2.29.1",
"rapidoc": "^9.0.0",
"rollup": "^2.51.1",
"rollup": "^2.51.2",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-cssimport": "^1.0.2",
@ -57,7 +57,7 @@
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-terser": "^7.0.2",
"ts-lit-plugin": "^1.2.1",
"tslib": "^2.2.0",
"tslib": "^2.3.0",
"typescript": "^4.3.2",
"webcomponent-qr-code": "^1.0.5",
"yaml": "^1.10.2"
@ -110,16 +110,16 @@
}
},
"node_modules/@babel/core": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.5.tgz",
"integrity": "sha512-RN/AwP2DJmQTZSfiDaD+JQQ/J99KsIpOCfBE5pL+5jJSt7nI3nYGoAXZu+ffYSQ029NLs2DstZb+eR81uuARgg==",
"version": "7.14.6",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz",
"integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==",
"dependencies": {
"@babel/code-frame": "^7.14.5",
"@babel/generator": "^7.14.5",
"@babel/helper-compilation-targets": "^7.14.5",
"@babel/helper-module-transforms": "^7.14.5",
"@babel/helpers": "^7.14.5",
"@babel/parser": "^7.14.5",
"@babel/helpers": "^7.14.6",
"@babel/parser": "^7.14.6",
"@babel/template": "^7.14.5",
"@babel/traverse": "^7.14.5",
"@babel/types": "^7.14.5",
@ -479,9 +479,9 @@
}
},
"node_modules/@babel/helpers": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.5.tgz",
"integrity": "sha512-xtcWOuN9VL6nApgVHtq3PPcQv5qFBJzoSZzJ/2c0QK/IP/gxVcoWSNQwFEGvmbQsuS9rhYqjILDGGXcTkA705Q==",
"version": "7.14.6",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz",
"integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==",
"dependencies": {
"@babel/template": "^7.14.5",
"@babel/traverse": "^7.14.5",
@ -505,9 +505,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.5.tgz",
"integrity": "sha512-TM8C+xtH/9n1qzX+JNHi7AN2zHMTiPUtspO0ZdHflW8KaskkALhMmuMHb4bCmNdv9VAPzJX3/bXqkVLnAvsPfg==",
"version": "7.14.6",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.6.tgz",
"integrity": "sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ==",
"bin": {
"parser": "bin/babel-parser.js"
},
@ -2047,9 +2047,9 @@
}
},
"node_modules/@lingui/core": {
"version": "3.10.2",
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.2.tgz",
"integrity": "sha512-RL4Bn1s4Ukd0GBlEFO/+GoxnK48xuZR2GwFslg/eQxcQmeOA4c1Jw/tbvMKDfi40XwqMBWcS0G2njpWjuHC3SA==",
"version": "3.10.3",
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.3.tgz",
"integrity": "sha512-BiuWi5xPpQa27oIWWnkOYNx4qTMdMeu7vp5y1AGPYQ/4SO0rHfAtOxXtvRU/ktVwht/lIgx5Ygq5J3F+XLvOQA==",
"dependencies": {
"@babel/runtime": "^7.11.2",
"make-plural": "^6.2.2",
@ -2314,13 +2314,13 @@
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="
},
"node_modules/@sentry/browser": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.5.1.tgz",
"integrity": "sha512-iVLCdEFwsoWAzE/hNknexPQjjDpMQV7mmaq9Z1P63bD6MfhwVTx4hG4pHn8HEvC38VvCVf1wv0v/LxtoODAYXg==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.0.tgz",
"integrity": "sha512-sZvy2fxHjHXPdlaz8Ax02BeUbdILRv6a4i9FvMHvgSBeDiAVRIS+ihBhJAqziNOqwwXYThCSPKcCYGyTTncrVw==",
"dependencies": {
"@sentry/core": "6.5.1",
"@sentry/types": "6.5.1",
"@sentry/utils": "6.5.1",
"@sentry/core": "6.7.0",
"@sentry/types": "6.7.0",
"@sentry/utils": "6.7.0",
"tslib": "^1.9.3"
},
"engines": {
@ -2333,14 +2333,14 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/@sentry/core": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.5.1.tgz",
"integrity": "sha512-Mh3sl/iUOT1myHmM6RlDy2ARzkUClx/g4DAt1rJ/IpQBOlDYQraplXSIW80i/hzRgQDfwhwgf4wUa5DicKBjKw==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.0.tgz",
"integrity": "sha512-1TzDQIsS71a+6T1o3+NPyIgsTc37wdGh7cKZ8DRQ4bsML7MAkBV/LJeTVbXa0S9xha1v9v/oPindnHX5vBLJbg==",
"dependencies": {
"@sentry/hub": "6.5.1",
"@sentry/minimal": "6.5.1",
"@sentry/types": "6.5.1",
"@sentry/utils": "6.5.1",
"@sentry/hub": "6.7.0",
"@sentry/minimal": "6.7.0",
"@sentry/types": "6.7.0",
"@sentry/utils": "6.7.0",
"tslib": "^1.9.3"
},
"engines": {
@ -2353,12 +2353,12 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/@sentry/hub": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.5.1.tgz",
"integrity": "sha512-lBRMBVMYP8B4PfRiM70murbtJAXiIAao/asDEMIRNGMP6pI2ArqXfJCBYDkStukhikYD0Kqb4trXq+JYF07Hbg==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.0.tgz",
"integrity": "sha512-8e1IF6v8OIjuZVsolBAFoHhY0fEolsWwmZzm9k5N1wXWRbu4gpLHnCtDw47u2O9CFYr+b//bNXjmsA+DTckPkw==",
"dependencies": {
"@sentry/types": "6.5.1",
"@sentry/utils": "6.5.1",
"@sentry/types": "6.7.0",
"@sentry/utils": "6.7.0",
"tslib": "^1.9.3"
},
"engines": {
@ -2371,12 +2371,12 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/@sentry/minimal": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.5.1.tgz",
"integrity": "sha512-q9Do/oreu1RP695CXCLowVDuQyk7ilE6FGdz2QLpTXAfx8247qOwk6+zy9Kea/Djk93+BoSDVQUSneNiVwl0nQ==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.0.tgz",
"integrity": "sha512-q0SX2t1+6c8TSe8nI4+EsWc8+kSsKiGhoGo2tN2OTk4EXKCYEsEEDqB9iu7md5StmtmrO3UnRiYwT7JV8QGOeg==",
"dependencies": {
"@sentry/hub": "6.5.1",
"@sentry/types": "6.5.1",
"@sentry/hub": "6.7.0",
"@sentry/types": "6.7.0",
"tslib": "^1.9.3"
},
"engines": {
@ -2389,14 +2389,14 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/@sentry/tracing": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.5.1.tgz",
"integrity": "sha512-y1W/xFC2hAuKqSuuaovkElHY4pbli3XoXrreesg8PtO7ilX6ZbatOQbHsEsHQyoUv0F6aVA+MABOxWH2jt7tfw==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.0.tgz",
"integrity": "sha512-5joTxxDB4v2J1B3CIGDj4AJKJpeGztqExQMkCrwwWgBsZ+fFfctRSCyiwYo50TU93Zt/rt0rDjj8QF4o8ZH09A==",
"dependencies": {
"@sentry/hub": "6.5.1",
"@sentry/minimal": "6.5.1",
"@sentry/types": "6.5.1",
"@sentry/utils": "6.5.1",
"@sentry/hub": "6.7.0",
"@sentry/minimal": "6.7.0",
"@sentry/types": "6.7.0",
"@sentry/utils": "6.7.0",
"tslib": "^1.9.3"
},
"engines": {
@ -2409,19 +2409,19 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/@sentry/types": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.5.1.tgz",
"integrity": "sha512-b/7a6CMoytaeFPx4IBjfxPw3nPvsQh7ui1C8Vw0LxNNDgBwVhPLzUOWeLWbo5YZCVbGEMIWwtCUQYWxneceZSA==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.0.tgz",
"integrity": "sha512-5pKv0yJEOnkjy3J3eiGaM1CD2+p3rXkctJa8loZH7QgY7mJgUTKpozO3YymUmGjblthlrbuhH+5wUIBnVF60Bg==",
"engines": {
"node": ">=6"
}
},
"node_modules/@sentry/utils": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.5.1.tgz",
"integrity": "sha512-Wv86JYGQH+ZJ5XGFQX7h6ijl32667ikenoL9EyXMn8UoOYX/MLwZoQZin1P60wmKkYR9ifTNVmpaI9OoTaH+UQ==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.0.tgz",
"integrity": "sha512-K6s9svqOF4TT4AwvlDdiV9ZSGStSnf64s8KH1DNqwu5EZULvXvg0kbqgi6ZJTDHcchbnwHm7hLMNfuw95Aqi4Q==",
"dependencies": {
"@sentry/types": "6.5.1",
"@sentry/types": "6.7.0",
"tslib": "^1.9.3"
},
"engines": {
@ -2579,12 +2579,12 @@
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.26.1.tgz",
"integrity": "sha512-aoIusj/8CR+xDWmZxARivZjbMBQTT9dImUtdZ8tVCVRXgBUuuZyM5Of5A9D9arQPxbi/0rlJLcuArclz/rCMJw==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.27.0.tgz",
"integrity": "sha512-DsLqxeUfLVNp3AO7PC3JyaddmEHTtI9qTSAs+RB6ja27QvIM0TA8Cizn1qcS6vOu+WDLFJzkwkgweiyFhssDdQ==",
"dependencies": {
"@typescript-eslint/experimental-utils": "4.26.1",
"@typescript-eslint/scope-manager": "4.26.1",
"@typescript-eslint/experimental-utils": "4.27.0",
"@typescript-eslint/scope-manager": "4.27.0",
"debug": "^4.3.1",
"functional-red-black-tree": "^1.0.1",
"lodash": "^4.17.21",
@ -2610,14 +2610,14 @@
}
},
"node_modules/@typescript-eslint/experimental-utils": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.26.1.tgz",
"integrity": "sha512-sQHBugRhrXzRCs9PaGg6rowie4i8s/iD/DpTB+EXte8OMDfdCG5TvO73XlO9Wc/zi0uyN4qOmX9hIjQEyhnbmQ==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.27.0.tgz",
"integrity": "sha512-n5NlbnmzT2MXlyT+Y0Jf0gsmAQzCnQSWXKy4RGSXVStjDvS5we9IWbh7qRVKdGcxT0WYlgcCYUK/HRg7xFhvjQ==",
"dependencies": {
"@types/json-schema": "^7.0.7",
"@typescript-eslint/scope-manager": "4.26.1",
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/typescript-estree": "4.26.1",
"@typescript-eslint/scope-manager": "4.27.0",
"@typescript-eslint/types": "4.27.0",
"@typescript-eslint/typescript-estree": "4.27.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0"
},
@ -2650,13 +2650,13 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.26.1.tgz",
"integrity": "sha512-q7F3zSo/nU6YJpPJvQveVlIIzx9/wu75lr6oDbDzoeIRWxpoc/HQ43G4rmMoCc5my/3uSj2VEpg/D83LYZF5HQ==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.27.0.tgz",
"integrity": "sha512-XpbxL+M+gClmJcJ5kHnUpBGmlGdgNvy6cehgR6ufyxkEJMGP25tZKCaKyC0W/JVpuhU3VU1RBn7SYUPKSMqQvQ==",
"dependencies": {
"@typescript-eslint/scope-manager": "4.26.1",
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/typescript-estree": "4.26.1",
"@typescript-eslint/scope-manager": "4.27.0",
"@typescript-eslint/types": "4.27.0",
"@typescript-eslint/typescript-estree": "4.27.0",
"debug": "^4.3.1"
},
"engines": {
@ -2676,12 +2676,12 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.26.1.tgz",
"integrity": "sha512-TW1X2p62FQ8Rlne+WEShyd7ac2LA6o27S9i131W4NwDSfyeVlQWhw8ylldNNS8JG6oJB9Ha9Xyc+IUcqipvheQ==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.27.0.tgz",
"integrity": "sha512-DY73jK6SEH6UDdzc6maF19AHQJBFVRf6fgAXHPXCGEmpqD4vYgPEzqpFz1lf/daSbOcMpPPj9tyXXDPW2XReAw==",
"dependencies": {
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/visitor-keys": "4.26.1"
"@typescript-eslint/types": "4.27.0",
"@typescript-eslint/visitor-keys": "4.27.0"
},
"engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
@ -2692,9 +2692,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.26.1.tgz",
"integrity": "sha512-STyMPxR3cS+LaNvS8yK15rb8Y0iL0tFXq0uyl6gY45glyI7w0CsyqyEXl/Fa0JlQy+pVANeK3sbwPneCbWE7yg==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.27.0.tgz",
"integrity": "sha512-I4ps3SCPFCKclRcvnsVA/7sWzh7naaM/b4pBO2hVxnM3wrU51Lveybdw5WoIktU/V4KfXrTt94V9b065b/0+wA==",
"engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
},
@ -2704,12 +2704,12 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.26.1.tgz",
"integrity": "sha512-l3ZXob+h0NQzz80lBGaykdScYaiEbFqznEs99uwzm8fPHhDjwaBFfQkjUC/slw6Sm7npFL8qrGEAMxcfBsBJUg==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.27.0.tgz",
"integrity": "sha512-KH03GUsUj41sRLLEy2JHstnezgpS5VNhrJouRdmh6yNdQ+yl8w5LrSwBkExM+jWwCJa7Ct2c8yl8NdtNRyQO6g==",
"dependencies": {
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/visitor-keys": "4.26.1",
"@typescript-eslint/types": "4.27.0",
"@typescript-eslint/visitor-keys": "4.27.0",
"debug": "^4.3.1",
"globby": "^11.0.3",
"is-glob": "^4.0.1",
@ -2749,11 +2749,11 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.26.1.tgz",
"integrity": "sha512-IGouNSSd+6x/fHtYRyLOM6/C+QxMDzWlDtN41ea+flWuSF9g02iqcIlX8wM53JkfljoIjP0U+yp7SiTS1onEkw==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.27.0.tgz",
"integrity": "sha512-es0GRYNZp0ieckZ938cEANfEhsfHrzuLrePukLKtY3/KPXcq1Xd555Mno9/GOgXhKzn0QfkDLVgqWO3dGY80bg==",
"dependencies": {
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/types": "4.27.0",
"eslint-visitor-keys": "^2.0.0"
},
"engines": {
@ -6771,9 +6771,9 @@
}
},
"node_modules/rollup": {
"version": "2.51.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.1.tgz",
"integrity": "sha512-8xfDbAtBleXotb6qKEHWuo/jkn94a9dVqGc7Rwl3sqspCVlnCfbRek7ldhCARSi7h32H0xR4QThm1t9zHN+3uw==",
"version": "2.51.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.2.tgz",
"integrity": "sha512-ReV2eGEadA7hmXSzjxdDKs10neqH2QURf2RxJ6ayAlq93ugy6qIvXMmbc5cWMGCDh1h5T4thuWO1e2VNbMq8FA==",
"bin": {
"rollup": "dist/bin/rollup"
},
@ -7570,9 +7570,9 @@
"integrity": "sha512-zKmsCQs4dZaeSKjEA7pLFDv7FHHqAFLPd0Mr//OIJvu8M+4p4bgSFJwZSEBEg3ec9W7RzRz1vi8giiX0+mheBQ=="
},
"node_modules/tslib": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"node_modules/tsutils": {
"version": "3.21.0",
@ -8071,16 +8071,16 @@
"integrity": "sha512-kixrYn4JwfAVPa0f2yfzc2AWti6WRRyO3XjWW5PJAvtE11qhSayrrcrEnee05KAtNaPC+EwehE8Qt1UedEVB8w=="
},
"@babel/core": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.5.tgz",
"integrity": "sha512-RN/AwP2DJmQTZSfiDaD+JQQ/J99KsIpOCfBE5pL+5jJSt7nI3nYGoAXZu+ffYSQ029NLs2DstZb+eR81uuARgg==",
"version": "7.14.6",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz",
"integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==",
"requires": {
"@babel/code-frame": "^7.14.5",
"@babel/generator": "^7.14.5",
"@babel/helper-compilation-targets": "^7.14.5",
"@babel/helper-module-transforms": "^7.14.5",
"@babel/helpers": "^7.14.5",
"@babel/parser": "^7.14.5",
"@babel/helpers": "^7.14.6",
"@babel/parser": "^7.14.6",
"@babel/template": "^7.14.5",
"@babel/traverse": "^7.14.5",
"@babel/types": "^7.14.5",
@ -8345,9 +8345,9 @@
}
},
"@babel/helpers": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.5.tgz",
"integrity": "sha512-xtcWOuN9VL6nApgVHtq3PPcQv5qFBJzoSZzJ/2c0QK/IP/gxVcoWSNQwFEGvmbQsuS9rhYqjILDGGXcTkA705Q==",
"version": "7.14.6",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz",
"integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==",
"requires": {
"@babel/template": "^7.14.5",
"@babel/traverse": "^7.14.5",
@ -8365,9 +8365,9 @@
}
},
"@babel/parser": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.5.tgz",
"integrity": "sha512-TM8C+xtH/9n1qzX+JNHi7AN2zHMTiPUtspO0ZdHflW8KaskkALhMmuMHb4bCmNdv9VAPzJX3/bXqkVLnAvsPfg=="
"version": "7.14.6",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.6.tgz",
"integrity": "sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ=="
},
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
"version": "7.14.5",
@ -9431,9 +9431,9 @@
}
},
"@lingui/core": {
"version": "3.10.2",
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.2.tgz",
"integrity": "sha512-RL4Bn1s4Ukd0GBlEFO/+GoxnK48xuZR2GwFslg/eQxcQmeOA4c1Jw/tbvMKDfi40XwqMBWcS0G2njpWjuHC3SA==",
"version": "3.10.3",
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.3.tgz",
"integrity": "sha512-BiuWi5xPpQa27oIWWnkOYNx4qTMdMeu7vp5y1AGPYQ/4SO0rHfAtOxXtvRU/ktVwht/lIgx5Ygq5J3F+XLvOQA==",
"requires": {
"@babel/runtime": "^7.11.2",
"make-plural": "^6.2.2",
@ -9670,13 +9670,13 @@
}
},
"@sentry/browser": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.5.1.tgz",
"integrity": "sha512-iVLCdEFwsoWAzE/hNknexPQjjDpMQV7mmaq9Z1P63bD6MfhwVTx4hG4pHn8HEvC38VvCVf1wv0v/LxtoODAYXg==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.0.tgz",
"integrity": "sha512-sZvy2fxHjHXPdlaz8Ax02BeUbdILRv6a4i9FvMHvgSBeDiAVRIS+ihBhJAqziNOqwwXYThCSPKcCYGyTTncrVw==",
"requires": {
"@sentry/core": "6.5.1",
"@sentry/types": "6.5.1",
"@sentry/utils": "6.5.1",
"@sentry/core": "6.7.0",
"@sentry/types": "6.7.0",
"@sentry/utils": "6.7.0",
"tslib": "^1.9.3"
},
"dependencies": {
@ -9688,14 +9688,14 @@
}
},
"@sentry/core": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.5.1.tgz",
"integrity": "sha512-Mh3sl/iUOT1myHmM6RlDy2ARzkUClx/g4DAt1rJ/IpQBOlDYQraplXSIW80i/hzRgQDfwhwgf4wUa5DicKBjKw==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.0.tgz",
"integrity": "sha512-1TzDQIsS71a+6T1o3+NPyIgsTc37wdGh7cKZ8DRQ4bsML7MAkBV/LJeTVbXa0S9xha1v9v/oPindnHX5vBLJbg==",
"requires": {
"@sentry/hub": "6.5.1",
"@sentry/minimal": "6.5.1",
"@sentry/types": "6.5.1",
"@sentry/utils": "6.5.1",
"@sentry/hub": "6.7.0",
"@sentry/minimal": "6.7.0",
"@sentry/types": "6.7.0",
"@sentry/utils": "6.7.0",
"tslib": "^1.9.3"
},
"dependencies": {
@ -9707,12 +9707,12 @@
}
},
"@sentry/hub": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.5.1.tgz",
"integrity": "sha512-lBRMBVMYP8B4PfRiM70murbtJAXiIAao/asDEMIRNGMP6pI2ArqXfJCBYDkStukhikYD0Kqb4trXq+JYF07Hbg==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.0.tgz",
"integrity": "sha512-8e1IF6v8OIjuZVsolBAFoHhY0fEolsWwmZzm9k5N1wXWRbu4gpLHnCtDw47u2O9CFYr+b//bNXjmsA+DTckPkw==",
"requires": {
"@sentry/types": "6.5.1",
"@sentry/utils": "6.5.1",
"@sentry/types": "6.7.0",
"@sentry/utils": "6.7.0",
"tslib": "^1.9.3"
},
"dependencies": {
@ -9724,12 +9724,12 @@
}
},
"@sentry/minimal": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.5.1.tgz",
"integrity": "sha512-q9Do/oreu1RP695CXCLowVDuQyk7ilE6FGdz2QLpTXAfx8247qOwk6+zy9Kea/Djk93+BoSDVQUSneNiVwl0nQ==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.0.tgz",
"integrity": "sha512-q0SX2t1+6c8TSe8nI4+EsWc8+kSsKiGhoGo2tN2OTk4EXKCYEsEEDqB9iu7md5StmtmrO3UnRiYwT7JV8QGOeg==",
"requires": {
"@sentry/hub": "6.5.1",
"@sentry/types": "6.5.1",
"@sentry/hub": "6.7.0",
"@sentry/types": "6.7.0",
"tslib": "^1.9.3"
},
"dependencies": {
@ -9741,14 +9741,14 @@
}
},
"@sentry/tracing": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.5.1.tgz",
"integrity": "sha512-y1W/xFC2hAuKqSuuaovkElHY4pbli3XoXrreesg8PtO7ilX6ZbatOQbHsEsHQyoUv0F6aVA+MABOxWH2jt7tfw==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.0.tgz",
"integrity": "sha512-5joTxxDB4v2J1B3CIGDj4AJKJpeGztqExQMkCrwwWgBsZ+fFfctRSCyiwYo50TU93Zt/rt0rDjj8QF4o8ZH09A==",
"requires": {
"@sentry/hub": "6.5.1",
"@sentry/minimal": "6.5.1",
"@sentry/types": "6.5.1",
"@sentry/utils": "6.5.1",
"@sentry/hub": "6.7.0",
"@sentry/minimal": "6.7.0",
"@sentry/types": "6.7.0",
"@sentry/utils": "6.7.0",
"tslib": "^1.9.3"
},
"dependencies": {
@ -9760,16 +9760,16 @@
}
},
"@sentry/types": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.5.1.tgz",
"integrity": "sha512-b/7a6CMoytaeFPx4IBjfxPw3nPvsQh7ui1C8Vw0LxNNDgBwVhPLzUOWeLWbo5YZCVbGEMIWwtCUQYWxneceZSA=="
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.0.tgz",
"integrity": "sha512-5pKv0yJEOnkjy3J3eiGaM1CD2+p3rXkctJa8loZH7QgY7mJgUTKpozO3YymUmGjblthlrbuhH+5wUIBnVF60Bg=="
},
"@sentry/utils": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.5.1.tgz",
"integrity": "sha512-Wv86JYGQH+ZJ5XGFQX7h6ijl32667ikenoL9EyXMn8UoOYX/MLwZoQZin1P60wmKkYR9ifTNVmpaI9OoTaH+UQ==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.0.tgz",
"integrity": "sha512-K6s9svqOF4TT4AwvlDdiV9ZSGStSnf64s8KH1DNqwu5EZULvXvg0kbqgi6ZJTDHcchbnwHm7hLMNfuw95Aqi4Q==",
"requires": {
"@sentry/types": "6.5.1",
"@sentry/types": "6.7.0",
"tslib": "^1.9.3"
},
"dependencies": {
@ -9926,12 +9926,12 @@
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
},
"@typescript-eslint/eslint-plugin": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.26.1.tgz",
"integrity": "sha512-aoIusj/8CR+xDWmZxARivZjbMBQTT9dImUtdZ8tVCVRXgBUuuZyM5Of5A9D9arQPxbi/0rlJLcuArclz/rCMJw==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.27.0.tgz",
"integrity": "sha512-DsLqxeUfLVNp3AO7PC3JyaddmEHTtI9qTSAs+RB6ja27QvIM0TA8Cizn1qcS6vOu+WDLFJzkwkgweiyFhssDdQ==",
"requires": {
"@typescript-eslint/experimental-utils": "4.26.1",
"@typescript-eslint/scope-manager": "4.26.1",
"@typescript-eslint/experimental-utils": "4.27.0",
"@typescript-eslint/scope-manager": "4.27.0",
"debug": "^4.3.1",
"functional-red-black-tree": "^1.0.1",
"lodash": "^4.17.21",
@ -9941,14 +9941,14 @@
}
},
"@typescript-eslint/experimental-utils": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.26.1.tgz",
"integrity": "sha512-sQHBugRhrXzRCs9PaGg6rowie4i8s/iD/DpTB+EXte8OMDfdCG5TvO73XlO9Wc/zi0uyN4qOmX9hIjQEyhnbmQ==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.27.0.tgz",
"integrity": "sha512-n5NlbnmzT2MXlyT+Y0Jf0gsmAQzCnQSWXKy4RGSXVStjDvS5we9IWbh7qRVKdGcxT0WYlgcCYUK/HRg7xFhvjQ==",
"requires": {
"@types/json-schema": "^7.0.7",
"@typescript-eslint/scope-manager": "4.26.1",
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/typescript-estree": "4.26.1",
"@typescript-eslint/scope-manager": "4.27.0",
"@typescript-eslint/types": "4.27.0",
"@typescript-eslint/typescript-estree": "4.27.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0"
},
@ -9964,37 +9964,37 @@
}
},
"@typescript-eslint/parser": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.26.1.tgz",
"integrity": "sha512-q7F3zSo/nU6YJpPJvQveVlIIzx9/wu75lr6oDbDzoeIRWxpoc/HQ43G4rmMoCc5my/3uSj2VEpg/D83LYZF5HQ==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.27.0.tgz",
"integrity": "sha512-XpbxL+M+gClmJcJ5kHnUpBGmlGdgNvy6cehgR6ufyxkEJMGP25tZKCaKyC0W/JVpuhU3VU1RBn7SYUPKSMqQvQ==",
"requires": {
"@typescript-eslint/scope-manager": "4.26.1",
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/typescript-estree": "4.26.1",
"@typescript-eslint/scope-manager": "4.27.0",
"@typescript-eslint/types": "4.27.0",
"@typescript-eslint/typescript-estree": "4.27.0",
"debug": "^4.3.1"
}
},
"@typescript-eslint/scope-manager": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.26.1.tgz",
"integrity": "sha512-TW1X2p62FQ8Rlne+WEShyd7ac2LA6o27S9i131W4NwDSfyeVlQWhw8ylldNNS8JG6oJB9Ha9Xyc+IUcqipvheQ==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.27.0.tgz",
"integrity": "sha512-DY73jK6SEH6UDdzc6maF19AHQJBFVRf6fgAXHPXCGEmpqD4vYgPEzqpFz1lf/daSbOcMpPPj9tyXXDPW2XReAw==",
"requires": {
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/visitor-keys": "4.26.1"
"@typescript-eslint/types": "4.27.0",
"@typescript-eslint/visitor-keys": "4.27.0"
}
},
"@typescript-eslint/types": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.26.1.tgz",
"integrity": "sha512-STyMPxR3cS+LaNvS8yK15rb8Y0iL0tFXq0uyl6gY45glyI7w0CsyqyEXl/Fa0JlQy+pVANeK3sbwPneCbWE7yg=="
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.27.0.tgz",
"integrity": "sha512-I4ps3SCPFCKclRcvnsVA/7sWzh7naaM/b4pBO2hVxnM3wrU51Lveybdw5WoIktU/V4KfXrTt94V9b065b/0+wA=="
},
"@typescript-eslint/typescript-estree": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.26.1.tgz",
"integrity": "sha512-l3ZXob+h0NQzz80lBGaykdScYaiEbFqznEs99uwzm8fPHhDjwaBFfQkjUC/slw6Sm7npFL8qrGEAMxcfBsBJUg==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.27.0.tgz",
"integrity": "sha512-KH03GUsUj41sRLLEy2JHstnezgpS5VNhrJouRdmh6yNdQ+yl8w5LrSwBkExM+jWwCJa7Ct2c8yl8NdtNRyQO6g==",
"requires": {
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/visitor-keys": "4.26.1",
"@typescript-eslint/types": "4.27.0",
"@typescript-eslint/visitor-keys": "4.27.0",
"debug": "^4.3.1",
"globby": "^11.0.3",
"is-glob": "^4.0.1",
@ -10018,11 +10018,11 @@
}
},
"@typescript-eslint/visitor-keys": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.26.1.tgz",
"integrity": "sha512-IGouNSSd+6x/fHtYRyLOM6/C+QxMDzWlDtN41ea+flWuSF9g02iqcIlX8wM53JkfljoIjP0U+yp7SiTS1onEkw==",
"version": "4.27.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.27.0.tgz",
"integrity": "sha512-es0GRYNZp0ieckZ938cEANfEhsfHrzuLrePukLKtY3/KPXcq1Xd555Mno9/GOgXhKzn0QfkDLVgqWO3dGY80bg==",
"requires": {
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/types": "4.27.0",
"eslint-visitor-keys": "^2.0.0"
}
},
@ -13202,9 +13202,9 @@
}
},
"rollup": {
"version": "2.51.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.1.tgz",
"integrity": "sha512-8xfDbAtBleXotb6qKEHWuo/jkn94a9dVqGc7Rwl3sqspCVlnCfbRek7ldhCARSi7h32H0xR4QThm1t9zHN+3uw==",
"version": "2.51.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.2.tgz",
"integrity": "sha512-ReV2eGEadA7hmXSzjxdDKs10neqH2QURf2RxJ6ayAlq93ugy6qIvXMmbc5cWMGCDh1h5T4thuWO1e2VNbMq8FA==",
"requires": {
"fsevents": "~2.3.1"
}
@ -13870,9 +13870,9 @@
"integrity": "sha512-zKmsCQs4dZaeSKjEA7pLFDv7FHHqAFLPd0Mr//OIJvu8M+4p4bgSFJwZSEBEg3ec9W7RzRz1vi8giiX0+mheBQ=="
},
"tslib": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"tsutils": {
"version": "3.21.0",

View File

@ -38,14 +38,14 @@
]
},
"dependencies": {
"@babel/core": "^7.14.5",
"@babel/core": "^7.14.6",
"@babel/plugin-proposal-decorators": "^7.14.5",
"@babel/plugin-transform-runtime": "^7.14.5",
"@babel/preset-env": "^7.14.5",
"@babel/preset-typescript": "^7.14.5",
"@fortawesome/fontawesome-free": "^5.15.3",
"@lingui/cli": "^3.10.2",
"@lingui/core": "^3.10.2",
"@lingui/core": "^3.10.3",
"@lingui/macro": "^3.10.2",
"@patternfly/patternfly": "^4.108.2",
"@polymer/iron-form": "^3.0.1",
@ -53,13 +53,13 @@
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-replace": "^2.4.2",
"@rollup/plugin-typescript": "^8.2.1",
"@sentry/browser": "^6.5.1",
"@sentry/tracing": "^6.5.1",
"@sentry/browser": "^6.7.0",
"@sentry/tracing": "^6.7.0",
"@types/chart.js": "^2.9.32",
"@types/codemirror": "5.60.0",
"@types/grecaptcha": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^4.26.1",
"@typescript-eslint/parser": "^4.26.1",
"@typescript-eslint/eslint-plugin": "^4.27.0",
"@typescript-eslint/parser": "^4.27.0",
"@webcomponents/webcomponentsjs": "^2.5.0",
"authentik-api": "file:api",
"babel-plugin-macros": "^3.1.0",
@ -77,7 +77,7 @@
"lit-html": "^1.4.1",
"moment": "^2.29.1",
"rapidoc": "^9.0.0",
"rollup": "^2.51.1",
"rollup": "^2.51.2",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-cssimport": "^1.0.2",
@ -86,7 +86,7 @@
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-terser": "^7.0.2",
"ts-lit-plugin": "^1.2.1",
"tslib": "^2.2.0",
"tslib": "^2.3.0",
"typescript": "^4.3.2",
"webcomponent-qr-code": "^1.0.5",
"yaml": "^1.10.2"

View File

@ -8,10 +8,22 @@ export interface EventUser {
}
export interface EventContext {
[key: string]: EventContext | string | number | string[];
[key: string]: EventContext | EventModel | string | number | string[];
}
export interface EventWithContext extends Event {
user: EventUser;
context: EventContext;
}
export interface EventModel {
pk: string;
name: string;
app: string;
model_name: string;
}
export interface EventRequest {
path: string;
method: string;
}

View File

@ -7,8 +7,9 @@ import { config } from "./Config";
import { Config } from "authentik-api";
export const TAG_SENTRY_COMPONENT = "authentik.component";
export const TAG_SENTRY_CAPABILITIES = "authentik.capabilities";
export function configureSentry(canDoPpi: boolean = false, tags: { [key: string]: string; } = {}): Promise<Config> {
export function configureSentry(canDoPpi: boolean = false): Promise<Config> {
return config().then((config) => {
if (config.errorReportingEnabled) {
Sentry.init({
@ -53,7 +54,7 @@ export function configureSentry(canDoPpi: boolean = false, tags: { [key: string]
return event;
},
});
Sentry.setTags(tags);
Sentry.setTag(TAG_SENTRY_CAPABILITIES, config.capabilities.join(","));
if (window.location.pathname.includes("if/")) {
// Get the interface name from URL
const intf = window.location.pathname.replace(/.+if\/(.+)\//, "$1");

View File

@ -257,6 +257,12 @@ body {
.pf-c-dropdown__toggle::before {
border-color: transparent;
}
.pf-c-toggle-group__button {
color: var(--ak-dark-foreground) !important;
}
.pf-c-toggle-group__button:not(.pf-m-selected) {
background-color: var(--ak-dark-background-light) !important;
}
/* inputs help text */
.pf-c-form__helper-text:not(.pf-m-error) {
color: var(--ak-dark-foreground);

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.6.1-rc2";
export const VERSION = "2021.6.1-rc6";
export const PAGE_SIZE = 20;
export const EVENT_REFRESH = "ak-refresh";
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";

View File

@ -1,27 +0,0 @@
import { customElement, CSSResult, html, LitElement, property, TemplateResult } from "lit-element";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css";
import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
import AKGlobal from "../authentik.css";
@customElement("ak-banner")
export class Banner extends LitElement {
@property()
level = "pf-m-warning";
static get styles(): CSSResult[] {
return [PFBase, PFBanner, PFFlex, AKGlobal];
}
render(): TemplateResult {
return html`<div class="pf-c-banner ${this.level} pf-m-sticky">
<div class="pf-l-flex pf-m-justify-content-center pf-m-justify-content-space-between-on-lg pf-m-nowrap" style="height: 100%;">
<div class="pf-u-display-none pf-u-display-block-on-lg">
<slot></slot>
</div>
</div>
</div>`;
}
}

View File

@ -7,7 +7,6 @@ import PFFormControl from "@patternfly/patternfly/components/FormControl/form-co
import PFBullseye from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";
import PFBackdrop from "@patternfly/patternfly/components/Backdrop/backdrop.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFStack from "@patternfly/patternfly/layouts/Stack/stack.css";
import PFCard from "@patternfly/patternfly/components/Card/card.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
@ -40,7 +39,7 @@ export class ModalButton extends LitElement {
open = false;
static get styles(): CSSResult[] {
return [PFBase, PFButton, PFModalBox, PFForm, PFTitle, PFFormControl, PFBullseye, PFBackdrop, PFPage, PFStack, PFCard, PFContent, AKGlobal, MODAL_BUTTON_STYLES];
return [PFBase, PFButton, PFModalBox, PFForm, PFTitle, PFFormControl, PFBullseye, PFBackdrop, PFPage, PFCard, PFContent, AKGlobal, MODAL_BUTTON_STYLES];
}
constructor() {

View File

@ -19,7 +19,6 @@ export class Sidebar extends LitElement {
css`
:host {
z-index: 100;
box-shadow: none !important;
}
.pf-c-nav__link.pf-m-current::after,
.pf-c-nav__link.pf-m-current:hover::after,

View File

@ -21,6 +21,13 @@ export class SidebarItem extends LitElement {
z-index: 100;
box-shadow: none !important;
}
:host([highlight]) .pf-c-nav__item {
background-color: var(--ak-accent);
margin: 16px;
}
:host([highlight]) .pf-c-nav__item .pf-c-nav__link {
padding-left: 0.5rem;
}
.pf-c-nav__link.pf-m-current::after,
.pf-c-nav__link.pf-m-current:hover::after,
.pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link::after {
@ -75,6 +82,12 @@ export class SidebarItem extends LitElement {
@property({ type: Boolean })
isActive = false;
@property({ type: Boolean })
isAbsoluteLink?: boolean;
@property({ type: Boolean })
highlight?: boolean;
parent?: SidebarItem;
get childItems(): SidebarItem[] {
@ -159,9 +172,15 @@ export class SidebarItem extends LitElement {
</li>`;
}
return html`<li class="pf-c-nav__item">
<a href="#${this.path}" class="pf-c-nav__link ${this.isActive ? "pf-m-current" : ""}">
<slot name="label"></slot>
</a>
${this.path ? html`
<a href="${this.isAbsoluteLink ? "" : "#"}${this.path}" class="pf-c-nav__link ${this.isActive ? "pf-m-current" : ""}">
<slot name="label"></slot>
</a>
` : html`
<span class="pf-c-nav__link">
<slot name="label"></slot>
</span>
`}
</li>`;
}
}

View File

@ -26,7 +26,7 @@ import "./stages/password/PasswordStage";
import "./stages/prompt/PromptStage";
import "./sources/plex/PlexLoginInit";
import { StageHost } from "./stages/base";
import { ChallengeChoices, CurrentTenant, FlowChallengeRequest, FlowChallengeResponseRequest, FlowsApi, RedirectChallenge, ShellChallenge } from "authentik-api";
import { ChallengeChoices, CurrentTenant, ChallengeTypes, FlowChallengeResponseRequest, FlowsApi, RedirectChallenge, ShellChallenge } from "authentik-api";
import { DEFAULT_CONFIG, tenant } from "../api/Config";
import { ifDefined } from "lit-html/directives/if-defined";
import { until } from "lit-html/directives/until";
@ -40,7 +40,7 @@ export class FlowExecutor extends LitElement implements StageHost {
flowSlug: string;
@property({attribute: false})
challenge?: FlowChallengeRequest;
challenge?: ChallengeTypes;
@property({type: Boolean})
loading = false;
@ -107,8 +107,8 @@ export class FlowExecutor extends LitElement implements StageHost {
}).then((data) => {
this.challenge = data;
this.postUpdate();
}).catch((e: Error) => {
this.errorMessage(e.toString());
}).catch((e: Error | Response) => {
this.errorMessage(e);
}).finally(() => {
this.loading = false;
});
@ -128,15 +128,21 @@ export class FlowExecutor extends LitElement implements StageHost {
this.setBackground(this.challenge.flowInfo.background);
}
this.postUpdate();
}).catch((e: Error) => {
}).catch((e: Error | Response) => {
// Catch JSON or Update errors
this.errorMessage(e.toString());
this.errorMessage(e);
}).finally(() => {
this.loading = false;
});
}
errorMessage(error: string): void {
async errorMessage(error: Error | Response): Promise<void> {
let body = "";
if (error instanceof Error) {
body = error.message;
} else if (error instanceof Response) {
body = await error.text();
}
this.challenge = {
type: ChallengeChoices.Shell,
body: `<header class="pf-c-login__main-header">
@ -146,7 +152,7 @@ export class FlowExecutor extends LitElement implements StageHost {
</header>
<div class="pf-c-login__main-body">
<h3>${t`Something went wrong! Please try again later.`}</h3>
<pre class="ak-exception">${error}</pre>
<pre class="ak-exception">${body}</pre>
</div>
<footer class="pf-c-login__main-footer">
<ul class="pf-c-login__main-footer-links">
@ -157,7 +163,7 @@ export class FlowExecutor extends LitElement implements StageHost {
</li>
</ul>
</footer>`
} as FlowChallengeRequest;
} as ChallengeTypes;
}
renderLoading(): TemplateResult {

View File

@ -11,7 +11,7 @@ import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
import AKGlobal from "../../../authentik.css";
import "../../../elements/forms/FormElement";
import "../../../elements/EmptyState";
import { FlowChallengeRequest, IdentificationChallenge, IdentificationChallengeResponseRequest, UILoginButton } from "authentik-api";
import { IdentificationChallenge, IdentificationChallengeResponseRequest, LoginSource, UserFieldsEnum } from "authentik-api";
export const PasswordManagerPrefill: {
password: string | undefined;
@ -21,6 +21,7 @@ export const PasswordManagerPrefill: {
totp: undefined,
};
export const OR_LIST_FORMATTERS = new Intl.ListFormat("default", { style: "short", type: "disjunction" });
@customElement("ak-stage-identification")
export class IdentificationStage extends BaseStage<IdentificationChallenge, IdentificationChallengeResponseRequest> {
@ -109,7 +110,7 @@ export class IdentificationStage extends BaseStage<IdentificationChallenge, Iden
wrapperForm.appendChild(totp);
}
renderSource(source: UILoginButton): TemplateResult {
renderSource(source: LoginSource): TemplateResult {
let icon = html`<i class="fas fas fa-share-square" title="${source.name}"></i>`;
if (source.iconUrl) {
icon = html`<img src="${source.iconUrl}" alt="${source.name}">`;
@ -117,7 +118,7 @@ export class IdentificationStage extends BaseStage<IdentificationChallenge, Iden
return html`<li class="pf-c-login__main-footer-links-item">
<button type="button" @click=${() => {
if (!this.host) return;
this.host.challenge = source.challenge as FlowChallengeRequest;
this.host.challenge = source.challenge;
}}>
${icon}
</button>
@ -142,21 +143,23 @@ export class IdentificationStage extends BaseStage<IdentificationChallenge, Iden
}
renderInput(): TemplateResult {
let label = "";
let type = "text";
if (!this.challenge?.userFields) {
return html`<p>
${t`Select one of the sources below to login.`}
</p>`;
}
if (this.challenge?.userFields === ["email"]) {
label = t`Email`;
const fields = (this.challenge?.userFields || []).sort();
// Check if the field should be *only* email to set the input type
if (fields.includes(UserFieldsEnum.Email) && fields.length === 1) {
type = "email";
} else if (this.challenge?.userFields === ["username"]) {
label = t`Username`;
} else {
label = t`Email or username`;
}
const uiFields: { [key: string]: string } = {
[UserFieldsEnum.Username]: t`Username`,
[UserFieldsEnum.Email]: t`Email`,
[UserFieldsEnum.Upn]: t`UPN`,
};
const label = OR_LIST_FORMATTERS.format(fields.map(f => uiFields[f]));
return html`<ak-form-element
label=${label}
?required="${true}"
@ -165,7 +168,7 @@ export class IdentificationStage extends BaseStage<IdentificationChallenge, Iden
<!-- @ts-ignore -->
<input type=${type}
name="uidField"
placeholder="Email or Username"
placeholder=${label}
autofocus=""
autocomplete="username"
class="pf-c-form-control"

7
web/src/global.d.ts vendored
View File

@ -1 +1,8 @@
declare module "*.css";
declare namespace Intl {
class ListFormat {
constructor(locale: string, args: { [key: string]: string });
public format: (items: string[]) => string;
}
}

View File

@ -1,20 +1,102 @@
import "../elements/messages/MessageContainer";
import { customElement, html, TemplateResult } from "lit-element";
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { me } from "../api/Users";
import { ID_REGEX, SLUG_REGEX, UUID_REGEX } from "../elements/router/Route";
import { Interface } from "./Interface";
import "./locale";
import "../elements/sidebar/SidebarItem";
import { t } from "@lingui/macro";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css";
import "../elements/router/RouterOutlet";
import "../elements/messages/MessageContainer";
import "../elements/notifications/NotificationDrawer";
import "../elements/sidebar/Sidebar";
import { until } from "lit-html/directives/until";
import { EVENT_NOTIFICATION_TOGGLE, EVENT_SIDEBAR_TOGGLE, VERSION } from "../constants";
import { AdminApi } from "authentik-api";
import { DEFAULT_CONFIG } from "../api/Config";
@customElement("ak-interface-admin")
export class AdminInterface extends Interface {
export class AdminInterface extends LitElement {
@property({type: Boolean})
sidebarOpen = true;
@property({type: Boolean})
notificationOpen = false;
static get styles(): CSSResult[] {
return [PFBase, PFPage, PFButton, PFDrawer, css`
.pf-c-page__main, .pf-c-drawer__content, .pf-c-page__drawer {
z-index: auto !important;
}
`];
}
constructor() {
super();
this.sidebarOpen = window.innerWidth >= 1280;
window.addEventListener("resize", () => {
this.sidebarOpen = window.innerWidth >= 1280;
});
window.addEventListener(EVENT_SIDEBAR_TOGGLE, () => {
this.sidebarOpen = !this.sidebarOpen;
});
window.addEventListener(EVENT_NOTIFICATION_TOGGLE, () => {
this.notificationOpen = !this.notificationOpen;
});
}
render(): TemplateResult {
return html`
<div class="pf-c-page">
<ak-sidebar class="pf-c-page__sidebar ${this.sidebarOpen ? "pf-m-expanded" : "pf-m-collapsed"}">
${this.renderSidebarItems()}
</ak-sidebar>
<div class="pf-c-page__drawer">
<div class="pf-c-drawer ${this.notificationOpen ? "pf-m-expanded" : "pf-m-collapsed"}">
<div class="pf-c-drawer__main">
<div class="pf-c-drawer__content">
<div class="pf-c-drawer__body">
<main class="pf-c-page__main">
<ak-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/library">
</ak-router-outlet>
</main>
</div>
</div>
<ak-notification-drawer class="pf-c-drawer__panel pf-m-width-33">
</ak-notification-drawer>
</div>
</div>
</div>
</div>`;
}
renderSidebarItems(): TemplateResult {
const superUserCondition = () => {
return me().then(u => u.user.isSuperuser || false);
};
return html`
${until(new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve().then(version => {
if (version.versionCurrent !== VERSION) {
return html`<ak-sidebar-item ?highlight=${true}>
<span slot="label">${t`A newer version of the frontend is available.`}</span>
</ak-sidebar-item>`;
}
return html``;
}))}
${until(me().then((u) => {
if (u.original) {
return html`<ak-sidebar-item ?highlight=${true} ?isAbsoluteLink=${true} path=${`/-/impersonation/end/?back=${window.location.pathname}%23${window.location.hash}`}>
<span slot="label">${t`You're currently impersonating ${u.user.username}. Click to stop.`}</span>
</ak-sidebar-item>`;
}
return html``;
}))}
<ak-sidebar-item path="/library">
<span slot="label">${t`Library`}</span>
</ak-sidebar-item>

View File

@ -1,99 +0,0 @@
import { css, CSSResult, html, LitElement, property, TemplateResult } from "lit-element";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css";
import "../elements/router/RouterOutlet";
import "../elements/messages/MessageContainer";
import "../elements/notifications/NotificationDrawer";
import "../elements/Banner";
import "../elements/sidebar/Sidebar";
import { until } from "lit-html/directives/until";
import { me } from "../api/Users";
import { t } from "@lingui/macro";
import { EVENT_NOTIFICATION_TOGGLE, EVENT_SIDEBAR_TOGGLE, VERSION } from "../constants";
import { AdminApi } from "authentik-api";
import { DEFAULT_CONFIG } from "../api/Config";
export abstract class Interface extends LitElement {
@property({type: Boolean})
sidebarOpen = true;
@property({type: Boolean})
notificationOpen = false;
static get styles(): CSSResult[] {
return [PFBase, PFPage, PFButton, PFDrawer, css`
.pf-c-page__main, .pf-c-drawer__content, .pf-c-page__drawer {
z-index: auto !important;
}
`];
}
constructor() {
super();
this.sidebarOpen = window.innerWidth >= 1280;
window.addEventListener("resize", () => {
this.sidebarOpen = window.innerWidth >= 1280;
});
window.addEventListener(EVENT_SIDEBAR_TOGGLE, () => {
this.sidebarOpen = !this.sidebarOpen;
});
window.addEventListener(EVENT_NOTIFICATION_TOGGLE, () => {
this.notificationOpen = !this.notificationOpen;
});
}
renderSidebarItems(): TemplateResult {
return html``;
}
render(): TemplateResult {
return html`
${until(new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve().then(version => {
if (version.versionCurrent !== VERSION) {
return html`<ak-banner>
${t`A newer version of the frontend is available.`}
<button @click=${() => { window.location.reload(true); }}>
${t`Reload`}
</button>
</ak-banner>`;
}
return html``;
}))}
${until(me().then((u) => {
if (u.original) {
return html`<ak-banner>
${t`You're currently impersonating ${u.user.username}.`}
<a href=${`/-/impersonation/end/?back=${window.location.pathname}%23${window.location.hash}`}>
${t`Stop impersonation`}
</a>
</ak-banner>`;
}
return html``;
}))}
<div class="pf-c-page">
<ak-sidebar class="pf-c-page__sidebar ${this.sidebarOpen ? "pf-m-expanded" : "pf-m-collapsed"}">
${this.renderSidebarItems()}
</ak-sidebar>
<div class="pf-c-page__drawer">
<div class="pf-c-drawer ${this.notificationOpen ? "pf-m-expanded" : "pf-m-collapsed"}">
<div class="pf-c-drawer__main">
<div class="pf-c-drawer__content">
<div class="pf-c-drawer__body">
<main class="pf-c-page__main">
<ak-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/library">
</ak-router-outlet>
</main>
</div>
</div>
<ak-notification-drawer class="pf-c-drawer__panel pf-m-width-33">
</ak-notification-drawer>
</div>
</div>
</div>
</div>`;
}
}

View File

@ -32,7 +32,7 @@ msgstr "6 digits, widely compatible"
msgid "8 digits, not compatible with apps like Google Authenticator"
msgstr "8 digits, not compatible with apps like Google Authenticator"
#: src/interfaces/Interface.ts
#: src/interfaces/AdminInterface.ts
msgid "A newer version of the frontend is available."
msgstr "A newer version of the frontend is available."
@ -674,11 +674,14 @@ msgstr "Configuration"
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts
msgid "Configuration flow"
msgstr "Configuration flow"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Configuration stage"
msgstr "Configuration stage"
#: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts
msgid "Configure WebAuthn"
msgstr "Configure WebAuthn"
@ -1283,10 +1286,6 @@ msgstr "Email address"
msgid "Email info:"
msgstr "Email info:"
#: src/flows/stages/identification/IdentificationStage.ts
msgid "Email or username"
msgstr "Email or username"
#: src/pages/stages/prompt/PromptForm.ts
msgid "Email: Text field with Email type."
msgstr "Email: Text field with Email type."
@ -1392,6 +1391,7 @@ msgstr "Event {0}"
msgid "Events"
msgstr "Events"
#: src/pages/events/EventInfo.ts
#: src/pages/events/EventInfo.ts
#: src/pages/events/EventInfo.ts
msgid "Exception"
@ -2498,6 +2498,10 @@ msgstr "Only send notification once, for example when sending a webhook into a c
msgid "Open application"
msgstr "Open application"
#: src/pages/events/EventInfo.ts
msgid "Open issue on GitHub..."
msgstr "Open issue on GitHub..."
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
msgid "OpenID Configuration Issuer"
msgstr "OpenID Configuration Issuer"
@ -2928,10 +2932,6 @@ msgstr "Regular expressions for which authentication is not required. Each new l
msgid "Related"
msgstr "Related"
#: src/interfaces/Interface.ts
msgid "Reload"
msgstr "Reload"
#: src/pages/stages/user_logout/UserLogoutStageForm.ts
msgid "Remove the user from the current session."
msgstr "Remove the user from the current session."
@ -3409,10 +3409,6 @@ msgstr "Status: Disabled"
msgid "Status: Enabled"
msgstr "Status: Enabled"
#: src/interfaces/Interface.ts
msgid "Stop impersonation"
msgstr "Stop impersonation"
#: src/pages/events/EventInfo.ts
#: src/pages/stages/email/EmailStageForm.ts
msgid "Subject"
@ -3772,6 +3768,7 @@ msgstr "Task finished with warnings"
msgid "Template"
msgstr "Template"
#: src/pages/events/EventListPage.ts
#: src/pages/tenants/TenantListPage.ts
msgid "Tenant"
msgstr "Tenant"
@ -3981,6 +3978,11 @@ msgstr "UI settings"
msgid "UID"
msgstr "UID"
#: src/flows/stages/identification/IdentificationStage.ts
#: src/pages/stages/identification/IdentificationStageForm.ts
msgid "UPN"
msgstr "UPN"
#: src/pages/sources/oauth/OAuthSourceForm.ts
msgid "URL settings"
msgstr "URL settings"
@ -4517,9 +4519,9 @@ msgstr "Yes"
msgid "You can only select providers that match the type of the outpost."
msgstr "You can only select providers that match the type of the outpost."
#: src/interfaces/Interface.ts
msgid "You're currently impersonating {0}."
msgstr "You're currently impersonating {0}."
#: src/interfaces/AdminInterface.ts
msgid "You're currently impersonating {0}. Click to stop."
msgstr "You're currently impersonating {0}. Click to stop."
#: src/pages/stages/password/PasswordStageForm.ts
msgid "authentik Builtin Database"
@ -4529,6 +4531,10 @@ msgstr "authentik Builtin Database"
msgid "authentik LDAP Backend"
msgstr "authentik LDAP Backend"
#: src/elements/forms/DeleteForm.ts
msgid "connecting object will be deleted"
msgstr "connecting object will be deleted"
#: src/elements/Tabs.ts
msgid "no tabs defined"
msgstr "no tabs defined"

View File

@ -669,10 +669,13 @@ msgstr ""
#:
#:
#:
#:
msgid "Configuration flow"
msgstr ""
#:
msgid "Configuration stage"
msgstr ""
#:
msgid "Configure WebAuthn"
msgstr ""
@ -1275,10 +1278,6 @@ msgstr ""
msgid "Email info:"
msgstr ""
#:
msgid "Email or username"
msgstr ""
#:
msgid "Email: Text field with Email type."
msgstr ""
@ -1384,6 +1383,7 @@ msgstr ""
msgid "Events"
msgstr ""
#:
#:
#:
msgid "Exception"
@ -2490,6 +2490,10 @@ msgstr ""
msgid "Open application"
msgstr ""
#:
msgid "Open issue on GitHub..."
msgstr ""
#:
msgid "OpenID Configuration Issuer"
msgstr ""
@ -2920,10 +2924,6 @@ msgstr ""
msgid "Related"
msgstr ""
#:
msgid "Reload"
msgstr ""
#:
msgid "Remove the user from the current session."
msgstr ""
@ -3401,10 +3401,6 @@ msgstr ""
msgid "Status: Enabled"
msgstr ""
#:
msgid "Stop impersonation"
msgstr ""
#:
#:
msgid "Subject"
@ -3764,6 +3760,7 @@ msgstr ""
msgid "Template"
msgstr ""
#:
#:
msgid "Tenant"
msgstr ""
@ -3969,6 +3966,11 @@ msgstr ""
msgid "UID"
msgstr ""
#:
#:
msgid "UPN"
msgstr ""
#:
msgid "URL settings"
msgstr ""
@ -4504,7 +4506,7 @@ msgid "You can only select providers that match the type of the outpost."
msgstr ""
#:
msgid "You're currently impersonating {0}."
msgid "You're currently impersonating {0}. Click to stop."
msgstr ""
#:
@ -4515,6 +4517,10 @@ msgstr ""
msgid "authentik LDAP Backend"
msgstr ""
#:
msgid "connecting object will be deleted"
msgstr ""
#:
msgid "no tabs defined"
msgstr ""

View File

@ -34,7 +34,7 @@ export class UserCountStatusChart extends AKChart<UserMetrics> {
pageSize: 1
})).pagination.count;
const superusers = (await api.coreUsersList({
isSuperuser: "true"
isSuperuser: true
})).pagination.count;
this.centerText = count.toString();
return {

View File

@ -1,4 +1,4 @@
import { Application, CoreApi, CheckAccessRequestRequest, PolicyTestResult } from "authentik-api";
import { Application, CoreApi, PolicyTestResult } from "authentik-api";
import { t } from "@lingui/macro";
import { customElement, property } from "lit-element";
import { html, TemplateResult } from "lit-html";
@ -8,7 +8,7 @@ import { until } from "lit-html/directives/until";
import "../../elements/forms/HorizontalFormElement";
@customElement("ak-application-check-access-form")
export class ApplicationCheckAccessForm extends Form<CheckAccessRequestRequest> {
export class ApplicationCheckAccessForm extends Form<number> {
@property({attribute: false})
application!: Application;
@ -17,17 +17,17 @@ export class ApplicationCheckAccessForm extends Form<CheckAccessRequestRequest>
result?: PolicyTestResult;
@property({ attribute: false})
request?: CheckAccessRequestRequest;
request?: number;
getSuccessMessage(): string {
return t`Successfully sent test-request.`;
}
send = (data: CheckAccessRequestRequest): Promise<PolicyTestResult> => {
send = (data: number): Promise<PolicyTestResult> => {
this.request = data;
return new CoreApi(DEFAULT_CONFIG).coreApplicationsCheckAccessCreate({
return new CoreApi(DEFAULT_CONFIG).coreApplicationsCheckAccessRetrieve({
slug: this.application?.slug,
checkAccessRequestRequest: data,
forUser: data,
}).then(result => this.result = result);
};
@ -68,7 +68,7 @@ export class ApplicationCheckAccessForm extends Form<CheckAccessRequestRequest>
ordering: "username",
}).then(users => {
return users.results.map(user => {
return html`<option ?selected=${user.pk.toString() === this.request?.forUser?.toString()} value=${user.pk}>${user.username}</option>`;
return html`<option ?selected=${user.pk.toString() === this.request?.toString()} value=${user.pk}>${user.username}</option>`;
});
}), html`<option>${t`Loading...`}</option>`)}
</select>

View File

@ -5,13 +5,14 @@ import { EventMatcherPolicyActionEnum, FlowsApi } from "authentik-api";
import "../../elements/Spinner";
import "../../elements/Expand";
import { PFSize } from "../../elements/Spinner";
import { EventContext, EventWithContext } from "../../api/Events";
import { EventContext, EventModel, EventWithContext } from "../../api/Events";
import { DEFAULT_CONFIG } from "../../api/Config";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFList from "@patternfly/patternfly/components/List/list.css";
import { VERSION } from "../../constants";
@customElement("ak-event-info")
export class EventInfo extends LitElement {
@ -20,7 +21,7 @@ export class EventInfo extends LitElement {
event!: EventWithContext;
static get styles(): CSSResult[] {
return [PFBase, PFFlex, PFList, PFDescriptionList,
return [PFBase, PFButton, PFFlex, PFList, PFDescriptionList,
css`
code {
display: block;
@ -40,7 +41,7 @@ export class EventInfo extends LitElement {
];
}
getModelInfo(context: EventContext): TemplateResult {
getModelInfo(context: EventModel): TemplateResult {
if (context === null) {
return html`<span>-</span>`;
}
@ -50,7 +51,7 @@ export class EventInfo extends LitElement {
<span class="pf-c-description-list__text">${t`UID`}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${context.pk as string}</div>
<div class="pf-c-description-list__text">${context.pk}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -58,7 +59,7 @@ export class EventInfo extends LitElement {
<span class="pf-c-description-list__text">${t`Name`}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${context.name as string}</div>
<div class="pf-c-description-list__text">${context.name}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -66,7 +67,7 @@ export class EventInfo extends LitElement {
<span class="pf-c-description-list__text">${t`App`}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${context.app as string}</div>
<div class="pf-c-description-list__text">${context.app}</div>
</dd>
</div>
<div class="pf-c-description-list__group">
@ -74,7 +75,7 @@ export class EventInfo extends LitElement {
<span class="pf-c-description-list__text">${t`Model Name`}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">${context.model_name as string}</div>
<div class="pf-c-description-list__text">${context.model_name}</div>
</dd>
</div>
</dl>`;
@ -137,6 +138,52 @@ export class EventInfo extends LitElement {
</div>`;
}
buildGitHubIssueUrl(context: EventContext): string {
const httpRequest = this.event.context.http_request as EventContext;
let title = "";
if (httpRequest) {
title = `${httpRequest?.method} ${httpRequest?.path}`;
}
// https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/about-automation-for-issues-and-pull-requests-with-query-parameters
const fullBody = `
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Logs**
<details>
<summary>Stacktrace from authentik</summary>
\`\`\`
${context.message as string}
\`\`\`
</details>
**Version and Deployment (please complete the following information):**
- authentik version: ${VERSION}
- Deployment: [e.g. docker-compose, helm]
**Additional context**
Add any other context about the problem here.
`;
return `https://github.com/goauthentik/authentik/issues/
new?labels=bug,from_authentik&title=${encodeURIComponent(title)}
&body=${encodeURIComponent(fullBody)}`.trim();
}
render(): TemplateResult {
if (!this.event) {
return html`<ak-spinner size=${PFSize.Medium}></ak-spinner>`;
@ -147,13 +194,13 @@ export class EventInfo extends LitElement {
case EventMatcherPolicyActionEnum.ModelDeleted:
return html`
<h3>${t`Affected model:`}</h3>
${this.getModelInfo(this.event.context?.model as EventContext)}
${this.getModelInfo(this.event.context?.model as EventModel)}
`;
case EventMatcherPolicyActionEnum.AuthorizeApplication:
return html`<div class="pf-l-flex">
<div class="pf-l-flex__item">
<h3>${t`Authorized application:`}</h3>
${this.getModelInfo(this.event.context.authorized_application as EventContext)}
${this.getModelInfo(this.event.context.authorized_application as EventModel)}
</div>
<div class="pf-l-flex__item">
<h3>${t`Using flow`}</h3>
@ -175,7 +222,24 @@ export class EventInfo extends LitElement {
case EventMatcherPolicyActionEnum.SecretView:
return html`
<h3>${t`Secret:`}</h3>
${this.getModelInfo(this.event.context.secret as EventContext)}`;
${this.getModelInfo(this.event.context.secret as EventModel)}`;
case EventMatcherPolicyActionEnum.SystemException:
return html`
<a
class="pf-c-button pf-m-primary"
target="_blank"
href=${this.buildGitHubIssueUrl(
this.event.context
)}>
${t`Open issue on GitHub...`}
</a>
<div class="pf-l-flex">
<div class="pf-l-flex__item">
<h3>${t`Exception`}</h3>
<code>${this.event.context.message}</code>
</div>
</div>
<ak-expand>${this.defaultResponse()}</ak-expand>`;
case EventMatcherPolicyActionEnum.PropertyMappingException:
return html`<div class="pf-l-flex">
<div class="pf-l-flex__item">
@ -192,12 +256,12 @@ export class EventInfo extends LitElement {
return html`<div class="pf-l-flex">
<div class="pf-l-flex__item">
<h3>${t`Binding`}</h3>
${this.getModelInfo(this.event.context.binding as EventContext)}
${this.getModelInfo(this.event.context.binding as EventModel)}
</div>
<div class="pf-l-flex__item">
<h3>${t`Request`}</h3>
<ul class="pf-c-list">
<li>${t`Object`}: ${this.getModelInfo((this.event.context.request as EventContext).obj as EventContext)}</li>
<li>${t`Object`}: ${this.getModelInfo((this.event.context.request as EventContext).obj as EventModel)}</li>
<li><span>${t`Context`}: <code>${JSON.stringify((this.event.context.request as EventContext).context, null, 4)}</code></span></li>
</ul>
</div>
@ -211,12 +275,12 @@ export class EventInfo extends LitElement {
return html`<div class="pf-l-flex">
<div class="pf-l-flex__item">
<h3>${t`Binding`}</h3>
${this.getModelInfo(this.event.context.binding as EventContext)}
${this.getModelInfo(this.event.context.binding as EventModel)}
</div>
<div class="pf-l-flex__item">
<h3>${t`Request`}</h3>
<ul class="pf-c-list">
<li>${t`Object`}: ${this.getModelInfo((this.event.context.request as EventContext).obj as EventContext)}</li>
<li>${t`Object`}: ${this.getModelInfo((this.event.context.request as EventContext).obj as EventModel)}</li>
<li><span>${t`Context`}: <code>${JSON.stringify((this.event.context.request as EventContext).context, null, 4)}</code></span></li>
</ul>
</div>
@ -252,7 +316,7 @@ export class EventInfo extends LitElement {
return html`<div class="pf-l-flex">
<div class="pf-l-flex__item">
<h3>${t`Using source`}</h3>
${this.getModelInfo(this.event.context.using_source as EventContext)}
${this.getModelInfo(this.event.context.using_source as EventModel)}
</div>
</div>`;
}

View File

@ -44,6 +44,7 @@ export class EventListPage extends TablePage<Event> {
new TableColumn(t`User`, "user"),
new TableColumn(t`Creation Date`, "created"),
new TableColumn(t`Client IP`, "client_ip"),
new TableColumn(t`Tenant`, "tenant_name"),
new TableColumn(""),
];
}
@ -62,6 +63,7 @@ export class EventListPage extends TablePage<Event> {
html`-`,
html`<span>${item.created?.toLocaleString()}</span>`,
html`<span>${item.clientIp || "-"}</span>`,
html`<span>${item.tenant?.name || "-"}</span>`,
html`<a href="#/events/log/${item.pk}">
<i class="fas fas fa-share-square"></i>
</a>`,

View File

@ -103,7 +103,7 @@ export class FlowListPage extends TablePage<Flow> {
}}>
${t`Execute`}
</button>
<a class="pf-c-button pf-m-secondary" href=${flow.exportUrl}>
<a class="pf-c-button pf-m-secondary" href=${item.exportUrl}>
${t`Export`}
</a>`,
];

View File

@ -102,7 +102,11 @@ export class OutpostForm extends ModelForm<Outpost, string> {
ordering: "pk"
}).then(scs => {
return scs.results.map(sc => {
return html`<option value=${ifDefined(sc.pk)} ?selected=${this.instance?.serviceConnection === sc.pk}>
let selected = this.instance?.serviceConnection === sc.pk;
if (scs.results.length === 1 && !this.instance) {
selected = true;
}
return html`<option value=${ifDefined(sc.pk)} ?selected=${selected}>
${sc.name} (${sc.verboseName})
</option>`;
});
@ -127,13 +131,16 @@ export class OutpostForm extends ModelForm<Outpost, string> {
label=${t`Configuration`}
name="config">
<ak-codemirror mode="yaml" value="${until(new OutpostsApi(DEFAULT_CONFIG).outpostsInstancesDefaultSettingsRetrieve().then(config => {
let fc = config.config;
if (this.instance) {
fc = this.instance.config;
}
return YAML.stringify(fc);
}))}"></ak-codemirror>
let fc = config.config;
if (this.instance) {
fc = this.instance.config;
}
return YAML.stringify(fc);
}))}"></ak-codemirror>
<p class="pf-c-form__helper-text">${t`Set custom attributes using YAML or JSON.`}</p>
<p class="pf-c-form__helper-text">
See <a target="_blank" href="https://goauthentik.io/docs/outposts/outposts#configuration">documentation</a>.
</p>
</ak-form-element-horizontal>
</form>`;
}

View File

@ -186,7 +186,7 @@ export class OAuth2ProviderFormPage extends ModelForm<OAuth2Provider, number> {
<option value="" ?selected=${this.instance?.rsaKey === undefined}>---------</option>
${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
ordering: "pk",
hasKey: "true",
hasKey: true,
}).then(keys => {
return keys.results.map(key => {
let selected = this.instance?.rsaKey === key.pk;

View File

@ -218,7 +218,7 @@ export class ProxyProviderFormPage extends ModelForm<ProxyProvider, number> {
<option value="" ?selected=${this.instance?.certificate === undefined}>---------</option>
${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
ordering: "pk",
hasKey: "true",
hasKey: true,
}).then(keys => {
return keys.results.map(key => {
return html`<option value=${ifDefined(key.pk)} ?selected=${this.instance?.certificate === key.pk}>${key.name}</option>`;

View File

@ -115,7 +115,7 @@ export class SAMLProviderFormPage extends ModelForm<SAMLProvider, number> {
<option value="" ?selected=${this.instance?.signingKp === undefined}>---------</option>
${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({
ordering: "pk",
hasKey: "true",
hasKey: true,
}).then(keys => {
return keys.results.map(key => {
return html`<option value=${ifDefined(key.pk)} ?selected=${this.instance?.signingKp === key.pk}>${key.name}</option>`;

View File

@ -163,7 +163,7 @@ export class SAMLProviderViewPage extends LitElement {
<ak-action-button
class="pf-m-secondary"
.apiRequest=${() => {
const fullUrl = window.location.origin + this.provider.metadataDownloadUrl;
const fullUrl = window.location.origin + this.provider?.metadataDownloadUrl;
return navigator.clipboard.writeText(fullUrl);
}}>
${t`Copy download URL`}

View File

@ -15,7 +15,7 @@ export class ConsentStageForm extends ModelForm<ConsentStage, string> {
return new StagesApi(DEFAULT_CONFIG).stagesConsentRetrieve({
stageUuid: pk,
}).then(stage => {
this.showExpiresIn = stage.name === ConsentStageModeEnum.Expiring;
this.showExpiresIn = stage.mode === ConsentStageModeEnum.Expiring;
return stage;
});
}

View File

@ -72,6 +72,9 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
<option value=${UserFieldsEnum.Email} ?selected=${this.isUserFieldSelected(UserFieldsEnum.Email)}>
${t`Email`}
</option>
<option value=${UserFieldsEnum.Upn} ?selected=${this.isUserFieldSelected(UserFieldsEnum.Upn)}>
${t`UPN`}
</option>
</select>
<p class="pf-c-form__helper-text">${t`Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources.`}</p>
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>

View File

@ -38,19 +38,19 @@ export class UserSettingsPage extends LitElement {
renderStageSettings(stage: UserSetting): TemplateResult {
switch (stage.component) {
case "ak-user-settings-authenticator-webauthn":
return html`<ak-user-settings-authenticator-webauthn objectId=${stage.objectUid} configureUrl=${stage.configureUrl}>
return html`<ak-user-settings-authenticator-webauthn objectId=${stage.objectUid} .configureUrl=${stage.configureUrl}>
</ak-user-settings-authenticator-webauthn>`;
case "ak-user-settings-password":
return html`<ak-user-settings-password objectId=${stage.objectUid} configureUrl=${stage.configureUrl}>
return html`<ak-user-settings-password objectId=${stage.objectUid} .configureUrl=${stage.configureUrl}>
</ak-user-settings-password>`;
case "ak-user-settings-authenticator-totp":
return html`<ak-user-settings-authenticator-totp objectId=${stage.objectUid} configureUrl=${stage.configureUrl}>
return html`<ak-user-settings-authenticator-totp objectId=${stage.objectUid} .configureUrl=${stage.configureUrl}>
</ak-user-settings-authenticator-totp>`;
case "ak-user-settings-authenticator-static":
return html`<ak-user-settings-authenticator-static objectId=${stage.objectUid} configureUrl=${stage.configureUrl}>
return html`<ak-user-settings-authenticator-static objectId=${stage.objectUid} .configureUrl=${stage.configureUrl}>
</ak-user-settings-authenticator-static>`;
case "ak-user-settings-authenticator-duo":
return html`<ak-user-settings-authenticator-duo objectId=${stage.objectUid} configureUrl=${stage.configureUrl}>
return html`<ak-user-settings-authenticator-duo objectId=${stage.objectUid} .configureUrl=${stage.configureUrl}>
</ak-user-settings-authenticator-duo>`;
default:
return html`<p>${t`Error: unsupported stage settings: ${stage.component}`}</p>`;
@ -60,7 +60,7 @@ export class UserSettingsPage extends LitElement {
renderSourceSettings(source: UserSetting): TemplateResult {
switch (source.component) {
case "ak-user-settings-source-oauth":
return html`<ak-user-settings-source-oauth objectId=${source.objectUid} title=${source.title} configureUrl=${source.configureUrl}>
return html`<ak-user-settings-source-oauth objectId=${source.objectUid} title=${source.title} .configureUrl=${source.configureUrl}>
</ak-user-settings-source-oauth>`;
default:
return html`<p>${t`Error: unsupported source settings: ${source.component}`}</p>`;

View File

@ -30,20 +30,12 @@ export class UserActiveForm extends DeleteForm {
</h1>
</div>
</section>
<section class="pf-c-page__main-section">
<div class="pf-l-stack">
<div class="pf-l-stack__item">
<div class="pf-c-card">
<div class="pf-c-card__body">
<form class="pf-c-form pf-m-horizontal">
<p>
${t`Are you sure you want to update ${this.objectLabel} "${this.obj?.name}"?`}
</p>
</form>
</div>
</div>
</div>
</div>
<section class="pf-c-page__main-section pf-m-light">
<form class="pf-c-form pf-m-horizontal">
<p>
${t`Are you sure you want to update ${this.objectLabel} "${this.obj?.name}"?`}
</p>
</form>
</section>
<footer class="pf-c-modal-box__footer">
<ak-spinner-button

View File

@ -19,10 +19,6 @@ This will send a POST request to the given URL with the following contents:
The `Content-Type` header is set to `text/json`.
:::warning
This will send a request for each user of the group selected in the trigger.
:::
## Slack Webhook
This sends a request using the Slack-specific format. This is also compatible with Discord's webhooks by appending `/slack` to the Discord webhook URL.

View File

@ -5,3 +5,7 @@ title: WebAuthn authenticator setup stage
This stage configures a WebAuthn-based Authenticator. This can either be a browser, biometrics or a Security stick like a YubiKey.
There are no stage-specific settings.
:::warning
Currently, the WebAuthn stage does NOT support Apple FaceID and Android Fingerprint/SafetyNet.
:::

View File

@ -12,11 +12,11 @@ This installation method is for test-setups and small-scale productive setups.
## Preparation
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.6.1-rc2/docker-compose.yml). Place it in a directory of your choice.
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.6.1-rc6/docker-compose.yml). Place it in a directory of your choice.
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.6.1-rc2 >> .env`
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.6.1-rc6 >> .env`
If this is a fresh authentik install run the following commands to generate a password:

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