Compare commits

..

60 Commits

Author SHA1 Message Date
4d791f4fef release: 2022.12.3 2023-03-02 20:18:21 +01:00
c03a069f02 security: fix CVE-2023-26481 (#4832)
fix CVE-2023-26481

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2023-03-02 20:16:01 +01:00
040adb8ce7 website: always show build version in version dropdown
Signed-off-by: Jens Langhammer <jens@goauthentik.io>

#3940

# Conflicts:
#	website/docusaurus.config.js
2023-02-16 14:40:07 +01:00
ac07833688 release: 2022.12.2 2023-01-05 10:01:30 +01:00
be473470a4 web/admin: fix lint
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-04 22:40:18 +01:00
445cd5b2c4 web: fix radio label code in dark mode
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-04 22:40:15 +01:00
805a4b766a web/admin: migrate webauthn forms to radio
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-04 22:40:12 +01:00
730139e43c *: improve general tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-04 22:40:09 +01:00
24e8915e0a providers/proxy: add tests for proxy basic auth (#4357)
* add tests for proxy basic auth

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

* stop bandit from complaining

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

* add API tests

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

* more tests

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

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-04 22:40:06 +01:00
1e01e9813d providers/saml: add prefix to entity descriptor (#4355)
add prefix to entity descriptor

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

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-04 16:44:52 +01:00
119a268eb7 web: add custom scrollbar
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-04 11:53:01 +01:00
e887a315be providers/oauth2: correctly advertise supported response_modes_supported
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-04 10:21:34 +01:00
c4bb51469b website/docs: prepare 2022.12.2
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-04 10:15:15 +01:00
6edc043775 web: bump eslint-plugin-custom-elements from 0.0.6 to 0.0.7 in /web (#4349)
Bumps [eslint-plugin-custom-elements](https://github.com/github/eslint-plugin-custom-elements) from 0.0.6 to 0.0.7.
- [Release notes](https://github.com/github/eslint-plugin-custom-elements/releases)
- [Commits](https://github.com/github/eslint-plugin-custom-elements/compare/v0.0.6...v0.0.7)

---
updated-dependencies:
- dependency-name: eslint-plugin-custom-elements
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-04 09:54:58 +01:00
4379f5bc8e core: bump coverage from 7.0.2 to 7.0.3 (#4350)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.0.2 to 7.0.3.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.0.2...7.0.3)

---
updated-dependencies:
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-04 09:54:49 +01:00
1ad56f4a13 web: bump @squoosh/cli from 0.7.2 to 0.7.3 in /web (#4348)
Bumps [@squoosh/cli](https://github.com/GoogleChromeLabs/squoosh) from 0.7.2 to 0.7.3.
- [Release notes](https://github.com/GoogleChromeLabs/squoosh/releases)
- [Commits](https://github.com/GoogleChromeLabs/squoosh/commits)

---
updated-dependencies:
- dependency-name: "@squoosh/cli"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-04 09:54:17 +01:00
f54e82781a web/elements: fix dropdown menu closing before selecting item sometimes
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-03 10:11:23 +01:00
e334d8ab00 web: bump @typescript-eslint/eslint-plugin from 5.47.1 to 5.48.0 in /web (#4342)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.47.1 to 5.48.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.48.0/packages/eslint-plugin)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-03 09:56:52 +01:00
e1c0f74152 web: bump @typescript-eslint/parser from 5.47.1 to 5.48.0 in /web (#4341)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.47.1 to 5.48.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.48.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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-03 09:55:21 +01:00
e8f850285e core: bump coverage from 7.0.1 to 7.0.2 (#4343)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.0.1 to 7.0.2.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.0.1...7.0.2)

---
updated-dependencies:
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-03 09:54:32 +01:00
4b93f40c5e providers/oauth2: fix null amr value not being removed from id_token
closes #4339

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-03 00:41:18 +01:00
57400925a4 providers/saml: don't error if no request in API serializer context
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-03 00:14:16 +01:00
ffed653cae web/admin: migrate api calls to async (#4335)
migrate api calls to async

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

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-02 16:13:07 +01:00
ba5cd6e719 web/admin: add Radio control, search-select fixes (#4333)
* move search select to forms folder

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

* add radio, migrate smaller lists

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

* move dropdown when scrolling, hide when container out of frame

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

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-02 14:51:44 +01:00
9564894eda web/elements: trigger search select data update on connected callback
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-02 10:26:52 +01:00
042cd0b2cb core: bump django from 4.1.4 to 4.1.5 (#4332)
Bumps [django](https://github.com/django/django) from 4.1.4 to 4.1.5.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/4.1.4...4.1.5)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 09:52:54 +01:00
049a97a800 web: bump yaml from 2.2.0 to 2.2.1 in /web (#4325)
Bumps [yaml](https://github.com/eemeli/yaml) from 2.2.0 to 2.2.1.
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](https://github.com/eemeli/yaml/compare/v2.2.0...v2.2.1)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 09:29:28 +01:00
aa6668f8cb web: bump @types/codemirror from 5.60.5 to 5.60.6 in /web (#4327)
Bumps [@types/codemirror](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/codemirror) from 5.60.5 to 5.60.6.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/codemirror)

---
updated-dependencies:
- dependency-name: "@types/codemirror"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 09:29:21 +01:00
13a129bb01 web: bump eslint from 8.30.0 to 8.31.0 in /web (#4326)
Bumps [eslint](https://github.com/eslint/eslint) from 8.30.0 to 8.31.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.30.0...v8.31.0)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 09:29:11 +01:00
0974f58367 core: bump github.com/jellydator/ttlcache/v3 from 3.0.0 to 3.0.1 (#4328)
Bumps [github.com/jellydator/ttlcache/v3](https://github.com/jellydator/ttlcache) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/jellydator/ttlcache/releases)
- [Changelog](https://github.com/jellydator/ttlcache/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jellydator/ttlcache/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: github.com/jellydator/ttlcache/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 09:29:04 +01:00
1d59bfd16e core: bump goauthentik.io/api/v3 from 3.2022120.3 to 3.2022121.4 (#4329)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2022120.3 to 3.2022121.4.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2022120.3...v3.2022121.4)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 09:28:55 +01:00
ebd73ec34f core: bump watchdog from 2.2.0 to 2.2.1 (#4330)
Bumps [watchdog](https://github.com/gorakhargosh/watchdog) from 2.2.0 to 2.2.1.
- [Release notes](https://github.com/gorakhargosh/watchdog/releases)
- [Changelog](https://github.com/gorakhargosh/watchdog/blob/master/changelog.rst)
- [Commits](https://github.com/gorakhargosh/watchdog/compare/v2.2.0...v2.2.1)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 09:28:46 +01:00
0629dee23b core: bump importlib-metadata from 5.2.0 to 6.0.0 (#4331)
Bumps [importlib-metadata](https://github.com/python/importlib_metadata) from 5.2.0 to 6.0.0.
- [Release notes](https://github.com/python/importlib_metadata/releases)
- [Changelog](https://github.com/python/importlib_metadata/blob/main/CHANGES.rst)
- [Commits](https://github.com/python/importlib_metadata/compare/v5.2.0...v6.0.0)

---
updated-dependencies:
- dependency-name: importlib-metadata
  dependency-type: direct:development
  update-type: version-update:semver-major
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 09:28:36 +01:00
2dc0792d9e stages/email: remove unused import
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-02 09:28:26 +01:00
fde848ee51 admin: remove unused import
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-02 00:12:14 +01:00
e9d52282b7 admin: use matching environment for system API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:58:12 +01:00
c810628fe3 stages/email: use pending user correctly
closes #4318

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:50:57 +01:00
de0a5191f7 core: remove unused import
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:50:42 +01:00
f6794829e4 web: bump API Client version (#4324)
Signed-off-by: GitHub <noreply@github.com>

Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2023-01-01 23:45:59 +01:00
475853fb14 web: update tsconfig strictness
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:44:15 +01:00
1c1319927e web: ensure locales are built for tsc check
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:36:14 +01:00
964fdf171b web: add check compile test to prevent compile errors/warnings
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:32:05 +01:00
93e20bce2e core: don't use inline_serializer for user operations
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:16:44 +01:00
960a2aab74 crypto: fix type for has_key
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:14:19 +01:00
2cae6596eb core: cleanup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:01:08 +01:00
11b1eb4173 stages/email: make template tests less flaky
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 23:00:32 +01:00
ee615c2d22 web: bump API Client version (#4323)
Signed-off-by: GitHub <noreply@github.com>

Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2023-01-01 22:57:12 +01:00
aef9a22331 web/admin: fix error in outpost form dropdown
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 22:27:23 +01:00
3980eea7c6 web/flows: rework error display, always use ak-stage-flow-error instead of shell
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 21:43:44 +01:00
d6d72489a7 web/flows: add close button to flow inspector
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 21:26:21 +01:00
9fdfb8c99b stages/dummy: add toggle to throw error for debugging
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 21:25:53 +01:00
b9bb27008e web/elements: fix selection of blank elements in search-select, fix issue when re-opening dropdown
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 20:10:16 +01:00
82184b2882 web/flows: fix alternate captchas not loading
closes #4321

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 18:49:41 +01:00
f90a52c7d6 web: bump API Client version (#4322)
Signed-off-by: GitHub <noreply@github.com>

Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2023-01-01 18:24:54 +01:00
9ea0441559 web/elements: correctly display selected empty option when blankable is enabled
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 18:19:32 +01:00
5cab280759 stages/captcha: fix captcha not loading correctly, add tests
closes #4320

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2023-01-01 18:15:41 +01:00
a03a64b35c web/admin: fix error when creating SAML Provider from metadata
closes #4315

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-12-31 12:54:42 +01:00
780b986be8 web/elements: only find pages for directly related slots
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-12-30 22:35:57 +01:00
9d422918b3 stages/prompt: use stage.get_pending_user() to fallback to the correct user
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-12-30 20:38:15 +01:00
b548ccca6e web: bump API Client version (#4312)
Signed-off-by: GitHub <noreply@github.com>

Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: BeryJu <BeryJu@users.noreply.github.com>
2022-12-30 14:33:07 +01:00
136 changed files with 2115 additions and 1353 deletions

View File

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

View File

@ -27,6 +27,22 @@ jobs:
- name: Eslint
working-directory: web/
run: npm run lint
lint-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3.5.1
with:
node-version: '16'
cache: 'npm'
cache-dependency-path: web/package-lock.json
- working-directory: web/
run: npm ci
- name: Generate API
run: make gen-client-ts
- name: TSC
working-directory: web/
run: npm run tsc
lint-prettier:
runs-on: ubuntu-latest
steps:
@ -69,6 +85,7 @@ jobs:
- lint-eslint
- lint-prettier
- lint-lit-analyse
- lint-build
runs-on: ubuntu-latest
steps:
- run: echo mark

View File

@ -126,7 +126,7 @@ gen: gen-build gen-clean gen-client-ts
web-build: web-install
cd web && npm run build
web: web-lint-fix web-lint
web: web-lint-fix web-lint web-check-compile
web-install:
cd web && npm ci
@ -144,6 +144,9 @@ web-lint:
cd web && npm run lint
cd web && npm run lit-analyse
web-check-compile:
cd web && npm run tsc
web-extract:
cd web && npm run extract

View File

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

View File

@ -8,7 +8,6 @@ from typing import TypedDict
from django.utils.timezone import now
from drf_spectacular.utils import extend_schema
from gunicorn import version_info as gunicorn_version
from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME
from rest_framework.fields import SerializerMethodField
from rest_framework.permissions import IsAdminUser
from rest_framework.request import Request
@ -16,6 +15,7 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from authentik.core.api.utils import PassiveSerializer
from authentik.lib.utils.reflection import get_env
from authentik.outposts.apps import MANAGED_OUTPOST
from authentik.outposts.models import Outpost
@ -69,7 +69,7 @@ class SystemSerializer(PassiveSerializer):
return {
"python_version": python_version,
"gunicorn_version": ".".join(str(x) for x in gunicorn_version),
"environment": "kubernetes" if SERVICE_HOST_ENV_NAME in os.environ else "compose",
"environment": get_env(),
"architecture": platform.machine(),
"platform": platform.platform(),
"uname": " ".join(platform.uname()),

View File

@ -68,7 +68,7 @@ class ConfigView(APIView):
caps.append(Capabilities.CAN_GEO_IP)
if CONFIG.y_bool("impersonation"):
caps.append(Capabilities.CAN_IMPERSONATE)
if settings.DEBUG:
if settings.DEBUG: # pragma: no cover
caps.append(Capabilities.CAN_DEBUG)
return caps

View File

@ -16,7 +16,7 @@ def serializer_tester_factory(test_model: Type[SerializerModel]) -> Callable:
"""Test serializer"""
def tester(self: TestModels):
if test_model._meta.abstract:
if test_model._meta.abstract: # pragma: no cover
return
model_class = test_model()
self.assertTrue(isinstance(model_class, SerializerModel))

View File

@ -26,8 +26,8 @@ class TestBlueprintOCI(TransactionTestCase):
self.assertEqual(
BlueprintInstance(
path="https://ghcr.io/goauthentik/blueprints/test:latest"
).retrieve_oci(),
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
).retrieve(),
"foo",
)
@ -40,7 +40,7 @@ class TestBlueprintOCI(TransactionTestCase):
with self.assertRaises(BlueprintRetrievalFailed):
BlueprintInstance(
path="https://ghcr.io/goauthentik/blueprints/test:latest"
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
).retrieve_oci()
def test_manifests_error_response(self):
@ -53,7 +53,7 @@ class TestBlueprintOCI(TransactionTestCase):
with self.assertRaises(BlueprintRetrievalFailed):
BlueprintInstance(
path="https://ghcr.io/goauthentik/blueprints/test:latest"
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
).retrieve_oci()
def test_no_matching_blob(self):
@ -72,7 +72,7 @@ class TestBlueprintOCI(TransactionTestCase):
)
with self.assertRaises(BlueprintRetrievalFailed):
BlueprintInstance(
path="https://ghcr.io/goauthentik/blueprints/test:latest"
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
).retrieve_oci()
def test_blob_error(self):
@ -93,5 +93,5 @@ class TestBlueprintOCI(TransactionTestCase):
with self.assertRaises(BlueprintRetrievalFailed):
BlueprintInstance(
path="https://ghcr.io/goauthentik/blueprints/test:latest"
path="oci://ghcr.io/goauthentik/blueprints/test:latest"
).retrieve_oci()

View File

@ -5,7 +5,7 @@ from django.db.models.query import QuerySet
from django.http import Http404
from django_filters.filters import CharFilter, ModelMultipleChoiceFilter
from django_filters.filterset import FilterSet
from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer
from drf_spectacular.utils import OpenApiResponse, extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action
from rest_framework.fields import CharField, IntegerField, JSONField
@ -17,7 +17,7 @@ from rest_framework_guardian.filters import ObjectPermissionsFilter
from authentik.api.decorators import permission_required
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import is_dict
from authentik.core.api.utils import PassiveSerializer, is_dict
from authentik.core.models import Group, User
@ -120,6 +120,12 @@ class GroupFilter(FilterSet):
fields = ["name", "is_superuser", "members_by_pk", "attributes", "members_by_username"]
class UserAccountSerializer(PassiveSerializer):
"""Account adding/removing operations"""
pk = IntegerField(required=True)
class GroupViewSet(UsedByMixin, ModelViewSet):
"""Group Viewset"""
@ -144,12 +150,7 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
@permission_required(None, ["authentik_core.add_user"])
@extend_schema(
request=inline_serializer(
"UserAccountSerializer",
{
"pk": IntegerField(required=True),
},
),
request=UserAccountSerializer,
responses={
204: OpenApiResponse(description="User added"),
404: OpenApiResponse(description="User not found"),
@ -174,12 +175,7 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
@permission_required(None, ["authentik_core.add_user"])
@extend_schema(
request=inline_serializer(
"UserAccountSerializer",
{
"pk": IntegerField(required=True),
},
),
request=UserAccountSerializer,
responses={
204: OpenApiResponse(description="User added"),
404: OpenApiResponse(description="User not found"),

View File

@ -1,5 +1,4 @@
"""Property Mapping Evaluator"""
from traceback import format_tb
from typing import Optional
from django.db.models import Model
@ -8,6 +7,7 @@ from django.http import HttpRequest
from authentik.core.models import User
from authentik.events.models import Event, EventAction
from authentik.lib.expression.evaluator import BaseEvaluator
from authentik.lib.utils.errors import exception_to_string
from authentik.policies.types import PolicyRequest
@ -38,7 +38,7 @@ class PropertyMappingEvaluator(BaseEvaluator):
def handle_error(self, exc: Exception, expression_source: str):
"""Exception Handler"""
error_string = "\n".join(format_tb(exc.__traceback__) + [str(exc)])
error_string = exception_to_string(exc)
event = Event.new(
EventAction.PROPERTY_MAPPING_EXCEPTION,
expression=expression_source,

View File

@ -35,7 +35,7 @@ def source_tester_factory(test_model: type[Stage]) -> Callable:
def tester(self: TestModels):
model_class = None
if test_model._meta.abstract:
if test_model._meta.abstract: # pragma: no cover
model_class = test_model.__bases__[0]()
else:
model_class = test_model()

View File

@ -209,6 +209,13 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
@extend_schema(
parameters=[
# Override the type for `has_key` above
OpenApiParameter(
"has_key",
bool,
required=False,
description="Only return certificate-key pairs with keys",
),
OpenApiParameter("include_details", bool, default=True),
]
)

View File

@ -39,6 +39,11 @@ def on_user_logged_in(sender, request: HttpRequest, user: User, **_):
request.session[SESSION_LOGIN_EVENT] = event
def get_login_event(request: HttpRequest) -> Optional[Event]:
"""Wrapper to get login event that can be mocked in tests"""
return request.session.get(SESSION_LOGIN_EVENT, None)
@receiver(user_logged_out)
# pylint: disable=unused-argument
def on_user_logged_out(sender, request: HttpRequest, user: User, **_):

View File

@ -1,7 +1,6 @@
"""Challenge helpers"""
from dataclasses import asdict, is_dataclass
from enum import Enum
from traceback import format_tb
from typing import TYPE_CHECKING, Optional, TypedDict
from uuid import UUID
@ -9,8 +8,10 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.db import models
from django.http import JsonResponse
from rest_framework.fields import CharField, ChoiceField, DictField
from rest_framework.request import Request
from authentik.core.api.utils import PassiveSerializer
from authentik.lib.utils.errors import exception_to_string
if TYPE_CHECKING:
from authentik.flows.stage import StageView
@ -90,32 +91,31 @@ class WithUserInfoChallenge(Challenge):
pending_user_avatar = CharField()
class FlowErrorChallenge(WithUserInfoChallenge):
class FlowErrorChallenge(Challenge):
"""Challenge class when an unhandled error occurs during a stage. Normal users
are shown an error message, superusers are shown a full stacktrace."""
component = CharField(default="xak-flow-error")
type = CharField(default=ChallengeTypes.NATIVE.value)
component = CharField(default="ak-stage-flow-error")
request_id = CharField()
error = CharField(required=False)
traceback = CharField(required=False)
def __init__(self, *args, **kwargs):
request = kwargs.pop("request", None)
error = kwargs.pop("error", None)
super().__init__(*args, **kwargs)
def __init__(self, request: Optional[Request] = None, error: Optional[Exception] = None):
super().__init__(data={})
if not request or not error:
return
self.request_id = request.request_id
self.initial_data["request_id"] = request.request_id
from authentik.core.models import USER_ATTRIBUTE_DEBUG
if request.user and request.user.is_authenticated:
if request.user.is_superuser or request.user.group_attributes(request).get(
USER_ATTRIBUTE_DEBUG, False
):
self.error = error
self.traceback = "".join(format_tb(self.error.__traceback__))
self.initial_data["error"] = str(error)
self.initial_data["traceback"] = exception_to_string(error)
class AccessDeniedChallenge(WithUserInfoChallenge):

View File

@ -162,7 +162,7 @@ class FlowExecutorView(APIView):
token.delete()
if not isinstance(plan, FlowPlan):
return None
plan.context[PLAN_CONTEXT_IS_RESTORED] = True
plan.context[PLAN_CONTEXT_IS_RESTORED] = token
self._logger.debug("f(exec): restored flow plan from token", plan=plan)
return plan
@ -255,7 +255,7 @@ class FlowExecutorView(APIView):
message=exception_to_string(exc),
).from_http(self.request)
challenge = FlowErrorChallenge(self.request, exc)
challenge.is_valid()
challenge.is_valid(raise_exception=True)
return to_stage_response(self.request, HttpChallengeResponse(challenge))
@extend_schema(

View File

@ -19,7 +19,7 @@ def model_tester_factory(test_model: type[Stage]) -> Callable:
def tester(self: TestModels):
try:
model_class = None
if test_model._meta.abstract:
if test_model._meta.abstract: # pragma: no cover
return
model_class = test_model()
self.assertTrue(issubclass(model_class.serializer, BaseSerializer))

View File

@ -48,14 +48,14 @@ def get_apps():
def get_env() -> str:
"""Get environment in which authentik is currently running"""
if SERVICE_HOST_ENV_NAME in os.environ:
return "kubernetes"
if "CI" in os.environ:
return "ci"
if Path("/tmp/authentik-mode").exists(): # nosec
return "compose"
if CONFIG.y_bool("debug"):
return "dev"
if SERVICE_HOST_ENV_NAME in os.environ:
return "kubernetes"
if Path("/tmp/authentik-mode").exists(): # nosec
return "compose"
if "AK_APPLIANCE" in os.environ:
return os.environ["AK_APPLIANCE"]
return "custom"

View File

@ -22,8 +22,7 @@ from rest_framework.serializers import Serializer
from authentik.core.models import ExpiringModel, PropertyMapping, Provider, User
from authentik.crypto.models import CertificateKeyPair
from authentik.events.models import Event
from authentik.events.signals import SESSION_LOGIN_EVENT
from authentik.events.signals import get_login_event
from authentik.lib.generators import generate_code_fixed_length, generate_id, generate_key
from authentik.lib.models import SerializerModel
from authentik.lib.utils.time import timedelta_string_validator
@ -419,6 +418,8 @@ class IDToken:
id_dict.pop("nonce")
if not self.c_hash:
id_dict.pop("c_hash")
if not self.amr:
id_dict.pop("amr")
id_dict.pop("claims")
id_dict.update(self.claims)
return id_dict
@ -503,8 +504,8 @@ class RefreshToken(SerializerModel, ExpiringModel, BaseGrantModel):
# We use the timestamp of the user's last successful login (EventAction.LOGIN) for auth_time
# Fallback in case we can't find any login events
auth_time = now
if SESSION_LOGIN_EVENT in request.session:
auth_event: Event = request.session[SESSION_LOGIN_EVENT]
auth_event = get_login_event(request)
if auth_event:
auth_time = auth_event.created
# Also check which method was used for authentication
method = auth_event.context.get(PLAN_CONTEXT_METHOD, "")
@ -526,6 +527,7 @@ class RefreshToken(SerializerModel, ExpiringModel, BaseGrantModel):
exp=exp_time,
iat=iat_time,
auth_time=auth_timestamp,
amr=amr if amr else None,
)
# Include (or not) user standard claims in the id_token.

View File

@ -1,10 +1,13 @@
"""Test authorize view"""
from unittest.mock import MagicMock, patch
from django.test import RequestFactory
from django.urls import reverse
from django.utils.timezone import now
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.events.models import Event, EventAction
from authentik.flows.challenge import ChallengeTypes
from authentik.lib.generators import generate_id, generate_key
from authentik.lib.utils.time import timedelta_from_string
@ -17,6 +20,7 @@ from authentik.providers.oauth2.models import (
)
from authentik.providers.oauth2.tests.utils import OAuthTestCase
from authentik.providers.oauth2.views.authorize import OAuthAuthorizationParams
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD
class TestAuthorize(OAuthTestCase):
@ -302,40 +306,51 @@ class TestAuthorize(OAuthTestCase):
state = generate_id()
user = create_test_admin_user()
self.client.force_login(user)
# Step 1, initiate params and get redirect to flow
self.client.get(
reverse("authentik_providers_oauth2:authorize"),
data={
"response_type": "id_token",
"client_id": "test",
"state": state,
"scope": "openid",
"redirect_uri": "http://localhost",
},
)
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
token: RefreshToken = RefreshToken.objects.filter(user=user).first()
expires = timedelta_from_string(provider.access_code_validity).total_seconds()
self.assertJSONEqual(
response.content.decode(),
{
"component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": (
f"http://localhost#access_token={token.access_token}"
f"&id_token={provider.encode(token.id_token.to_dict())}&token_type=bearer"
f"&expires_in={int(expires)}&state={state}"
),
},
)
jwt = self.validate_jwt(token, provider)
self.assertAlmostEqual(
jwt["exp"] - now().timestamp(),
expires,
delta=5,
)
with patch(
"authentik.providers.oauth2.models.get_login_event",
MagicMock(
return_value=Event(
action=EventAction.LOGIN,
context={PLAN_CONTEXT_METHOD: "password"},
created=now(),
)
),
):
# Step 1, initiate params and get redirect to flow
self.client.get(
reverse("authentik_providers_oauth2:authorize"),
data={
"response_type": "id_token",
"client_id": "test",
"state": state,
"scope": "openid",
"redirect_uri": "http://localhost",
},
)
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
)
token: RefreshToken = RefreshToken.objects.filter(user=user).first()
expires = timedelta_from_string(provider.access_code_validity).total_seconds()
self.assertJSONEqual(
response.content.decode(),
{
"component": "xak-flow-redirect",
"type": ChallengeTypes.REDIRECT.value,
"to": (
f"http://localhost#access_token={token.access_token}"
f"&id_token={provider.encode(token.id_token.to_dict())}&token_type=bearer"
f"&expires_in={int(expires)}&state={state}"
),
},
)
jwt = self.validate_jwt(token, provider)
self.assertEqual(jwt["amr"], ["pwd"])
self.assertAlmostEqual(
jwt["exp"] - now().timestamp(),
expires,
delta=5,
)
def test_full_form_post_id_token(self):
"""Test full authorization (form_post response)"""

View File

@ -27,6 +27,11 @@ class OAuthTestCase(TestCase):
cls.keypair = create_test_cert()
super().setUpClass()
def assert_non_none_or_unset(self, container: dict, key: str):
"""Check that a key, if set, is not none"""
if key in container:
self.assertIsNotNone(container[key])
def validate_jwt(self, token: RefreshToken, provider: OAuth2Provider) -> dict[str, Any]:
"""Validate that all required fields are set"""
key, alg = provider.jwt_key
@ -39,6 +44,10 @@ class OAuthTestCase(TestCase):
audience=provider.client_id,
)
id_token = token.id_token.to_dict()
self.assert_non_none_or_unset(id_token, "at_hash")
self.assert_non_none_or_unset(id_token, "nonce")
self.assert_non_none_or_unset(id_token, "c_hash")
self.assert_non_none_or_unset(id_token, "amr")
for key in self.required_jwt_keys:
self.assertIsNotNone(jwt[key], f"Key {key} is missing in access_token")
self.assertIsNotNone(id_token[key], f"Key {key} is missing in id_token")

View File

@ -17,7 +17,12 @@ from authentik.providers.oauth2.constants import (
GRANT_TYPE_REFRESH_TOKEN,
SCOPE_OPENID,
)
from authentik.providers.oauth2.models import OAuth2Provider, ResponseTypes, ScopeMapping
from authentik.providers.oauth2.models import (
OAuth2Provider,
ResponseMode,
ResponseTypes,
ScopeMapping,
)
from authentik.providers.oauth2.utils import cors_allow
LOGGER = get_logger()
@ -73,6 +78,11 @@ class ProviderInfoView(View):
ResponseTypes.CODE_ID_TOKEN,
ResponseTypes.CODE_ID_TOKEN_TOKEN,
],
"response_modes_supported": [
ResponseMode.QUERY,
ResponseMode.FRAGMENT,
ResponseMode.FORM_POST,
],
"jwks_uri": self.request.build_absolute_uri(
reverse(
"authentik_providers_oauth2:jwks",

View File

@ -1,6 +1,7 @@
"""ProxyProvider API Views"""
from typing import Any, Optional
from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema_field
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, ListField, ReadOnlyField, SerializerMethodField
@ -39,22 +40,34 @@ class ProxyProviderSerializer(ProviderSerializer):
redirect_uris = CharField(read_only=True)
outpost_set = ListField(child=CharField(), read_only=True, source="outpost_set.all")
def validate_basic_auth_enabled(self, value: bool) -> bool:
"""Ensure user and password attributes are set"""
if value:
if (
self.initial_data.get("basic_auth_password_attribute", "") == ""
or self.initial_data.get("basic_auth_user_attribute", "") == ""
):
raise ValidationError(
_("User and password attributes must be set when basic auth is enabled.")
)
return value
def validate(self, attrs) -> dict[Any, str]:
"""Check that internal_host is set when mode is Proxy"""
if (
attrs.get("mode", ProxyMode.PROXY) == ProxyMode.PROXY
and attrs.get("internal_host", "") == ""
):
raise ValidationError("Internal host cannot be empty when forward auth is disabled.")
raise ValidationError(_("Internal host cannot be empty when forward auth is disabled."))
return attrs
def create(self, validated_data):
def create(self, validated_data: dict):
instance: ProxyProvider = super().create(validated_data)
instance.set_oauth_defaults()
instance.save()
return instance
def update(self, instance: ProxyProvider, validated_data):
def update(self, instance: ProxyProvider, validated_data: dict):
instance = super().update(instance, validated_data)
instance.set_oauth_defaults()
instance.save()

View File

@ -0,0 +1,122 @@
"""proxy provider tests"""
from django.urls import reverse
from rest_framework.test import APITestCase
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.lib.generators import generate_id
from authentik.providers.oauth2.models import ClientTypes
from authentik.providers.proxy.models import ProxyMode, ProxyProvider
class ProxyProviderTests(APITestCase):
"""proxy provider tests"""
def setUp(self) -> None:
self.user = create_test_admin_user()
self.client.force_login(self.user)
def test_basic_auth(self):
"""Test basic_auth_enabled"""
response = self.client.post(
reverse("authentik_api:proxyprovider-list"),
{
"name": generate_id(),
"mode": ProxyMode.PROXY,
"authorization_flow": create_test_flow().pk.hex,
"external_host": "http://localhost",
"internal_host": "http://localhost",
"basic_auth_enabled": True,
"basic_auth_user_attribute": generate_id(),
"basic_auth_password_attribute": generate_id(),
},
)
self.assertEqual(response.status_code, 201)
def test_basic_auth_invalid(self):
"""Test basic_auth_enabled"""
response = self.client.post(
reverse("authentik_api:proxyprovider-list"),
{
"name": generate_id(),
"mode": ProxyMode.PROXY,
"authorization_flow": create_test_flow().pk.hex,
"external_host": "http://localhost",
"internal_host": "http://localhost",
"basic_auth_enabled": True,
},
)
self.assertEqual(response.status_code, 400)
self.assertJSONEqual(
response.content.decode(),
{
"basic_auth_enabled": [
"User and password attributes must be set when basic auth is enabled."
]
},
)
def test_validate(self):
"""Test validate"""
response = self.client.post(
reverse("authentik_api:proxyprovider-list"),
{
"name": generate_id(),
"mode": ProxyMode.PROXY,
"authorization_flow": create_test_flow().pk.hex,
"external_host": "http://localhost",
},
)
self.assertEqual(response.status_code, 400)
self.assertJSONEqual(
response.content.decode(),
{"non_field_errors": ["Internal host cannot be empty when forward auth is disabled."]},
)
def test_create_defaults(self):
"""Test create"""
name = generate_id()
response = self.client.post(
reverse("authentik_api:proxyprovider-list"),
{
"name": name,
"mode": ProxyMode.PROXY,
"authorization_flow": create_test_flow().pk.hex,
"external_host": "http://localhost",
"internal_host": "http://localhost",
},
)
self.assertEqual(response.status_code, 201)
provider: ProxyProvider = ProxyProvider.objects.get(name=name)
self.assertEqual(provider.client_type, ClientTypes.CONFIDENTIAL)
def test_update_defaults(self):
"""Test create"""
name = generate_id()
response = self.client.post(
reverse("authentik_api:proxyprovider-list"),
{
"name": name,
"mode": ProxyMode.PROXY,
"authorization_flow": create_test_flow().pk.hex,
"external_host": "http://localhost",
"internal_host": "http://localhost",
},
)
self.assertEqual(response.status_code, 201)
provider: ProxyProvider = ProxyProvider.objects.get(name=name)
self.assertEqual(provider.client_type, ClientTypes.CONFIDENTIAL)
provider.client_type = ClientTypes.PUBLIC
provider.save()
response = self.client.put(
reverse("authentik_api:proxyprovider-detail", kwargs={"pk": provider.pk}),
{
"name": name,
"mode": ProxyMode.PROXY,
"authorization_flow": create_test_flow().pk.hex,
"external_host": "http://localhost",
"internal_host": "http://localhost",
},
)
self.assertEqual(response.status_code, 200)
provider: ProxyProvider = ProxyProvider.objects.get(name=name)
self.assertEqual(provider.client_type, ClientTypes.CONFIDENTIAL)

View File

@ -47,6 +47,8 @@ class SAMLProviderSerializer(ProviderSerializer):
def get_url_download_metadata(self, instance: SAMLProvider) -> str:
"""Get metadata download URL"""
if "request" not in self._context:
return ""
request: HttpRequest = self._context["request"]._request
return request.build_absolute_uri(
reverse("authentik_api:samlprovider-metadata", kwargs={"pk": instance.pk}) + "?download"
@ -54,6 +56,8 @@ class SAMLProviderSerializer(ProviderSerializer):
def get_url_sso_post(self, instance: SAMLProvider) -> str:
"""Get SSO Post URL"""
if "request" not in self._context:
return ""
request: HttpRequest = self._context["request"]._request
try:
return request.build_absolute_uri(
@ -67,6 +71,8 @@ class SAMLProviderSerializer(ProviderSerializer):
def get_url_sso_redirect(self, instance: SAMLProvider) -> str:
"""Get SSO Redirect URL"""
if "request" not in self._context:
return ""
request: HttpRequest = self._context["request"]._request
try:
return request.build_absolute_uri(
@ -80,6 +86,8 @@ class SAMLProviderSerializer(ProviderSerializer):
def get_url_sso_init(self, instance: SAMLProvider) -> str:
"""Get SSO IDP-Initiated URL"""
if "request" not in self._context:
return ""
request: HttpRequest = self._context["request"]._request
try:
return request.build_absolute_uri(

View File

@ -10,7 +10,7 @@ from structlog.stdlib import get_logger
from authentik.core.exceptions import PropertyMappingExpressionException
from authentik.events.models import Event, EventAction
from authentik.events.signals import SESSION_LOGIN_EVENT
from authentik.events.signals import get_login_event
from authentik.lib.utils.time import timedelta_from_string
from authentik.providers.saml.models import SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.request_parser import AuthNRequest
@ -132,8 +132,8 @@ class AssertionProcessor:
auth_n_context, f"{{{NS_SAML_ASSERTION}}}AuthnContextClassRef"
)
auth_n_context_class_ref.text = "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"
if SESSION_LOGIN_EVENT in self.http_request.session:
event: Event = self.http_request.session[SESSION_LOGIN_EVENT]
event = get_login_event(self.http_request)
if event:
method = event.context.get(PLAN_CONTEXT_METHOD, "")
method_args = event.context.get(PLAN_CONTEXT_METHOD_ARGS, {})
if method == "password":

View File

@ -13,6 +13,7 @@ from authentik.sources.saml.processors.constants import (
DIGEST_ALGORITHM_TRANSLATION_MAP,
NS_MAP,
NS_SAML_METADATA,
NS_SAML_PROTOCOL,
NS_SIGNATURE,
SAML_BINDING_POST,
SAML_BINDING_REDIRECT,
@ -35,7 +36,7 @@ class MetadataProcessor:
self.provider = provider
self.http_request = request
self.force_binding = None
self.xml_id = sha256(f"{provider.name}-{provider.pk}".encode("ascii")).hexdigest()
self.xml_id = "_" + sha256(f"{provider.name}-{provider.pk}".encode("ascii")).hexdigest()
def get_signing_key_descriptor(self) -> Optional[Element]:
"""Get Signing KeyDescriptor, if enabled for the provider"""
@ -143,9 +144,7 @@ class MetadataProcessor:
idp_sso_descriptor = SubElement(
entity_descriptor, f"{{{NS_SAML_METADATA}}}IDPSSODescriptor"
)
idp_sso_descriptor.attrib[
"protocolSupportEnumeration"
] = "urn:oasis:names:tc:SAML:2.0:protocol"
idp_sso_descriptor.attrib["protocolSupportEnumeration"] = NS_SAML_PROTOCOL
signing_descriptor = self.get_signing_key_descriptor()
if signing_descriptor is not None:

View File

@ -20,7 +20,7 @@ class CaptchaChallenge(WithUserInfoChallenge):
"""Site public key"""
site_key = CharField()
js_url = CharField(read_only=True)
js_url = CharField()
component = CharField(default="ak-stage-captcha")

View File

@ -22,7 +22,7 @@ class TestCaptchaStage(FlowTestCase):
self.user = create_test_admin_user()
self.flow = create_test_flow(FlowDesignation.AUTHENTICATION)
self.stage = CaptchaStage.objects.create(
self.stage: CaptchaStage = CaptchaStage.objects.create(
name="captcha",
public_key=RECAPTCHA_PUBLIC_KEY,
private_key=RECAPTCHA_PRIVATE_KEY,
@ -41,3 +41,22 @@ class TestCaptchaStage(FlowTestCase):
)
self.assertEqual(response.status_code, 200)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
def test_urls(self):
"""Test URLs captcha"""
self.stage.js_url = "https://test.goauthentik.io/test.js"
self.stage.api_url = "https://test.goauthentik.io/test"
self.stage.save()
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
js_url="https://test.goauthentik.io/test.js",
)

View File

@ -12,7 +12,7 @@ class DummyStageSerializer(StageSerializer):
class Meta:
model = DummyStage
fields = StageSerializer.Meta.fields
fields = StageSerializer.Meta.fields + ["throw_error"]
class DummyStageViewSet(UsedByMixin, ModelViewSet):

View File

@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2023-01-01 19:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_stages_dummy", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="dummystage",
name="throw_error",
field=models.BooleanField(default=False),
),
]

View File

@ -1,5 +1,5 @@
"""dummy stage models"""
from django.db import models
from django.utils.translation import gettext as _
from django.views import View
from rest_framework.serializers import BaseSerializer
@ -10,6 +10,8 @@ from authentik.flows.models import Stage
class DummyStage(Stage):
"""Used for debugging."""
throw_error = models.BooleanField(default=False)
__debug_only__ = True
@property

View File

@ -4,6 +4,7 @@ from rest_framework.fields import CharField
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
from authentik.flows.stage import ChallengeStageView
from authentik.lib.sentry import SentryIgnoredException
class DummyChallenge(Challenge):
@ -27,6 +28,8 @@ class DummyStageView(ChallengeStageView):
return self.executor.stage_ok()
def get_challenge(self, *args, **kwargs) -> Challenge:
if self.executor.current_stage.throw_error:
raise SentryIgnoredException("Test error")
return DummyChallenge(
data={
"type": ChallengeTypes.NATIVE.value,

View File

@ -11,12 +11,11 @@ from django.utils.translation import gettext as _
from rest_framework.fields import CharField
from rest_framework.serializers import ValidationError
from authentik.core.models import User
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
from authentik.flows.models import FlowToken
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
from authentik.flows.stage import ChallengeStageView
from authentik.flows.views.executor import QS_KEY_TOKEN, SESSION_KEY_GET
from authentik.flows.views.executor import QS_KEY_TOKEN
from authentik.stages.email.models import EmailStage
from authentik.stages.email.tasks import send_mails
from authentik.stages.email.utils import TemplateEmailMessage
@ -57,7 +56,7 @@ class EmailStageView(ChallengeStageView):
def get_token(self) -> FlowToken:
"""Get token"""
pending_user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
pending_user = self.get_pending_user()
current_stage: EmailStage = self.executor.current_stage
valid_delta = timedelta(
minutes=current_stage.token_expiry + 1
@ -82,7 +81,7 @@ class EmailStageView(ChallengeStageView):
def send_email(self):
"""Helper function that sends the actual email. Implies that you've
already checked that there is a pending user."""
pending_user: User = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
pending_user = self.get_pending_user()
email = self.executor.plan.context.get(PLAN_CONTEXT_EMAIL_OVERRIDE, None)
if not email:
email = pending_user.email
@ -104,13 +103,16 @@ class EmailStageView(ChallengeStageView):
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
# Check if the user came back from the email link to verify
if QS_KEY_TOKEN in request.session.get(
SESSION_KEY_GET, {}
) and self.executor.plan.context.get(PLAN_CONTEXT_IS_RESTORED, False):
restore_token: FlowToken = self.executor.plan.context.get(PLAN_CONTEXT_IS_RESTORED, None)
user = self.get_pending_user()
if restore_token:
if restore_token.user != user:
self.logger.warning("Flow token for non-matching user, denying request")
return self.executor.stage_invalid()
messages.success(request, _("Successfully verified Email."))
if self.executor.current_stage.activate_user_on_success:
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER].is_active = True
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER].save()
user.is_active = True
user.save()
return self.executor.stage_ok()
if PLAN_CONTEXT_PENDING_USER not in self.executor.plan.context:
self.logger.debug("No pending user")

View File

@ -7,10 +7,9 @@ from django.core.mail.backends.smtp import EmailBackend as SMTPEmailBackend
from django.urls import reverse
from django.utils.http import urlencode
from authentik.core.models import Token
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.markers import StageMarker
from authentik.flows.models import FlowDesignation, FlowStageBinding
from authentik.flows.models import FlowDesignation, FlowStageBinding, FlowToken
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
from authentik.flows.tests import FlowTestCase
from authentik.flows.views.executor import SESSION_KEY_PLAN
@ -136,7 +135,7 @@ class TestEmailStage(FlowTestCase):
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
token: Token = Token.objects.get(user=self.user)
token: FlowToken = FlowToken.objects.get(user=self.user)
with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()):
# Call the executor shell to preseed the session
@ -167,3 +166,43 @@ class TestEmailStage(FlowTestCase):
plan: FlowPlan = session[SESSION_KEY_PLAN]
self.assertEqual(plan.context[PLAN_CONTEXT_PENDING_USER], self.user)
self.assertTrue(plan.context[PLAN_CONTEXT_PENDING_USER].is_active)
def test_token_invalid_user(self):
"""Test with token with invalid user"""
# Make sure token exists
self.test_pending_user()
self.user.is_active = False
self.user.save()
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
# Set flow token user to a different user
token: FlowToken = FlowToken.objects.get(user=self.user)
token.user = create_test_admin_user()
token.save()
with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()):
# Call the executor shell to preseed the session
url = reverse(
"authentik_api:flow-executor",
kwargs={"flow_slug": self.flow.slug},
)
url_query = urlencode(
{
QS_KEY_TOKEN: token.key,
}
)
url += f"?query={url_query}"
self.client.get(url)
# Call the actual executor to get the JSON Response
response = self.client.get(
reverse(
"authentik_api:flow-executor",
kwargs={"flow_slug": self.flow.slug},
)
)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(response, component="ak-stage-access-denied")

View File

@ -1,7 +1,8 @@
"""email tests"""
from os import chmod, unlink
from pathlib import Path
from tempfile import gettempdir, mkstemp
from shutil import rmtree
from tempfile import mkdtemp, mkstemp
from typing import Any
from django.conf import settings
@ -20,11 +21,17 @@ def get_templates_setting(temp_dir: str) -> dict[str, Any]:
class TestEmailStageTemplates(TestCase):
"""Email tests"""
def setUp(self) -> None:
self.dir = mkdtemp()
def tearDown(self) -> None:
rmtree(self.dir)
def test_custom_template(self):
"""Test with custom template"""
with self.settings(TEMPLATES=get_templates_setting(gettempdir())):
_, file = mkstemp(suffix=".html")
_, file2 = mkstemp(suffix=".html")
with self.settings(TEMPLATES=get_templates_setting(self.dir)):
_, file = mkstemp(suffix=".html", dir=self.dir)
_, file2 = mkstemp(suffix=".html", dir=self.dir)
chmod(file2, 0o000) # Remove all permissions so we can't read the file
choices = get_template_choices()
self.assertEqual(choices[-1][0], Path(file).name)

View File

@ -7,14 +7,13 @@ from django.db.models.query import QuerySet
from django.http import HttpRequest, HttpResponse
from django.http.request import QueryDict
from django.utils.translation import gettext_lazy as _
from guardian.shortcuts import get_anonymous_user
from rest_framework.fields import BooleanField, CharField, ChoiceField, IntegerField, empty
from rest_framework.serializers import ValidationError
from authentik.core.api.utils import PassiveSerializer
from authentik.core.models import User
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
from authentik.flows.planner import FlowPlan
from authentik.flows.stage import ChallengeStageView
from authentik.policies.engine import PolicyEngine
from authentik.policies.models import PolicyBinding, PolicyBindingModel, PolicyEngineMode
@ -47,21 +46,23 @@ class PromptChallengeResponse(ChallengeResponse):
"""Validate response, fields are dynamically created based
on the stage"""
stage_instance: PromptStage
component = CharField(default="ak-stage-prompt")
def __init__(self, *args, **kwargs):
stage: PromptStage = kwargs.pop("stage", None)
stage: PromptStage = kwargs.pop("stage_instance", None)
plan: FlowPlan = kwargs.pop("plan", None)
request: HttpRequest = kwargs.pop("request", None)
user: User = kwargs.pop("user", None)
super().__init__(*args, **kwargs)
self.stage = stage
self.stage_instance = stage
self.plan = plan
self.request = request
if not self.stage:
if not self.stage_instance:
return
# list() is called so we only load the fields once
fields = list(self.stage.fields.all())
fields = list(self.stage_instance.fields.all())
for field in fields:
field: Prompt
current = field.get_placeholder(
@ -97,7 +98,7 @@ class PromptChallengeResponse(ChallengeResponse):
def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
# Check if we have any static or hidden fields, and ensure they
# still have the same value
static_hidden_fields: QuerySet[Prompt] = self.stage.fields.filter(
static_hidden_fields: QuerySet[Prompt] = self.stage_instance.fields.filter(
type__in=[FieldTypes.HIDDEN, FieldTypes.STATIC, FieldTypes.TEXT_READ_ONLY]
)
for static_hidden in static_hidden_fields:
@ -109,12 +110,17 @@ class PromptChallengeResponse(ChallengeResponse):
attrs[static_hidden.field_key] = default
# Check if we have two password fields, and make sure they are the same
password_fields: QuerySet[Prompt] = self.stage.fields.filter(type=FieldTypes.PASSWORD)
password_fields: QuerySet[Prompt] = self.stage_instance.fields.filter(
type=FieldTypes.PASSWORD
)
if password_fields.exists() and password_fields.count() == 2:
self._validate_password_fields(*[field.field_key for field in password_fields])
user = self.plan.context.get(PLAN_CONTEXT_PENDING_USER, get_anonymous_user())
engine = ListPolicyEngine(self.stage.validation_policies.all(), user, self.request)
engine = ListPolicyEngine(
self.stage_instance.validation_policies.all(),
self.stage.get_pending_user(),
self.request,
)
engine.mode = PolicyEngineMode.MODE_ALL
engine.request.context[PLAN_CONTEXT_PROMPT] = attrs
engine.use_cache = False
@ -194,7 +200,8 @@ class PromptStageView(ChallengeStageView):
instance=None,
data=data,
request=self.request,
stage=self.executor.current_stage,
stage_instance=self.executor.current_stage,
stage=self,
plan=self.executor.plan,
user=self.get_pending_user(),
)

View File

@ -10,11 +10,15 @@ from authentik.flows.markers import StageMarker
from authentik.flows.models import FlowStageBinding
from authentik.flows.planner import FlowPlan
from authentik.flows.tests import FlowTestCase
from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.flows.views.executor import SESSION_KEY_PLAN, FlowExecutorView
from authentik.lib.generators import generate_id
from authentik.policies.expression.models import ExpressionPolicy
from authentik.stages.prompt.models import FieldTypes, InlineFileField, Prompt, PromptStage
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT, PromptChallengeResponse
from authentik.stages.prompt.stage import (
PLAN_CONTEXT_PROMPT,
PromptChallengeResponse,
PromptStageView,
)
class TestPromptStage(FlowTestCase):
@ -106,6 +110,11 @@ class TestPromptStage(FlowTestCase):
self.binding = FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)
self.request = RequestFactory().get("/")
self.request.user = create_test_admin_user()
self.flow_executor = FlowExecutorView(request=self.request)
self.stage_view = PromptStageView(self.flow_executor, request=self.request)
def test_inline_file_field(self):
"""test InlineFileField"""
with self.assertRaises(ValidationError):
@ -148,7 +157,11 @@ class TestPromptStage(FlowTestCase):
self.stage.validation_policies.set([expr_policy])
self.stage.save()
challenge_response = PromptChallengeResponse(
None, stage=self.stage, plan=plan, data=self.prompt_data
None,
stage_instance=self.stage,
plan=plan,
data=self.prompt_data,
stage=self.stage_view,
)
self.assertEqual(challenge_response.is_valid(), True)
@ -160,7 +173,7 @@ class TestPromptStage(FlowTestCase):
self.stage.validation_policies.set([expr_policy])
self.stage.save()
challenge_response = PromptChallengeResponse(
None, stage=self.stage, plan=plan, data=self.prompt_data
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
)
self.assertEqual(challenge_response.is_valid(), False)
@ -180,7 +193,7 @@ class TestPromptStage(FlowTestCase):
self.stage.validation_policies.set([expr_policy])
self.stage.save()
challenge_response = PromptChallengeResponse(
None, stage=self.stage, plan=plan, data=self.prompt_data
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
)
self.assertEqual(challenge_response.is_valid(), True)
@ -208,7 +221,7 @@ class TestPromptStage(FlowTestCase):
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
self.prompt_data["password2_prompt"] = "qwerqwerqr"
challenge_response = PromptChallengeResponse(
None, stage=self.stage, plan=plan, data=self.prompt_data
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
)
self.assertEqual(challenge_response.is_valid(), False)
self.assertEqual(
@ -222,7 +235,7 @@ class TestPromptStage(FlowTestCase):
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
self.prompt_data["username_prompt"] = user.username
challenge_response = PromptChallengeResponse(
None, stage=self.stage, plan=plan, data=self.prompt_data
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
)
self.assertEqual(challenge_response.is_valid(), False)
self.assertEqual(
@ -237,7 +250,7 @@ class TestPromptStage(FlowTestCase):
self.prompt_data["hidden_prompt"] = "foo"
self.prompt_data["static_prompt"] = "foo"
challenge_response = PromptChallengeResponse(
None, stage=self.stage, plan=plan, data=self.prompt_data
None, stage_instance=self.stage, plan=plan, data=self.prompt_data, stage=self.stage_view
)
self.assertEqual(challenge_response.is_valid(), True)
self.assertNotEqual(challenge_response.validated_data["hidden_prompt"], "foo")

View File

@ -73,6 +73,9 @@ class TestUserWriteStage(FlowTestCase):
"username": "test-user-new",
"password": new_password,
"attributes.some.custom-attribute": "test",
"attributes": {
"foo": "bar",
},
"some_ignored_attribute": "bar",
}
session = self.client.session
@ -89,6 +92,7 @@ class TestUserWriteStage(FlowTestCase):
self.assertTrue(user_qs.exists())
self.assertTrue(user_qs.first().check_password(new_password))
self.assertEqual(user_qs.first().attributes["some"]["custom-attribute"], "test")
self.assertEqual(user_qs.first().attributes["foo"], "bar")
self.assertNotIn("some_ignored_attribute", user_qs.first().attributes)
@patch(

View File

@ -154,6 +154,7 @@ entries:
policy: !KeyOf default-recovery-skip-if-restored
target: !KeyOf flow-binding-email
order: 0
state: absent
model: authentik_policies.policybinding
attrs:
negate: false

View File

@ -32,7 +32,7 @@ services:
volumes:
- redis:/data
server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.12.1}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.12.3}
restart: unless-stopped
command: server
environment:
@ -50,7 +50,7 @@ services:
- "0.0.0.0:${AUTHENTIK_PORT_HTTP:-9000}:9000"
- "0.0.0.0:${AUTHENTIK_PORT_HTTPS:-9443}:9443"
worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.12.1}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2022.12.3}
restart: unless-stopped
command: worker
environment:

4
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/gorilla/securecookie v1.1.1
github.com/gorilla/sessions v1.2.1
github.com/gorilla/websocket v1.5.0
github.com/jellydator/ttlcache/v3 v3.0.0
github.com/jellydator/ttlcache/v3 v3.0.1
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba
github.com/pires/go-proxyproto v0.6.2
@ -25,7 +25,7 @@ require (
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.8.1
goauthentik.io/api/v3 v3.2022120.3
goauthentik.io/api/v3 v3.2022121.4
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b

8
go.sum
View File

@ -232,8 +232,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jellydator/ttlcache/v3 v3.0.0 h1:zmFhqrB/4sKiEiJHhtseJsNRE32IMVmJSs4++4gaQO4=
github.com/jellydator/ttlcache/v3 v3.0.0/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4=
github.com/jellydator/ttlcache/v3 v3.0.1 h1:cHgCSMS7TdQcoprXnWUptJZzyFsqs18Lt8VVhRuZYVU=
github.com/jellydator/ttlcache/v3 v3.0.1/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
@ -382,8 +382,8 @@ go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZp
go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ=
go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk=
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
goauthentik.io/api/v3 v3.2022120.3 h1:1HnMlz9IQViazSIdGB7WuFVSCyoHNlwj9V/Yg9LPtSU=
goauthentik.io/api/v3 v3.2022120.3/go.mod h1:QM9J32HgYE4gL71lWAfAoXSPdSmLVLW08itfLI3Mo10=
goauthentik.io/api/v3 v3.2022121.4 h1:WCwbjXB6Q2VkASkgNc2SFaW36tEBhvOR2tIzmSnheYk=
goauthentik.io/api/v3 v3.2022121.4/go.mod h1:QM9J32HgYE4gL71lWAfAoXSPdSmLVLW08itfLI3Mo10=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=

View File

@ -29,4 +29,4 @@ func UserAgent() string {
return fmt.Sprintf("authentik@%s", FullVersion())
}
const VERSION = "2022.12.1"
const VERSION = "2022.12.3"

174
poetry.lock generated
View File

@ -454,7 +454,7 @@ python-versions = "*"
[[package]]
name = "coverage"
version = "7.0.1"
version = "7.0.3"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
@ -552,7 +552,7 @@ graph = ["objgraph (>=1.7.2)"]
[[package]]
name = "django"
version = "4.1.4"
version = "4.1.5"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
category = "main"
optional = false
@ -906,7 +906,7 @@ python-versions = ">=3.5"
[[package]]
name = "importlib-metadata"
version = "5.2.0"
version = "6.0.0"
description = "Read metadata from Python packages"
category = "dev"
optional = false
@ -1979,7 +1979,7 @@ python-versions = ">=3.6"
[[package]]
name = "watchdog"
version = "2.2.0"
version = "2.2.1"
description = "Filesystem events monitoring"
category = "main"
optional = false
@ -2461,57 +2461,57 @@ constantly = [
{file = "constantly-15.1.0.tar.gz", hash = "sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"},
]
coverage = [
{file = "coverage-7.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b3695c4f4750bca943b3e1f74ad4be8d29e4aeab927d50772c41359107bd5d5c"},
{file = "coverage-7.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa6a5a224b7f4cfb226f4fc55a57e8537fcc096f42219128c2c74c0e7d0953e1"},
{file = "coverage-7.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74f70cd92669394eaf8d7756d1b195c8032cf7bbbdfce3bc489d4e15b3b8cf73"},
{file = "coverage-7.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b66bb21a23680dee0be66557dc6b02a3152ddb55edf9f6723fa4a93368f7158d"},
{file = "coverage-7.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d87717959d4d0ee9db08a0f1d80d21eb585aafe30f9b0a54ecf779a69cb015f6"},
{file = "coverage-7.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:854f22fa361d1ff914c7efa347398374cc7d567bdafa48ac3aa22334650dfba2"},
{file = "coverage-7.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1e414dc32ee5c3f36544ea466b6f52f28a7af788653744b8570d0bf12ff34bc0"},
{file = "coverage-7.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6c5ad996c6fa4d8ed669cfa1e8551348729d008a2caf81489ab9ea67cfbc7498"},
{file = "coverage-7.0.1-cp310-cp310-win32.whl", hash = "sha256:691571f31ace1837838b7e421d3a09a8c00b4aac32efacb4fc9bd0a5c647d25a"},
{file = "coverage-7.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:89caf4425fe88889e2973a8e9a3f6f5f9bbe5dd411d7d521e86428c08a873a4a"},
{file = "coverage-7.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:63d56165a7c76265468d7e0c5548215a5ba515fc2cba5232d17df97bffa10f6c"},
{file = "coverage-7.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f943a3b2bc520102dd3e0bb465e1286e12c9a54f58accd71b9e65324d9c7c01"},
{file = "coverage-7.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:830525361249dc4cd013652b0efad645a385707a5ae49350c894b67d23fbb07c"},
{file = "coverage-7.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd1b9c5adc066db699ccf7fa839189a649afcdd9e02cb5dc9d24e67e7922737d"},
{file = "coverage-7.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00c14720b8b3b6c23b487e70bd406abafc976ddc50490f645166f111c419c39"},
{file = "coverage-7.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6d55d840e1b8c0002fce66443e124e8581f30f9ead2e54fbf6709fb593181f2c"},
{file = "coverage-7.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:66b18c3cf8bbab0cce0d7b9e4262dc830e93588986865a8c78ab2ae324b3ed56"},
{file = "coverage-7.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:12a5aa77783d49e05439fbe6e6b427484f8a0f9f456b46a51d8aac022cfd024d"},
{file = "coverage-7.0.1-cp311-cp311-win32.whl", hash = "sha256:b77015d1cb8fe941be1222a5a8b4e3fbca88180cfa7e2d4a4e58aeabadef0ab7"},
{file = "coverage-7.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb992c47cb1e5bd6a01e97182400bcc2ba2077080a17fcd7be23aaa6e572e390"},
{file = "coverage-7.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e78e9dcbf4f3853d3ae18a8f9272111242531535ec9e1009fa8ec4a2b74557dc"},
{file = "coverage-7.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60bef2e2416f15fdc05772bf87db06c6a6f9870d1db08fdd019fbec98ae24a9"},
{file = "coverage-7.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9823e4789ab70f3ec88724bba1a203f2856331986cd893dedbe3e23a6cfc1e4e"},
{file = "coverage-7.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9158f8fb06747ac17bd237930c4372336edc85b6e13bdc778e60f9d685c3ca37"},
{file = "coverage-7.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:486ee81fa694b4b796fc5617e376326a088f7b9729c74d9defa211813f3861e4"},
{file = "coverage-7.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1285648428a6101b5f41a18991c84f1c3959cee359e51b8375c5882fc364a13f"},
{file = "coverage-7.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2c44fcfb3781b41409d0f060a4ed748537557de9362a8a9282182fafb7a76ab4"},
{file = "coverage-7.0.1-cp37-cp37m-win32.whl", hash = "sha256:d6814854c02cbcd9c873c0f3286a02e3ac1250625cca822ca6bc1018c5b19f1c"},
{file = "coverage-7.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f66460f17c9319ea4f91c165d46840314f0a7c004720b20be58594d162a441d8"},
{file = "coverage-7.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b373c9345c584bb4b5f5b8840df7f4ab48c4cbb7934b58d52c57020d911b856"},
{file = "coverage-7.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d3022c3007d3267a880b5adcf18c2a9bf1fc64469b394a804886b401959b8742"},
{file = "coverage-7.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92651580bd46519067e36493acb394ea0607b55b45bd81dd4e26379ed1871f55"},
{file = "coverage-7.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cfc595d2af13856505631be072835c59f1acf30028d1c860b435c5fc9c15b69"},
{file = "coverage-7.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b4b3a4d9915b2be879aff6299c0a6129f3d08a775d5a061f503cf79571f73e4"},
{file = "coverage-7.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b6f22bb64cc39bcb883e5910f99a27b200fdc14cdd79df8696fa96b0005c9444"},
{file = "coverage-7.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72d1507f152abacea81f65fee38e4ef3ac3c02ff8bc16f21d935fd3a8a4ad910"},
{file = "coverage-7.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0a79137fc99815fff6a852c233628e735ec15903cfd16da0f229d9c4d45926ab"},
{file = "coverage-7.0.1-cp38-cp38-win32.whl", hash = "sha256:b3763e7fcade2ff6c8e62340af9277f54336920489ceb6a8cd6cc96da52fcc62"},
{file = "coverage-7.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:09f6b5a8415b6b3e136d5fec62b552972187265cb705097bf030eb9d4ffb9b60"},
{file = "coverage-7.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:978258fec36c154b5e250d356c59af7d4c3ba02bef4b99cda90b6029441d797d"},
{file = "coverage-7.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:19ec666533f0f70a0993f88b8273057b96c07b9d26457b41863ccd021a043b9a"},
{file = "coverage-7.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfded268092a84605f1cc19e5c737f9ce630a8900a3589e9289622db161967e9"},
{file = "coverage-7.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07bcfb1d8ac94af886b54e18a88b393f6a73d5959bb31e46644a02453c36e475"},
{file = "coverage-7.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b4a923cc7566bbc7ae2dfd0ba5a039b61d19c740f1373791f2ebd11caea59"},
{file = "coverage-7.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aec2d1515d9d39ff270059fd3afbb3b44e6ec5758af73caf18991807138c7118"},
{file = "coverage-7.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c20cfebcc149a4c212f6491a5f9ff56f41829cd4f607b5be71bb2d530ef243b1"},
{file = "coverage-7.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fd556ff16a57a070ce4f31c635953cc44e25244f91a0378c6e9bdfd40fdb249f"},
{file = "coverage-7.0.1-cp39-cp39-win32.whl", hash = "sha256:b9ea158775c7c2d3e54530a92da79496fb3fb577c876eec761c23e028f1e216c"},
{file = "coverage-7.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:d1991f1dd95eba69d2cd7708ff6c2bbd2426160ffc73c2b81f617a053ebcb1a8"},
{file = "coverage-7.0.1-pp37.pp38.pp39-none-any.whl", hash = "sha256:3dd4ee135e08037f458425b8842d24a95a0961831a33f89685ff86b77d378f89"},
{file = "coverage-7.0.1.tar.gz", hash = "sha256:a4a574a19eeb67575a5328a5760bbbb737faa685616586a9f9da4281f940109c"},
{file = "coverage-7.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f7c51b6074a8a3063c341953dffe48fd6674f8e4b1d3c8aa8a91f58d6e716a8"},
{file = "coverage-7.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:628f47eaf66727fc986d3b190d6fa32f5e6b7754a243919d28bc0fd7974c449f"},
{file = "coverage-7.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89d5abf86c104de808108a25d171ad646c07eda96ca76c8b237b94b9c71e518"},
{file = "coverage-7.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75e43c6f4ea4d122dac389aabdf9d4f0e160770a75e63372f88005d90f5bcc80"},
{file = "coverage-7.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49da0ff241827ebb52d5d6d5a36d33b455fa5e721d44689c95df99fd8db82437"},
{file = "coverage-7.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0bce4ad5bdd0b02e177a085d28d2cea5fc57bb4ba2cead395e763e34cf934eb1"},
{file = "coverage-7.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f79691335257d60951638dd43576b9bcd6f52baa5c1c2cd07a509bb003238372"},
{file = "coverage-7.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5722269ed05fbdb94eef431787c66b66260ff3125d1a9afcc00facff8c45adf9"},
{file = "coverage-7.0.3-cp310-cp310-win32.whl", hash = "sha256:bdbda870e0fda7dd0fe7db7135ca226ec4c1ade8aa76e96614829b56ca491012"},
{file = "coverage-7.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:e56fae4292e216b8deeee38ace84557b9fa85b52db005368a275427cdabb8192"},
{file = "coverage-7.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b82343a5bc51627b9d606f0b6b6b9551db7b6311a5dd920fa52a94beae2e8959"},
{file = "coverage-7.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fd0a8aa431f9b7ad9eb8264f55ef83cbb254962af3775092fb6e93890dea9ca2"},
{file = "coverage-7.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:112cfead1bd22eada8a8db9ed387bd3e8be5528debc42b5d3c1f7da4ffaf9fb5"},
{file = "coverage-7.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af87e906355fa42447be5c08c5d44e6e1c005bf142f303f726ddf5ed6e0c8a4d"},
{file = "coverage-7.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f30090e22a301952c5abd0e493a1c8358b4f0b368b49fa3e4568ed3ed68b8d1f"},
{file = "coverage-7.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ae871d09901911eedda1981ea6fd0f62a999107293cdc4c4fd612321c5b34745"},
{file = "coverage-7.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ed7c9debf7bfc63c9b9f8b595409237774ff4b061bf29fba6f53b287a2fdeab9"},
{file = "coverage-7.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:13121fa22dcd2c7b19c5161e3fd725692448f05377b788da4502a383573227b3"},
{file = "coverage-7.0.3-cp311-cp311-win32.whl", hash = "sha256:037b51ee86bc600f99b3b957c20a172431c35c2ef9c1ca34bc813ab5b51fd9f5"},
{file = "coverage-7.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:25fde928306034e8deecd5fc91a07432dcc282c8acb76749581a28963c9f4f3f"},
{file = "coverage-7.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7e8b0642c38b3d3b3c01417643ccc645345b03c32a2e84ef93cdd6844d6fe530"},
{file = "coverage-7.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18b09811f849cc958d23f733a350a66b54a8de3fed1e6128ba55a5c97ffb6f65"},
{file = "coverage-7.0.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:349d0b545520e8516f7b4f12373afc705d17d901e1de6a37a20e4ec9332b61f7"},
{file = "coverage-7.0.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b38813eee5b4739f505d94247604c72eae626d5088a16dd77b08b8b1724ab3"},
{file = "coverage-7.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ba9af1218fa01b1f11c72271bc7290b701d11ad4dbc2ae97c445ecacf6858dba"},
{file = "coverage-7.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c5648c7eec5cf1ba5db1cf2d6c10036a582d7f09e172990474a122e30c841361"},
{file = "coverage-7.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d0df04495b76a885bfef009f45eebe8fe2fbf815ad7a83dabcf5aced62f33162"},
{file = "coverage-7.0.3-cp37-cp37m-win32.whl", hash = "sha256:af6cef3796b8068713a48dd67d258dc9a6e2ebc3bd4645bfac03a09672fa5d20"},
{file = "coverage-7.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:62ef3800c4058844e2e3fa35faa9dd0ccde8a8aba6c763aae50342e00d4479d4"},
{file = "coverage-7.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:acef7f3a3825a2d218a03dd02f5f3cc7f27aa31d882dd780191d1ad101120d74"},
{file = "coverage-7.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a530663a361eb27375cec28aea5cd282089b5e4b022ae451c4c3493b026a68a5"},
{file = "coverage-7.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c58cd6bb46dcb922e0d5792850aab5964433d511b3a020867650f8d930dde4f4"},
{file = "coverage-7.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f918e9ef4c98f477a5458238dde2a1643aed956c7213873ab6b6b82e32b8ef61"},
{file = "coverage-7.0.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b865aa679bee7fbd1c55960940dbd3252621dd81468268786c67122bbd15343"},
{file = "coverage-7.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c5d9b480ebae60fc2cbc8d6865194136bc690538fa542ba58726433bed6e04cc"},
{file = "coverage-7.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:985ad2af5ec3dbb4fd75d5b0735752c527ad183455520055a08cf8d6794cabfc"},
{file = "coverage-7.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ca15308ef722f120967af7474ba6a453e0f5b6f331251e20b8145497cf1bc14a"},
{file = "coverage-7.0.3-cp38-cp38-win32.whl", hash = "sha256:c1cee10662c25c94415bbb987f2ec0e6ba9e8fce786334b10be7e6a7ab958f69"},
{file = "coverage-7.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:44d6a556de4418f1f3bfd57094b8c49f0408df5a433cf0d253eeb3075261c762"},
{file = "coverage-7.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e6dcc70a25cb95df0ae33dfc701de9b09c37f7dd9f00394d684a5b57257f8246"},
{file = "coverage-7.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf76d79dfaea802f0f28f50153ffbc1a74ae1ee73e480baeda410b4f3e7ab25f"},
{file = "coverage-7.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88834e5d56d01c141c29deedacba5773fe0bed900b1edc957595a8a6c0da1c3c"},
{file = "coverage-7.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef001a60e888f8741e42e5aa79ae55c91be73761e4df5e806efca1ddd62fd400"},
{file = "coverage-7.0.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4959dc506be74e4963bd2c42f7b87d8e4b289891201e19ec551e64c6aa5441f8"},
{file = "coverage-7.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b791beb17b32ac019a78cfbe6184f992b6273fdca31145b928ad2099435e2fcb"},
{file = "coverage-7.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b07651e3b9af8f1a092861d88b4c74d913634a7f1f2280fca0ad041ad84e9e96"},
{file = "coverage-7.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:55e46fa4168ccb7497c9be78627fcb147e06f474f846a10d55feeb5108a24ef0"},
{file = "coverage-7.0.3-cp39-cp39-win32.whl", hash = "sha256:e3f1cd1cd65695b1540b3cf7828d05b3515974a9d7c7530f762ac40f58a18161"},
{file = "coverage-7.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:d8249666c23683f74f8f93aeaa8794ac87cc61c40ff70374a825f3352a4371dc"},
{file = "coverage-7.0.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:b1ffc8f58b81baed3f8962e28c30d99442079b82ce1ec836a1f67c0accad91c1"},
{file = "coverage-7.0.3.tar.gz", hash = "sha256:d5be4e93acce64f516bf4fd239c0e6118fc913c93fa1a3f52d15bdcc60d97b2d"},
]
cryptography = [
{file = "cryptography-38.0.3-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:984fe150f350a3c91e84de405fe49e688aa6092b3525f407a18b9646f6612320"},
@ -2566,8 +2566,8 @@ dill = [
{file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"},
]
django = [
{file = "Django-4.1.4-py3-none-any.whl", hash = "sha256:0b223bfa55511f950ff741983d408d78d772351284c75e9f77d2b830b6b4d148"},
{file = "Django-4.1.4.tar.gz", hash = "sha256:d38a4e108d2386cb9637da66a82dc8d0733caede4c83c4afdbda78af4214211b"},
{file = "Django-4.1.5-py3-none-any.whl", hash = "sha256:4b214a05fe4c99476e99e2445c8b978c8369c18d4dea8e22ec412862715ad763"},
{file = "Django-4.1.5.tar.gz", hash = "sha256:ff56ebd7ead0fd5dbe06fe157b0024a7aaea2e0593bb3785fb594cf94dad58ef"},
]
django-filter = [
{file = "django-filter-22.1.tar.gz", hash = "sha256:ed473b76e84f7e83b2511bb2050c3efb36d135207d0128dfe3ae4b36e3594ba5"},
@ -2792,8 +2792,8 @@ idna = [
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
]
importlib-metadata = [
{file = "importlib_metadata-5.2.0-py3-none-any.whl", hash = "sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f"},
{file = "importlib_metadata-5.2.0.tar.gz", hash = "sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd"},
{file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"},
{file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"},
]
incremental = [
{file = "incremental-22.10.0-py2.py3-none-any.whl", hash = "sha256:b864a1f30885ee72c5ac2835a761b8fe8aa9c28b9395cacf27286602688d3e51"},
@ -3628,34 +3628,34 @@ vine = [
{file = "vine-5.0.0.tar.gz", hash = "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"},
]
watchdog = [
{file = "watchdog-2.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed91c3ccfc23398e7aa9715abf679d5c163394b8cad994f34f156d57a7c163dc"},
{file = "watchdog-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:76a2743402b794629a955d96ea2e240bd0e903aa26e02e93cd2d57b33900962b"},
{file = "watchdog-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:920a4bda7daa47545c3201a3292e99300ba81ca26b7569575bd086c865889090"},
{file = "watchdog-2.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ceaa9268d81205876bedb1069f9feab3eccddd4b90d9a45d06a0df592a04cae9"},
{file = "watchdog-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1893d425ef4fb4f129ee8ef72226836619c2950dd0559bba022b0818c63a7b60"},
{file = "watchdog-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e99c1713e4436d2563f5828c8910e5ff25abd6ce999e75f15c15d81d41980b6"},
{file = "watchdog-2.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a5bd9e8656d07cae89ac464ee4bcb6f1b9cecbedc3bf1334683bed3d5afd39ba"},
{file = "watchdog-2.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a048865c828389cb06c0bebf8a883cec3ae58ad3e366bcc38c61d8455a3138f"},
{file = "watchdog-2.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e722755d995035dd32177a9c633d158f2ec604f2a358b545bba5bed53ab25bca"},
{file = "watchdog-2.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af4b5c7ba60206759a1d99811b5938ca666ea9562a1052b410637bb96ff97512"},
{file = "watchdog-2.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:619d63fa5be69f89ff3a93e165e602c08ed8da402ca42b99cd59a8ec115673e1"},
{file = "watchdog-2.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f2b0665c57358ce9786f06f5475bc083fea9d81ecc0efa4733fd0c320940a37"},
{file = "watchdog-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:441024df19253bb108d3a8a5de7a186003d68564084576fecf7333a441271ef7"},
{file = "watchdog-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a410dd4d0adcc86b4c71d1317ba2ea2c92babaf5b83321e4bde2514525544d5"},
{file = "watchdog-2.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28704c71afdb79c3f215c90231e41c52b056ea880b6be6cee035c6149d658ed1"},
{file = "watchdog-2.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2ac0bd7c206bb6df78ef9e8ad27cc1346f2b41b1fef610395607319cdab89bc1"},
{file = "watchdog-2.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:27e49268735b3c27310883012ab3bd86ea0a96dcab90fe3feb682472e30c90f3"},
{file = "watchdog-2.2.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:2af1a29fd14fc0a87fb6ed762d3e1ae5694dcde22372eebba50e9e5be47af03c"},
{file = "watchdog-2.2.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:c7bd98813d34bfa9b464cf8122e7d4bec0a5a427399094d2c17dd5f70d59bc61"},
{file = "watchdog-2.2.0-py3-none-manylinux2014_i686.whl", hash = "sha256:56fb3f40fc3deecf6e518303c7533f5e2a722e377b12507f6de891583f1b48aa"},
{file = "watchdog-2.2.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:74535e955359d79d126885e642d3683616e6d9ab3aae0e7dcccd043bd5a3ff4f"},
{file = "watchdog-2.2.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cf05e6ff677b9655c6e9511d02e9cc55e730c4e430b7a54af9c28912294605a4"},
{file = "watchdog-2.2.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:d6ae890798a3560688b441ef086bb66e87af6b400a92749a18b856a134fc0318"},
{file = "watchdog-2.2.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e5aed2a700a18c194c39c266900d41f3db0c1ebe6b8a0834b9995c835d2ca66e"},
{file = "watchdog-2.2.0-py3-none-win32.whl", hash = "sha256:d0fb5f2b513556c2abb578c1066f5f467d729f2eb689bc2db0739daf81c6bb7e"},
{file = "watchdog-2.2.0-py3-none-win_amd64.whl", hash = "sha256:1f8eca9d294a4f194ce9df0d97d19b5598f310950d3ac3dd6e8d25ae456d4c8a"},
{file = "watchdog-2.2.0-py3-none-win_ia64.whl", hash = "sha256:ad0150536469fa4b693531e497ffe220d5b6cd76ad2eda474a5e641ee204bbb6"},
{file = "watchdog-2.2.0.tar.gz", hash = "sha256:83cf8bc60d9c613b66a4c018051873d6273d9e45d040eed06d6a96241bd8ec01"},
{file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a09483249d25cbdb4c268e020cb861c51baab2d1affd9a6affc68ffe6a231260"},
{file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5100eae58133355d3ca6c1083a33b81355c4f452afa474c2633bd2fbbba398b3"},
{file = "watchdog-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e618a4863726bc7a3c64f95c218437f3349fb9d909eb9ea3a1ed3b567417c661"},
{file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:102a60093090fc3ff76c983367b19849b7cc24ec414a43c0333680106e62aae1"},
{file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:748ca797ff59962e83cc8e4b233f87113f3cf247c23e6be58b8a2885c7337aa3"},
{file = "watchdog-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ccd8d84b9490a82b51b230740468116b8205822ea5fdc700a553d92661253a3"},
{file = "watchdog-2.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6e01d699cd260d59b84da6bda019dce0a3353e3fcc774408ae767fe88ee096b7"},
{file = "watchdog-2.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8586d98c494690482c963ffb24c49bf9c8c2fe0589cec4dc2f753b78d1ec301d"},
{file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:adaf2ece15f3afa33a6b45f76b333a7da9256e1360003032524d61bdb4c422ae"},
{file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83a7cead445008e880dbde833cb9e5cc7b9a0958edb697a96b936621975f15b9"},
{file = "watchdog-2.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8ac23ff2c2df4471a61af6490f847633024e5aa120567e08d07af5718c9d092"},
{file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d0f29fd9f3f149a5277929de33b4f121a04cf84bb494634707cfa8ea8ae106a8"},
{file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:967636031fa4c4955f0f3f22da3c5c418aa65d50908d31b73b3b3ffd66d60640"},
{file = "watchdog-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96cbeb494e6cbe3ae6aacc430e678ce4b4dd3ae5125035f72b6eb4e5e9eb4f4e"},
{file = "watchdog-2.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61fdb8e9c57baf625e27e1420e7ca17f7d2023929cd0065eb79c83da1dfbeacd"},
{file = "watchdog-2.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cb5ecc332112017fbdb19ede78d92e29a8165c46b68a0b8ccbd0a154f196d5e"},
{file = "watchdog-2.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a480d122740debf0afac4ddd583c6c0bb519c24f817b42ed6f850e2f6f9d64a8"},
{file = "watchdog-2.2.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:978a1aed55de0b807913b7482d09943b23a2d634040b112bdf31811a422f6344"},
{file = "watchdog-2.2.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:8c28c23972ec9c524967895ccb1954bc6f6d4a557d36e681a36e84368660c4ce"},
{file = "watchdog-2.2.1-py3-none-manylinux2014_i686.whl", hash = "sha256:c27d8c1535fd4474e40a4b5e01f4ba6720bac58e6751c667895cbc5c8a7af33c"},
{file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d6b87477752bd86ac5392ecb9eeed92b416898c30bd40c7e2dd03c3146105646"},
{file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cece1aa596027ff56369f0b50a9de209920e1df9ac6d02c7f9e5d8162eb4f02b"},
{file = "watchdog-2.2.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:8b5cde14e5c72b2df5d074774bdff69e9b55da77e102a91f36ef26ca35f9819c"},
{file = "watchdog-2.2.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e038be858425c4f621900b8ff1a3a1330d9edcfeaa1c0468aeb7e330fb87693e"},
{file = "watchdog-2.2.1-py3-none-win32.whl", hash = "sha256:bc43c1b24d2f86b6e1cc15f68635a959388219426109233e606517ff7d0a5a73"},
{file = "watchdog-2.2.1-py3-none-win_amd64.whl", hash = "sha256:17f1708f7410af92ddf591e94ae71a27a13974559e72f7e9fde3ec174b26ba2e"},
{file = "watchdog-2.2.1-py3-none-win_ia64.whl", hash = "sha256:195ab1d9d611a4c1e5311cbf42273bc541e18ea8c32712f2fb703cfc6ff006f9"},
{file = "watchdog-2.2.1.tar.gz", hash = "sha256:cdcc23c9528601a8a293eb4369cbd14f6b4f34f07ae8769421252e9c22718b6f"},
]
watchfiles = [
{file = "watchfiles-0.18.1-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:9891d3c94272108bcecf5597a592e61105279def1313521e637f2d5acbe08bc9"},

View File

@ -100,7 +100,7 @@ addopts = "-p no:celery --junitxml=unittest.xml"
[tool.poetry]
name = "authentik"
version = "2022.12.1"
version = "2022.12.3"
description = ""
authors = ["authentik Team <hello@goauthentik.io>"]

View File

@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: authentik
version: 2022.12.1
version: 2022.12.3
description: Making authentication simple.
contact:
email: hello@goauthentik.io
@ -5021,12 +5021,11 @@ paths:
operationId: crypto_certificatekeypairs_list
description: CertificateKeyPair Viewset
parameters:
- name: has_key
required: false
in: query
description: Only return certificate-key pairs with keys
- in: query
name: has_key
schema:
type: string
type: boolean
description: Only return certificate-key pairs with keys
- in: query
name: include_details
schema:
@ -21607,6 +21606,10 @@ paths:
schema:
type: string
format: uuid
- in: query
name: throw_error
schema:
type: boolean
tags:
- stages
security:
@ -26358,7 +26361,6 @@ components:
type: string
js_url:
type: string
readOnly: true
required:
- js_url
- pending_user
@ -26608,7 +26610,7 @@ components:
ak-stage-consent: '#/components/schemas/ConsentChallenge'
ak-stage-dummy: '#/components/schemas/DummyChallenge'
ak-stage-email: '#/components/schemas/EmailChallenge'
xak-flow-error: '#/components/schemas/FlowErrorChallenge'
ak-stage-flow-error: '#/components/schemas/FlowErrorChallenge'
ak-stage-identification: '#/components/schemas/IdentificationChallenge'
ak-provider-oauth2-device-code: '#/components/schemas/OAuthDeviceCodeChallenge'
ak-provider-oauth2-device-code-finish: '#/components/schemas/OAuthDeviceCodeFinishChallenge'
@ -27178,6 +27180,8 @@ components:
type: array
items:
$ref: '#/components/schemas/FlowSet'
throw_error:
type: boolean
required:
- component
- meta_model_name
@ -27196,6 +27200,8 @@ components:
type: array
items:
$ref: '#/components/schemas/FlowSetRequest'
throw_error:
type: boolean
required:
- name
DuoDevice:
@ -27869,22 +27875,19 @@ components:
are shown an error message, superusers are shown a full stacktrace.
properties:
type:
$ref: '#/components/schemas/ChallengeChoices'
type: string
default: native
flow_info:
$ref: '#/components/schemas/ContextualFlowInfo'
component:
type: string
default: xak-flow-error
default: ak-stage-flow-error
response_errors:
type: object
additionalProperties:
type: array
items:
$ref: '#/components/schemas/ErrorDetail'
pending_user:
type: string
pending_user_avatar:
type: string
request_id:
type: string
error:
@ -27892,10 +27895,7 @@ components:
traceback:
type: string
required:
- pending_user
- pending_user_avatar
- request_id
- type
FlowImportResult:
type: object
description: Logs of an attempted flow import
@ -33740,6 +33740,8 @@ components:
type: array
items:
$ref: '#/components/schemas/FlowSetRequest'
throw_error:
type: boolean
PatchedDuoDeviceRequest:
type: object
description: Serializer for Duo authenticator devices
@ -37938,6 +37940,7 @@ components:
- username
UserAccountRequest:
type: object
description: Account adding/removing operations
properties:
pk:
type: integer

View File

@ -47,7 +47,6 @@ class TestProviderLDAP(SeleniumTestCase):
def _prepare(self) -> User:
"""prepare user, provider, app and container"""
# set additionalHeaders to test later
self.user.attributes["extraAttribute"] = "bar"
self.user.save()

View File

@ -1,4 +1,5 @@
"""Proxy and Outpost e2e tests"""
from base64 import b64encode
from dataclasses import asdict
from sys import platform
from time import sleep
@ -14,6 +15,7 @@ from authentik import __version__
from authentik.blueprints.tests import apply_blueprint, reconcile_app
from authentik.core.models import Application
from authentik.flows.models import Flow
from authentik.lib.generators import generate_id
from authentik.outposts.models import DockerServiceConnection, Outpost, OutpostConfig, OutpostType
from authentik.outposts.tasks import outpost_local_connection
from authentik.providers.proxy.models import ProxyProvider
@ -119,6 +121,78 @@ class TestProviderProxy(SeleniumTestCase):
full_body_text = self.driver.find_element(By.CSS_SELECTOR, ".pf-c-title.pf-m-3xl").text
self.assertIn("You've logged out of proxy.", full_body_text)
@retry()
@apply_blueprint(
"default/10-flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml",
)
@apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml",
)
@apply_blueprint(
"system/providers-oauth2.yaml",
"system/providers-proxy.yaml",
)
@reconcile_app("authentik_crypto")
def test_proxy_basic_auth(self):
"""Test simple outpost setup with single provider"""
cred = generate_id()
attr = "basic-password" # nosec
self.user.attributes["basic-username"] = cred
self.user.attributes[attr] = cred
self.user.save()
proxy: ProxyProvider = ProxyProvider.objects.create(
name="proxy_provider",
authorization_flow=Flow.objects.get(
slug="default-provider-authorization-implicit-consent"
),
internal_host="http://localhost",
external_host="http://localhost:9000",
basic_auth_enabled=True,
basic_auth_user_attribute="basic-username",
basic_auth_password_attribute=attr,
)
# Ensure OAuth2 Params are set
proxy.set_oauth_defaults()
proxy.save()
# we need to create an application to actually access the proxy
Application.objects.create(name="proxy", slug="proxy", provider=proxy)
outpost: Outpost = Outpost.objects.create(
name="proxy_outpost",
type=OutpostType.PROXY,
)
outpost.providers.add(proxy)
outpost.build_user_permissions(outpost.user)
self.proxy_container = self.start_proxy(outpost)
# Wait until outpost healthcheck succeeds
healthcheck_retries = 0
while healthcheck_retries < 50:
if len(outpost.state) > 0:
state = outpost.state[0]
if state.last_seen:
break
healthcheck_retries += 1
sleep(0.5)
sleep(5)
self.driver.get("http://localhost:9000")
self.login()
sleep(1)
full_body_text = self.driver.find_element(By.CSS_SELECTOR, "pre").text
self.assertIn(f"X-Authentik-Username: {self.user.username}", full_body_text)
auth_header = b64encode(f"{cred}:{cred}".encode()).decode()
self.assertIn(f"Authorization: Basic {auth_header}", full_body_text)
self.driver.get("http://localhost:9000/outpost.goauthentik.io/sign_out")
sleep(2)
full_body_text = self.driver.find_element(By.CSS_SELECTOR, ".pf-c-title.pf-m-3xl").text
self.assertIn("You've logged out of proxy.", full_body_text)
@skipUnless(platform.startswith("linux"), "requires local docker")
class TestProviderProxyConnect(ChannelsLiveServerTestCase):

286
web/package-lock.json generated
View File

@ -21,7 +21,8 @@
"@codemirror/legacy-modes": "^6.3.1",
"@formatjs/intl-listformat": "^7.1.7",
"@fortawesome/fontawesome-free": "^6.2.1",
"@goauthentik/api": "^2022.12.0-1672308901",
"@goauthentik/api": "^2022.12.1-1672612412",
"@hcaptcha/types": "^1.0.3",
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
"@lingui/cli": "^3.15.0",
"@lingui/core": "^3.15.0",
@ -37,13 +38,13 @@
"@rollup/plugin-typescript": "^10.0.1",
"@sentry/browser": "^7.28.1",
"@sentry/tracing": "^7.28.1",
"@squoosh/cli": "^0.7.2",
"@squoosh/cli": "^0.7.3",
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
"@types/chart.js": "^2.9.37",
"@types/codemirror": "5.60.5",
"@types/codemirror": "5.60.6",
"@types/grecaptcha": "^3.0.4",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"@webcomponents/webcomponentsjs": "^2.7.0",
"babel-plugin-macros": "^3.1.0",
"babel-plugin-tsconfig-paths": "^1.0.3",
@ -53,9 +54,9 @@
"codemirror": "^6.0.1",
"construct-style-sheets-polyfill": "^3.1.0",
"country-flag-icons": "^1.5.5",
"eslint": "^8.30.0",
"eslint": "^8.31.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-custom-elements": "0.0.6",
"eslint-plugin-custom-elements": "0.0.7",
"eslint-plugin-lit": "^1.7.2",
"fuse.js": "^6.6.2",
"lit": "^2.5.0",
@ -71,9 +72,10 @@
"rollup-plugin-terser": "^7.0.2",
"ts-lit-plugin": "^1.2.1",
"tslib": "^2.4.1",
"turnstile-types": "^1.0.2",
"typescript": "^4.9.4",
"webcomponent-qr-code": "^1.1.0",
"yaml": "^2.2.0"
"yaml": "^2.2.1"
}
},
"node_modules/@ampproject/remapping": {
@ -1874,9 +1876,9 @@
}
},
"node_modules/@eslint/eslintrc": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz",
"integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==",
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
"integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
@ -1957,9 +1959,14 @@
}
},
"node_modules/@goauthentik/api": {
"version": "2022.12.0-1672308901",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2022.12.0-1672308901.tgz",
"integrity": "sha512-Wj3dzxiR83cOLyTEbr4T8MQZ2Vb7Oaq3ub6oWZXNv7zsk3sn7w7YN1/vXBU74KCbZk569zRIAAR+QLL+i2UNEw=="
"version": "2022.12.1-1672612412",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2022.12.1-1672612412.tgz",
"integrity": "sha512-fyAk76avWt0KzBfcrUPPopwRW2KWw/yo+MYva3ocWcU+4dbYlwEiT3LehToPMOOHoM81vRbyP9oVE5f472TyUQ=="
},
"node_modules/@hcaptcha/types": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@hcaptcha/types/-/types-1.0.3.tgz",
"integrity": "sha512-1mbU6eSGawRrqeahRrOzZo/SVLI6oZ5/azuBpSyVrRRR96CnS3fOVDWfzxpngfxKD0/I9Rwu6c/3ITqD8rXeTQ=="
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.8",
@ -3047,9 +3054,9 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/@squoosh/cli": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/@squoosh/cli/-/cli-0.7.2.tgz",
"integrity": "sha512-uMnUWMx4S8UApO/EfPyRyvUmw+0jI9wwAfdHfGjvVg4DAIvEgsA+VWK2KOBnJiChvVd768K27g09ESzptyX93w==",
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/@squoosh/cli/-/cli-0.7.3.tgz",
"integrity": "sha512-mU/iWbVWqLXX+gJJa4RBl5U4LdKYaiD9cmxW7bjyw8EEFAuMXFDGAQcq7hEvUZwoP5Em5s7sjimBPirSBJQ87g==",
"dependencies": {
"@squoosh/lib": "^0.4.0",
"commander": "^7.2.0",
@ -3234,9 +3241,9 @@
}
},
"node_modules/@types/codemirror": {
"version": "5.60.5",
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.5.tgz",
"integrity": "sha512-TiECZmm8St5YxjFUp64LK0c8WU5bxMDt9YaAek1UqUb9swrSCoJhh92fWu1p3mTEqlHjhB5sY7OFBhWroJXZVg==",
"version": "5.60.6",
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.6.tgz",
"integrity": "sha512-JIDPSvkYRlcv/2F0erqD+de2ni/Mz6FJMEGb0vwF6ByQOcHIKfiEfwrO4d6dSRwYeHyNUMpGjev0PyjX2M0XWw==",
"dependencies": {
"@types/tern": "*"
}
@ -3382,13 +3389,13 @@
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.1.tgz",
"integrity": "sha512-r4RZ2Jl9kcQN7K/dcOT+J7NAimbiis4sSM9spvWimsBvDegMhKLA5vri2jG19PmIPbDjPeWzfUPQ2hjEzA4Nmg==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz",
"integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==",
"dependencies": {
"@typescript-eslint/scope-manager": "5.47.1",
"@typescript-eslint/type-utils": "5.47.1",
"@typescript-eslint/utils": "5.47.1",
"@typescript-eslint/scope-manager": "5.48.0",
"@typescript-eslint/type-utils": "5.48.0",
"@typescript-eslint/utils": "5.48.0",
"debug": "^4.3.4",
"ignore": "^5.2.0",
"natural-compare-lite": "^1.4.0",
@ -3428,13 +3435,13 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.1.tgz",
"integrity": "sha512-9Vb+KIv29r6GPu4EboWOnQM7T+UjpjXvjCPhNORlgm40a9Ia9bvaPJswvtae1gip2QEeVeGh6YquqAzEgoRAlw==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.0.tgz",
"integrity": "sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==",
"dependencies": {
"@typescript-eslint/scope-manager": "5.47.1",
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/typescript-estree": "5.47.1",
"@typescript-eslint/scope-manager": "5.48.0",
"@typescript-eslint/types": "5.48.0",
"@typescript-eslint/typescript-estree": "5.48.0",
"debug": "^4.3.4"
},
"engines": {
@ -3454,12 +3461,12 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.1.tgz",
"integrity": "sha512-9hsFDsgUwrdOoW1D97Ewog7DYSHaq4WKuNs0LHF9RiCmqB0Z+XRR4Pf7u7u9z/8CciHuJ6yxNws1XznI3ddjEw==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz",
"integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==",
"dependencies": {
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/visitor-keys": "5.47.1"
"@typescript-eslint/types": "5.48.0",
"@typescript-eslint/visitor-keys": "5.48.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -3470,12 +3477,12 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.1.tgz",
"integrity": "sha512-/UKOeo8ee80A7/GJA427oIrBi/Gd4osk/3auBUg4Rn9EahFpevVV1mUK8hjyQD5lHPqX397x6CwOk5WGh1E/1w==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz",
"integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==",
"dependencies": {
"@typescript-eslint/typescript-estree": "5.47.1",
"@typescript-eslint/utils": "5.47.1",
"@typescript-eslint/typescript-estree": "5.48.0",
"@typescript-eslint/utils": "5.48.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@ -3496,9 +3503,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz",
"integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@ -3508,12 +3515,12 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.1.tgz",
"integrity": "sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz",
"integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==",
"dependencies": {
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/visitor-keys": "5.47.1",
"@typescript-eslint/types": "5.48.0",
"@typescript-eslint/visitor-keys": "5.48.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -3548,15 +3555,15 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.1.tgz",
"integrity": "sha512-l90SdwqfmkuIVaREZ2ykEfCezepCLxzWMo5gVfcJsJCaT4jHT+QjgSkYhs5BMQmWqE9k3AtIfk4g211z/sTMVw==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz",
"integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==",
"dependencies": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.47.1",
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/typescript-estree": "5.47.1",
"@typescript-eslint/scope-manager": "5.48.0",
"@typescript-eslint/types": "5.48.0",
"@typescript-eslint/typescript-estree": "5.48.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
@ -3587,11 +3594,11 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz",
"integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==",
"dependencies": {
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/types": "5.48.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@ -5181,11 +5188,11 @@
}
},
"node_modules/eslint": {
"version": "8.30.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz",
"integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==",
"version": "8.31.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz",
"integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==",
"dependencies": {
"@eslint/eslintrc": "^1.4.0",
"@eslint/eslintrc": "^1.4.1",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@ -5247,9 +5254,9 @@
}
},
"node_modules/eslint-plugin-custom-elements": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/eslint-plugin-custom-elements/-/eslint-plugin-custom-elements-0.0.6.tgz",
"integrity": "sha512-JwPHRSOUe7y8dpC5hg90ySHejsfnQ3yqprv0902VMZ3j8FRZDudj+yzxqqkRDhZTNFUxP3r+0TWuveZhLgJONg==",
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/eslint-plugin-custom-elements/-/eslint-plugin-custom-elements-0.0.7.tgz",
"integrity": "sha512-s37mXujv/fAsPlvoLbO8jiZDM2gc/dFXIDf7wK52LMrsTsLpE5ITugQCwPM8lmcONjYdswS5kneX9LzJlt7aTA==",
"peerDependencies": {
"eslint": ">=4.19.0"
}
@ -9511,6 +9518,11 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/turnstile-types": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/turnstile-types/-/turnstile-types-1.0.2.tgz",
"integrity": "sha512-Y98xYhxf9xtYuu1QCrQm7og0o2zw2bGdsyUNXeWgPVXsHFkJIwTrRY6o3Oioa9PjFtoYM+oHe1n23V+oE27WUQ=="
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -9961,9 +9973,9 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/yaml": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.0.tgz",
"integrity": "sha512-auf7Gi6QwO7HW//GA9seGvTXVGWl1CM/ADWh1+RxtXr6XOxnT65ovDl9fTi4e0monEyJxCHqDpF6QnFDXmJE4g==",
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz",
"integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==",
"engines": {
"node": ">= 14"
}
@ -11333,9 +11345,9 @@
}
},
"@eslint/eslintrc": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz",
"integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==",
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
"integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
"requires": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
@ -11396,9 +11408,14 @@
"integrity": "sha512-viouXhegu/TjkvYQoiRZK3aax69dGXxgEjpvZW81wIJdxm5Fnvp3VVIP4VHKqX4SvFw6qpmkILkD4RJWAdrt7A=="
},
"@goauthentik/api": {
"version": "2022.12.0-1672308901",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2022.12.0-1672308901.tgz",
"integrity": "sha512-Wj3dzxiR83cOLyTEbr4T8MQZ2Vb7Oaq3ub6oWZXNv7zsk3sn7w7YN1/vXBU74KCbZk569zRIAAR+QLL+i2UNEw=="
"version": "2022.12.1-1672612412",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2022.12.1-1672612412.tgz",
"integrity": "sha512-fyAk76avWt0KzBfcrUPPopwRW2KWw/yo+MYva3ocWcU+4dbYlwEiT3LehToPMOOHoM81vRbyP9oVE5f472TyUQ=="
},
"@hcaptcha/types": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@hcaptcha/types/-/types-1.0.3.tgz",
"integrity": "sha512-1mbU6eSGawRrqeahRrOzZo/SVLI6oZ5/azuBpSyVrRRR96CnS3fOVDWfzxpngfxKD0/I9Rwu6c/3ITqD8rXeTQ=="
},
"@humanwhocodes/config-array": {
"version": "0.11.8",
@ -12217,9 +12234,9 @@
}
},
"@squoosh/cli": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/@squoosh/cli/-/cli-0.7.2.tgz",
"integrity": "sha512-uMnUWMx4S8UApO/EfPyRyvUmw+0jI9wwAfdHfGjvVg4DAIvEgsA+VWK2KOBnJiChvVd768K27g09ESzptyX93w==",
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/@squoosh/cli/-/cli-0.7.3.tgz",
"integrity": "sha512-mU/iWbVWqLXX+gJJa4RBl5U4LdKYaiD9cmxW7bjyw8EEFAuMXFDGAQcq7hEvUZwoP5Em5s7sjimBPirSBJQ87g==",
"requires": {
"@squoosh/lib": "^0.4.0",
"commander": "^7.2.0",
@ -12368,9 +12385,9 @@
}
},
"@types/codemirror": {
"version": "5.60.5",
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.5.tgz",
"integrity": "sha512-TiECZmm8St5YxjFUp64LK0c8WU5bxMDt9YaAek1UqUb9swrSCoJhh92fWu1p3mTEqlHjhB5sY7OFBhWroJXZVg==",
"version": "5.60.6",
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.6.tgz",
"integrity": "sha512-JIDPSvkYRlcv/2F0erqD+de2ni/Mz6FJMEGb0vwF6ByQOcHIKfiEfwrO4d6dSRwYeHyNUMpGjev0PyjX2M0XWw==",
"requires": {
"@types/tern": "*"
}
@ -12515,13 +12532,13 @@
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
},
"@typescript-eslint/eslint-plugin": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.1.tgz",
"integrity": "sha512-r4RZ2Jl9kcQN7K/dcOT+J7NAimbiis4sSM9spvWimsBvDegMhKLA5vri2jG19PmIPbDjPeWzfUPQ2hjEzA4Nmg==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz",
"integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==",
"requires": {
"@typescript-eslint/scope-manager": "5.47.1",
"@typescript-eslint/type-utils": "5.47.1",
"@typescript-eslint/utils": "5.47.1",
"@typescript-eslint/scope-manager": "5.48.0",
"@typescript-eslint/type-utils": "5.48.0",
"@typescript-eslint/utils": "5.48.0",
"debug": "^4.3.4",
"ignore": "^5.2.0",
"natural-compare-lite": "^1.4.0",
@ -12541,48 +12558,48 @@
}
},
"@typescript-eslint/parser": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.1.tgz",
"integrity": "sha512-9Vb+KIv29r6GPu4EboWOnQM7T+UjpjXvjCPhNORlgm40a9Ia9bvaPJswvtae1gip2QEeVeGh6YquqAzEgoRAlw==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.0.tgz",
"integrity": "sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==",
"requires": {
"@typescript-eslint/scope-manager": "5.47.1",
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/typescript-estree": "5.47.1",
"@typescript-eslint/scope-manager": "5.48.0",
"@typescript-eslint/types": "5.48.0",
"@typescript-eslint/typescript-estree": "5.48.0",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.1.tgz",
"integrity": "sha512-9hsFDsgUwrdOoW1D97Ewog7DYSHaq4WKuNs0LHF9RiCmqB0Z+XRR4Pf7u7u9z/8CciHuJ6yxNws1XznI3ddjEw==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz",
"integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==",
"requires": {
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/visitor-keys": "5.47.1"
"@typescript-eslint/types": "5.48.0",
"@typescript-eslint/visitor-keys": "5.48.0"
}
},
"@typescript-eslint/type-utils": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.1.tgz",
"integrity": "sha512-/UKOeo8ee80A7/GJA427oIrBi/Gd4osk/3auBUg4Rn9EahFpevVV1mUK8hjyQD5lHPqX397x6CwOk5WGh1E/1w==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz",
"integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==",
"requires": {
"@typescript-eslint/typescript-estree": "5.47.1",
"@typescript-eslint/utils": "5.47.1",
"@typescript-eslint/typescript-estree": "5.48.0",
"@typescript-eslint/utils": "5.48.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/types": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A=="
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz",
"integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw=="
},
"@typescript-eslint/typescript-estree": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.1.tgz",
"integrity": "sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz",
"integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==",
"requires": {
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/visitor-keys": "5.47.1",
"@typescript-eslint/types": "5.48.0",
"@typescript-eslint/visitor-keys": "5.48.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -12601,15 +12618,15 @@
}
},
"@typescript-eslint/utils": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.1.tgz",
"integrity": "sha512-l90SdwqfmkuIVaREZ2ykEfCezepCLxzWMo5gVfcJsJCaT4jHT+QjgSkYhs5BMQmWqE9k3AtIfk4g211z/sTMVw==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz",
"integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==",
"requires": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.47.1",
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/typescript-estree": "5.47.1",
"@typescript-eslint/scope-manager": "5.48.0",
"@typescript-eslint/types": "5.48.0",
"@typescript-eslint/typescript-estree": "5.48.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
@ -12626,11 +12643,11 @@
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz",
"integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==",
"requires": {
"@typescript-eslint/types": "5.47.1",
"@typescript-eslint/types": "5.48.0",
"eslint-visitor-keys": "^3.3.0"
},
"dependencies": {
@ -13796,11 +13813,11 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"eslint": {
"version": "8.30.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz",
"integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==",
"version": "8.31.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz",
"integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==",
"requires": {
"@eslint/eslintrc": "^1.4.0",
"@eslint/eslintrc": "^1.4.1",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@ -13976,9 +13993,9 @@
"requires": {}
},
"eslint-plugin-custom-elements": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/eslint-plugin-custom-elements/-/eslint-plugin-custom-elements-0.0.6.tgz",
"integrity": "sha512-JwPHRSOUe7y8dpC5hg90ySHejsfnQ3yqprv0902VMZ3j8FRZDudj+yzxqqkRDhZTNFUxP3r+0TWuveZhLgJONg==",
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/eslint-plugin-custom-elements/-/eslint-plugin-custom-elements-0.0.7.tgz",
"integrity": "sha512-s37mXujv/fAsPlvoLbO8jiZDM2gc/dFXIDf7wK52LMrsTsLpE5ITugQCwPM8lmcONjYdswS5kneX9LzJlt7aTA==",
"requires": {}
},
"eslint-plugin-lit": {
@ -17025,6 +17042,11 @@
}
}
},
"turnstile-types": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/turnstile-types/-/turnstile-types-1.0.2.tgz",
"integrity": "sha512-Y98xYhxf9xtYuu1QCrQm7og0o2zw2bGdsyUNXeWgPVXsHFkJIwTrRY6o3Oioa9PjFtoYM+oHe1n23V+oE27WUQ=="
},
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -17374,9 +17396,9 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"yaml": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.0.tgz",
"integrity": "sha512-auf7Gi6QwO7HW//GA9seGvTXVGWl1CM/ADWh1+RxtXr6XOxnT65ovDl9fTi4e0monEyJxCHqDpF6QnFDXmJE4g=="
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz",
"integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw=="
},
"yargs": {
"version": "15.4.1",

View File

@ -12,6 +12,7 @@
"lit-analyse": "lit-analyzer src",
"prettier-check": "prettier --check .",
"prettier": "prettier --write .",
"tsc": "lingui compile && tsc --noEmit -p .",
"background-image": "npx @squoosh/cli -d src/assets/images --resize '{\"enabled\":true,\"width\":2560,\"method\":\"lanczos3\",\"fitMethod\":\"contain\",\"premultiply\":true,\"linearRGB\":true}' --mozjpeg '{\"quality\":75,\"baseline\":false,\"arithmetic\":false,\"progressive\":true,\"optimize_coding\":true,\"smoothing\":0,\"color_space\":3,\"quant_table\":3,\"trellis_multipass\":false,\"trellis_opt_zero\":false,\"trellis_opt_table\":false,\"trellis_loops\":1,\"auto_subsample\":true,\"chroma_subsample\":2,\"separate_chroma_quality\":false,\"chroma_quality\":75}' src/assets/images/flow_background.jpg"
},
"lingui": {
@ -64,7 +65,8 @@
"@codemirror/legacy-modes": "^6.3.1",
"@formatjs/intl-listformat": "^7.1.7",
"@fortawesome/fontawesome-free": "^6.2.1",
"@goauthentik/api": "^2022.12.0-1672308901",
"@goauthentik/api": "^2022.12.1-1672612412",
"@hcaptcha/types": "^1.0.3",
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
"@lingui/cli": "^3.15.0",
"@lingui/core": "^3.15.0",
@ -80,13 +82,13 @@
"@rollup/plugin-typescript": "^10.0.1",
"@sentry/browser": "^7.28.1",
"@sentry/tracing": "^7.28.1",
"@squoosh/cli": "^0.7.2",
"@squoosh/cli": "^0.7.3",
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
"@types/chart.js": "^2.9.37",
"@types/codemirror": "5.60.5",
"@types/codemirror": "5.60.6",
"@types/grecaptcha": "^3.0.4",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"@webcomponents/webcomponentsjs": "^2.7.0",
"babel-plugin-macros": "^3.1.0",
"babel-plugin-tsconfig-paths": "^1.0.3",
@ -96,9 +98,9 @@
"codemirror": "^6.0.1",
"construct-style-sheets-polyfill": "^3.1.0",
"country-flag-icons": "^1.5.5",
"eslint": "^8.30.0",
"eslint": "^8.31.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-custom-elements": "0.0.6",
"eslint-plugin-custom-elements": "0.0.7",
"eslint-plugin-lit": "^1.7.2",
"fuse.js": "^6.6.2",
"lit": "^2.5.0",
@ -114,8 +116,9 @@
"rollup-plugin-terser": "^7.0.2",
"ts-lit-plugin": "^1.2.1",
"tslib": "^2.4.1",
"turnstile-types": "^1.0.2",
"typescript": "^4.9.4",
"webcomponent-qr-code": "^1.1.0",
"yaml": "^2.2.0"
"yaml": "^2.2.1"
}
}

View File

@ -10,7 +10,7 @@ import { AdminApi, LoginMetrics } from "@goauthentik/api";
@customElement("ak-charts-admin-login-authorization")
export class AdminLoginAuthorizeChart extends AKChart<LoginMetrics> {
apiRequest(): Promise<LoginMetrics> {
async apiRequest(): Promise<LoginMetrics> {
return new AdminApi(DEFAULT_CONFIG).adminMetricsRetrieve();
}

View File

@ -1,8 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { PFColor } from "@goauthentik/elements/Label";
import "@goauthentik/elements/SearchSelect";
import { Form } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -34,14 +34,13 @@ export class ApplicationCheckAccessForm extends Form<{ forUser: number }> {
return t`Successfully sent test-request.`;
}
send = (data: { forUser: number }): Promise<PolicyTestResult> => {
send = async (data: { forUser: number }): Promise<PolicyTestResult> => {
this.request = data.forUser;
return new CoreApi(DEFAULT_CONFIG)
.coreApplicationsCheckAccessRetrieve({
slug: this.application?.slug,
forUser: data.forUser,
})
.then((result) => (this.result = result));
const result = await new CoreApi(DEFAULT_CONFIG).coreApplicationsCheckAccessRetrieve({
slug: this.application?.slug,
forUser: data.forUser,
});
return (this.result = result);
};
resetForm(): void {

View File

@ -1,12 +1,13 @@
import "@goauthentik/admin/providers/ProviderWizard";
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
import { first, groupBy } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/ModalForm";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/ProxyForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -153,20 +154,23 @@ export class ApplicationForm extends ModelForm<Application, string> {
?required=${true}
name="policyEngineMode"
>
<select class="pf-c-form-control">
<option
value=${PolicyEngineMode.Any}
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.Any}
>
${t`ANY, any policy must match to grant access.`}
</option>
<option
value=${PolicyEngineMode.All}
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.All}
>
${t`ALL, all policies must match to grant access.`}
</option>
</select>
<ak-radio
.options=${[
{
label: "ANY",
value: PolicyEngineMode.Any,
default: true,
description: html`${t`Any policy must match to grant access`}`,
},
{
label: "ALL",
value: PolicyEngineMode.All,
description: html`${t`All policies must match to grant access`}`,
},
]}
.value=${this.instance?.policyEngineMode}
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-group .expanded=${true}>
<span slot="header"> ${t`UI settings`} </span>

View File

@ -1,7 +1,7 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/SearchSelect";
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect";
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
import "@goauthentik/elements/wizard/WizardFormPage";

View File

@ -2,10 +2,10 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { docLink } from "@goauthentik/common/global";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import YAML from "yaml";
import { t } from "@lingui/macro";

View File

@ -1,7 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -48,29 +49,6 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
}
};
renderSeverity(): TemplateResult {
return html`
<option
value=${SeverityEnum.Alert}
?selected=${this.instance?.severity === SeverityEnum.Alert}
>
${t`Alert`}
</option>
<option
value=${SeverityEnum.Warning}
?selected=${this.instance?.severity === SeverityEnum.Warning}
>
${t`Warning`}
</option>
<option
value=${SeverityEnum.Notice}
?selected=${this.instance?.severity === SeverityEnum.Notice}
>
${t`Notice`}
</option>
`;
}
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
@ -107,10 +85,12 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
</ak-search-select>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Transports`} ?required=${true} name="transports">
<select name="users" class="pf-c-form-control" multiple>
<select class="pf-c-form-control" multiple>
${until(
new EventsApi(DEFAULT_CONFIG)
.eventsTransportsList({})
.eventsTransportsList({
ordering: "name",
})
.then((transports) => {
return transports.results.map((transport) => {
const selected = Array.from(
@ -137,9 +117,25 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Severity`} ?required=${true} name="severity">
<select class="pf-c-form-control">
${this.renderSeverity()}
</select>
<ak-radio
.options=${[
{
label: "Alert",
value: SeverityEnum.Alert,
default: true,
},
{
label: t`Warning`,
value: SeverityEnum.Warning,
},
{
label: t`Notice`,
value: SeverityEnum.Notice,
},
]}
.value=${this.instance?.severity}
>
</ak-radio>
</ak-form-element-horizontal>
</form>`;
}

View File

@ -1,8 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -2,8 +2,10 @@ import { DesignationToLabel, LayoutToLabel } from "@goauthentik/admin/flows/util
import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum";
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import { t } from "@lingui/macro";
@ -74,140 +76,6 @@ export class FlowForm extends ModelForm<Flow, string> {
return flow;
};
renderDesignations(): TemplateResult {
return html`
<option
value=${FlowDesignationEnum.Authentication}
?selected=${this.instance?.designation === FlowDesignationEnum.Authentication}
>
${DesignationToLabel(FlowDesignationEnum.Authentication)}
</option>
<option
value=${FlowDesignationEnum.Authorization}
?selected=${this.instance?.designation === FlowDesignationEnum.Authorization}
>
${DesignationToLabel(FlowDesignationEnum.Authorization)}
</option>
<option
value=${FlowDesignationEnum.Enrollment}
?selected=${this.instance?.designation === FlowDesignationEnum.Enrollment}
>
${DesignationToLabel(FlowDesignationEnum.Enrollment)}
</option>
<option
value=${FlowDesignationEnum.Invalidation}
?selected=${this.instance?.designation === FlowDesignationEnum.Invalidation}
>
${DesignationToLabel(FlowDesignationEnum.Invalidation)}
</option>
<option
value=${FlowDesignationEnum.Recovery}
?selected=${this.instance?.designation === FlowDesignationEnum.Recovery}
>
${DesignationToLabel(FlowDesignationEnum.Recovery)}
</option>
<option
value=${FlowDesignationEnum.StageConfiguration}
?selected=${this.instance?.designation === FlowDesignationEnum.StageConfiguration}
>
${DesignationToLabel(FlowDesignationEnum.StageConfiguration)}
</option>
<option
value=${FlowDesignationEnum.Unenrollment}
?selected=${this.instance?.designation === FlowDesignationEnum.Unenrollment}
>
${DesignationToLabel(FlowDesignationEnum.Unenrollment)}
</option>
`;
}
renderDeniedAction(): TemplateResult {
return html` <option
value=${DeniedActionEnum.MessageContinue}
?selected=${this.instance?.deniedAction === DeniedActionEnum.MessageContinue}
>
${t`MESSAGE_CONTINUE will follow the ?next parameter if set, otherwise show a message.`}
</option>
<option
value=${DeniedActionEnum.Continue}
?selected=${this.instance?.deniedAction === DeniedActionEnum.Continue}
>
${t`CONTINUE will either follow the ?next parameter or redirect to the default interface.`}
</option>
<option
value=${DeniedActionEnum.Message}
?selected=${this.instance?.deniedAction === DeniedActionEnum.Message}
>
${t`MESSAGE will notify the user the flow isn't applicable.`}
</option>`;
}
renderAuthentication(): TemplateResult {
return html`
<option
value=${AuthenticationEnum.None}
?selected=${this.instance?.authentication === AuthenticationEnum.None}
>
${t`No requirement`}
</option>
<option
value=${AuthenticationEnum.RequireAuthenticated}
?selected=${this.instance?.authentication ===
AuthenticationEnum.RequireAuthenticated}
>
${t`Require authentication`}
</option>
<option
value=${AuthenticationEnum.RequireUnauthenticated}
?selected=${this.instance?.authentication ===
AuthenticationEnum.RequireUnauthenticated}
>
${t`Require no authentication.`}
</option>
<option
value=${AuthenticationEnum.RequireSuperuser}
?selected=${this.instance?.authentication === AuthenticationEnum.RequireSuperuser}
>
${t`Require superuser.`}
</option>
`;
}
renderLayout(): TemplateResult {
return html`
<option
value=${LayoutEnum.Stacked}
?selected=${this.instance?.layout === LayoutEnum.Stacked}
>
${LayoutToLabel(LayoutEnum.Stacked)}
</option>
<option
value=${LayoutEnum.ContentLeft}
?selected=${this.instance?.layout === LayoutEnum.ContentLeft}
>
${LayoutToLabel(LayoutEnum.ContentLeft)}
</option>
<option
value=${LayoutEnum.ContentRight}
?selected=${this.instance?.layout === LayoutEnum.ContentRight}
>
${LayoutToLabel(LayoutEnum.ContentRight)}
</option>
<option
value=${LayoutEnum.SidebarLeft}
?selected=${this.instance?.layout === LayoutEnum.SidebarLeft}
>
${LayoutToLabel(LayoutEnum.SidebarLeft)}
</option>
<option
value=${LayoutEnum.SidebarRight}
?selected=${this.instance?.layout === LayoutEnum.SidebarRight}
>
${LayoutToLabel(LayoutEnum.SidebarRight)}
</option>
`;
}
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
@ -236,38 +104,6 @@ export class FlowForm extends ModelForm<Flow, string> {
/>
<p class="pf-c-form__helper-text">${t`Visible in the URL.`}</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Policy engine mode`}
?required=${true}
name="policyEngineMode"
>
<select class="pf-c-form-control">
<option
value=${PolicyEngineMode.Any}
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.Any}
>
${t`ANY, any policy must match to grant access.`}
</option>
<option
value=${PolicyEngineMode.All}
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.All}
>
${t`ALL, all policies must match to grant access.`}
</option>
</select>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Authentication`}
?required=${true}
name="authentication"
>
<select class="pf-c-form-control">
${this.renderAuthentication()}
</select>
<p class="pf-c-form__helper-text">
${t`Required authentication level for this flow.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Designation`}
?required=${true}
@ -277,99 +113,264 @@ export class FlowForm extends ModelForm<Flow, string> {
<option value="" ?selected=${this.instance?.designation === undefined}>
---------
</option>
${this.renderDesignations()}
<option
value=${FlowDesignationEnum.Authentication}
?selected=${this.instance?.designation ===
FlowDesignationEnum.Authentication}
>
${DesignationToLabel(FlowDesignationEnum.Authentication)}
</option>
<option
value=${FlowDesignationEnum.Authorization}
?selected=${this.instance?.designation ===
FlowDesignationEnum.Authorization}
>
${DesignationToLabel(FlowDesignationEnum.Authorization)}
</option>
<option
value=${FlowDesignationEnum.Enrollment}
?selected=${this.instance?.designation === FlowDesignationEnum.Enrollment}
>
${DesignationToLabel(FlowDesignationEnum.Enrollment)}
</option>
<option
value=${FlowDesignationEnum.Invalidation}
?selected=${this.instance?.designation === FlowDesignationEnum.Invalidation}
>
${DesignationToLabel(FlowDesignationEnum.Invalidation)}
</option>
<option
value=${FlowDesignationEnum.Recovery}
?selected=${this.instance?.designation === FlowDesignationEnum.Recovery}
>
${DesignationToLabel(FlowDesignationEnum.Recovery)}
</option>
<option
value=${FlowDesignationEnum.StageConfiguration}
?selected=${this.instance?.designation ===
FlowDesignationEnum.StageConfiguration}
>
${DesignationToLabel(FlowDesignationEnum.StageConfiguration)}
</option>
<option
value=${FlowDesignationEnum.Unenrollment}
?selected=${this.instance?.designation === FlowDesignationEnum.Unenrollment}
>
${DesignationToLabel(FlowDesignationEnum.Unenrollment)}
</option>
</select>
<p class="pf-c-form__helper-text">
${t`Decides what this Flow is used for. For example, the Authentication flow is redirect to when an un-authenticated user visits authentik.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Denied action`}
label=${t`Authentication`}
?required=${true}
name="deniedAction"
name="authentication"
>
<select class="pf-c-form-control">
${this.renderDeniedAction()}
<option
value=${AuthenticationEnum.None}
?selected=${this.instance?.authentication === AuthenticationEnum.None}
>
${t`No requirement`}
</option>
<option
value=${AuthenticationEnum.RequireAuthenticated}
?selected=${this.instance?.authentication ===
AuthenticationEnum.RequireAuthenticated}
>
${t`Require authentication`}
</option>
<option
value=${AuthenticationEnum.RequireUnauthenticated}
?selected=${this.instance?.authentication ===
AuthenticationEnum.RequireUnauthenticated}
>
${t`Require no authentication.`}
</option>
<option
value=${AuthenticationEnum.RequireSuperuser}
?selected=${this.instance?.authentication ===
AuthenticationEnum.RequireSuperuser}
>
${t`Require superuser.`}
</option>
</select>
<p class="pf-c-form__helper-text">
${t`Decides the response when a policy denies access to this flow for a user.`}
${t`Required authentication level for this flow.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Layout`} ?required=${true} name="layout">
<select class="pf-c-form-control">
${this.renderLayout()}
</select>
</ak-form-element-horizontal>
${until(
config().then((c) => {
if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) {
return html`<ak-form-element-horizontal
<ak-form-group>
<span slot="header"> ${t`Behavior settings`} </span>
<div slot="body" class="pf-c-form">
<ak-form-element-horizontal name="compatibilityMode">
<div class="pf-c-check">
<input
type="checkbox"
class="pf-c-check__input"
?checked=${first(this.instance?.compatibilityMode, false)}
/>
<label class="pf-c-check__label"> ${t`Compatibility mode`} </label>
</div>
<p class="pf-c-form__helper-text">
${t`Increases compatibility with password managers and mobile devices.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Denied action`}
?required=${true}
name="deniedAction"
>
<ak-radio
.options=${[
{
label: "MESSAGE_CONTINUE",
value: DeniedActionEnum.MessageContinue,
default: true,
description: html`${t`Will follow the ?next parameter if set, otherwise show a message`}`,
},
{
label: "CONTINUE",
value: DeniedActionEnum.Continue,
description: html`${t`Will either follow the ?next parameter or redirect to the default interface`}`,
},
{
label: "MESSAGE",
value: DeniedActionEnum.Message,
description: html`${t`Will notify the user the flow isn't applicable`}`,
},
]}
.value=${this.instance?.deniedAction}
>
</ak-radio>
<p class="pf-c-form__helper-text">
${t`Decides the response when a policy denies access to this flow for a user.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Policy engine mode`}
?required=${true}
name="policyEngineMode"
>
<ak-radio
.options=${[
{
label: "ANY",
value: PolicyEngineMode.Any,
default: true,
description: html`${t`Any policy must match to grant access`}`,
},
{
label: "ALL",
value: PolicyEngineMode.All,
description: html`${t`All policies must match to grant access`}`,
},
]}
.value=${this.instance?.policyEngineMode}
>
</ak-radio>
</ak-form-element-horizontal>
</div>
</ak-form-group>
<ak-form-group>
<span slot="header"> ${t`Appearance settings`} </span>
<div slot="body" class="pf-c-form">
<ak-form-element-horizontal label=${t`Layout`} ?required=${true} name="layout">
<select class="pf-c-form-control">
<option
value=${LayoutEnum.Stacked}
?selected=${this.instance?.layout === LayoutEnum.Stacked}
>
${LayoutToLabel(LayoutEnum.Stacked)}
</option>
<option
value=${LayoutEnum.ContentLeft}
?selected=${this.instance?.layout === LayoutEnum.ContentLeft}
>
${LayoutToLabel(LayoutEnum.ContentLeft)}
</option>
<option
value=${LayoutEnum.ContentRight}
?selected=${this.instance?.layout === LayoutEnum.ContentRight}
>
${LayoutToLabel(LayoutEnum.ContentRight)}
</option>
<option
value=${LayoutEnum.SidebarLeft}
?selected=${this.instance?.layout === LayoutEnum.SidebarLeft}
>
${LayoutToLabel(LayoutEnum.SidebarLeft)}
</option>
<option
value=${LayoutEnum.SidebarRight}
?selected=${this.instance?.layout === LayoutEnum.SidebarRight}
>
${LayoutToLabel(LayoutEnum.SidebarRight)}
</option>
</select>
</ak-form-element-horizontal>
${until(
config().then((c) => {
if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) {
return html`<ak-form-element-horizontal
label=${t`Background`}
name="background"
>
<input type="file" value="" class="pf-c-form-control" />
${this.instance?.background
? html`
<p class="pf-c-form__helper-text">
${t`Currently set to:`}
${this.instance?.background}
</p>
`
: html``}
<p class="pf-c-form__helper-text">
${t`Background shown during execution.`}
</p>
</ak-form-element-horizontal>
${this.instance?.background
? html`
<ak-form-element-horizontal>
<div class="pf-c-check">
<input
type="checkbox"
class="pf-c-check__input"
@change=${(ev: Event) => {
const target =
ev.target as HTMLInputElement;
this.clearBackground = target.checked;
}}
/>
<label class="pf-c-check__label">
${t`Clear background image`}
</label>
</div>
<p class="pf-c-form__helper-text">
${t`Delete currently set background image.`}
</p>
</ak-form-element-horizontal>
`
: html``}`;
}
return html`<ak-form-element-horizontal
label=${t`Background`}
name="background"
>
<input type="file" value="" class="pf-c-form-control" />
${this.instance?.background
? html`
<p class="pf-c-form__helper-text">
${t`Currently set to:`} ${this.instance?.background}
</p>
`
: html``}
<input
type="text"
value="${first(this.instance?.background, "")}"
class="pf-c-form-control"
/>
<p class="pf-c-form__helper-text">
${t`Background shown during execution.`}
</p>
</ak-form-element-horizontal>
${this.instance?.background
? html`
<ak-form-element-horizontal>
<div class="pf-c-check">
<input
type="checkbox"
class="pf-c-check__input"
@change=${(ev: Event) => {
const target = ev.target as HTMLInputElement;
this.clearBackground = target.checked;
}}
/>
<label class="pf-c-check__label">
${t`Clear background image`}
</label>
</div>
<p class="pf-c-form__helper-text">
${t`Delete currently set background image.`}
</p>
</ak-form-element-horizontal>
`
: html``}`;
}
return html`<ak-form-element-horizontal
label=${t`Background`}
name="background"
>
<input
type="text"
value="${first(this.instance?.background, "")}"
class="pf-c-form-control"
/>
<p class="pf-c-form__helper-text">
${t`Background shown during execution.`}
</p>
</ak-form-element-horizontal>`;
}),
)}
<ak-form-element-horizontal name="compatibilityMode">
<div class="pf-c-check">
<input
type="checkbox"
class="pf-c-check__input"
?checked=${first(this.instance?.compatibilityMode, false)}
/>
<label class="pf-c-check__label"> ${t`Compatibility mode`} </label>
</ak-form-element-horizontal>`;
}),
)}
</div>
<p class="pf-c-form__helper-text">
${t`Enable compatibility mode, increases compatibility with password managers on mobile devices.`}
</p>
</ak-form-element-horizontal>
</ak-form-group>
</form>`;
}
}

View File

@ -26,23 +26,19 @@ export class FlowImportForm extends Form<Flow> {
return super.styles.concat(PFDescriptionList);
}
// eslint-disable-next-line
send = (data: Flow): Promise<FlowImportResult> => {
send = async (): Promise<FlowImportResult> => {
const file = this.getFormFiles()["flow"];
if (!file) {
throw new SentryIgnoredError("No form data");
}
return new FlowsApi(DEFAULT_CONFIG)
.flowsInstancesImportCreate({
file: file,
})
.then((result) => {
if (!result.success) {
this.result = result;
throw new SentryIgnoredError("Failed to import flow");
}
return result;
});
const result = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesImportCreate({
file: file,
});
if (!result.success) {
this.result = result;
throw new SentryIgnoredError("Failed to import flow");
}
return result;
};
renderResult(): TemplateResult {

View File

@ -1,8 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first, groupBy } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -165,35 +166,34 @@ export class StageBindingForm extends ModelForm<FlowStageBinding, string> {
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Invalid response action`}
label=${t`Invalid response behavior`}
?required=${true}
name="invalidResponseAction"
>
<select class="pf-c-form-control">
<option
value=${InvalidResponseActionEnum.Retry}
?selected=${this.instance?.invalidResponseAction ===
InvalidResponseActionEnum.Retry}
>
${t`RETRY returns the error message and a similar challenge to the executor.`}
</option>
<option
value=${InvalidResponseActionEnum.Restart}
?selected=${this.instance?.invalidResponseAction ===
InvalidResponseActionEnum.Restart}
>
${t`RESTART restarts the flow from the beginning.`}
</option>
<option
value=${InvalidResponseActionEnum.RestartWithContext}
?selected=${this.instance?.invalidResponseAction ===
InvalidResponseActionEnum.RestartWithContext}
>
${t`RESTART_WITH_CONTEXT restarts the flow from the beginning, while keeping the flow context.`}
</option>
</select>
<ak-radio
.options=${[
{
label: "RETRY",
value: InvalidResponseActionEnum.Retry,
default: true,
description: html`${t`Returns the error message and a similar challenge to the executor`}`,
},
{
label: "RESTART",
value: InvalidResponseActionEnum.Restart,
description: html`${t`Restarts the flow from the beginning`}`,
},
{
label: "RESTART_WITH_CONTEXT",
value: InvalidResponseActionEnum.RestartWithContext,
description: html`${t`Restarts the flow from the beginning, while keeping the flow context`}`,
},
]}
.value=${this.instance?.invalidResponseAction}
>
</ak-radio>
<p class="pf-c-form__helper-text">
${t`Configure how the flow executor should handle an invalid response to a challenge.`}
${t`Configure how the flow executor should handle an invalid response to a challenge given by this bound stage.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
@ -201,20 +201,23 @@ export class StageBindingForm extends ModelForm<FlowStageBinding, string> {
?required=${true}
name="policyEngineMode"
>
<select class="pf-c-form-control">
<option
value=${PolicyEngineMode.Any}
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.Any}
>
${t`ANY, any policy must match to include this stage access.`}
</option>
<option
value=${PolicyEngineMode.All}
?selected=${this.instance?.policyEngineMode === PolicyEngineMode.All}
>
${t`ALL, all policies must match to include this stage access.`}
</option>
</select>
<ak-radio
.options=${[
{
label: "ANY",
value: PolicyEngineMode.Any,
default: true,
description: html`${t`Any policy must match to grant access`}`,
},
{
label: "ALL",
value: PolicyEngineMode.All,
description: html`${t`All policies must match to grant access`}`,
},
]}
.value=${this.instance?.policyEngineMode}
>
</ak-radio>
</ak-form-element-horizontal>
</form>`;
}

View File

@ -18,6 +18,8 @@ export function DesignationToLabel(designation: FlowDesignationEnum): string {
return t`Stage Configuration`;
case FlowDesignationEnum.Unenrollment:
return t`Unenrollment`;
case FlowDesignationEnum.UnknownDefaultOpenApi:
return t`Unknown designation`;
}
}
@ -33,5 +35,7 @@ export function LayoutToLabel(layout: LayoutEnum): string {
return t`Sidebar left`;
case LayoutEnum.SidebarRight:
return t`Sidebar right`;
case LayoutEnum.UnknownDefaultOpenApi:
return t`Unknown layout`;
}
}

View File

@ -2,11 +2,11 @@ import "@goauthentik/admin/groups/MemberSelectModal";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/chips/Chip";
import "@goauthentik/elements/chips/ChipGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { UserOption } from "@goauthentik/elements/user/utils";
import YAML from "yaml";

View File

@ -32,8 +32,8 @@ export class RelatedGroupAdd extends Form<{ groups: string[] }> {
return t`Successfully added user to group(s).`;
}
send = (data: { groups: string[] }): Promise<{ groups: string[] }> => {
return Promise.all(
send = async (data: { groups: string[] }): Promise<{ groups: string[] }> => {
await Promise.all(
data.groups.map((group) => {
return new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
groupUuid: group,
@ -42,9 +42,8 @@ export class RelatedGroupAdd extends Form<{ groups: string[] }> {
},
});
}),
).then(() => {
return data;
});
);
return data;
};
renderForm(): TemplateResult {

View File

@ -2,9 +2,9 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { docLink } from "@goauthentik/common/global";
import { groupBy } from "@goauthentik/common/utils";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import YAML from "yaml";
import { t } from "@lingui/macro";
@ -107,6 +107,10 @@ export class OutpostForm extends ModelForm<Outpost, string> {
</option>`;
});
});
case OutpostTypeEnum.UnknownDefaultOpenApi:
return Promise.resolve([
html` <option value="">${t`Unknown outpost type`}</option>`,
]);
}
}
@ -166,7 +170,7 @@ export class OutpostForm extends ModelForm<Outpost, string> {
return groupBy(items, (item) => item.verboseName);
}}
.selected=${(item: ServiceConnection, items: ServiceConnection[]): boolean => {
let selected = this.instance?.serviceConnection === sc.pk;
let selected = this.instance?.serviceConnection === item.pk;
if (items.length === 1 && !this.instance) {
selected = true;
}

View File

@ -33,6 +33,8 @@ export function TypeToLabel(type?: OutpostTypeEnum): string {
return t`Proxy`;
case OutpostTypeEnum.Ldap:
return t`LDAP`;
case OutpostTypeEnum.UnknownDefaultOpenApi:
return t`Unknown type`;
}
}

View File

@ -1,8 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -1,8 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first, groupBy } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -2,9 +2,9 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/CodeMirror";
import { PFColor } from "@goauthentik/elements/Label";
import "@goauthentik/elements/SearchSelect";
import { Form } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect";
import YAML from "yaml";
import { t } from "@lingui/macro";
@ -39,14 +39,13 @@ export class PolicyTestForm extends Form<PolicyTestRequest> {
return t`Successfully sent test-request.`;
}
send = (data: PolicyTestRequest): Promise<PolicyTestResult> => {
send = async (data: PolicyTestRequest): Promise<PolicyTestResult> => {
this.request = data;
return new PoliciesApi(DEFAULT_CONFIG)
.policiesAllTestCreate({
policyUuid: this.policy?.pk || "",
policyTestRequest: data,
})
.then((result) => (this.result = result));
const result = await new PoliciesApi(DEFAULT_CONFIG).policiesAllTestCreate({
policyUuid: this.policy?.pk || "",
policyTestRequest: data,
});
return (this.result = result);
};
static get styles(): CSSResult[] {

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/SearchSelect";
import { Form } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect";
import YAML from "yaml";
import { t } from "@lingui/macro";
@ -37,15 +37,14 @@ export class PolicyTestForm extends Form<PolicyTestRequest> {
return t`Successfully sent test-request.`;
}
send = (data: PolicyTestRequest): Promise<PropertyMappingTestResult> => {
send = async (data: PolicyTestRequest): Promise<PropertyMappingTestResult> => {
this.request = data;
return new PropertymappingsApi(DEFAULT_CONFIG)
.propertymappingsAllTestCreate({
pmUuid: this.mapping?.pk || "",
policyTestRequest: data,
formatResult: true,
})
.then((result) => (this.result = result));
const result = await new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsAllTestCreate({
pmUuid: this.mapping?.pk || "",
policyTestRequest: data,
formatResult: true,
});
return (this.result = result);
};
renderResult(): TemplateResult {

View File

@ -1,9 +1,10 @@
import { DEFAULT_CONFIG, tenant } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -146,44 +147,49 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Bind mode`} name="bindMode">
<select class="pf-c-form-control">
<option
value="${LDAPAPIAccessMode.Cached}"
?selected=${this.instance?.bindMode === LDAPAPIAccessMode.Cached}
>
${t`Cached binding, flow is executed and session is cached in memory. Flow is executed when session expires.`}
</option>
<option
value="${LDAPAPIAccessMode.Direct}"
?selected=${this.instance?.bindMode === LDAPAPIAccessMode.Direct}
>
${t`Direct binding, always execute the configured bind flow to authenticate the user.`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`Cached binding`,
value: LDAPAPIAccessMode.Cached,
default: true,
description: html`${t`Flow is executed and session is cached in memory. Flow is executed when session expires`}`,
},
{
label: t`Direct binding`,
value: LDAPAPIAccessMode.Direct,
description: html`${t`Always execute the configured bind flow to authenticate the user`}`,
},
]}
.value=${this.instance?.bindMode}
>
</ak-radio>
<p class="pf-c-form__helper-text">
${t`Configure how the outpost authenticates requests.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Search mode`} name="searchMode">
<select class="pf-c-form-control">
<option
value="${LDAPAPIAccessMode.Cached}"
?selected=${this.instance?.searchMode === LDAPAPIAccessMode.Cached}
>
${t`Cached querying, the outpost holds all users and groups in-memory and will refresh every 5 Minutes.`}
</option>
<option
value="${LDAPAPIAccessMode.Direct}"
?selected=${this.instance?.searchMode === LDAPAPIAccessMode.Direct}
>
${t`Direct querying, always returns the latest data, but slower than cached querying.`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`Cached querying`,
value: LDAPAPIAccessMode.Cached,
default: true,
description: html`${t`The outpost holds all users and groups in-memory and will refresh every 5 Minutes`}`,
},
{
label: t`Direct querying`,
value: LDAPAPIAccessMode.Direct,
description: html`${t`Always returns the latest data, but slower than cached querying`}`,
},
]}
.value=${this.instance?.searchMode}
>
</ak-radio>
<p class="pf-c-form__helper-text">
${t`Configure how the outpost queries the core authentik server's users.`}
</p>
</ak-form-element-horizontal>
<ak-form-group .expanded=${true}>
<span slot="header"> ${t`Protocol settings`} </span>
<div slot="body" class="pf-c-form">

View File

@ -1,9 +1,10 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first, randomString } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import "@goauthentik/elements/utils/TimeDeltaHelp";
import { t } from "@lingui/macro";
@ -365,21 +366,21 @@ ${this.instance?.redirectUris}</textarea
?required=${true}
name="issuerMode"
>
<select class="pf-c-form-control">
<option
value="${IssuerModeEnum.PerProvider}"
?selected=${this.instance?.issuerMode ===
IssuerModeEnum.PerProvider}
>
${t`Each provider has a different issuer, based on the application slug.`}
</option>
<option
value="${IssuerModeEnum.Global}"
?selected=${this.instance?.issuerMode === IssuerModeEnum.Global}
>
${t`Same identifier is used for all providers`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`Each provider has a different issuer, based on the application slug`,
value: IssuerModeEnum.PerProvider,
default: true,
},
{
label: t`Same identifier is used for all providers`,
value: IssuerModeEnum.Global,
},
]}
.value=${this.instance?.issuerMode}
>
</ak-radio>
<p class="pf-c-form__helper-text">
${t`Configure how the issuer field of the ID Token should be filled.`}
</p>

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import "@goauthentik/elements/utils/TimeDeltaHelp";
import { t } from "@lingui/macro";
@ -279,6 +279,8 @@ export class ProxyProviderFormPage extends ModelForm<ProxyProvider, number> {
${t`Set this to the domain you wish the authentication to be valid for. Must be a parent domain of the URL above. If you're running applications as app1.domain.tld, app2.domain.tld, set this to 'domain.tld'.`}
</p>
</ak-form-element-horizontal>`;
case ProxyMode.UnknownDefaultOpenApi:
return html`<p>${t`Unknown proxy mode`}</p>`;
}
}

View File

@ -47,6 +47,8 @@ export function ModeToLabel(action?: ProxyMode): string {
return t`Forward auth (single application)`;
case ProxyMode.ForwardDomain:
return t`Forward auth (domain-level)`;
case ProxyMode.UnknownDefaultOpenApi:
return t`Unknown proxy mode`;
}
}
@ -57,6 +59,8 @@ export function isForward(mode: ProxyMode): boolean {
case ProxyMode.ForwardSingle:
case ProxyMode.ForwardDomain:
return true;
case ProxyMode.UnknownDefaultOpenApi:
return false;
}
}

View File

@ -1,8 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import "@goauthentik/elements/utils/TimeDeltaHelp";
import { t } from "@lingui/macro";
@ -130,20 +131,21 @@ export class SAMLProviderFormPage extends ModelForm<SAMLProvider, number> {
?required=${true}
name="spBinding"
>
<select class="pf-c-form-control">
<option
value=${SpBindingEnum.Redirect}
?selected=${this.instance?.spBinding === SpBindingEnum.Redirect}
>
${t`Redirect`}
</option>
<option
value=${SpBindingEnum.Post}
?selected=${this.instance?.spBinding === SpBindingEnum.Post}
>
${t`Post`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`Redirect`,
value: SpBindingEnum.Redirect,
default: true,
},
{
label: t`Post`,
value: SpBindingEnum.Post,
},
]}
.value=${this.instance?.spBinding}
>
</ak-radio>
<p class="pf-c-form__helper-text">
${t`Determines how authentik sends the response back to the Service Provider.`}
</p>
@ -366,81 +368,62 @@ export class SAMLProviderFormPage extends ModelForm<SAMLProvider, number> {
?required=${true}
name="digestAlgorithm"
>
<select class="pf-c-form-control">
<option
value=${DigestAlgorithmEnum._200009Xmldsigsha1}
?selected=${this.instance?.digestAlgorithm ===
DigestAlgorithmEnum._200009Xmldsigsha1}
>
${t`SHA1`}
</option>
<option
value=${DigestAlgorithmEnum._200104Xmlencsha256}
?selected=${this.instance?.digestAlgorithm ===
DigestAlgorithmEnum._200104Xmlencsha256 ||
this.instance?.digestAlgorithm === undefined}
>
${t`SHA256`}
</option>
<option
value=${DigestAlgorithmEnum._200104XmldsigMoresha384}
?selected=${this.instance?.digestAlgorithm ===
DigestAlgorithmEnum._200104XmldsigMoresha384}
>
${t`SHA384`}
</option>
<option
value=${DigestAlgorithmEnum._200104Xmlencsha512}
?selected=${this.instance?.digestAlgorithm ===
DigestAlgorithmEnum._200104Xmlencsha512}
>
${t`SHA512`}
</option>
</select>
<ak-radio
.options=${[
{
label: "SHA1",
value: DigestAlgorithmEnum._200009Xmldsigsha1,
},
{
label: "SHA256",
value: DigestAlgorithmEnum._200104Xmlencsha256,
default: true,
},
{
label: "SHA384",
value: DigestAlgorithmEnum._200104XmldsigMoresha384,
},
{
label: "SHA512",
value: DigestAlgorithmEnum._200104Xmlencsha512,
},
]}
.value=${this.instance?.digestAlgorithm}
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Signature algorithm`}
?required=${true}
name="signatureAlgorithm"
>
<select class="pf-c-form-control">
<option
value=${SignatureAlgorithmEnum._200009XmldsigrsaSha1}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200009XmldsigrsaSha1}
>
${t`RSA-SHA1`}
</option>
<option
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha256}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200104XmldsigMorersaSha256 ||
this.instance?.signatureAlgorithm === undefined}
>
${t`RSA-SHA256`}
</option>
<option
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha384}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200104XmldsigMorersaSha384}
>
${t`RSA-SHA384`}
</option>
<option
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha512}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200104XmldsigMorersaSha512}
>
${t`RSA-SHA512`}
</option>
<option
value=${SignatureAlgorithmEnum._200009XmldsigdsaSha1}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200009XmldsigdsaSha1}
>
${t`DSA-SHA1`}
</option>
</select>
<ak-radio
.options=${[
{
label: "RSA-SHA1",
value: SignatureAlgorithmEnum._200009XmldsigrsaSha1,
},
{
label: "RSA-SHA256",
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha256,
default: true,
},
{
label: "RSA-SHA384",
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha384,
},
{
label: "RSA-SHA512",
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha512,
},
{
label: "DSA-SHA1",
value: SignatureAlgorithmEnum._200009XmldsigdsaSha1,
},
]}
.value=${this.instance?.signatureAlgorithm}
>
</ak-radio>
</ak-form-element-horizontal>
</div>
</ak-form-group>

View File

@ -1,8 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { SentryIgnoredError } from "@goauthentik/common/errors";
import "@goauthentik/elements/SearchSelect";
import { Form } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -24,7 +24,6 @@ export class SAMLProviderImportForm extends Form<SAMLProvider> {
return t`Successfully imported provider.`;
}
// eslint-disable-next-line
send = (data: SAMLProvider): Promise<void> => {
const file = this.getFormFiles()["metadata"];
if (!file) {
@ -66,7 +65,7 @@ export class SAMLProviderImportForm extends Form<SAMLProvider> {
return html`${flow.name}`;
}}
.value=${(flow: Flow | undefined): string | undefined => {
return flow?.pk;
return flow?.slug;
}}
>
</ak-search-select>

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -2,10 +2,10 @@ import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -27,8 +27,9 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { OAuthSource, ProviderTypeEnum, SourcesApi } from "@goauthentik/api";
export function ProviderToLabel(provider?: ProviderTypeEnum): string {
if (!provider) return "";
switch (provider) {
case undefined:
return "";
case ProviderTypeEnum.Apple:
return "Apple";
case ProviderTypeEnum.Azuread:
@ -51,6 +52,10 @@ export function ProviderToLabel(provider?: ProviderTypeEnum): string {
return "Reddit";
case ProviderTypeEnum.Twitter:
return "Twitter";
case ProviderTypeEnum.Twitch:
return "Twitch";
case ProviderTypeEnum.UnknownDefaultOpenApi:
return t`Unknown provider type`;
}
}

View File

@ -15,5 +15,7 @@ export function UserMatchingModeToLabel(mode?: UserMatchingModeEnum): string {
return t`Link to a user with identical username. Can have security implications when a username is used with another source`;
case UserMatchingModeEnum.UsernameDeny:
return t`Use the user's username, but deny enrollment when the username already exists`;
case UserMatchingModeEnum.UnknownDefaultOpenApi:
return t`Unknown user matching mode`;
}
}

View File

@ -2,10 +2,10 @@ import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
import { first, randomString } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -4,6 +4,7 @@ import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/utils/TimeDeltaHelp";
import { t } from "@lingui/macro";
@ -242,26 +243,26 @@ export class SAMLSourceForm extends ModelForm<SAMLSource, string> {
?required=${true}
name="bindingType"
>
<select class="pf-c-form-control">
<option
value=${BindingTypeEnum.Redirect}
?selected=${this.instance?.bindingType === BindingTypeEnum.Redirect}
>
${t`Redirect binding`}
</option>
<option
value=${BindingTypeEnum.PostAuto}
?selected=${this.instance?.bindingType === BindingTypeEnum.PostAuto}
>
${t`Post binding (auto-submit)`}
</option>
<option
value=${BindingTypeEnum.Post}
?selected=${this.instance?.bindingType === BindingTypeEnum.Post}
>
${t`Post binding`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`Redirect binding`,
value: BindingTypeEnum.Redirect,
default: true,
},
{
label: t`Post-auto binding`,
value: BindingTypeEnum.PostAuto,
description: html`${t`Post binding but the request is automatically sent and the user doesn't have to confirm.`}`,
},
{
label: t`Post binding`,
value: BindingTypeEnum.Post,
},
]}
.value=${this.instance?.bindingType}
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Signing keypair`} name="signingKp">
<ak-search-select
@ -394,81 +395,62 @@ export class SAMLSourceForm extends ModelForm<SAMLSource, string> {
?required=${true}
name="digestAlgorithm"
>
<select class="pf-c-form-control">
<option
value=${DigestAlgorithmEnum._200009Xmldsigsha1}
?selected=${this.instance?.digestAlgorithm ===
DigestAlgorithmEnum._200009Xmldsigsha1}
>
${t`SHA1`}
</option>
<option
value=${DigestAlgorithmEnum._200104Xmlencsha256}
?selected=${this.instance?.digestAlgorithm ===
DigestAlgorithmEnum._200104Xmlencsha256 ||
this.instance?.digestAlgorithm === undefined}
>
${t`SHA256`}
</option>
<option
value=${DigestAlgorithmEnum._200104XmldsigMoresha384}
?selected=${this.instance?.digestAlgorithm ===
DigestAlgorithmEnum._200104XmldsigMoresha384}
>
${t`SHA384`}
</option>
<option
value=${DigestAlgorithmEnum._200104Xmlencsha512}
?selected=${this.instance?.digestAlgorithm ===
DigestAlgorithmEnum._200104Xmlencsha512}
>
${t`SHA512`}
</option>
</select>
<ak-radio
.options=${[
{
label: "SHA1",
value: DigestAlgorithmEnum._200009Xmldsigsha1,
},
{
label: "SHA256",
value: DigestAlgorithmEnum._200104Xmlencsha256,
default: true,
},
{
label: "SHA384",
value: DigestAlgorithmEnum._200104XmldsigMoresha384,
},
{
label: "SHA512",
value: DigestAlgorithmEnum._200104Xmlencsha512,
},
]}
.value=${this.instance?.digestAlgorithm}
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Signature algorithm`}
?required=${true}
name="signatureAlgorithm"
>
<select class="pf-c-form-control">
<option
value=${SignatureAlgorithmEnum._200009XmldsigrsaSha1}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200009XmldsigrsaSha1}
>
${t`RSA-SHA1`}
</option>
<option
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha256}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200104XmldsigMorersaSha256 ||
this.instance?.signatureAlgorithm === undefined}
>
${t`RSA-SHA256`}
</option>
<option
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha384}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200104XmldsigMorersaSha384}
>
${t`RSA-SHA384`}
</option>
<option
value=${SignatureAlgorithmEnum._200104XmldsigMorersaSha512}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200104XmldsigMorersaSha512}
>
${t`RSA-SHA512`}
</option>
<option
value=${SignatureAlgorithmEnum._200009XmldsigdsaSha1}
?selected=${this.instance?.signatureAlgorithm ===
SignatureAlgorithmEnum._200009XmldsigdsaSha1}
>
${t`DSA-SHA1`}
</option>
</select>
<ak-radio
.options=${[
{
label: "RSA-SHA1",
value: SignatureAlgorithmEnum._200009XmldsigrsaSha1,
},
{
label: "RSA-SHA256",
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha256,
default: true,
},
{
label: "RSA-SHA384",
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha384,
},
{
label: "RSA-SHA512",
value: SignatureAlgorithmEnum._200104XmldsigMorersaSha512,
},
{
label: "DSA-SHA1",
value: SignatureAlgorithmEnum._200009XmldsigdsaSha1,
},
]}
.value=${this.instance?.signatureAlgorithm}
>
</ak-radio>
</ak-form-element-horizontal>
</div>
</ak-form-group>

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -1,11 +1,11 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { MessageLevel } from "@goauthentik/common/messages";
import "@goauthentik/elements/Divider";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModalForm } from "@goauthentik/elements/forms/ModalForm";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
import { t } from "@lingui/macro";

View File

@ -1,9 +1,10 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -106,20 +107,21 @@ export class AuthenticatorSMSStageForm extends ModelForm<AuthenticatorSMSStage,
?required=${true}
name="authType"
>
<select class="pf-c-form-control">
<option
value="${AuthTypeEnum.Basic}"
?selected=${this.instance?.authType === AuthTypeEnum.Basic}
>
${t`Basic Auth`}
</option>
<option
value="${AuthTypeEnum.Bearer}"
?selected=${this.instance?.authType === AuthTypeEnum.Bearer}
>
${t`Bearer Token`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`Basic Auth`,
value: AuthTypeEnum.Basic,
default: true,
},
{
label: t`Bearer Token`,
value: AuthTypeEnum.Bearer,
},
]}
.value=${this.instance?.authType}
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`External API URL`}

View File

@ -1,8 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -1,8 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -2,6 +2,7 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/utils/TimeDeltaHelp";
import { t } from "@lingui/macro";
@ -188,29 +189,25 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
?required=${true}
name="webauthnUserVerification"
>
<select class="pf-c-form-control">
<option
value="${UserVerificationEnum.Required}"
?selected=${this.instance?.webauthnUserVerification ===
UserVerificationEnum.Required}
>
${t`User verification must occur.`}
</option>
<option
value="${UserVerificationEnum.Preferred}"
?selected=${this.instance?.webauthnUserVerification ===
UserVerificationEnum.Preferred}
>
${t`User verification is preferred if available, but not required.`}
</option>
<option
value="${UserVerificationEnum.Discouraged}"
?selected=${this.instance?.webauthnUserVerification ===
UserVerificationEnum.Discouraged}
>
${t`User verification should not occur.`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`User verification must occur.`,
value: UserVerificationEnum.Required,
default: true,
},
{
label: t`User verification is preferred if available, but not required.`,
value: UserVerificationEnum.Preferred,
},
{
label: t`User verification should not occur.`,
value: UserVerificationEnum.Discouraged,
},
]}
.value=${this.instance?.webauthnUserVerification}
>
</ak-radio>
</ak-form-element-horizontal>
${this.showConfigurationStages
? html`

View File

@ -1,7 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -74,86 +75,75 @@ export class AuthenticateWebAuthnStageForm extends ModelForm<AuthenticateWebAuth
?required=${true}
name="userVerification"
>
<select class="pf-c-form-control">
<option
value="${UserVerificationEnum.Required}"
?selected=${this.instance?.userVerification ===
UserVerificationEnum.Required}
>
${t`User verification must occur.`}
</option>
<option
value="${UserVerificationEnum.Preferred}"
?selected=${this.instance?.userVerification ===
UserVerificationEnum.Preferred}
>
${t`User verification is preferred if available, but not required.`}
</option>
<option
value="${UserVerificationEnum.Discouraged}"
?selected=${this.instance?.userVerification ===
UserVerificationEnum.Discouraged}
>
${t`User verification should not occur.`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`User verification must occur.`,
value: UserVerificationEnum.Required,
default: true,
},
{
label: t`User verification is preferred if available, but not required.`,
value: UserVerificationEnum.Preferred,
},
{
label: t`User verification should not occur.`,
value: UserVerificationEnum.Discouraged,
},
]}
.value=${this.instance?.userVerification}
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Resident key requirement`}
?required=${true}
name="residentKeyRequirement"
>
<select class="pf-c-form-control">
<option
value="${ResidentKeyRequirementEnum.Discouraged}"
?selected=${this.instance?.residentKeyRequirement ===
ResidentKeyRequirementEnum.Discouraged}
>
${t`The authenticator should not create a dedicated credential`}
</option>
<option
value="${ResidentKeyRequirementEnum.Preferred}"
?selected=${this.instance?.residentKeyRequirement ===
ResidentKeyRequirementEnum.Preferred}
>
${t`The authenticator can create and store a dedicated credential, but if it doesn't that's alright too`}
</option>
<option
value="${ResidentKeyRequirementEnum.Required}"
?selected=${this.instance?.residentKeyRequirement ===
ResidentKeyRequirementEnum.Required}
>
${t`The authenticator MUST create a dedicated credential. If it cannot, the RP is prepared for an error to occur`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`The authenticator should not create a dedicated credential`,
value: ResidentKeyRequirementEnum.Required,
default: true,
},
{
label: t`The authenticator can create and store a dedicated credential, but if it doesn't that's alright too`,
value: ResidentKeyRequirementEnum.Preferred,
},
{
label: t`The authenticator MUST create a dedicated credential. If it cannot, the RP is prepared for an error to occur`,
value: ResidentKeyRequirementEnum.Discouraged,
},
]}
.value=${this.instance?.residentKeyRequirement}
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Authenticator Attachment`}
?required=${true}
name="authenticatorAttachment"
>
<select class="pf-c-form-control">
<option
value=""
?selected=${this.instance?.authenticatorAttachment === null}
>
${t`No preference is sent`}
</option>
<option
value="${AuthenticatorAttachmentEnum.Platform}"
?selected=${this.instance?.authenticatorAttachment ===
AuthenticatorAttachmentEnum.Platform}
>
${t`A non-removable authenticator, like TouchID or Windows Hello`}
</option>
<option
value="${AuthenticatorAttachmentEnum.CrossPlatform}"
?selected=${this.instance?.authenticatorAttachment ===
AuthenticatorAttachmentEnum.CrossPlatform}
>
${t`A "roaming" authenticator, like a YubiKey`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`No preference is sent`,
value: null,
default: true,
},
{
label: t`A non-removable authenticator, like TouchID or Windows Hello`,
value: AuthenticatorAttachmentEnum.Platform,
},
{
label: t`A "roaming" authenticator, like a YubiKey`,
value: AuthenticatorAttachmentEnum.CrossPlatform,
},
]}
.value=${this.instance?.authenticatorAttachment}
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Configuration flow`} name="configureFlow">
<ak-search-select

View File

@ -1,4 +1,5 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
@ -52,6 +53,16 @@ export class DummyStageForm extends ModelForm<DummyStage, string> {
required
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal name="throwError">
<div class="pf-c-check">
<input
type="checkbox"
class="pf-c-check__input"
?checked=${first(this.instance?.throwError, false)}
/>
<label class="pf-c-check__label"> ${t`Throw error?`} </label>
</div>
</ak-form-element-horizontal>
</form>`;
}
}

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first, groupBy } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -154,6 +154,24 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
${t`When enabled, user fields are matched regardless of their casing.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal name="showMatchedUser">
<div class="pf-c-check">
<input
type="checkbox"
class="pf-c-check__input"
?checked=${first(this.instance?.showMatchedUser, true)}
/>
<label class="pf-c-check__label"> ${t`Show matched user`} </label>
</div>
<p class="pf-c-form__helper-text">
${t`When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown.`}
</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>
<ak-form-group>
<span slot="header"> ${t`Source settings`} </span>
<div slot="body" class="pf-c-form">
<ak-form-element-horizontal
label=${t`Sources`}
?required=${true}
@ -210,19 +228,6 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
${t`By default, only icons are shown for sources. Enable this to show their full names.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal name="showMatchedUser">
<div class="pf-c-check">
<input
type="checkbox"
class="pf-c-check__input"
?checked=${first(this.instance?.showMatchedUser, true)}
/>
<label class="pf-c-check__label"> ${t`Show matched user`} </label>
</div>
<p class="pf-c-form__helper-text">
${t`When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown.`}
</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>
<ak-form-group>

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { dateTimeLocal, first } from "@goauthentik/common/utils";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import YAML from "yaml";
import { t } from "@lingui/macro";

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

View File

@ -1,10 +1,10 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { DefaultTenant } from "@goauthentik/elements/sidebar/SidebarBrand";
import YAML from "yaml";

View File

@ -1,9 +1,10 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { dateTimeLocal, first } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";
@ -82,20 +83,23 @@ export class TokenForm extends ModelForm<Token, string> {
</ak-search-select>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Intent`} ?required=${true} name="intent">
<select class="pf-c-form-control">
<option
value=${IntentEnum.Api}
?selected=${this.instance?.intent === IntentEnum.Api}
>
${t`API Token (can be used to access the API programmatically)`}
</option>
<option
value=${IntentEnum.AppPassword}
?selected=${this.instance?.intent === IntentEnum.AppPassword}
>
${t`App password (can be used to login using a flow executor)`}
</option>
</select>
<ak-radio
.options=${[
{
label: t`API Token`,
value: IntentEnum.Api,
default: true,
description: html`${t`Used to access the API programmatically`}`,
},
{
label: t`App password.`,
value: IntentEnum.AppPassword,
description: html`${t`Used to login using a flow executor`}`,
},
]}
.value=${this.instance?.intent}
>
</ak-radio>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Description`} name="description">
<input

View File

@ -27,6 +27,8 @@ export function IntentToLabel(intent: IntentEnum): string {
return t`Recovery`;
case IntentEnum.Verification:
return t`Verification`;
case IntentEnum.UnknownDefaultOpenApi:
return t`Unknown intent`;
}
}

View File

@ -44,8 +44,8 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
return t`Successfully added user(s).`;
}
send = (data: { users: number[] }): Promise<{ users: number[] }> => {
return Promise.all(
send = async (data: { users: number[] }): Promise<{ users: number[] }> => {
await Promise.all(
data.users.map((user) => {
return new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
groupUuid: this.group?.pk || "",
@ -54,9 +54,8 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
},
});
}),
).then(() => {
return data;
});
);
return data;
};
renderForm(): TemplateResult {

View File

@ -20,16 +20,13 @@ export class ServiceAccountForm extends Form<UserServiceAccountRequest> {
return t`Successfully created user.`;
}
send = (data: UserServiceAccountRequest): Promise<UserServiceAccountResponse> => {
return new CoreApi(DEFAULT_CONFIG)
.coreUsersServiceAccountCreate({
userServiceAccountRequest: data,
})
.then((result) => {
this.result = result;
(this.parentElement as ModalForm).showSubmitButton = false;
return result;
});
send = async (data: UserServiceAccountRequest): Promise<UserServiceAccountResponse> => {
const result = await new CoreApi(DEFAULT_CONFIG).coreUsersServiceAccountCreate({
userServiceAccountRequest: data,
});
this.result = result;
(this.parentElement as ModalForm).showSubmitButton = false;
return result;
};
resetForm(): void {

View File

@ -1,8 +1,8 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { groupBy } from "@goauthentik/common/utils";
import "@goauthentik/elements/SearchSelect";
import { Form } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect";
import { t } from "@lingui/macro";

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