Merge branch 'master' into inbuilt-proxy
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> # Conflicts: # internal/constants/constants.go # outpost/pkg/version.go
|
@ -1,5 +1,5 @@
|
|||
[bumpversion]
|
||||
current_version = 2021.6.1-rc6
|
||||
current_version = 2021.6.2
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*)
|
||||
|
|
|
@ -6,6 +6,7 @@ daysUntilClose: 7
|
|||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
- pr_wanted
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
|
|
|
@ -33,22 +33,21 @@ jobs:
|
|||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik:2021.6.1-rc6,
|
||||
beryju/authentik:2021.6.2,
|
||||
beryju/authentik:latest,
|
||||
ghcr.io/goauthentik/server:2021.6.1-rc6,
|
||||
ghcr.io/goauthentik/server:2021.6.2,
|
||||
ghcr.io/goauthentik/server:latest
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
- name: Building Docker Image (stable)
|
||||
uses: docker/build-push-action@v2
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.1-rc6', 'rc') }}
|
||||
with:
|
||||
push: true
|
||||
tags: |
|
||||
beryju/authentik:stable,
|
||||
ghcr.io/goauthentik/server:stable
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.2', 'rc') }}
|
||||
run: |
|
||||
docker pull beryju/authentik:latest
|
||||
docker tag beryju/authentik:latest beryju/authentik:stable
|
||||
docker push beryju/authentik:stable
|
||||
docker pull ghcr.io/goauthentik/server:latest
|
||||
docker tag ghcr.io/goauthentik/server:latest ghcr.io/goauthentik/server:stable
|
||||
docker push ghcr.io/goauthentik/server:stable
|
||||
build-proxy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@ -76,22 +75,21 @@ jobs:
|
|||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-proxy:2021.6.1-rc6,
|
||||
beryju/authentik-proxy:2021.6.2,
|
||||
beryju/authentik-proxy:latest,
|
||||
ghcr.io/goauthentik/proxy:2021.6.1-rc6,
|
||||
ghcr.io/goauthentik/proxy:2021.6.2,
|
||||
ghcr.io/goauthentik/proxy:latest
|
||||
file: proxy.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: Building Docker Image (stable)
|
||||
uses: docker/build-push-action@v2
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.1-rc6', 'rc') }}
|
||||
with:
|
||||
push: true
|
||||
tags: |
|
||||
beryju/authentik-proxy:stable,
|
||||
ghcr.io/goauthentik/proxy:stable
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.2', 'rc') }}
|
||||
run: |
|
||||
docker pull beryju/authentik-proxy:latest
|
||||
docker tag beryju/authentik-proxy:latest beryju/authentik-proxy:stable
|
||||
docker push beryju/authentik-proxy:stable
|
||||
docker pull ghcr.io/goauthentik/proxy:latest
|
||||
docker tag ghcr.io/goauthentik/proxy:latest ghcr.io/goauthentik/proxy:stable
|
||||
docker push ghcr.io/goauthentik/proxy:stable
|
||||
build-ldap:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@ -119,24 +117,22 @@ jobs:
|
|||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-ldap:2021.6.1-rc6,
|
||||
beryju/authentik-ldap:2021.6.2,
|
||||
beryju/authentik-ldap:latest,
|
||||
ghcr.io/goauthentik/ldap:2021.6.1-rc6,
|
||||
ghcr.io/goauthentik/ldap:2021.6.2,
|
||||
ghcr.io/goauthentik/ldap:latest
|
||||
file: ldap.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: Building Docker Image (stable)
|
||||
uses: docker/build-push-action@v2
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.1-rc6', 'rc') }}
|
||||
with:
|
||||
push: true
|
||||
tags: |
|
||||
beryju/authentik-ldap:stable,
|
||||
ghcr.io/goauthentik/ldap:stable
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.2', 'rc') }}
|
||||
run: |
|
||||
docker pull beryju/authentik-ldap:latest
|
||||
docker tag beryju/authentik-ldap:latest beryju/authentik-ldap:stable
|
||||
docker push beryju/authentik-ldap:stable
|
||||
docker pull ghcr.io/goauthentik/ldap:latest
|
||||
docker tag ghcr.io/goauthentik/ldap:latest ghcr.io/goauthentik/ldap:stable
|
||||
docker push ghcr.io/goauthentik/ldap:stable
|
||||
test-release:
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
needs:
|
||||
- build-server
|
||||
- build-proxy
|
||||
|
@ -160,13 +156,26 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v2.1.5
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Build web api client and web ui
|
||||
run: |
|
||||
export NODE_ENV=production
|
||||
make gen-web
|
||||
cd web
|
||||
npm i
|
||||
npm run build
|
||||
- name: Create a Sentry.io release
|
||||
uses: getsentry/action-release@v1
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: beryjuorg
|
||||
SENTRY_PROJECT: authentik
|
||||
SENTRY_URL: https://sentry.beryju.org
|
||||
with:
|
||||
version: authentik@2021.6.1-rc6
|
||||
version: authentik@2021.6.2
|
||||
environment: beryjuorg-prod
|
||||
sourcemaps: './web/dist'
|
||||
|
|
1
Pipfile
|
@ -46,6 +46,7 @@ webauthn = "*"
|
|||
xmlsec = "*"
|
||||
duo-client = "*"
|
||||
ua-parser = "*"
|
||||
deepmerge = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "4fa1ad681762c867a95410074f31ac5d00119e187e0f38982cd59fdf301cccf5"
|
||||
"sha256": "f90d9fb4713eaf9c5ffe6a3858e64843670f79ab5007e7debf914c1f094c8d63"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -122,19 +122,19 @@
|
|||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:8e5af9c7ea16ce1c35b7c3220d073dea9735bb1790107820d475462500ae1eff",
|
||||
"sha256:e61607211816c194dbe2701db48dcddc87cf19372e6f57a9ebe4dfe93dfe177c"
|
||||
"sha256:2c2f70608934b03f9c08f4cd185de223b5abd18245dd4d4800e1fbc2a2523e31",
|
||||
"sha256:fccfa81cda69bb2317ed97e7149d7d84d19e6ec3bfbe3f721139e7ac0c407c73"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.17.95"
|
||||
"version": "==1.17.98"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:240a9ef007292e986a4e11662f9038435d9d4fd242e083db160c86eb5c24af30",
|
||||
"sha256:dc215f59735a3abde6c66a61f43f10d95bc18754d310da4e2037b3b8c4d8aa2d"
|
||||
"sha256:b2a49de4ee04b690142c8e7240f0f5758e3f7673dd39cf398efe893bf5e11c3f",
|
||||
"sha256:b955b23fe2fbdbbc8e66f37fe2970de6b5d8169f940b200bcf434751709d38f6"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.20.95"
|
||||
"version": "==1.20.98"
|
||||
},
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
|
@ -165,11 +165,11 @@
|
|||
},
|
||||
"celery": {
|
||||
"hashes": [
|
||||
"sha256:1329de1edeaf734ef859e630cb42df2c116d53e59d2f46433b13aed196e85620",
|
||||
"sha256:65f061c04578cf189cd7352c192e1a79fdeb370b916bff792bcc769560e81184"
|
||||
"sha256:54436cd97b031bf2e08064223240e2a83d601d9414bcb1b702f94c6c33c29485",
|
||||
"sha256:b5399d76cf70d5cfac3ec993f8796ec1aa90d4cef55972295751f384758a80d7"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.1.0"
|
||||
"version": "==5.1.1"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
|
@ -324,6 +324,14 @@
|
|||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.2"
|
||||
},
|
||||
"deepmerge": {
|
||||
"hashes": [
|
||||
"sha256:87166dbe9ba1a3348a45c9d4ada6778f518d41afc0b85aa017ea3041facc3f9c",
|
||||
"sha256:f6fd7f1293c535fb599e197e750dbe8674503c5d2a89759b3c72a3c46746d4fd"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.3.0"
|
||||
},
|
||||
"defusedxml": {
|
||||
"hashes": [
|
||||
"sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69",
|
||||
|
@ -465,11 +473,11 @@
|
|||
},
|
||||
"google-auth": {
|
||||
"hashes": [
|
||||
"sha256:154f7889c5d679a6f626f36adb12afbd4dbb0a9a04ec575d989d6ba79c4fd65e",
|
||||
"sha256:6d47c79b5d09fbc7e8355fd9594cc4cf65fdde5d401c63951eaac4baa1ba2ae1"
|
||||
"sha256:b3a67fa9ba5b768861dacf374c2135eb09fa14a0e40c851c3b8ea7abe6fc8fef",
|
||||
"sha256:e34e5f5de5610b202f9b40ebd9f8b27571d5c5537db9afed3a72b2db5a345039"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.31.0"
|
||||
"version": "==1.32.0"
|
||||
},
|
||||
"gunicorn": {
|
||||
"hashes": [
|
||||
|
@ -786,52 +794,46 @@
|
|||
},
|
||||
"prompt-toolkit": {
|
||||
"hashes": [
|
||||
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
|
||||
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
|
||||
"sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f",
|
||||
"sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.1'",
|
||||
"version": "==3.0.18"
|
||||
"version": "==3.0.19"
|
||||
},
|
||||
"psycopg2-binary": {
|
||||
"hashes": [
|
||||
"sha256:0deac2af1a587ae12836aa07970f5cb91964f05a7c6cdb69d8425ff4c15d4e2c",
|
||||
"sha256:0e4dc3d5996760104746e6cfcdb519d9d2cd27c738296525d5867ea695774e67",
|
||||
"sha256:11b9c0ebce097180129e422379b824ae21c8f2a6596b159c7659e2e5a00e1aa0",
|
||||
"sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6",
|
||||
"sha256:1fabed9ea2acc4efe4671b92c669a213db744d2af8a9fc5d69a8e9bc14b7a9db",
|
||||
"sha256:2dac98e85565d5688e8ab7bdea5446674a83a3945a8f416ad0110018d1501b94",
|
||||
"sha256:42ec1035841b389e8cc3692277a0bd81cdfe0b65d575a2c8862cec7a80e62e52",
|
||||
"sha256:6422f2ff0919fd720195f64ffd8f924c1395d30f9a495f31e2392c2efafb5056",
|
||||
"sha256:6a32f3a4cb2f6e1a0b15215f448e8ce2da192fd4ff35084d80d5e39da683e79b",
|
||||
"sha256:7312e931b90fe14f925729cde58022f5d034241918a5c4f9797cac62f6b3a9dd",
|
||||
"sha256:7d92a09b788cbb1aec325af5fcba9fed7203897bbd9269d5691bb1e3bce29550",
|
||||
"sha256:833709a5c66ca52f1d21d41865a637223b368c0ee76ea54ca5bad6f2526c7679",
|
||||
"sha256:89705f45ce07b2dfa806ee84439ec67c5d9a0ef20154e0e475e2b2ed392a5b83",
|
||||
"sha256:8cd0fb36c7412996859cb4606a35969dd01f4ea34d9812a141cd920c3b18be77",
|
||||
"sha256:950bc22bb56ee6ff142a2cb9ee980b571dd0912b0334aa3fe0fe3788d860bea2",
|
||||
"sha256:a0c50db33c32594305b0ef9abc0cb7db13de7621d2cadf8392a1d9b3c437ef77",
|
||||
"sha256:a0eb43a07386c3f1f1ebb4dc7aafb13f67188eab896e7397aa1ee95a9c884eb2",
|
||||
"sha256:aaa4213c862f0ef00022751161df35804127b78adf4a2755b9f991a507e425fd",
|
||||
"sha256:ac0c682111fbf404525dfc0f18a8b5f11be52657d4f96e9fcb75daf4f3984859",
|
||||
"sha256:ad20d2eb875aaa1ea6d0f2916949f5c08a19c74d05b16ce6ebf6d24f2c9f75d1",
|
||||
"sha256:b4afc542c0ac0db720cf516dd20c0846f71c248d2b3d21013aa0d4ef9c71ca25",
|
||||
"sha256:b8a3715b3c4e604bcc94c90a825cd7f5635417453b253499664f784fc4da0152",
|
||||
"sha256:ba28584e6bca48c59eecbf7efb1576ca214b47f05194646b081717fa628dfddf",
|
||||
"sha256:ba381aec3a5dc29634f20692349d73f2d21f17653bda1decf0b52b11d694541f",
|
||||
"sha256:bd1be66dde2b82f80afb9459fc618216753f67109b859a361cf7def5c7968729",
|
||||
"sha256:c2507d796fca339c8fb03216364cca68d87e037c1f774977c8fc377627d01c71",
|
||||
"sha256:cec7e622ebc545dbb4564e483dd20e4e404da17ae07e06f3e780b2dacd5cee66",
|
||||
"sha256:d14b140a4439d816e3b1229a4a525df917d6ea22a0771a2a78332273fd9528a4",
|
||||
"sha256:d1b4ab59e02d9008efe10ceabd0b31e79519da6fb67f7d8e8977118832d0f449",
|
||||
"sha256:d5227b229005a696cc67676e24c214740efd90b148de5733419ac9aaba3773da",
|
||||
"sha256:e1f57aa70d3f7cc6947fd88636a481638263ba04a742b4a37dd25c373e41491a",
|
||||
"sha256:e74a55f6bad0e7d3968399deb50f61f4db1926acf4a6d83beaaa7df986f48b1c",
|
||||
"sha256:e82aba2188b9ba309fd8e271702bd0d0fc9148ae3150532bbb474f4590039ffb",
|
||||
"sha256:ee69dad2c7155756ad114c02db06002f4cded41132cc51378e57aad79cc8e4f4",
|
||||
"sha256:f5ab93a2cb2d8338b1674be43b442a7f544a0971da062a5da774ed40587f18f5"
|
||||
"sha256:0b7dae87f0b729922e06f85f667de7bf16455d411971b2043bbd9577af9d1975",
|
||||
"sha256:0f2e04bd2a2ab54fa44ee67fe2d002bb90cee1c0f1cc0ebc3148af7b02034cbd",
|
||||
"sha256:123c3fb684e9abfc47218d3784c7b4c47c8587951ea4dd5bc38b6636ac57f616",
|
||||
"sha256:1473c0215b0613dd938db54a653f68251a45a78b05f6fc21af4326f40e8360a2",
|
||||
"sha256:14db1752acdd2187d99cb2ca0a1a6dfe57fc65c3281e0f20e597aac8d2a5bd90",
|
||||
"sha256:1e3a362790edc0a365385b1ac4cc0acc429a0c0d662d829a50b6ce743ae61b5a",
|
||||
"sha256:1e85b74cbbb3056e3656f1cc4781294df03383127a8114cbc6531e8b8367bf1e",
|
||||
"sha256:20f1ab44d8c352074e2d7ca67dc00843067788791be373e67a0911998787ce7d",
|
||||
"sha256:2f62c207d1740b0bde5c4e949f857b044818f734a3d57f1d0d0edc65050532ed",
|
||||
"sha256:3242b9619de955ab44581a03a64bdd7d5e470cc4183e8fcadd85ab9d3756ce7a",
|
||||
"sha256:35c4310f8febe41f442d3c65066ca93cccefd75013df3d8c736c5b93ec288140",
|
||||
"sha256:4235f9d5ddcab0b8dbd723dca56ea2922b485ea00e1dafacf33b0c7e840b3d32",
|
||||
"sha256:5ced67f1e34e1a450cdb48eb53ca73b60aa0af21c46b9b35ac3e581cf9f00e31",
|
||||
"sha256:7360647ea04db2e7dff1648d1da825c8cf68dc5fbd80b8fb5b3ee9f068dcd21a",
|
||||
"sha256:8c13d72ed6af7fd2c8acbd95661cf9477f94e381fce0792c04981a8283b52917",
|
||||
"sha256:988b47ac70d204aed01589ed342303da7c4d84b56c2f4c4b8b00deda123372bf",
|
||||
"sha256:995fc41ebda5a7a663a254a1dcac52638c3e847f48307b5416ee373da15075d7",
|
||||
"sha256:a36c7eb6152ba5467fb264d73844877be8b0847874d4822b7cf2d3c0cb8cdcb0",
|
||||
"sha256:aed4a9a7e3221b3e252c39d0bf794c438dc5453bc2963e8befe9d4cd324dff72",
|
||||
"sha256:aef9aee84ec78af51107181d02fe8773b100b01c5dfde351184ad9223eab3698",
|
||||
"sha256:b0221ca5a9837e040ebf61f48899926b5783668b7807419e4adae8175a31f773",
|
||||
"sha256:b4d7679a08fea64573c969f6994a2631908bb2c0e69a7235648642f3d2e39a68",
|
||||
"sha256:c250a7ec489b652c892e4f0a5d122cc14c3780f9f643e1a326754aedf82d9a76",
|
||||
"sha256:ca86db5b561b894f9e5f115d6a159fff2a2570a652e07889d8a383b5fae66eb4",
|
||||
"sha256:cfc523edecddaef56f6740d7de1ce24a2fdf94fd5e704091856a201872e37f9f",
|
||||
"sha256:da113b70f6ec40e7d81b43d1b139b9db6a05727ab8be1ee559f3a69854a69d34",
|
||||
"sha256:f6fac64a38f6768e7bc7b035b9e10d8a538a9fadce06b983fb3e6fa55ac5f5ce",
|
||||
"sha256:f8559617b1fcf59a9aedba2c9838b5b6aa211ffedecabca412b92a1ff75aac1a",
|
||||
"sha256:fbb42a541b1093385a2d8c7eec94d26d30437d0e77c1d25dae1dcc46741a385e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.8.6"
|
||||
"version": "==2.9.1"
|
||||
},
|
||||
"pyasn1": {
|
||||
"hashes": [
|
||||
|
@ -961,10 +963,10 @@
|
|||
},
|
||||
"python-dotenv": {
|
||||
"hashes": [
|
||||
"sha256:00aa34e92d992e9f8383730816359647f358f4a3be1ba45e5a5cefd27ee91544",
|
||||
"sha256:b1ae5e9643d5ed987fc57cc2583021e38db531946518130777734f9589b3141f"
|
||||
"sha256:dd8fe852847f4fbfadabf6183ddd4c824a9651f02d51714fa075c95561959c7d",
|
||||
"sha256:effaac3c1e58d89b3ccb4d04a40dc7ad6e0275fda25fd75ae9d323e2465e202d"
|
||||
],
|
||||
"version": "==0.17.1"
|
||||
"version": "==0.18.0"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
|
@ -1538,11 +1540,11 @@
|
|||
},
|
||||
"gitpython": {
|
||||
"hashes": [
|
||||
"sha256:3283ae2fba31c913d857e12e5ba5f9a7772bbc064ae2bb09efafa71b0dd4939b",
|
||||
"sha256:be27633e7509e58391f10207cd32b2a6cf5b908f92d9cd30da2e514e1137af61"
|
||||
"sha256:b838a895977b45ab6f0cc926a9045c8d1c44e2b653c1fcc39fe91f42c6e8f05b",
|
||||
"sha256:fce760879cd2aebd2991b3542876dc5c4a909b30c9d69dfc488e504a8db37ee8"
|
||||
],
|
||||
"markers": "python_version >= '3.4'",
|
||||
"version": "==3.1.14"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.1.18"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
|
@ -1560,11 +1562,11 @@
|
|||
},
|
||||
"isort": {
|
||||
"hashes": [
|
||||
"sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
|
||||
"sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
|
||||
"sha256:83510593e07e433b77bd5bff0f6f607dbafa06d1a89022616f02d8b699cfcd56",
|
||||
"sha256:8e2c107091cfec7286bc0f68a547d0ba4c094d460b732075b6fba674f1035c0c"
|
||||
],
|
||||
"markers": "python_version >= '3.6' and python_version < '4'",
|
||||
"version": "==5.8.0"
|
||||
"markers": "python_version < '4.0' and python_full_version >= '3.6.1'",
|
||||
"version": "==5.9.1"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
"hashes": [
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
"""authentik"""
|
||||
__version__ = "2021.6.1-rc6"
|
||||
__version__ = "2021.6.2"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
|
|
@ -3,23 +3,33 @@ from traceback import format_tb
|
|||
from typing import Optional
|
||||
|
||||
from django.http import HttpRequest
|
||||
from guardian.utils import get_anonymous_user
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.core.models import PropertyMapping, User
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.lib.expression.evaluator import BaseEvaluator
|
||||
from authentik.policies.types import PolicyRequest
|
||||
|
||||
|
||||
class PropertyMappingEvaluator(BaseEvaluator):
|
||||
"""Custom Evalautor that adds some different context variables."""
|
||||
|
||||
def set_context(
|
||||
self, user: Optional[User], request: Optional[HttpRequest], **kwargs
|
||||
self,
|
||||
user: Optional[User],
|
||||
request: Optional[HttpRequest],
|
||||
mapping: PropertyMapping,
|
||||
**kwargs,
|
||||
):
|
||||
"""Update context with context from PropertyMapping's evaluate"""
|
||||
req = PolicyRequest(user=get_anonymous_user())
|
||||
req.obj = mapping
|
||||
if user:
|
||||
req.user = user
|
||||
self._context["user"] = user
|
||||
if request:
|
||||
self._context["request"] = request
|
||||
req.http_request = request
|
||||
self._context["request"] = req
|
||||
self._context.update(**kwargs)
|
||||
|
||||
def handle_error(self, exc: Exception, expression_source: str):
|
||||
|
@ -30,9 +40,8 @@ class PropertyMappingEvaluator(BaseEvaluator):
|
|||
expression=expression_source,
|
||||
message=error_string,
|
||||
)
|
||||
if "user" in self._context:
|
||||
event.set_user(self._context["user"])
|
||||
if "request" in self._context:
|
||||
event.from_http(self._context["request"])
|
||||
req: PolicyRequest = self._context["request"]
|
||||
event.from_http(req.http_request, req.user)
|
||||
return
|
||||
event.save()
|
||||
|
|
|
@ -6,6 +6,7 @@ from urllib.parse import urlencode
|
|||
from uuid import uuid4
|
||||
|
||||
import django.db.models.options as options
|
||||
from deepmerge import always_merger
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
||||
|
@ -114,8 +115,8 @@ class User(GuardianUserMixin, AbstractUser):
|
|||
including the users attributes"""
|
||||
final_attributes = {}
|
||||
for group in self.ak_groups.all().order_by("name"):
|
||||
final_attributes.update(group.attributes)
|
||||
final_attributes.update(self.attributes)
|
||||
always_merger.merge(final_attributes, group.attributes)
|
||||
always_merger.merge(final_attributes, self.attributes)
|
||||
return final_attributes
|
||||
|
||||
@cached_property
|
||||
|
@ -142,21 +143,25 @@ class User(GuardianUserMixin, AbstractUser):
|
|||
@property
|
||||
def avatar(self) -> str:
|
||||
"""Get avatar, depending on authentik.avatar setting"""
|
||||
mode = CONFIG.raw.get("authentik").get("avatars")
|
||||
mode: str = CONFIG.y("avatars", "none")
|
||||
if mode == "none":
|
||||
return DEFAULT_AVATAR
|
||||
# gravatar uses md5 for their URLs, so md5 can't be avoided
|
||||
mail_hash = md5(self.email.encode("utf-8")).hexdigest() # nosec
|
||||
if mode == "gravatar":
|
||||
parameters = [
|
||||
("s", "158"),
|
||||
("r", "g"),
|
||||
]
|
||||
# gravatar uses md5 for their URLs, so md5 can't be avoided
|
||||
mail_hash = md5(self.email.encode("utf-8")).hexdigest() # nosec
|
||||
gravatar_url = (
|
||||
f"{GRAVATAR_URL}/avatar/{mail_hash}?{urlencode(parameters, doseq=True)}"
|
||||
)
|
||||
return escape(gravatar_url)
|
||||
raise ValueError(f"Invalid avatar mode {mode}")
|
||||
return mode % {
|
||||
"username": self.username,
|
||||
"mail_hash": mail_hash,
|
||||
"upn": self.attributes.get("upn", ""),
|
||||
}
|
||||
|
||||
class Meta:
|
||||
|
||||
|
@ -460,7 +465,7 @@ class PropertyMapping(SerializerModel, ManagedModel):
|
|||
from authentik.core.expression import PropertyMappingEvaluator
|
||||
|
||||
evaluator = PropertyMappingEvaluator()
|
||||
evaluator.set_context(user, request, **kwargs)
|
||||
evaluator.set_context(user, request, self, **kwargs)
|
||||
try:
|
||||
return evaluator.evaluate(self.expression)
|
||||
except (ValueError, SyntaxError) as exc:
|
||||
|
@ -494,8 +499,12 @@ class AuthenticatedSession(ExpiringModel):
|
|||
last_used = models.DateTimeField(auto_now=True)
|
||||
|
||||
@staticmethod
|
||||
def from_request(request: HttpRequest, user: User) -> "AuthenticatedSession":
|
||||
def from_request(
|
||||
request: HttpRequest, user: User
|
||||
) -> Optional["AuthenticatedSession"]:
|
||||
"""Create a new session from a http request"""
|
||||
if not hasattr(request, "session") or not request.session.session_key:
|
||||
return None
|
||||
return AuthenticatedSession(
|
||||
session_key=request.session.session_key,
|
||||
user=user,
|
||||
|
|
|
@ -49,7 +49,9 @@ def user_logged_in_session(sender, request: HttpRequest, user: "User", **_):
|
|||
"""Create an AuthenticatedSession from request"""
|
||||
from authentik.core.models import AuthenticatedSession
|
||||
|
||||
AuthenticatedSession.from_request(request, user).save()
|
||||
session = AuthenticatedSession.from_request(request, user)
|
||||
if session:
|
||||
session.save()
|
||||
|
||||
|
||||
@receiver(user_logged_out)
|
||||
|
|
|
@ -183,6 +183,8 @@ class SourceFlowManager:
|
|||
# pylint: disable=unused-argument
|
||||
def get_stages_to_append(self, flow: Flow) -> list[Stage]:
|
||||
"""Hook to override stages which are appended to the flow"""
|
||||
if not self.source.enrollment_flow:
|
||||
return []
|
||||
if flow.slug == self.source.enrollment_flow.slug:
|
||||
return [
|
||||
in_memory_stage(PostUserEnrollmentStage),
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
|
||||
{% block head %}
|
||||
<script src="{% static 'dist/FlowInterface.js' %}?v={{ ak_version }}" type="module"></script>
|
||||
<style>
|
||||
.pf-c-background-image::before {
|
||||
background-image: url("{{ flow.background_url }}");
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
|
|
@ -7,6 +7,14 @@
|
|||
<link rel="stylesheet" type="text/css" href="{% static 'dist/patternfly.min.css' %}?v={{ ak_version }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<style>
|
||||
.pf-c-background-image::before {
|
||||
background-image: url("/static/dist/assets/images/flow_background.jpg");
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="pf-c-background-image">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="pf-c-background-image__filter" width="0" height="0">
|
||||
|
|
|
@ -55,11 +55,16 @@ class CertificateKeyPair(CreatedUpdatedModel):
|
|||
def private_key(self) -> Optional[RSAPrivateKey]:
|
||||
"""Get python cryptography PrivateKey instance"""
|
||||
if not self._private_key and self._private_key != "":
|
||||
try:
|
||||
self._private_key = load_pem_private_key(
|
||||
str.encode("\n".join([x.strip() for x in self.key_data.split("\n")])),
|
||||
str.encode(
|
||||
"\n".join([x.strip() for x in self.key_data.split("\n")])
|
||||
),
|
||||
password=None,
|
||||
backend=default_backend(),
|
||||
)
|
||||
except ValueError:
|
||||
return None
|
||||
return self._private_key
|
||||
|
||||
@property
|
||||
|
|
|
@ -14,6 +14,7 @@ from authentik.events.models import cleanse_dict
|
|||
from authentik.flows.exceptions import EmptyFlowException, FlowNonApplicableException
|
||||
from authentik.flows.markers import ReevaluateMarker, StageMarker
|
||||
from authentik.flows.models import Flow, FlowStageBinding, Stage
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.policies.engine import PolicyEngine
|
||||
from authentik.root.monitoring import UpdatingGauge
|
||||
|
||||
|
@ -33,6 +34,7 @@ HIST_FLOWS_PLAN_TIME = Histogram(
|
|||
"Duration to build a plan for a flow",
|
||||
["flow_slug"],
|
||||
)
|
||||
CACHE_TIMEOUT = int(CONFIG.y("redis.cache_timeout_flows"))
|
||||
|
||||
|
||||
def cache_key(flow: Flow, user: Optional[User] = None) -> str:
|
||||
|
@ -157,7 +159,7 @@ class FlowPlanner:
|
|||
"f(plan): building plan",
|
||||
)
|
||||
plan = self._build_plan(user, request, default_context)
|
||||
cache.set(cache_key(self.flow, user), plan)
|
||||
cache.set(cache_key(self.flow, user), plan, CACHE_TIMEOUT)
|
||||
GAUGE_FLOWS_CACHED.update()
|
||||
if not plan.stages and not self.allow_empty_flows:
|
||||
raise EmptyFlowException()
|
||||
|
|
|
@ -18,27 +18,11 @@ from authentik.flows.challenge import (
|
|||
)
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||
from authentik.flows.views import FlowExecutorView
|
||||
from authentik.lib.sentry import SentryIgnoredException
|
||||
|
||||
PLAN_CONTEXT_PENDING_USER_IDENTIFIER = "pending_user_identifier"
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
class InvalidChallengeError(SentryIgnoredException):
|
||||
"""Error raised when a challenge from a stage is not valid"""
|
||||
|
||||
def __init__(self, errors, stage_view: View, challenge: Challenge) -> None:
|
||||
super().__init__()
|
||||
self.errors = errors
|
||||
self.stage_view = stage_view
|
||||
self.challenge = challenge
|
||||
|
||||
def __str__(self) -> str:
|
||||
return (
|
||||
f"Invalid challenge from {self.stage_view}: {self.errors}\n{self.challenge}"
|
||||
)
|
||||
|
||||
|
||||
class StageView(View):
|
||||
"""Abstract Stage, inherits TemplateView but can be combined with FormView"""
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ from authentik.flows.planner import (
|
|||
FlowPlan,
|
||||
FlowPlanner,
|
||||
)
|
||||
from authentik.lib.sentry import SentryIgnoredException
|
||||
from authentik.lib.utils.reflection import all_subclasses, class_to_path
|
||||
from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs
|
||||
from authentik.tenants.models import Tenant
|
||||
|
@ -93,6 +94,10 @@ def challenge_response_types():
|
|||
return Inner()
|
||||
|
||||
|
||||
class InvalidStageError(SentryIgnoredException):
|
||||
"""Error raised when a challenge from a stage is not valid"""
|
||||
|
||||
|
||||
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
||||
class FlowExecutorView(APIView):
|
||||
"""Stage 1 Flow executor, passing requests to Stage Views"""
|
||||
|
@ -164,12 +169,19 @@ class FlowExecutorView(APIView):
|
|||
current_stage=self.current_stage,
|
||||
flow_slug=self.flow.slug,
|
||||
)
|
||||
try:
|
||||
stage_cls = self.current_stage.type
|
||||
except NotImplementedError as exc:
|
||||
self._logger.debug("Error getting stage type", exc=exc)
|
||||
return self.stage_invalid()
|
||||
self.current_stage_view = stage_cls(self)
|
||||
self.current_stage_view.args = self.args
|
||||
self.current_stage_view.kwargs = self.kwargs
|
||||
self.current_stage_view.request = request
|
||||
try:
|
||||
return super().dispatch(request)
|
||||
except InvalidStageError as exc:
|
||||
return self.stage_invalid(str(exc))
|
||||
|
||||
@extend_schema(
|
||||
responses={
|
||||
|
@ -353,8 +365,11 @@ class FlowErrorResponse(TemplateResponse):
|
|||
context = {}
|
||||
context["error"] = self.error
|
||||
if self._request.user and self._request.user.is_authenticated:
|
||||
if self._request.user.is_superuser or self._request.user.attributes.get(
|
||||
if (
|
||||
self._request.user.is_superuser
|
||||
or self._request.user.group_attributes().get(
|
||||
USER_ATTRIBUTE_DEBUG, False
|
||||
)
|
||||
):
|
||||
context["tb"] = "".join(format_tb(self.error.__traceback__))
|
||||
return context
|
||||
|
|
|
@ -62,7 +62,7 @@ class ConfigLoader:
|
|||
output.update(kwargs)
|
||||
print(dumps(output))
|
||||
|
||||
def update(self, root, updatee):
|
||||
def update(self, root: dict[str, Any], updatee: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Recursively update dictionary"""
|
||||
for key, value in updatee.items():
|
||||
if isinstance(value, Mapping):
|
||||
|
@ -73,7 +73,7 @@ class ConfigLoader:
|
|||
root[key] = value
|
||||
return root
|
||||
|
||||
def parse_uri(self, value):
|
||||
def parse_uri(self, value: str) -> str:
|
||||
"""Parse string values which start with a URI"""
|
||||
url = urlparse(value)
|
||||
if url.scheme == "env":
|
||||
|
@ -99,7 +99,10 @@ class ConfigLoader:
|
|||
raise ImproperlyConfigured from exc
|
||||
except PermissionError as exc:
|
||||
self._log(
|
||||
"warning", "Permission denied while reading file", path=path, error=exc
|
||||
"warning",
|
||||
"Permission denied while reading file",
|
||||
path=path,
|
||||
error=str(exc),
|
||||
)
|
||||
|
||||
def update_from_dict(self, update: dict):
|
||||
|
|
|
@ -9,6 +9,7 @@ postgresql:
|
|||
web:
|
||||
listen: 0.0.0.0:9000
|
||||
listen_tls: 0.0.0.0:9443
|
||||
load_local_files: false
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
|
@ -16,6 +17,10 @@ redis:
|
|||
cache_db: 0
|
||||
message_queue_db: 1
|
||||
ws_db: 2
|
||||
cache_timeout: 300
|
||||
cache_timeout_flows: 300
|
||||
cache_timeout_policies: 300
|
||||
cache_timeout_reputation: 300
|
||||
|
||||
debug: false
|
||||
|
||||
|
@ -45,10 +50,10 @@ outposts:
|
|||
# %(build_hash)s: Build hash if you're running a beta version
|
||||
docker_image_base: "ghcr.io/goauthentik/%(type)s:%(version)s"
|
||||
|
||||
authentik:
|
||||
avatars: gravatar # gravatar or none
|
||||
avatars: env://AUTHENTIK_AUTHENTIK__AVATARS?gravatar
|
||||
geoip: "./GeoLite2-City.mmdb"
|
||||
# Optionally add links to the footer on the login page
|
||||
|
||||
# Can't currently be configured via environment variables, only yaml
|
||||
footer_links:
|
||||
- name: Documentation
|
||||
href: https://goauthentik.io/docs/
|
||||
|
|
|
@ -3,6 +3,7 @@ import re
|
|||
from textwrap import indent
|
||||
from typing import Any, Iterable, Optional
|
||||
|
||||
from django.core.exceptions import FieldError
|
||||
from requests import Session
|
||||
from rest_framework.serializers import ValidationError
|
||||
from sentry_sdk.hub import Hub
|
||||
|
@ -29,10 +30,10 @@ class BaseEvaluator:
|
|||
# update website/docs/expressions/_objects.md
|
||||
# update website/docs/expressions/_functions.md
|
||||
self._globals = {
|
||||
"regex_match": BaseEvaluator.expr_filter_regex_match,
|
||||
"regex_replace": BaseEvaluator.expr_filter_regex_replace,
|
||||
"ak_is_group_member": BaseEvaluator.expr_func_is_group_member,
|
||||
"ak_user_by": BaseEvaluator.expr_func_user_by,
|
||||
"regex_match": BaseEvaluator.expr_regex_match,
|
||||
"regex_replace": BaseEvaluator.expr_regex_replace,
|
||||
"ak_is_group_member": BaseEvaluator.expr_is_group_member,
|
||||
"ak_user_by": BaseEvaluator.expr_user_by,
|
||||
"ak_logger": get_logger(),
|
||||
"requests": Session(),
|
||||
}
|
||||
|
@ -40,25 +41,28 @@ class BaseEvaluator:
|
|||
self._filename = "BaseEvalautor"
|
||||
|
||||
@staticmethod
|
||||
def expr_filter_regex_match(value: Any, regex: str) -> bool:
|
||||
def expr_regex_match(value: Any, regex: str) -> bool:
|
||||
"""Expression Filter to run re.search"""
|
||||
return re.search(regex, value) is None
|
||||
return re.search(regex, value) is not None
|
||||
|
||||
@staticmethod
|
||||
def expr_filter_regex_replace(value: Any, regex: str, repl: str) -> str:
|
||||
def expr_regex_replace(value: Any, regex: str, repl: str) -> str:
|
||||
"""Expression Filter to run re.sub"""
|
||||
return re.sub(regex, repl, value)
|
||||
|
||||
@staticmethod
|
||||
def expr_func_user_by(**filters) -> Optional[User]:
|
||||
def expr_user_by(**filters) -> Optional[User]:
|
||||
"""Get user by filters"""
|
||||
try:
|
||||
users = User.objects.filter(**filters)
|
||||
if users:
|
||||
return users.first()
|
||||
return None
|
||||
except FieldError:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def expr_func_is_group_member(user: User, **group_filters) -> bool:
|
||||
def expr_is_group_member(user: User, **group_filters) -> bool:
|
||||
"""Check if `user` is member of group with name `group_name`"""
|
||||
return user.ak_groups.filter(**group_filters).exists()
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
"""Test config loader"""
|
||||
from os import chmod, environ, unlink, write
|
||||
from tempfile import mkstemp
|
||||
|
||||
from django.conf import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from authentik.lib.config import ENV_PREFIX, ConfigLoader
|
||||
|
||||
|
||||
class TestConfig(TestCase):
|
||||
"""Test config loader"""
|
||||
|
||||
def test_env(self):
|
||||
"""Test simple instance"""
|
||||
config = ConfigLoader()
|
||||
environ[ENV_PREFIX + "_test__test"] = "bar"
|
||||
config.update_from_env()
|
||||
self.assertEqual(config.y("test.test"), "bar")
|
||||
|
||||
def test_patch(self):
|
||||
"""Test patch decorator"""
|
||||
config = ConfigLoader()
|
||||
config.y_set("foo.bar", "bar")
|
||||
self.assertEqual(config.y("foo.bar"), "bar")
|
||||
with config.patch("foo.bar", "baz"):
|
||||
self.assertEqual(config.y("foo.bar"), "baz")
|
||||
self.assertEqual(config.y("foo.bar"), "bar")
|
||||
|
||||
def test_uri_env(self):
|
||||
"""Test URI parsing (environment)"""
|
||||
config = ConfigLoader()
|
||||
environ["foo"] = "bar"
|
||||
self.assertEqual(config.parse_uri("env://foo"), "bar")
|
||||
self.assertEqual(config.parse_uri("env://fo?bar"), "bar")
|
||||
|
||||
def test_uri_file(self):
|
||||
"""Test URI parsing (file load)"""
|
||||
config = ConfigLoader()
|
||||
file, file_name = mkstemp()
|
||||
write(file, "foo".encode())
|
||||
_, file2_name = mkstemp()
|
||||
chmod(file2_name, 0o000) # Remove all permissions so we can't read the file
|
||||
self.assertEqual(config.parse_uri(f"file://{file_name}"), "foo")
|
||||
self.assertEqual(config.parse_uri(f"file://{file2_name}?def"), "def")
|
||||
unlink(file_name)
|
||||
unlink(file2_name)
|
||||
|
||||
def test_file_update(self):
|
||||
"""Test update_from_file"""
|
||||
config = ConfigLoader()
|
||||
file, file_name = mkstemp()
|
||||
write(file, "{".encode())
|
||||
file2, file2_name = mkstemp()
|
||||
write(file2, "{".encode())
|
||||
chmod(file2_name, 0o000) # Remove all permissions so we can't read the file
|
||||
with self.assertRaises(ImproperlyConfigured):
|
||||
config.update_from_file(file_name)
|
||||
config.update_from_file(file2_name)
|
||||
unlink(file_name)
|
||||
unlink(file2_name)
|
|
@ -0,0 +1,32 @@
|
|||
"""Test Evaluator base functions"""
|
||||
from django.test import TestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.lib.expression.evaluator import BaseEvaluator
|
||||
|
||||
|
||||
class TestEvaluator(TestCase):
|
||||
"""Test Evaluator base functions"""
|
||||
|
||||
def test_regex_match(self):
|
||||
"""Test expr_regex_match"""
|
||||
self.assertFalse(BaseEvaluator.expr_regex_match("foo", "bar"))
|
||||
self.assertTrue(BaseEvaluator.expr_regex_match("foo", "foo"))
|
||||
|
||||
def test_regex_replace(self):
|
||||
"""Test expr_regex_replace"""
|
||||
self.assertEqual(BaseEvaluator.expr_regex_replace("foo", "o", "a"), "faa")
|
||||
|
||||
def test_user_by(self):
|
||||
"""Test expr_user_by"""
|
||||
self.assertIsNotNone(BaseEvaluator.expr_user_by(username="akadmin"))
|
||||
self.assertIsNone(BaseEvaluator.expr_user_by(username="bar"))
|
||||
self.assertIsNone(BaseEvaluator.expr_user_by(foo="bar"))
|
||||
|
||||
def test_is_group_member(self):
|
||||
"""Test expr_is_group_member"""
|
||||
self.assertFalse(
|
||||
BaseEvaluator.expr_is_group_member(
|
||||
User.objects.get(username="akadmin"), name="test"
|
||||
)
|
||||
)
|
|
@ -33,7 +33,7 @@ def _get_outpost_override_ip(request: HttpRequest) -> Optional[str]:
|
|||
return None
|
||||
if OUTPOST_REMOTE_IP_HEADER not in request.META:
|
||||
return None
|
||||
if request.user.attributes.get(USER_ATTRIBUTE_CAN_OVERRIDE_IP, False):
|
||||
if request.user.group_attributes().get(USER_ATTRIBUTE_CAN_OVERRIDE_IP, False):
|
||||
return None
|
||||
return request.META[OUTPOST_REMOTE_IP_HEADER]
|
||||
|
||||
|
|
|
@ -67,11 +67,6 @@ class OutpostConsumer(AuthJsonConsumer):
|
|||
self.accept()
|
||||
self.outpost = outpost.first()
|
||||
self.last_uid = self.channel_name
|
||||
LOGGER.debug(
|
||||
"added outpost instace to cache",
|
||||
outpost=self.outpost,
|
||||
channel_name=self.channel_name,
|
||||
)
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def disconnect(self, close_code):
|
||||
|
@ -108,6 +103,11 @@ class OutpostConsumer(AuthJsonConsumer):
|
|||
outpost=self.outpost.name,
|
||||
uid=self.last_uid,
|
||||
).inc()
|
||||
LOGGER.debug(
|
||||
"added outpost instace to cache",
|
||||
outpost=self.outpost,
|
||||
instance_uuid=self.last_uid,
|
||||
)
|
||||
self.first_msg = True
|
||||
|
||||
if msg.instruction == WebsocketMessageInstruction.HELLO:
|
||||
|
|
|
@ -66,7 +66,7 @@ class DockerController(BaseController):
|
|||
"name": container_name,
|
||||
"detach": True,
|
||||
"ports": {
|
||||
f"{port.port}/{port.protocol.lower()}": port.inner_port or port.port
|
||||
f"{port.inner_port or port.port}/{port.protocol.lower()}": port.port
|
||||
for port in self.deployment_ports
|
||||
},
|
||||
"environment": self._get_env(),
|
||||
|
|
|
@ -37,7 +37,9 @@ class AccessDeniedResponse(TemplateResponse):
|
|||
if self._request.user and self._request.user.is_authenticated:
|
||||
if (
|
||||
self._request.user.is_superuser
|
||||
or self._request.user.attributes.get(USER_ATTRIBUTE_DEBUG, False)
|
||||
or self._request.user.group_attributes().get(
|
||||
USER_ATTRIBUTE_DEBUG, False
|
||||
)
|
||||
):
|
||||
context["policy_result"] = self.policy_result
|
||||
return context
|
||||
|
|
|
@ -10,6 +10,7 @@ from sentry_sdk.tracing import Span
|
|||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.lib.utils.errors import exception_to_string
|
||||
from authentik.policies.exceptions import PolicyException
|
||||
from authentik.policies.models import PolicyBinding
|
||||
|
@ -18,6 +19,7 @@ from authentik.policies.types import PolicyRequest, PolicyResult
|
|||
LOGGER = get_logger()
|
||||
|
||||
FORK_CTX = get_context("fork")
|
||||
CACHE_TIMEOUT = int(CONFIG.y("redis.cache_timeout_policies"))
|
||||
PROCESS_CLASS = FORK_CTX.Process
|
||||
HIST_POLICIES_EXECUTION_TIME = Histogram(
|
||||
"authentik_policies_execution_time",
|
||||
|
@ -114,7 +116,7 @@ class PolicyProcess(PROCESS_CLASS):
|
|||
policy_result.source_binding = self.binding
|
||||
if not self.request.debug:
|
||||
key = cache_key(self.binding, self.request)
|
||||
cache.set(key, policy_result)
|
||||
cache.set(key, policy_result, CACHE_TIMEOUT)
|
||||
LOGGER.debug(
|
||||
"P_ENG(proc): finished and cached ",
|
||||
policy=self.binding.policy,
|
||||
|
|
|
@ -5,6 +5,7 @@ from django.dispatch import receiver
|
|||
from django.http import HttpRequest
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.lib.utils.http import get_client_ip
|
||||
from authentik.policies.reputation.models import (
|
||||
CACHE_KEY_IP_PREFIX,
|
||||
|
@ -13,6 +14,7 @@ from authentik.policies.reputation.models import (
|
|||
from authentik.stages.identification.signals import identification_failed
|
||||
|
||||
LOGGER = get_logger()
|
||||
CACHE_TIMEOUT = int(CONFIG.y("redis.cache_timeout_reputation"))
|
||||
|
||||
|
||||
def update_score(request: HttpRequest, username: str, amount: int):
|
||||
|
@ -20,10 +22,10 @@ def update_score(request: HttpRequest, username: str, amount: int):
|
|||
remote_ip = get_client_ip(request)
|
||||
|
||||
# We only update the cache here, as its faster than writing to the DB
|
||||
cache.get_or_set(CACHE_KEY_IP_PREFIX + remote_ip, 0)
|
||||
cache.get_or_set(CACHE_KEY_IP_PREFIX + remote_ip, 0, CACHE_TIMEOUT)
|
||||
cache.incr(CACHE_KEY_IP_PREFIX + remote_ip, amount)
|
||||
|
||||
cache.get_or_set(CACHE_KEY_USER_PREFIX + username, 0)
|
||||
cache.get_or_set(CACHE_KEY_USER_PREFIX + username, 0, CACHE_TIMEOUT)
|
||||
cache.incr(CACHE_KEY_USER_PREFIX + username, amount)
|
||||
|
||||
LOGGER.debug("Updated score", amount=amount, for_user=username, for_ip=remote_ip)
|
||||
|
|
|
@ -105,6 +105,7 @@ class PolicyAccessView(AccessMixin, View):
|
|||
policy_engine = PolicyEngine(
|
||||
self.application, user or self.request.user, self.request
|
||||
)
|
||||
policy_engine.use_cache = False
|
||||
policy_engine.build()
|
||||
result = policy_engine.result
|
||||
LOGGER.debug(
|
||||
|
|
|
@ -9,7 +9,7 @@ return {}
|
|||
"""
|
||||
SCOPE_EMAIL_EXPRESSION = """
|
||||
return {
|
||||
"email": user.email,
|
||||
"email": request.user.email,
|
||||
"email_verified": True
|
||||
}
|
||||
"""
|
||||
|
@ -17,14 +17,14 @@ SCOPE_PROFILE_EXPRESSION = """
|
|||
return {
|
||||
# Because authentik only saves the user's full name, and has no concept of first and last names,
|
||||
# the full name is used as given name.
|
||||
# You can override this behaviour in custom mappings, i.e. `user.name.split(" ")`
|
||||
"name": user.name,
|
||||
"given_name": user.name,
|
||||
# You can override this behaviour in custom mappings, i.e. `request.user.name.split(" ")`
|
||||
"name": request.user.name,
|
||||
"given_name": request.user.name,
|
||||
"family_name": "",
|
||||
"preferred_username": user.username,
|
||||
"nickname": user.username,
|
||||
"preferred_username": request.user.username,
|
||||
"nickname": request.user.username,
|
||||
# groups is not part of the official userinfo schema, but is a quasi-standard
|
||||
"groups": [group.name for group in user.ak_groups.all()],
|
||||
"groups": [group.name for group in request.user.ak_groups.all()],
|
||||
}
|
||||
"""
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ SCOPE_AK_PROXY_EXPRESSION = """
|
|||
# which are used for example for the HTTP-Basic Authentication mapping.
|
||||
return {
|
||||
"ak_proxy": {
|
||||
"user_attributes": user.group_attributes()
|
||||
"user_attributes": request.user.group_attributes()
|
||||
}
|
||||
}"""
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from authentik.managed.manager import EnsureExists, ObjectManager
|
|||
from authentik.providers.saml.models import SAMLPropertyMapping
|
||||
|
||||
GROUP_EXPRESSION = """
|
||||
for group in user.ak_groups.all():
|
||||
for group in request.user.ak_groups.all():
|
||||
yield group.name
|
||||
"""
|
||||
|
||||
|
@ -18,7 +18,7 @@ class SAMLProviderManager(ObjectManager):
|
|||
"goauthentik.io/providers/saml/upn",
|
||||
name="authentik default SAML Mapping: UPN",
|
||||
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
|
||||
expression="return user.attributes.get('upn', user.email)",
|
||||
expression="return request.user.attributes.get('upn', request.user.email)",
|
||||
friendly_name="",
|
||||
),
|
||||
EnsureExists(
|
||||
|
@ -26,7 +26,7 @@ class SAMLProviderManager(ObjectManager):
|
|||
"goauthentik.io/providers/saml/name",
|
||||
name="authentik default SAML Mapping: Name",
|
||||
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
|
||||
expression="return user.name",
|
||||
expression="return request.user.name",
|
||||
friendly_name="",
|
||||
),
|
||||
EnsureExists(
|
||||
|
@ -34,7 +34,7 @@ class SAMLProviderManager(ObjectManager):
|
|||
"goauthentik.io/providers/saml/email",
|
||||
name="authentik default SAML Mapping: Email",
|
||||
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
|
||||
expression="return user.email",
|
||||
expression="return request.user.email",
|
||||
friendly_name="",
|
||||
),
|
||||
EnsureExists(
|
||||
|
@ -42,7 +42,7 @@ class SAMLProviderManager(ObjectManager):
|
|||
"goauthentik.io/providers/saml/username",
|
||||
name="authentik default SAML Mapping: Username",
|
||||
saml_name="http://schemas.goauthentik.io/2021/02/saml/username",
|
||||
expression="return user.username",
|
||||
expression="return request.user.username",
|
||||
friendly_name="",
|
||||
),
|
||||
EnsureExists(
|
||||
|
@ -50,7 +50,7 @@ class SAMLProviderManager(ObjectManager):
|
|||
"goauthentik.io/providers/saml/uid",
|
||||
name="authentik default SAML Mapping: User ID",
|
||||
saml_name="http://schemas.goauthentik.io/2021/02/saml/uid",
|
||||
expression="return user.pk",
|
||||
expression="return request.user.pk",
|
||||
friendly_name="",
|
||||
),
|
||||
EnsureExists(
|
||||
|
@ -68,7 +68,7 @@ class SAMLProviderManager(ObjectManager):
|
|||
saml_name=(
|
||||
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"
|
||||
),
|
||||
expression="return user.username",
|
||||
expression="return request.user.username",
|
||||
friendly_name="",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -24,6 +24,7 @@ from authentik.sources.saml.processors.constants import (
|
|||
SAML_NAME_ID_FORMAT_EMAIL,
|
||||
SAML_NAME_ID_FORMAT_PERSISTENT,
|
||||
SAML_NAME_ID_FORMAT_TRANSIENT,
|
||||
SAML_NAME_ID_FORMAT_UNSPECIFIED,
|
||||
SAML_NAME_ID_FORMAT_WINDOWS,
|
||||
SAML_NAME_ID_FORMAT_X509,
|
||||
SIGN_ALGORITHM_TRANSFORM_MAP,
|
||||
|
@ -165,7 +166,10 @@ class AssertionProcessor:
|
|||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_EMAIL:
|
||||
name_id.text = self.http_request.user.email
|
||||
return name_id
|
||||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_PERSISTENT:
|
||||
if name_id.attrib["Format"] in [
|
||||
SAML_NAME_ID_FORMAT_PERSISTENT,
|
||||
SAML_NAME_ID_FORMAT_UNSPECIFIED,
|
||||
]:
|
||||
name_id.text = persistent
|
||||
return name_id
|
||||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_X509:
|
||||
|
@ -180,7 +184,7 @@ class AssertionProcessor:
|
|||
return name_id
|
||||
if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_TRANSIENT:
|
||||
# Use the hash of the user's session, which changes every session
|
||||
session_key: str = self.http_request.user.session.session_key
|
||||
session_key: str = self.http_request.session.session_key
|
||||
name_id.text = sha256(session_key.encode()).hexdigest()
|
||||
return name_id
|
||||
raise UnsupportedNameIDFormat(
|
||||
|
|
|
@ -20,10 +20,11 @@ from authentik.sources.saml.processors.constants import (
|
|||
RSA_SHA256,
|
||||
RSA_SHA384,
|
||||
RSA_SHA512,
|
||||
SAML_NAME_ID_FORMAT_EMAIL,
|
||||
SAML_NAME_ID_FORMAT_UNSPECIFIED,
|
||||
)
|
||||
|
||||
LOGGER = get_logger()
|
||||
ERROR_CANNOT_DECODE_REQUEST = "Cannot decode SAML request."
|
||||
ERROR_SIGNATURE_REQUIRED_BUT_ABSENT = (
|
||||
"Verification Certificate configured, but request is not signed."
|
||||
)
|
||||
|
@ -42,7 +43,7 @@ class AuthNRequest:
|
|||
|
||||
relay_state: Optional[str] = None
|
||||
|
||||
name_id_policy: str = SAML_NAME_ID_FORMAT_EMAIL
|
||||
name_id_policy: str = SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||
|
||||
|
||||
class AuthNRequestParser:
|
||||
|
@ -69,16 +70,21 @@ class AuthNRequestParser:
|
|||
auth_n_request = AuthNRequest(id=root.attrib["ID"], relay_state=relay_state)
|
||||
|
||||
# Check if AuthnRequest has a NameID Policy object
|
||||
name_id_policies = root.findall(f"{{{NS_SAML_PROTOCOL}}}:NameIDPolicy")
|
||||
name_id_policies = root.findall(f"{{{NS_SAML_PROTOCOL}}}NameIDPolicy")
|
||||
if len(name_id_policies) > 0:
|
||||
name_id_policy = name_id_policies[0]
|
||||
auth_n_request.name_id_policy = name_id_policy.attrib["Format"]
|
||||
auth_n_request.name_id_policy = name_id_policy.attrib.get(
|
||||
"Format", SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||
)
|
||||
|
||||
return auth_n_request
|
||||
|
||||
def parse(self, saml_request: str, relay_state: Optional[str]) -> AuthNRequest:
|
||||
"""Validate and parse raw request with enveloped signautre."""
|
||||
try:
|
||||
decoded_xml = b64decode(saml_request.encode()).decode()
|
||||
except UnicodeDecodeError:
|
||||
raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST)
|
||||
|
||||
verifier = self.provider.verification_kp
|
||||
|
||||
|
@ -121,7 +127,10 @@ class AuthNRequestParser:
|
|||
sig_alg: Optional[str] = None,
|
||||
) -> AuthNRequest:
|
||||
"""Validate and parse raw request with detached signature"""
|
||||
try:
|
||||
decoded_xml = decode_base64_and_inflate(saml_request)
|
||||
except UnicodeDecodeError:
|
||||
raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST)
|
||||
|
||||
verifier = self.provider.verification_kp
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ from authentik.providers.saml.processors.assertion import AssertionProcessor
|
|||
from authentik.providers.saml.processors.request_parser import AuthNRequestParser
|
||||
from authentik.sources.saml.exceptions import MismatchedRequestID
|
||||
from authentik.sources.saml.models import SAMLSource
|
||||
from authentik.sources.saml.processors.constants import SAML_NAME_ID_FORMAT_EMAIL
|
||||
from authentik.sources.saml.processors.constants import SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||
from authentik.sources.saml.processors.request import (
|
||||
SESSION_REQUEST_ID,
|
||||
RequestProcessor,
|
||||
|
@ -206,5 +206,5 @@ class TestAuthNRequest(TestCase):
|
|||
REDIRECT_REQUEST, REDIRECT_RELAY_STATE, REDIRECT_SIGNATURE, REDIRECT_SIG_ALG
|
||||
)
|
||||
self.assertEqual(parsed_request.id, "_dcf55fcd27a887e60a7ef9ee6fd3adab")
|
||||
self.assertEqual(parsed_request.name_id_policy, SAML_NAME_ID_FORMAT_EMAIL)
|
||||
self.assertEqual(parsed_request.name_id_policy, SAML_NAME_ID_FORMAT_UNSPECIFIED)
|
||||
self.assertEqual(parsed_request.relay_state, REDIRECT_RELAY_STATE)
|
||||
|
|
|
@ -17,6 +17,7 @@ from authentik.providers.saml.models import SAMLBindings, SAMLProvider
|
|||
from authentik.providers.saml.processors.assertion import AssertionProcessor
|
||||
from authentik.providers.saml.processors.request_parser import AuthNRequest
|
||||
from authentik.providers.saml.utils.encoding import deflate_and_base64_encode, nice64
|
||||
from authentik.sources.saml.exceptions import SAMLException
|
||||
|
||||
LOGGER = get_logger()
|
||||
URL_VALIDATOR = URLValidator(schemes=("http", "https"))
|
||||
|
@ -56,22 +57,30 @@ class SAMLFlowFinalView(ChallengeStageView):
|
|||
provider: SAMLProvider = get_object_or_404(
|
||||
SAMLProvider, pk=application.provider_id
|
||||
)
|
||||
# Log Application Authorization
|
||||
Event.new(
|
||||
EventAction.AUTHORIZE_APPLICATION,
|
||||
authorized_application=application,
|
||||
flow=self.executor.plan.flow_pk,
|
||||
).from_http(self.request)
|
||||
|
||||
if SESSION_KEY_AUTH_N_REQUEST not in self.request.session:
|
||||
return self.executor.stage_invalid()
|
||||
|
||||
auth_n_request: AuthNRequest = self.request.session.pop(
|
||||
SESSION_KEY_AUTH_N_REQUEST
|
||||
)
|
||||
try:
|
||||
response = AssertionProcessor(
|
||||
provider, request, auth_n_request
|
||||
).build_response()
|
||||
except SAMLException as exc:
|
||||
Event.new(
|
||||
EventAction.CONFIGURATION_ERROR,
|
||||
message=f"Failed to process SAML assertion: {str(exc)}",
|
||||
provider=provider,
|
||||
).from_http(self.request)
|
||||
return self.executor.stage_invalid()
|
||||
|
||||
# Log Application Authorization
|
||||
Event.new(
|
||||
EventAction.AUTHORIZE_APPLICATION,
|
||||
authorized_application=application,
|
||||
flow=self.executor.plan.flow_pk,
|
||||
).from_http(self.request)
|
||||
|
||||
if provider.sp_binding == SAMLBindings.POST:
|
||||
form_attrs = {
|
||||
|
|
|
@ -44,7 +44,7 @@ class Command(BaseCommand):
|
|||
user=user,
|
||||
intent=TokenIntents.INTENT_RECOVERY,
|
||||
description=f"Recovery Token generated by {getuser()} on {_now}",
|
||||
identifier=f"ak-recovery-{user}",
|
||||
identifier=f"ak-recovery-{user}-{_now}",
|
||||
)
|
||||
self.stdout.write(
|
||||
(
|
||||
|
|
|
@ -15,6 +15,7 @@ import logging
|
|||
import os
|
||||
import sys
|
||||
from json import dumps
|
||||
from tempfile import gettempdir
|
||||
from time import time
|
||||
|
||||
import structlog
|
||||
|
@ -193,6 +194,7 @@ CACHES = {
|
|||
f"redis://:{CONFIG.y('redis.password')}@{CONFIG.y('redis.host')}:6379"
|
||||
f"/{CONFIG.y('redis.cache_db')}"
|
||||
),
|
||||
"TIMEOUT": int(CONFIG.y("redis.cache_timeout", 300)),
|
||||
"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
|
||||
}
|
||||
}
|
||||
|
@ -341,7 +343,7 @@ DBBACKUP_FILENAME_TEMPLATE = "authentik-backup-{datetime}.sql"
|
|||
DBBACKUP_CONNECTOR_MAPPING = {
|
||||
"django_prometheus.db.backends.postgresql": "dbbackup.db.postgresql.PgDumpConnector",
|
||||
}
|
||||
|
||||
DBBACKUP_TMP_DIR = gettempdir() if DEBUG else "/tmp" # nosec
|
||||
if CONFIG.y("postgresql.s3_backup"):
|
||||
DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
|
||||
DBBACKUP_STORAGE_OPTIONS = {
|
||||
|
|
|
@ -15,6 +15,10 @@ class PytestTestRunner: # pragma: no cover
|
|||
settings.CELERY_TASK_ALWAYS_EAGER = True
|
||||
CONFIG.y_set("authentik.avatars", "none")
|
||||
CONFIG.y_set("authentik.geoip", "tests/GeoLite2-City-Test.mmdb")
|
||||
CONFIG.y_set(
|
||||
"outposts.docker_image_base",
|
||||
"beryju.org/authentik/outpost-%(type)s:gh-master",
|
||||
)
|
||||
|
||||
def run_tests(self, test_labels):
|
||||
"""Run pytest and return the exitcode.
|
||||
|
|
|
@ -60,14 +60,21 @@ class LDAPPasswordChanger:
|
|||
def check_ad_password_complexity_enabled(self) -> bool:
|
||||
"""Check if DOMAIN_PASSWORD_COMPLEX is enabled"""
|
||||
root_dn = self.get_domain_root_dn()
|
||||
try:
|
||||
root_attrs = self._source.connection.extend.standard.paged_search(
|
||||
search_base=root_dn,
|
||||
search_filter="(objectClass=*)",
|
||||
search_scope=ldap3.BASE,
|
||||
attributes=["pwdProperties"],
|
||||
)
|
||||
except ldap3.core.exceptions.LDAPAttributeError:
|
||||
return False
|
||||
root_attrs = list(root_attrs)[0]
|
||||
pwd_properties = PwdProperties(root_attrs["attributes"]["pwdProperties"])
|
||||
raw_pwd_properties = root_attrs.get("attributes", {}).get("pwdProperties", None)
|
||||
if raw_pwd_properties is None:
|
||||
return False
|
||||
|
||||
pwd_properties = PwdProperties(raw_pwd_properties)
|
||||
if PwdProperties.DOMAIN_PASSWORD_COMPLEX in pwd_properties:
|
||||
return True
|
||||
|
||||
|
|
|
@ -2,17 +2,21 @@
|
|||
from authentik.lib.sentry import SentryIgnoredException
|
||||
|
||||
|
||||
class MissingSAMLResponse(SentryIgnoredException):
|
||||
class SAMLException(SentryIgnoredException):
|
||||
"""Base SAML Exception"""
|
||||
|
||||
|
||||
class MissingSAMLResponse(SAMLException):
|
||||
"""Exception raised when request does not contain SAML Response."""
|
||||
|
||||
|
||||
class UnsupportedNameIDFormat(SentryIgnoredException):
|
||||
class UnsupportedNameIDFormat(SAMLException):
|
||||
"""Exception raised when SAML Response contains NameID Format not supported."""
|
||||
|
||||
|
||||
class MismatchedRequestID(SentryIgnoredException):
|
||||
class MismatchedRequestID(SAMLException):
|
||||
"""Exception raised when the returned request ID doesn't match the saved ID."""
|
||||
|
||||
|
||||
class InvalidSignature(SentryIgnoredException):
|
||||
class InvalidSignature(SAMLException):
|
||||
"""Signature of XML Object is either missing or invalid"""
|
||||
|
|
|
@ -15,6 +15,9 @@ NS_MAP = {
|
|||
|
||||
SAML_NAME_ID_FORMAT_EMAIL = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
||||
SAML_NAME_ID_FORMAT_PERSISTENT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
|
||||
SAML_NAME_ID_FORMAT_UNSPECIFIED = (
|
||||
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
||||
)
|
||||
SAML_NAME_ID_FORMAT_X509 = "urn:oasis:names:tc:SAML:2.0:nameid-format:X509SubjectName"
|
||||
SAML_NAME_ID_FORMAT_WINDOWS = (
|
||||
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName"
|
||||
|
|
|
@ -9,7 +9,7 @@ from rest_framework.permissions import IsAdminUser
|
|||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||
|
||||
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
|
@ -94,7 +94,7 @@ class DuoDeviceViewSet(
|
|||
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||
|
||||
|
||||
class DuoAdminDeviceViewSet(ReadOnlyModelViewSet):
|
||||
class DuoAdminDeviceViewSet(ModelViewSet):
|
||||
"""Viewset for Duo authenticator devices (for admins)"""
|
||||
|
||||
permission_classes = [IsAdminUser]
|
||||
|
|
|
@ -3,6 +3,7 @@ from django.http import HttpRequest, HttpResponse
|
|||
from rest_framework.fields import CharField
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.challenge import (
|
||||
Challenge,
|
||||
ChallengeResponse,
|
||||
|
@ -11,6 +12,7 @@ from authentik.flows.challenge import (
|
|||
)
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||
from authentik.flows.stage import ChallengeStageView
|
||||
from authentik.flows.views import InvalidStageError
|
||||
from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
@ -42,7 +44,15 @@ class AuthenticatorDuoStageView(ChallengeStageView):
|
|||
def get_challenge(self, *args, **kwargs) -> Challenge:
|
||||
user = self.get_pending_user()
|
||||
stage: AuthenticatorDuoStage = self.executor.current_stage
|
||||
try:
|
||||
enroll = stage.client.enroll(user.username)
|
||||
except RuntimeError as exc:
|
||||
Event.new(
|
||||
EventAction.CONFIGURATION_ERROR,
|
||||
message=f"Failed to enroll user: {str(exc)}",
|
||||
user=user,
|
||||
).from_http(self.request, user)
|
||||
raise InvalidStageError(str(exc)) from exc
|
||||
user_id = enroll["user_id"]
|
||||
self.request.session[SESSION_KEY_DUO_USER_ID] = user_id
|
||||
self.request.session[SESSION_KEY_DUO_ACTIVATION_CODE] = enroll[
|
||||
|
|
|
@ -10,7 +10,7 @@ from authentik.flows.challenge import (
|
|||
ChallengeTypes,
|
||||
WithUserInfoChallenge,
|
||||
)
|
||||
from authentik.flows.models import NotConfiguredAction
|
||||
from authentik.flows.models import NotConfiguredAction, Stage
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||
from authentik.flows.stage import ChallengeStageView
|
||||
from authentik.stages.authenticator_validate.challenge import (
|
||||
|
@ -143,9 +143,12 @@ class AuthenticatorValidateStageView(ChallengeStageView):
|
|||
return self.executor.stage_invalid()
|
||||
if stage.not_configured_action == NotConfiguredAction.CONFIGURE:
|
||||
LOGGER.debug("Authenticator not configured, sending user to configure")
|
||||
# Because the foreign key to stage.configuration_stage points to
|
||||
# a base stage class, we need to do another lookup
|
||||
stage = Stage.objects.get_subclass(pk=stage.configuration_stage.pk)
|
||||
# plan.insert inserts at 1 index, so when stage_ok pops 0,
|
||||
# the configuration stage is next
|
||||
self.executor.plan.insert(stage.configuration_stage)
|
||||
self.executor.plan.insert(stage)
|
||||
return self.executor.stage_ok()
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
|
|
@ -4,11 +4,14 @@ from unittest.mock import MagicMock, patch
|
|||
from django.contrib.sessions.middleware import SessionMiddleware
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls.base import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.models import NotConfiguredAction
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
from authentik.flows.models import Flow, FlowStageBinding, NotConfiguredAction
|
||||
from authentik.flows.tests.test_planner import dummy_get_response
|
||||
from authentik.providers.oauth2.generators import (
|
||||
generate_client_id,
|
||||
|
@ -24,7 +27,9 @@ from authentik.stages.authenticator_validate.challenge import (
|
|||
validate_challenge_duo,
|
||||
validate_challenge_webauthn,
|
||||
)
|
||||
from authentik.stages.authenticator_validate.models import AuthenticatorValidateStage
|
||||
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
||||
from authentik.stages.identification.models import IdentificationStage, UserFields
|
||||
|
||||
|
||||
class AuthenticatorValidateStageTests(TestCase):
|
||||
|
@ -34,6 +39,50 @@ class AuthenticatorValidateStageTests(TestCase):
|
|||
self.user = User.objects.get(username="akadmin")
|
||||
self.request_factory = RequestFactory()
|
||||
|
||||
def test_not_configured_action(self):
|
||||
"""Test not_configured_action"""
|
||||
conf_stage = IdentificationStage.objects.create(
|
||||
name="conf",
|
||||
user_fields=[
|
||||
UserFields.USERNAME,
|
||||
],
|
||||
)
|
||||
stage = AuthenticatorValidateStage.objects.create(
|
||||
name="foo",
|
||||
not_configured_action=NotConfiguredAction.CONFIGURE,
|
||||
configuration_stage=conf_stage,
|
||||
)
|
||||
flow = Flow.objects.create(name="test", slug="test", title="test")
|
||||
FlowStageBinding.objects.create(target=flow, stage=conf_stage, order=0)
|
||||
FlowStageBinding.objects.create(target=flow, stage=stage, order=1)
|
||||
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
|
||||
{"uid_field": "akadmin"},
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
|
||||
follow=True,
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{
|
||||
"type": ChallengeTypes.NATIVE.value,
|
||||
"component": "ak-stage-identification",
|
||||
"password_fields": False,
|
||||
"primary_action": "Log in",
|
||||
"flow_info": {
|
||||
"background": flow.background_url,
|
||||
"cancel_url": reverse("authentik_flows:cancel"),
|
||||
"title": flow.title,
|
||||
},
|
||||
"user_fields": ["username"],
|
||||
"sources": [],
|
||||
},
|
||||
)
|
||||
|
||||
def test_stage_validation(self):
|
||||
"""Test serializer validation"""
|
||||
self.client.force_login(self.user)
|
||||
|
|
|
@ -51,7 +51,7 @@ class CurrentTenantSerializer(PassiveSerializer):
|
|||
ui_footer_links = ListField(
|
||||
child=FooterLinkSerializer(),
|
||||
read_only=True,
|
||||
default=CONFIG.y("authentik.footer_links"),
|
||||
default=CONFIG.y("footer_links", []),
|
||||
)
|
||||
|
||||
flow_unenrollment = CharField(source="flow_unenrollment.slug", required=False)
|
||||
|
|
|
@ -19,7 +19,26 @@ class TestTenants(TestCase):
|
|||
"branding_favicon": "/static/dist/assets/icons/icon.png",
|
||||
"branding_title": "authentik",
|
||||
"matched_domain": "authentik-default",
|
||||
"ui_footer_links": CONFIG.y("authentik.footer_links"),
|
||||
"ui_footer_links": CONFIG.y("footer_links"),
|
||||
},
|
||||
)
|
||||
|
||||
def test_tenant_subdomain(self):
|
||||
"""Test Current tenant API"""
|
||||
Tenant.objects.all().delete()
|
||||
Tenant.objects.create(domain="bar.baz", branding_title="custom")
|
||||
self.assertJSONEqual(
|
||||
force_str(
|
||||
self.client.get(
|
||||
reverse("authentik_api:tenant-current"), HTTP_HOST="foo.bar.baz"
|
||||
).content
|
||||
),
|
||||
{
|
||||
"branding_logo": "/static/dist/assets/icons/icon_left_brand.svg",
|
||||
"branding_favicon": "/static/dist/assets/icons/icon.png",
|
||||
"branding_title": "custom",
|
||||
"matched_domain": "bar.baz",
|
||||
"ui_footer_links": CONFIG.y("footer_links"),
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -33,6 +52,6 @@ class TestTenants(TestCase):
|
|||
"branding_favicon": "/static/dist/assets/icons/icon.png",
|
||||
"branding_title": "authentik",
|
||||
"matched_domain": "fallback",
|
||||
"ui_footer_links": CONFIG.y("authentik.footer_links"),
|
||||
"ui_footer_links": CONFIG.y("footer_links"),
|
||||
},
|
||||
)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
"""Tenant utilities"""
|
||||
from typing import Any
|
||||
|
||||
from django.db.models import Q
|
||||
from django.db.models import F, Q
|
||||
from django.db.models import Value as V
|
||||
from django.http.request import HttpRequest
|
||||
|
||||
from authentik import __version__
|
||||
|
@ -14,8 +15,10 @@ DEFAULT_TENANT = Tenant(domain="fallback")
|
|||
|
||||
def get_tenant_for_request(request: HttpRequest) -> Tenant:
|
||||
"""Get tenant object for current request"""
|
||||
db_tenants = Tenant.objects.filter(
|
||||
Q(domain__iendswith=request.get_host()) | _q_default
|
||||
db_tenants = (
|
||||
Tenant.objects.annotate(host_domain=V(request.get_host()))
|
||||
.filter(Q(host_domain__iendswith=F("domain")) | _q_default)
|
||||
.order_by("default")
|
||||
)
|
||||
if not db_tenants.exists():
|
||||
return DEFAULT_TENANT
|
||||
|
@ -28,5 +31,5 @@ def context_processor(request: HttpRequest) -> dict[str, Any]:
|
|||
return {
|
||||
"tenant": tenant,
|
||||
"ak_version": __version__,
|
||||
"footer_links": CONFIG.y("authentik.footer_links"),
|
||||
"footer_links": CONFIG.y("footer_links"),
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ stages:
|
|||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run ./manage.py migrate
|
||||
pipenv run python -m lifecycle.migrate
|
||||
- job: migrations_from_previous_release
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
@ -10,6 +13,8 @@ import (
|
|||
"goauthentik.io/internal/config"
|
||||
"goauthentik.io/internal/constants"
|
||||
"goauthentik.io/internal/gounicorn"
|
||||
"goauthentik.io/internal/outpost/ak"
|
||||
"goauthentik.io/internal/outpost/proxy"
|
||||
"goauthentik.io/internal/web"
|
||||
)
|
||||
|
||||
|
@ -30,23 +35,53 @@ func main() {
|
|||
})
|
||||
}
|
||||
|
||||
ex := common.Init()
|
||||
defer common.Defer()
|
||||
|
||||
rl := log.WithField("logger", "authentik.g")
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(3)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g := gounicorn.NewGoUnicorn()
|
||||
u, _ := url.Parse("http://localhost:8000")
|
||||
|
||||
for {
|
||||
err := g.Start()
|
||||
rl.WithError(err).Warning("gunicorn process died, restarting")
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g := gounicorn.NewGoUnicorn()
|
||||
go attemptStartBackend(g)
|
||||
|
||||
ws := web.NewWebServer()
|
||||
ws.Run()
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
proxy :=
|
||||
|
||||
<-ex
|
||||
ws.Stop()
|
||||
g.Kill()
|
||||
}
|
||||
go func() {
|
||||
|
||||
maxTries := 100
|
||||
attempt := 0
|
||||
for {
|
||||
err := attemptProxyStart(u, ex)
|
||||
if err != nil {
|
||||
attempt += 1
|
||||
time.Sleep(5 * time.Second)
|
||||
if attempt > maxTries {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func attemptStartBackend(g *gounicorn.GoUnicorn) error {
|
||||
for {
|
||||
err := g.Start()
|
||||
log.WithField("logger", "authentik.g").WithError(err).Warning("gunicorn process died, restarting")
|
||||
}
|
||||
}
|
||||
|
||||
func attemptProxyStart(u *url.URL, exitSignal chan os.Signal) (*ak.APIController, error) {
|
||||
ac := ak.NewAPIController(*u, config.G.SecretKey)
|
||||
if ac == nil {
|
||||
return nil, errors.New("failed to start")
|
||||
}
|
||||
ac.Server = proxy.NewServer(ac)
|
||||
return ac, nil
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ services:
|
|||
networks:
|
||||
- internal
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.1-rc6}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.2}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
|
@ -38,21 +38,13 @@ services:
|
|||
- geoip:/geoip
|
||||
networks:
|
||||
- internal
|
||||
labels:
|
||||
traefik.enable: 'true'
|
||||
traefik.docker.network: internal
|
||||
traefik.http.routers.app-router.rule: PathPrefix(`/`)
|
||||
traefik.http.routers.app-router.service: app-service
|
||||
traefik.http.routers.app-router.tls: 'true'
|
||||
traefik.http.services.app-service.loadbalancer.healthcheck.path: /-/health/live/
|
||||
traefik.http.services.app-service.loadbalancer.server.port: '9000'
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "0.0.0.0:9000:9000"
|
||||
- "0.0.0.0:9443:9443"
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.1-rc6}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.2}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
networks:
|
||||
|
|
|
@ -18,6 +18,7 @@ func DefaultConfig() {
|
|||
Web: WebConfig{
|
||||
Listen: "localhost:9000",
|
||||
ListenTLS: "localhost:9443",
|
||||
LoadLocalFiles: false,
|
||||
},
|
||||
Paths: PathsConfig{
|
||||
Media: "./media",
|
||||
|
|
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
type Config struct {
|
||||
Debug bool `yaml:"debug"`
|
||||
SecretKey string `yaml:"secret_key"`
|
||||
Web WebConfig `yaml:"web"`
|
||||
Paths PathsConfig `yaml:"paths"`
|
||||
LogLevel string `yaml:"log_level"`
|
||||
|
@ -11,6 +12,7 @@ type Config struct {
|
|||
type WebConfig struct {
|
||||
Listen string `yaml:"listen"`
|
||||
ListenTLS string `yaml:"listen_tls"`
|
||||
LoadLocalFiles bool `yaml:"load_local_files"`
|
||||
}
|
||||
|
||||
type PathsConfig struct {
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
const VERSION = "2021.6.1-rc6"
|
||||
const VERSION = "2021.6.2"
|
||||
|
||||
func BUILD() string {
|
||||
build := os.Getenv("GIT_BUILD_HASH")
|
||||
|
|
|
@ -10,27 +10,34 @@ import (
|
|||
|
||||
type GoUnicorn struct {
|
||||
log *log.Entry
|
||||
p *exec.Cmd
|
||||
}
|
||||
|
||||
func NewGoUnicorn() *GoUnicorn {
|
||||
return &GoUnicorn{
|
||||
log: log.WithField("logger", "authentik.g.unicorn"),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GoUnicorn) Start() error {
|
||||
logger := log.WithField("logger", "authentik.g.unicorn")
|
||||
command := "gunicorn"
|
||||
args := []string{"-c", "./lifecycle/gunicorn.conf.py", "authentik.root.asgi:application"}
|
||||
if config.G.Debug {
|
||||
command = "python"
|
||||
args = []string{"manage.py", "runserver", "localhost:8000"}
|
||||
}
|
||||
g.log.WithField("args", args).WithField("cmd", command).Debug("Starting gunicorn")
|
||||
logger.WithField("args", args).WithField("cmd", command).Debug("Starting gunicorn")
|
||||
p := exec.Command(command, args...)
|
||||
p.Env = append(os.Environ(),
|
||||
"WORKERS=2",
|
||||
)
|
||||
p.Stdout = os.Stdout
|
||||
p.Stderr = os.Stderr
|
||||
return p.Run()
|
||||
return &GoUnicorn{
|
||||
log: logger,
|
||||
p: p,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GoUnicorn) Start() error {
|
||||
return g.p.Run()
|
||||
}
|
||||
|
||||
func (g *GoUnicorn) Kill() error {
|
||||
return g.p.Process.Kill()
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
@ -59,7 +58,7 @@ func NewAPIController(akURL url.URL, token string) *APIController {
|
|||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to fetch configuration")
|
||||
os.Exit(1)
|
||||
return nil
|
||||
}
|
||||
outpost := outposts.Results[0]
|
||||
doGlobalSetup(outpost.Config)
|
||||
|
|
|
@ -446,15 +446,17 @@ func (p *OAuthProxy) addHeadersForProxying(rw http.ResponseWriter, req *http.Req
|
|||
username = session.Email
|
||||
}
|
||||
authVal := b64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||
p.logger.WithField("username", username).Trace("setting http basic auth")
|
||||
req.Header["Authorization"] = []string{fmt.Sprintf("Basic %s", authVal)}
|
||||
}
|
||||
// Check if user has additional headers set that we should sent
|
||||
if additionalHeaders, ok := userAttributes["additionalHeaders"].(map[string]string); ok {
|
||||
if additionalHeaders, ok := userAttributes["additionalHeaders"].(map[string]interface{}); ok {
|
||||
p.logger.WithField("headers", additionalHeaders).Trace("setting additional headers")
|
||||
if additionalHeaders == nil {
|
||||
return
|
||||
}
|
||||
for key, value := range additionalHeaders {
|
||||
req.Header.Set(key, value)
|
||||
req.Header.Set(key, toString(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package proxy
|
|||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var xForwardedHost = http.CanonicalHeaderKey("X-Forwarded-Host")
|
||||
|
@ -18,3 +19,16 @@ func getHost(req *http.Request) string {
|
|||
}
|
||||
return hostOnly
|
||||
}
|
||||
|
||||
// toString Generic to string function, currently supports actual strings and integers
|
||||
func toString(in interface{}) string {
|
||||
switch v := in.(type) {
|
||||
case string:
|
||||
return v
|
||||
case *string:
|
||||
return *v
|
||||
case int:
|
||||
return strconv.Itoa(v)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/gorilla/mux"
|
||||
|
@ -49,17 +48,12 @@ func NewWebServer() *WebServer {
|
|||
}
|
||||
|
||||
func (ws *WebServer) Run() {
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ws.listenPlain()
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ws.listenTLS()
|
||||
}()
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
func (ws *WebServer) Stop() {
|
||||
ws.stop <- struct{}{}
|
||||
}
|
||||
|
||||
func (ws *WebServer) listenPlain() {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
func (ws *WebServer) configureStatic() {
|
||||
statRouter := ws.lh.NewRoute().Subrouter()
|
||||
if config.G.Debug {
|
||||
if config.G.Debug || config.G.Web.LoadLocalFiles {
|
||||
ws.log.Debug("Using local static files")
|
||||
ws.lh.PathPrefix("/static/dist").Handler(http.StripPrefix("/static/dist", http.FileServer(http.Dir("./web/dist"))))
|
||||
ws.lh.PathPrefix("/static/authentik").Handler(http.StripPrefix("/static/authentik", http.FileServer(http.Dir("./web/authentik"))))
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
all: clean
|
||||
|
||||
run:
|
||||
go run -v .
|
||||
|
||||
clean:
|
||||
go mod tidy
|
||||
go clean .
|
||||
|
||||
|
|
130
schema.yml
|
@ -1,7 +1,7 @@
|
|||
openapi: 3.0.3
|
||||
info:
|
||||
title: authentik
|
||||
version: 2021.6.1-rc5
|
||||
version: 2021.6.2
|
||||
description: Making authentication simple.
|
||||
contact:
|
||||
email: hello@beryju.org
|
||||
|
@ -236,6 +236,37 @@ paths:
|
|||
$ref: '#/components/schemas/ValidationError'
|
||||
'403':
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
post:
|
||||
operationId: authenticators_admin_duo_create
|
||||
description: Viewset for Duo authenticator devices (for admins)
|
||||
tags:
|
||||
- authenticators
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||
multipart/form-data:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
- cookieAuth: []
|
||||
responses:
|
||||
'201':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDevice'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
'403':
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
/api/v2beta/authenticators/admin/duo/{id}/:
|
||||
get:
|
||||
operationId: authenticators_admin_duo_retrieve
|
||||
|
@ -263,6 +294,103 @@ paths:
|
|||
$ref: '#/components/schemas/ValidationError'
|
||||
'403':
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
put:
|
||||
operationId: authenticators_admin_duo_update
|
||||
description: Viewset for Duo authenticator devices (for admins)
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
description: A unique integer value identifying this Duo Device.
|
||||
required: true
|
||||
tags:
|
||||
- authenticators
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||
multipart/form-data:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDeviceRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
- cookieAuth: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDevice'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
'403':
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
patch:
|
||||
operationId: authenticators_admin_duo_partial_update
|
||||
description: Viewset for Duo authenticator devices (for admins)
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
description: A unique integer value identifying this Duo Device.
|
||||
required: true
|
||||
tags:
|
||||
- authenticators
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PatchedDuoDeviceRequest'
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PatchedDuoDeviceRequest'
|
||||
multipart/form-data:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PatchedDuoDeviceRequest'
|
||||
security:
|
||||
- authentik: []
|
||||
- cookieAuth: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDevice'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
'403':
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
delete:
|
||||
operationId: authenticators_admin_duo_destroy
|
||||
description: Viewset for Duo authenticator devices (for admins)
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
description: A unique integer value identifying this Duo Device.
|
||||
required: true
|
||||
tags:
|
||||
- authenticators
|
||||
security:
|
||||
- authentik: []
|
||||
- cookieAuth: []
|
||||
responses:
|
||||
'204':
|
||||
description: No response body
|
||||
'400':
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
'403':
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
/api/v2beta/authenticators/admin/static/:
|
||||
get:
|
||||
operationId: authenticators_admin_static_list
|
||||
|
|
|
@ -21,7 +21,13 @@ from authentik.outposts.models import (
|
|||
)
|
||||
from authentik.outposts.tasks import outpost_local_connection
|
||||
from authentik.providers.proxy.models import ProxyProvider
|
||||
from tests.e2e.utils import SeleniumTestCase, apply_migration, object_manager, retry
|
||||
from tests.e2e.utils import (
|
||||
USER,
|
||||
SeleniumTestCase,
|
||||
apply_migration,
|
||||
object_manager,
|
||||
retry,
|
||||
)
|
||||
|
||||
|
||||
@skipUnless(platform.startswith("linux"), "requires local docker")
|
||||
|
@ -47,7 +53,7 @@ class TestProviderProxy(SeleniumTestCase):
|
|||
"""Start proxy container based on outpost created"""
|
||||
client: DockerClient = from_env()
|
||||
container = client.containers.run(
|
||||
image=f"ghcr.io/goauthentik/proxy:{__version__}",
|
||||
image="beryju.org/authentik/outpost-proxy:gh-master",
|
||||
detach=True,
|
||||
network_mode="host",
|
||||
auto_remove=True,
|
||||
|
@ -67,6 +73,11 @@ class TestProviderProxy(SeleniumTestCase):
|
|||
@object_manager
|
||||
def test_proxy_simple(self):
|
||||
"""Test simple outpost setup with single provider"""
|
||||
# set additionalHeaders to test later
|
||||
user = USER()
|
||||
user.attributes["additionalHeaders"] = {"X-Foo": "bar"}
|
||||
user.save()
|
||||
|
||||
proxy: ProxyProvider = ProxyProvider.objects.create(
|
||||
name="proxy_provider",
|
||||
authorization_flow=Flow.objects.get(
|
||||
|
@ -106,6 +117,7 @@ class TestProviderProxy(SeleniumTestCase):
|
|||
|
||||
full_body_text = self.driver.find_element(By.CSS_SELECTOR, "pre").text
|
||||
self.assertIn("X-Forwarded-Preferred-Username: akadmin", full_body_text)
|
||||
self.assertIn("X-Foo: bar", full_body_text)
|
||||
|
||||
|
||||
@skipUnless(platform.startswith("linux"), "requires local docker")
|
||||
|
|
|
@ -104,5 +104,5 @@ class OutpostDockerTests(TestCase):
|
|||
self.assertEqual(compose["version"], "3.5")
|
||||
self.assertEqual(
|
||||
compose["services"]["authentik_proxy"]["image"],
|
||||
f"ghcr.io/goauthentik/proxy:{__version__}",
|
||||
"beryju.org/authentik/outpost-proxy:gh-master",
|
||||
)
|
||||
|
|
|
@ -104,5 +104,5 @@ class TestProxyDocker(TestCase):
|
|||
self.assertEqual(compose["version"], "3.5")
|
||||
self.assertEqual(
|
||||
compose["services"]["authentik_proxy"]["image"],
|
||||
f"ghcr.io/goauthentik/proxy:{__version__}",
|
||||
"beryju.org/authentik/outpost-proxy:gh-master",
|
||||
)
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
"@babel/core": "^7.14.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.14.5",
|
||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.7",
|
||||
"@babel/preset-typescript": "^7.14.5",
|
||||
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||
"@lingui/cli": "^3.10.2",
|
||||
"@lingui/core": "^3.10.3",
|
||||
"@lingui/core": "^3.10.4",
|
||||
"@lingui/macro": "^3.10.2",
|
||||
"@patternfly/patternfly": "^4.108.2",
|
||||
"@polymer/iron-form": "^3.0.1",
|
||||
|
@ -24,22 +24,22 @@
|
|||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-replace": "^2.4.2",
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@sentry/browser": "^6.7.1",
|
||||
"@sentry/tracing": "^6.7.1",
|
||||
"@sentry/browser": "^6.7.2",
|
||||
"@sentry/tracing": "^6.7.2",
|
||||
"@types/chart.js": "^2.9.32",
|
||||
"@types/codemirror": "5.60.0",
|
||||
"@types/grecaptcha": "^3.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.27.0",
|
||||
"@typescript-eslint/parser": "^4.27.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.28.0",
|
||||
"@typescript-eslint/parser": "^4.28.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.5.0",
|
||||
"authentik-api": "file:api",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"chart.js": "^3.3.2",
|
||||
"chartjs-adapter-moment": "^1.0.0",
|
||||
"codemirror": "^5.61.1",
|
||||
"codemirror": "^5.62.0",
|
||||
"construct-style-sheets-polyfill": "^2.4.16",
|
||||
"eslint": "^7.28.0",
|
||||
"eslint": "^7.29.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.2",
|
||||
"eslint-plugin-lit": "^1.5.1",
|
||||
|
@ -48,7 +48,7 @@
|
|||
"lit-html": "^1.4.1",
|
||||
"moment": "^2.29.1",
|
||||
"rapidoc": "^9.0.0",
|
||||
"rollup": "^2.51.2",
|
||||
"rollup": "^2.52.2",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-cssimport": "^1.0.2",
|
||||
|
@ -58,7 +58,7 @@
|
|||
"rollup-plugin-terser": "^7.0.2",
|
||||
"ts-lit-plugin": "^1.2.1",
|
||||
"tslib": "^2.3.0",
|
||||
"typescript": "^4.3.2",
|
||||
"typescript": "^4.3.4",
|
||||
"webcomponent-qr-code": "^1.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
}
|
||||
|
@ -102,9 +102,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.5.tgz",
|
||||
"integrity": "sha512-kixrYn4JwfAVPa0f2yfzc2AWti6WRRyO3XjWW5PJAvtE11qhSayrrcrEnee05KAtNaPC+EwehE8Qt1UedEVB8w==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz",
|
||||
"integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
|
@ -532,9 +532,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-proposal-async-generator-functions": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.5.tgz",
|
||||
"integrity": "sha512-tbD/CG3l43FIXxmu4a7RBe4zH7MLJ+S/lFowPFO7HetS2hyOZ/0nnnznegDuzFzfkyQYTxqdTH/hKmuBngaDAA==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz",
|
||||
"integrity": "sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/helper-remap-async-to-generator": "^7.14.5",
|
||||
|
@ -685,11 +685,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-proposal-object-rest-spread": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.5.tgz",
|
||||
"integrity": "sha512-VzMyY6PWNPPT3pxc5hi9LloKNr4SSrVCg7Yr6aZpW4Ym07r7KqSU/QXYwjXLVxqwSv0t/XSXkFoKBPUkZ8vb2A==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz",
|
||||
"integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.14.5",
|
||||
"@babel/compat-data": "^7.14.7",
|
||||
"@babel/helper-compilation-targets": "^7.14.5",
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
||||
|
@ -1077,9 +1077,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-destructuring": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.5.tgz",
|
||||
"integrity": "sha512-wU9tYisEbRMxqDezKUqC9GleLycCRoUsai9ddlsq54r8QRLaeEhc+d+9DqCG+kV9W2GgQjTZESPTpn5bAFMDww==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz",
|
||||
"integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
},
|
||||
|
@ -1258,9 +1258,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.5.tgz",
|
||||
"integrity": "sha512-+Xe5+6MWFo311U8SchgeX5c1+lJM+eZDBZgD+tvXu9VVQPXwwVzeManMMjYX6xw2HczngfOSZjoFYKwdeB/Jvw==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz",
|
||||
"integrity": "sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.14.5"
|
||||
},
|
||||
|
@ -1398,9 +1398,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-spread": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.5.tgz",
|
||||
"integrity": "sha512-/3iqoQdiWergnShZYl0xACb4ADeYCJ7X/RgmwtXshn6cIvautRPAFzhd58frQlokLO6Jb4/3JXvmm6WNTPtiTw==",
|
||||
"version": "7.14.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz",
|
||||
"integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.14.5"
|
||||
|
@ -1500,16 +1500,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.5.tgz",
|
||||
"integrity": "sha512-ci6TsS0bjrdPpWGnQ+m4f+JSSzDKlckqKIJJt9UZ/+g7Zz9k0N8lYU8IeLg/01o2h8LyNZDMLGgRLDTxpudLsA==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.7.tgz",
|
||||
"integrity": "sha512-itOGqCKLsSUl0Y+1nSfhbuuOlTs0MJk2Iv7iSH+XT/mR8U1zRLO7NjWlYXB47yhK4J/7j+HYty/EhFZDYKa/VA==",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.14.5",
|
||||
"@babel/compat-data": "^7.14.7",
|
||||
"@babel/helper-compilation-targets": "^7.14.5",
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/helper-validator-option": "^7.14.5",
|
||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5",
|
||||
"@babel/plugin-proposal-async-generator-functions": "^7.14.5",
|
||||
"@babel/plugin-proposal-async-generator-functions": "^7.14.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@babel/plugin-proposal-class-static-block": "^7.14.5",
|
||||
"@babel/plugin-proposal-dynamic-import": "^7.14.5",
|
||||
|
@ -1518,7 +1518,7 @@
|
|||
"@babel/plugin-proposal-logical-assignment-operators": "^7.14.5",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
||||
"@babel/plugin-proposal-numeric-separator": "^7.14.5",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.14.5",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.14.7",
|
||||
"@babel/plugin-proposal-optional-catch-binding": "^7.14.5",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
||||
"@babel/plugin-proposal-private-methods": "^7.14.5",
|
||||
|
@ -1544,7 +1544,7 @@
|
|||
"@babel/plugin-transform-block-scoping": "^7.14.5",
|
||||
"@babel/plugin-transform-classes": "^7.14.5",
|
||||
"@babel/plugin-transform-computed-properties": "^7.14.5",
|
||||
"@babel/plugin-transform-destructuring": "^7.14.5",
|
||||
"@babel/plugin-transform-destructuring": "^7.14.7",
|
||||
"@babel/plugin-transform-dotall-regex": "^7.14.5",
|
||||
"@babel/plugin-transform-duplicate-keys": "^7.14.5",
|
||||
"@babel/plugin-transform-exponentiation-operator": "^7.14.5",
|
||||
|
@ -1556,7 +1556,7 @@
|
|||
"@babel/plugin-transform-modules-commonjs": "^7.14.5",
|
||||
"@babel/plugin-transform-modules-systemjs": "^7.14.5",
|
||||
"@babel/plugin-transform-modules-umd": "^7.14.5",
|
||||
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.5",
|
||||
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.7",
|
||||
"@babel/plugin-transform-new-target": "^7.14.5",
|
||||
"@babel/plugin-transform-object-super": "^7.14.5",
|
||||
"@babel/plugin-transform-parameters": "^7.14.5",
|
||||
|
@ -1564,7 +1564,7 @@
|
|||
"@babel/plugin-transform-regenerator": "^7.14.5",
|
||||
"@babel/plugin-transform-reserved-words": "^7.14.5",
|
||||
"@babel/plugin-transform-shorthand-properties": "^7.14.5",
|
||||
"@babel/plugin-transform-spread": "^7.14.5",
|
||||
"@babel/plugin-transform-spread": "^7.14.6",
|
||||
"@babel/plugin-transform-sticky-regex": "^7.14.5",
|
||||
"@babel/plugin-transform-template-literals": "^7.14.5",
|
||||
"@babel/plugin-transform-typeof-symbol": "^7.14.5",
|
||||
|
@ -1575,7 +1575,7 @@
|
|||
"babel-plugin-polyfill-corejs2": "^0.2.2",
|
||||
"babel-plugin-polyfill-corejs3": "^0.2.2",
|
||||
"babel-plugin-polyfill-regenerator": "^0.2.2",
|
||||
"core-js-compat": "^3.14.0",
|
||||
"core-js-compat": "^3.15.0",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2047,9 +2047,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@lingui/core": {
|
||||
"version": "3.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.3.tgz",
|
||||
"integrity": "sha512-BiuWi5xPpQa27oIWWnkOYNx4qTMdMeu7vp5y1AGPYQ/4SO0rHfAtOxXtvRU/ktVwht/lIgx5Ygq5J3F+XLvOQA==",
|
||||
"version": "3.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.4.tgz",
|
||||
"integrity": "sha512-V9QKQ9PFMTPrGGz2PaeKHZcxFikQZzJbptyQbVFJdXaKhdE2RH6HhdK1PIziDHqp6ZWPthVIfVLURT3ku8eu5w==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"make-plural": "^6.2.2",
|
||||
|
@ -2314,13 +2314,13 @@
|
|||
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.1.tgz",
|
||||
"integrity": "sha512-R5PYx4TTvifcU790XkK6JVGwavKaXwycDU0MaAwfc4Vf7BLm5KCNJCsDySu1RPAap/017MVYf54p6dWvKiRviA==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.2.tgz",
|
||||
"integrity": "sha512-Lv0Ne1QcesyGAhVcQDfQa3hDPR/MhPSDTMg3xFi+LxqztchVc4w/ynzR0wCZFb8KIHpTj5SpJHfxpDhXYMtS9g==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "6.7.1",
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/utils": "6.7.1",
|
||||
"@sentry/core": "6.7.2",
|
||||
"@sentry/types": "6.7.2",
|
||||
"@sentry/utils": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2333,14 +2333,14 @@
|
|||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.1.tgz",
|
||||
"integrity": "sha512-VAv8OR/7INn2JfiLcuop4hfDcyC7mfL9fdPndQEhlacjmw8gRrgXjR7qyhnCTgzFLkHI7V5bcdIzA83TRPYQpA==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.2.tgz",
|
||||
"integrity": "sha512-NTZqwN5nR94yrXmSfekoPs1mIFuKvf8esdIW/DadwSKWAdLJwQTJY9xK/8PQv+SEzd7wiitPAx+mCw2By1xiNQ==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "6.7.1",
|
||||
"@sentry/minimal": "6.7.1",
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/utils": "6.7.1",
|
||||
"@sentry/hub": "6.7.2",
|
||||
"@sentry/minimal": "6.7.2",
|
||||
"@sentry/types": "6.7.2",
|
||||
"@sentry/utils": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2353,12 +2353,12 @@
|
|||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/hub": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.1.tgz",
|
||||
"integrity": "sha512-eVCTWvvcp6xa0A5GGNHMQEWslmKPlisE5rGmsV/kjvSUv3zSrI0eIDfb51ikdnCiBjHpK2NBWP8Vy8cZOEJegg==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.2.tgz",
|
||||
"integrity": "sha512-05qVW6ymChJsXag4+fYCQokW3AcABIgcqrVYZUBf6GMU/Gbz5SJqpV7y1+njwWvnPZydMncP9LaDVpMKbE7UYQ==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/utils": "6.7.1",
|
||||
"@sentry/types": "6.7.2",
|
||||
"@sentry/utils": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2371,12 +2371,12 @@
|
|||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/minimal": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.1.tgz",
|
||||
"integrity": "sha512-HDDPEnQRD6hC0qaHdqqKDStcdE1KhkFh0RCtJNMCDn0zpav8Dj9AteF70x6kLSlliAJ/JFwi6AmQrLz+FxPexw==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.2.tgz",
|
||||
"integrity": "sha512-jkpwFv2GFHoVl5vnK+9/Q+Ea8eVdbJ3hn3/Dqq9MOLFnVK7ED6MhdHKLT79puGSFj+85OuhM5m2Q44mIhyS5mw==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "6.7.1",
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/hub": "6.7.2",
|
||||
"@sentry/types": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2389,14 +2389,14 @@
|
|||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/tracing": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.1.tgz",
|
||||
"integrity": "sha512-wyS3nWNl5mzaC1qZ2AIp1hjXnfO9EERjMIJjCihs2LWBz1r3efxrHxJHs8wXlNWvrT3KLhq/7vvF5CdU82uPeQ==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.2.tgz",
|
||||
"integrity": "sha512-juKlI7FICKONWJFJxDxerj0A+8mNRhmtrdR+OXFqOkqSAy/QXlSFZcA/j//O19k2CfwK1BrvoMcQ/4gnffUOVg==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "6.7.1",
|
||||
"@sentry/minimal": "6.7.1",
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/utils": "6.7.1",
|
||||
"@sentry/hub": "6.7.2",
|
||||
"@sentry/minimal": "6.7.2",
|
||||
"@sentry/types": "6.7.2",
|
||||
"@sentry/utils": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2409,19 +2409,19 @@
|
|||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/types": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.1.tgz",
|
||||
"integrity": "sha512-9AO7HKoip2MBMNQJEd6+AKtjj2+q9Ze4ooWUdEvdOVSt5drg7BGpK221/p9JEOyJAZwEPEXdcMd3VAIMiOb4MA==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.2.tgz",
|
||||
"integrity": "sha512-h21Go/PfstUN+ZV6SbwRSZVg9GXRJWdLfHoO5PSVb3TVEMckuxk8tAE57/u+UZDwX8wu+Xyon2TgsKpiWKxqUg==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/utils": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.1.tgz",
|
||||
"integrity": "sha512-Tq2otdbWlHAkctD+EWTYKkEx6BL1Qn3Z/imkO06/PvzpWvVhJWQ5qHAzz5XnwwqNHyV03KVzYB6znq1Bea9HuA==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.2.tgz",
|
||||
"integrity": "sha512-9COL7aaBbe61Hp5BlArtXZ1o/cxli1NGONLPrVT4fMyeQFmLonhUiy77NdsW19XnvhvaA+2IoV5dg3dnFiF/og==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/types": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2579,15 +2579,14 @@
|
|||
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.27.0.tgz",
|
||||
"integrity": "sha512-DsLqxeUfLVNp3AO7PC3JyaddmEHTtI9qTSAs+RB6ja27QvIM0TA8Cizn1qcS6vOu+WDLFJzkwkgweiyFhssDdQ==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz",
|
||||
"integrity": "sha512-KcF6p3zWhf1f8xO84tuBailV5cN92vhS+VT7UJsPzGBm9VnQqfI9AsiMUFUCYHTYPg1uCCo+HyiDnpDuvkAMfQ==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/experimental-utils": "4.27.0",
|
||||
"@typescript-eslint/scope-manager": "4.27.0",
|
||||
"@typescript-eslint/experimental-utils": "4.28.0",
|
||||
"@typescript-eslint/scope-manager": "4.28.0",
|
||||
"debug": "^4.3.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"regexpp": "^3.1.0",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
|
@ -2610,14 +2609,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/experimental-utils": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.27.0.tgz",
|
||||
"integrity": "sha512-n5NlbnmzT2MXlyT+Y0Jf0gsmAQzCnQSWXKy4RGSXVStjDvS5we9IWbh7qRVKdGcxT0WYlgcCYUK/HRg7xFhvjQ==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz",
|
||||
"integrity": "sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ==",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.7",
|
||||
"@typescript-eslint/scope-manager": "4.27.0",
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/typescript-estree": "4.27.0",
|
||||
"@typescript-eslint/scope-manager": "4.28.0",
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"@typescript-eslint/typescript-estree": "4.28.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
|
@ -2650,13 +2649,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.27.0.tgz",
|
||||
"integrity": "sha512-XpbxL+M+gClmJcJ5kHnUpBGmlGdgNvy6cehgR6ufyxkEJMGP25tZKCaKyC0W/JVpuhU3VU1RBn7SYUPKSMqQvQ==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.0.tgz",
|
||||
"integrity": "sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "4.27.0",
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/typescript-estree": "4.27.0",
|
||||
"@typescript-eslint/scope-manager": "4.28.0",
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"@typescript-eslint/typescript-estree": "4.28.0",
|
||||
"debug": "^4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2676,12 +2675,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.27.0.tgz",
|
||||
"integrity": "sha512-DY73jK6SEH6UDdzc6maF19AHQJBFVRf6fgAXHPXCGEmpqD4vYgPEzqpFz1lf/daSbOcMpPPj9tyXXDPW2XReAw==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz",
|
||||
"integrity": "sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/visitor-keys": "4.27.0"
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"@typescript-eslint/visitor-keys": "4.28.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
||||
|
@ -2692,9 +2691,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.27.0.tgz",
|
||||
"integrity": "sha512-I4ps3SCPFCKclRcvnsVA/7sWzh7naaM/b4pBO2hVxnM3wrU51Lveybdw5WoIktU/V4KfXrTt94V9b065b/0+wA==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.0.tgz",
|
||||
"integrity": "sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA==",
|
||||
"engines": {
|
||||
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
||||
},
|
||||
|
@ -2704,12 +2703,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.27.0.tgz",
|
||||
"integrity": "sha512-KH03GUsUj41sRLLEy2JHstnezgpS5VNhrJouRdmh6yNdQ+yl8w5LrSwBkExM+jWwCJa7Ct2c8yl8NdtNRyQO6g==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz",
|
||||
"integrity": "sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/visitor-keys": "4.27.0",
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"@typescript-eslint/visitor-keys": "4.28.0",
|
||||
"debug": "^4.3.1",
|
||||
"globby": "^11.0.3",
|
||||
"is-glob": "^4.0.1",
|
||||
|
@ -2730,9 +2729,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/globby": {
|
||||
"version": "11.0.3",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
|
||||
"integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
|
||||
"integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
|
||||
"dependencies": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
|
@ -2749,11 +2748,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.27.0.tgz",
|
||||
"integrity": "sha512-es0GRYNZp0ieckZ938cEANfEhsfHrzuLrePukLKtY3/KPXcq1Xd555Mno9/GOgXhKzn0QfkDLVgqWO3dGY80bg==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz",
|
||||
"integrity": "sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -3476,9 +3475,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/codemirror": {
|
||||
"version": "5.61.1",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.61.1.tgz",
|
||||
"integrity": "sha512-+D1NZjAucuzE93vJGbAaXzvoBHwp9nJZWWWF9utjv25+5AZUiah6CIlfb4ikG4MoDsFsCG8niiJH5++OO2LgIQ=="
|
||||
"version": "5.62.0",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.0.tgz",
|
||||
"integrity": "sha512-Xnl3304iCc8nyVZuRkzDVVwc794uc9QNX0UcPGeNic1fbzkSrO4l4GVXho9tRNKBgPYZXgocUqXyfIv3BILhCQ=="
|
||||
},
|
||||
"node_modules/collection-visit": {
|
||||
"version": "1.0.0",
|
||||
|
@ -3579,9 +3578,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/core-js-compat": {
|
||||
"version": "3.14.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.14.0.tgz",
|
||||
"integrity": "sha512-R4NS2eupxtiJU+VwgkF9WTpnSfZW4pogwKHd8bclWU2sp93Pr5S1uYJI84cMOubJRou7bcfL0vmwtLslWN5p3A==",
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.15.0.tgz",
|
||||
"integrity": "sha512-8X6lWsG+s7IfOKzV93a7fRYfWRZobOfjw5V5rrq43Vh/W+V6qYxl7Akalsvgab4PFT/4L/pjQbdBUEM36NXKrw==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.16.6",
|
||||
"semver": "7.0.0"
|
||||
|
@ -3862,9 +3861,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "7.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz",
|
||||
"integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==",
|
||||
"version": "7.29.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz",
|
||||
"integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.12.11",
|
||||
"@eslint/eslintrc": "^0.4.2",
|
||||
|
@ -6771,9 +6770,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.51.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.2.tgz",
|
||||
"integrity": "sha512-ReV2eGEadA7hmXSzjxdDKs10neqH2QURf2RxJ6ayAlq93ugy6qIvXMmbc5cWMGCDh1h5T4thuWO1e2VNbMq8FA==",
|
||||
"version": "2.52.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.2.tgz",
|
||||
"integrity": "sha512-4RlFC3k2BIHlUsJ9mGd8OO+9Lm2eDF5P7+6DNQOp5sx+7N/1tFM01kELfbxlMX3MxT6owvLB1ln4S3QvvQlbUA==",
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
|
@ -6781,7 +6780,7 @@
|
|||
"node": ">=10.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.1"
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-commonjs": {
|
||||
|
@ -7605,9 +7604,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
|
||||
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz",
|
||||
"integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
@ -8066,9 +8065,9 @@
|
|||
}
|
||||
},
|
||||
"@babel/compat-data": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.5.tgz",
|
||||
"integrity": "sha512-kixrYn4JwfAVPa0f2yfzc2AWti6WRRyO3XjWW5PJAvtE11qhSayrrcrEnee05KAtNaPC+EwehE8Qt1UedEVB8w=="
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz",
|
||||
"integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw=="
|
||||
},
|
||||
"@babel/core": {
|
||||
"version": "7.14.6",
|
||||
|
@ -8380,9 +8379,9 @@
|
|||
}
|
||||
},
|
||||
"@babel/plugin-proposal-async-generator-functions": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.5.tgz",
|
||||
"integrity": "sha512-tbD/CG3l43FIXxmu4a7RBe4zH7MLJ+S/lFowPFO7HetS2hyOZ/0nnnznegDuzFzfkyQYTxqdTH/hKmuBngaDAA==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz",
|
||||
"integrity": "sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/helper-remap-async-to-generator": "^7.14.5",
|
||||
|
@ -8473,11 +8472,11 @@
|
|||
}
|
||||
},
|
||||
"@babel/plugin-proposal-object-rest-spread": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.5.tgz",
|
||||
"integrity": "sha512-VzMyY6PWNPPT3pxc5hi9LloKNr4SSrVCg7Yr6aZpW4Ym07r7KqSU/QXYwjXLVxqwSv0t/XSXkFoKBPUkZ8vb2A==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz",
|
||||
"integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==",
|
||||
"requires": {
|
||||
"@babel/compat-data": "^7.14.5",
|
||||
"@babel/compat-data": "^7.14.7",
|
||||
"@babel/helper-compilation-targets": "^7.14.5",
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
||||
|
@ -8732,9 +8731,9 @@
|
|||
}
|
||||
},
|
||||
"@babel/plugin-transform-destructuring": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.5.tgz",
|
||||
"integrity": "sha512-wU9tYisEbRMxqDezKUqC9GleLycCRoUsai9ddlsq54r8QRLaeEhc+d+9DqCG+kV9W2GgQjTZESPTpn5bAFMDww==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz",
|
||||
"integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
}
|
||||
|
@ -8841,9 +8840,9 @@
|
|||
}
|
||||
},
|
||||
"@babel/plugin-transform-named-capturing-groups-regex": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.5.tgz",
|
||||
"integrity": "sha512-+Xe5+6MWFo311U8SchgeX5c1+lJM+eZDBZgD+tvXu9VVQPXwwVzeManMMjYX6xw2HczngfOSZjoFYKwdeB/Jvw==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz",
|
||||
"integrity": "sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg==",
|
||||
"requires": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.14.5"
|
||||
}
|
||||
|
@ -8926,9 +8925,9 @@
|
|||
}
|
||||
},
|
||||
"@babel/plugin-transform-spread": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.5.tgz",
|
||||
"integrity": "sha512-/3iqoQdiWergnShZYl0xACb4ADeYCJ7X/RgmwtXshn6cIvautRPAFzhd58frQlokLO6Jb4/3JXvmm6WNTPtiTw==",
|
||||
"version": "7.14.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz",
|
||||
"integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.14.5"
|
||||
|
@ -8986,16 +8985,16 @@
|
|||
}
|
||||
},
|
||||
"@babel/preset-env": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.5.tgz",
|
||||
"integrity": "sha512-ci6TsS0bjrdPpWGnQ+m4f+JSSzDKlckqKIJJt9UZ/+g7Zz9k0N8lYU8IeLg/01o2h8LyNZDMLGgRLDTxpudLsA==",
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.7.tgz",
|
||||
"integrity": "sha512-itOGqCKLsSUl0Y+1nSfhbuuOlTs0MJk2Iv7iSH+XT/mR8U1zRLO7NjWlYXB47yhK4J/7j+HYty/EhFZDYKa/VA==",
|
||||
"requires": {
|
||||
"@babel/compat-data": "^7.14.5",
|
||||
"@babel/compat-data": "^7.14.7",
|
||||
"@babel/helper-compilation-targets": "^7.14.5",
|
||||
"@babel/helper-plugin-utils": "^7.14.5",
|
||||
"@babel/helper-validator-option": "^7.14.5",
|
||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5",
|
||||
"@babel/plugin-proposal-async-generator-functions": "^7.14.5",
|
||||
"@babel/plugin-proposal-async-generator-functions": "^7.14.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@babel/plugin-proposal-class-static-block": "^7.14.5",
|
||||
"@babel/plugin-proposal-dynamic-import": "^7.14.5",
|
||||
|
@ -9004,7 +9003,7 @@
|
|||
"@babel/plugin-proposal-logical-assignment-operators": "^7.14.5",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
||||
"@babel/plugin-proposal-numeric-separator": "^7.14.5",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.14.5",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.14.7",
|
||||
"@babel/plugin-proposal-optional-catch-binding": "^7.14.5",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
||||
"@babel/plugin-proposal-private-methods": "^7.14.5",
|
||||
|
@ -9030,7 +9029,7 @@
|
|||
"@babel/plugin-transform-block-scoping": "^7.14.5",
|
||||
"@babel/plugin-transform-classes": "^7.14.5",
|
||||
"@babel/plugin-transform-computed-properties": "^7.14.5",
|
||||
"@babel/plugin-transform-destructuring": "^7.14.5",
|
||||
"@babel/plugin-transform-destructuring": "^7.14.7",
|
||||
"@babel/plugin-transform-dotall-regex": "^7.14.5",
|
||||
"@babel/plugin-transform-duplicate-keys": "^7.14.5",
|
||||
"@babel/plugin-transform-exponentiation-operator": "^7.14.5",
|
||||
|
@ -9042,7 +9041,7 @@
|
|||
"@babel/plugin-transform-modules-commonjs": "^7.14.5",
|
||||
"@babel/plugin-transform-modules-systemjs": "^7.14.5",
|
||||
"@babel/plugin-transform-modules-umd": "^7.14.5",
|
||||
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.5",
|
||||
"@babel/plugin-transform-named-capturing-groups-regex": "^7.14.7",
|
||||
"@babel/plugin-transform-new-target": "^7.14.5",
|
||||
"@babel/plugin-transform-object-super": "^7.14.5",
|
||||
"@babel/plugin-transform-parameters": "^7.14.5",
|
||||
|
@ -9050,7 +9049,7 @@
|
|||
"@babel/plugin-transform-regenerator": "^7.14.5",
|
||||
"@babel/plugin-transform-reserved-words": "^7.14.5",
|
||||
"@babel/plugin-transform-shorthand-properties": "^7.14.5",
|
||||
"@babel/plugin-transform-spread": "^7.14.5",
|
||||
"@babel/plugin-transform-spread": "^7.14.6",
|
||||
"@babel/plugin-transform-sticky-regex": "^7.14.5",
|
||||
"@babel/plugin-transform-template-literals": "^7.14.5",
|
||||
"@babel/plugin-transform-typeof-symbol": "^7.14.5",
|
||||
|
@ -9061,7 +9060,7 @@
|
|||
"babel-plugin-polyfill-corejs2": "^0.2.2",
|
||||
"babel-plugin-polyfill-corejs3": "^0.2.2",
|
||||
"babel-plugin-polyfill-regenerator": "^0.2.2",
|
||||
"core-js-compat": "^3.14.0",
|
||||
"core-js-compat": "^3.15.0",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -9431,9 +9430,9 @@
|
|||
}
|
||||
},
|
||||
"@lingui/core": {
|
||||
"version": "3.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.3.tgz",
|
||||
"integrity": "sha512-BiuWi5xPpQa27oIWWnkOYNx4qTMdMeu7vp5y1AGPYQ/4SO0rHfAtOxXtvRU/ktVwht/lIgx5Ygq5J3F+XLvOQA==",
|
||||
"version": "3.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.10.4.tgz",
|
||||
"integrity": "sha512-V9QKQ9PFMTPrGGz2PaeKHZcxFikQZzJbptyQbVFJdXaKhdE2RH6HhdK1PIziDHqp6ZWPthVIfVLURT3ku8eu5w==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"make-plural": "^6.2.2",
|
||||
|
@ -9670,13 +9669,13 @@
|
|||
}
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.1.tgz",
|
||||
"integrity": "sha512-R5PYx4TTvifcU790XkK6JVGwavKaXwycDU0MaAwfc4Vf7BLm5KCNJCsDySu1RPAap/017MVYf54p6dWvKiRviA==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.7.2.tgz",
|
||||
"integrity": "sha512-Lv0Ne1QcesyGAhVcQDfQa3hDPR/MhPSDTMg3xFi+LxqztchVc4w/ynzR0wCZFb8KIHpTj5SpJHfxpDhXYMtS9g==",
|
||||
"requires": {
|
||||
"@sentry/core": "6.7.1",
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/utils": "6.7.1",
|
||||
"@sentry/core": "6.7.2",
|
||||
"@sentry/types": "6.7.2",
|
||||
"@sentry/utils": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -9688,14 +9687,14 @@
|
|||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.1.tgz",
|
||||
"integrity": "sha512-VAv8OR/7INn2JfiLcuop4hfDcyC7mfL9fdPndQEhlacjmw8gRrgXjR7qyhnCTgzFLkHI7V5bcdIzA83TRPYQpA==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.7.2.tgz",
|
||||
"integrity": "sha512-NTZqwN5nR94yrXmSfekoPs1mIFuKvf8esdIW/DadwSKWAdLJwQTJY9xK/8PQv+SEzd7wiitPAx+mCw2By1xiNQ==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.7.1",
|
||||
"@sentry/minimal": "6.7.1",
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/utils": "6.7.1",
|
||||
"@sentry/hub": "6.7.2",
|
||||
"@sentry/minimal": "6.7.2",
|
||||
"@sentry/types": "6.7.2",
|
||||
"@sentry/utils": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -9707,12 +9706,12 @@
|
|||
}
|
||||
},
|
||||
"@sentry/hub": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.1.tgz",
|
||||
"integrity": "sha512-eVCTWvvcp6xa0A5GGNHMQEWslmKPlisE5rGmsV/kjvSUv3zSrI0eIDfb51ikdnCiBjHpK2NBWP8Vy8cZOEJegg==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.7.2.tgz",
|
||||
"integrity": "sha512-05qVW6ymChJsXag4+fYCQokW3AcABIgcqrVYZUBf6GMU/Gbz5SJqpV7y1+njwWvnPZydMncP9LaDVpMKbE7UYQ==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/utils": "6.7.1",
|
||||
"@sentry/types": "6.7.2",
|
||||
"@sentry/utils": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -9724,12 +9723,12 @@
|
|||
}
|
||||
},
|
||||
"@sentry/minimal": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.1.tgz",
|
||||
"integrity": "sha512-HDDPEnQRD6hC0qaHdqqKDStcdE1KhkFh0RCtJNMCDn0zpav8Dj9AteF70x6kLSlliAJ/JFwi6AmQrLz+FxPexw==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.7.2.tgz",
|
||||
"integrity": "sha512-jkpwFv2GFHoVl5vnK+9/Q+Ea8eVdbJ3hn3/Dqq9MOLFnVK7ED6MhdHKLT79puGSFj+85OuhM5m2Q44mIhyS5mw==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.7.1",
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/hub": "6.7.2",
|
||||
"@sentry/types": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -9741,14 +9740,14 @@
|
|||
}
|
||||
},
|
||||
"@sentry/tracing": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.1.tgz",
|
||||
"integrity": "sha512-wyS3nWNl5mzaC1qZ2AIp1hjXnfO9EERjMIJjCihs2LWBz1r3efxrHxJHs8wXlNWvrT3KLhq/7vvF5CdU82uPeQ==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.7.2.tgz",
|
||||
"integrity": "sha512-juKlI7FICKONWJFJxDxerj0A+8mNRhmtrdR+OXFqOkqSAy/QXlSFZcA/j//O19k2CfwK1BrvoMcQ/4gnffUOVg==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.7.1",
|
||||
"@sentry/minimal": "6.7.1",
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/utils": "6.7.1",
|
||||
"@sentry/hub": "6.7.2",
|
||||
"@sentry/minimal": "6.7.2",
|
||||
"@sentry/types": "6.7.2",
|
||||
"@sentry/utils": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -9760,16 +9759,16 @@
|
|||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.1.tgz",
|
||||
"integrity": "sha512-9AO7HKoip2MBMNQJEd6+AKtjj2+q9Ze4ooWUdEvdOVSt5drg7BGpK221/p9JEOyJAZwEPEXdcMd3VAIMiOb4MA=="
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.7.2.tgz",
|
||||
"integrity": "sha512-h21Go/PfstUN+ZV6SbwRSZVg9GXRJWdLfHoO5PSVb3TVEMckuxk8tAE57/u+UZDwX8wu+Xyon2TgsKpiWKxqUg=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.1.tgz",
|
||||
"integrity": "sha512-Tq2otdbWlHAkctD+EWTYKkEx6BL1Qn3Z/imkO06/PvzpWvVhJWQ5qHAzz5XnwwqNHyV03KVzYB6znq1Bea9HuA==",
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.7.2.tgz",
|
||||
"integrity": "sha512-9COL7aaBbe61Hp5BlArtXZ1o/cxli1NGONLPrVT4fMyeQFmLonhUiy77NdsW19XnvhvaA+2IoV5dg3dnFiF/og==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.7.1",
|
||||
"@sentry/types": "6.7.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -9926,29 +9925,28 @@
|
|||
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.27.0.tgz",
|
||||
"integrity": "sha512-DsLqxeUfLVNp3AO7PC3JyaddmEHTtI9qTSAs+RB6ja27QvIM0TA8Cizn1qcS6vOu+WDLFJzkwkgweiyFhssDdQ==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz",
|
||||
"integrity": "sha512-KcF6p3zWhf1f8xO84tuBailV5cN92vhS+VT7UJsPzGBm9VnQqfI9AsiMUFUCYHTYPg1uCCo+HyiDnpDuvkAMfQ==",
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "4.27.0",
|
||||
"@typescript-eslint/scope-manager": "4.27.0",
|
||||
"@typescript-eslint/experimental-utils": "4.28.0",
|
||||
"@typescript-eslint/scope-manager": "4.28.0",
|
||||
"debug": "^4.3.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"regexpp": "^3.1.0",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.27.0.tgz",
|
||||
"integrity": "sha512-n5NlbnmzT2MXlyT+Y0Jf0gsmAQzCnQSWXKy4RGSXVStjDvS5we9IWbh7qRVKdGcxT0WYlgcCYUK/HRg7xFhvjQ==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz",
|
||||
"integrity": "sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ==",
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.7",
|
||||
"@typescript-eslint/scope-manager": "4.27.0",
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/typescript-estree": "4.27.0",
|
||||
"@typescript-eslint/scope-manager": "4.28.0",
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"@typescript-eslint/typescript-estree": "4.28.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
|
@ -9964,37 +9962,37 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.27.0.tgz",
|
||||
"integrity": "sha512-XpbxL+M+gClmJcJ5kHnUpBGmlGdgNvy6cehgR6ufyxkEJMGP25tZKCaKyC0W/JVpuhU3VU1RBn7SYUPKSMqQvQ==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.0.tgz",
|
||||
"integrity": "sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A==",
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "4.27.0",
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/typescript-estree": "4.27.0",
|
||||
"@typescript-eslint/scope-manager": "4.28.0",
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"@typescript-eslint/typescript-estree": "4.28.0",
|
||||
"debug": "^4.3.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.27.0.tgz",
|
||||
"integrity": "sha512-DY73jK6SEH6UDdzc6maF19AHQJBFVRf6fgAXHPXCGEmpqD4vYgPEzqpFz1lf/daSbOcMpPPj9tyXXDPW2XReAw==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz",
|
||||
"integrity": "sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/visitor-keys": "4.27.0"
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"@typescript-eslint/visitor-keys": "4.28.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.27.0.tgz",
|
||||
"integrity": "sha512-I4ps3SCPFCKclRcvnsVA/7sWzh7naaM/b4pBO2hVxnM3wrU51Lveybdw5WoIktU/V4KfXrTt94V9b065b/0+wA=="
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.0.tgz",
|
||||
"integrity": "sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA=="
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.27.0.tgz",
|
||||
"integrity": "sha512-KH03GUsUj41sRLLEy2JHstnezgpS5VNhrJouRdmh6yNdQ+yl8w5LrSwBkExM+jWwCJa7Ct2c8yl8NdtNRyQO6g==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz",
|
||||
"integrity": "sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/visitor-keys": "4.27.0",
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"@typescript-eslint/visitor-keys": "4.28.0",
|
||||
"debug": "^4.3.1",
|
||||
"globby": "^11.0.3",
|
||||
"is-glob": "^4.0.1",
|
||||
|
@ -10003,9 +10001,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"globby": {
|
||||
"version": "11.0.3",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
|
||||
"integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
|
||||
"integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
|
||||
"requires": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
|
@ -10018,11 +10016,11 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "4.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.27.0.tgz",
|
||||
"integrity": "sha512-es0GRYNZp0ieckZ938cEANfEhsfHrzuLrePukLKtY3/KPXcq1Xd555Mno9/GOgXhKzn0QfkDLVgqWO3dGY80bg==",
|
||||
"version": "4.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz",
|
||||
"integrity": "sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.27.0",
|
||||
"@typescript-eslint/types": "4.28.0",
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
}
|
||||
},
|
||||
|
@ -10591,9 +10589,9 @@
|
|||
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
|
||||
},
|
||||
"codemirror": {
|
||||
"version": "5.61.1",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.61.1.tgz",
|
||||
"integrity": "sha512-+D1NZjAucuzE93vJGbAaXzvoBHwp9nJZWWWF9utjv25+5AZUiah6CIlfb4ikG4MoDsFsCG8niiJH5++OO2LgIQ=="
|
||||
"version": "5.62.0",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.0.tgz",
|
||||
"integrity": "sha512-Xnl3304iCc8nyVZuRkzDVVwc794uc9QNX0UcPGeNic1fbzkSrO4l4GVXho9tRNKBgPYZXgocUqXyfIv3BILhCQ=="
|
||||
},
|
||||
"collection-visit": {
|
||||
"version": "1.0.0",
|
||||
|
@ -10681,9 +10679,9 @@
|
|||
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
|
||||
},
|
||||
"core-js-compat": {
|
||||
"version": "3.14.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.14.0.tgz",
|
||||
"integrity": "sha512-R4NS2eupxtiJU+VwgkF9WTpnSfZW4pogwKHd8bclWU2sp93Pr5S1uYJI84cMOubJRou7bcfL0vmwtLslWN5p3A==",
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.15.0.tgz",
|
||||
"integrity": "sha512-8X6lWsG+s7IfOKzV93a7fRYfWRZobOfjw5V5rrq43Vh/W+V6qYxl7Akalsvgab4PFT/4L/pjQbdBUEM36NXKrw==",
|
||||
"requires": {
|
||||
"browserslist": "^4.16.6",
|
||||
"semver": "7.0.0"
|
||||
|
@ -10901,9 +10899,9 @@
|
|||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"eslint": {
|
||||
"version": "7.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz",
|
||||
"integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==",
|
||||
"version": "7.29.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz",
|
||||
"integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "7.12.11",
|
||||
"@eslint/eslintrc": "^0.4.2",
|
||||
|
@ -13202,11 +13200,11 @@
|
|||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.51.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.51.2.tgz",
|
||||
"integrity": "sha512-ReV2eGEadA7hmXSzjxdDKs10neqH2QURf2RxJ6ayAlq93ugy6qIvXMmbc5cWMGCDh1h5T4thuWO1e2VNbMq8FA==",
|
||||
"version": "2.52.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.2.tgz",
|
||||
"integrity": "sha512-4RlFC3k2BIHlUsJ9mGd8OO+9Lm2eDF5P7+6DNQOp5sx+7N/1tFM01kELfbxlMX3MxT6owvLB1ln4S3QvvQlbUA==",
|
||||
"requires": {
|
||||
"fsevents": "~2.3.1"
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"rollup-plugin-commonjs": {
|
||||
|
@ -13898,9 +13896,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
|
||||
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw=="
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz",
|
||||
"integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew=="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.13.0",
|
||||
|
|
|
@ -41,11 +41,11 @@
|
|||
"@babel/core": "^7.14.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.14.5",
|
||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.7",
|
||||
"@babel/preset-typescript": "^7.14.5",
|
||||
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||
"@lingui/cli": "^3.10.2",
|
||||
"@lingui/core": "^3.10.3",
|
||||
"@lingui/core": "^3.10.4",
|
||||
"@lingui/macro": "^3.10.2",
|
||||
"@patternfly/patternfly": "^4.108.2",
|
||||
"@polymer/iron-form": "^3.0.1",
|
||||
|
@ -53,22 +53,22 @@
|
|||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-replace": "^2.4.2",
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@sentry/browser": "^6.7.1",
|
||||
"@sentry/tracing": "^6.7.1",
|
||||
"@sentry/browser": "^6.7.2",
|
||||
"@sentry/tracing": "^6.7.2",
|
||||
"@types/chart.js": "^2.9.32",
|
||||
"@types/codemirror": "5.60.0",
|
||||
"@types/grecaptcha": "^3.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.27.0",
|
||||
"@typescript-eslint/parser": "^4.27.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.28.0",
|
||||
"@typescript-eslint/parser": "^4.28.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.5.0",
|
||||
"authentik-api": "file:api",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"chart.js": "^3.3.2",
|
||||
"chartjs-adapter-moment": "^1.0.0",
|
||||
"codemirror": "^5.61.1",
|
||||
"codemirror": "^5.62.0",
|
||||
"construct-style-sheets-polyfill": "^2.4.16",
|
||||
"eslint": "^7.28.0",
|
||||
"eslint": "^7.29.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.2",
|
||||
"eslint-plugin-lit": "^1.5.1",
|
||||
|
@ -77,7 +77,7 @@
|
|||
"lit-html": "^1.4.1",
|
||||
"moment": "^2.29.1",
|
||||
"rapidoc": "^9.0.0",
|
||||
"rollup": "^2.51.2",
|
||||
"rollup": "^2.52.2",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-cssimport": "^1.0.2",
|
||||
|
@ -87,7 +87,7 @@
|
|||
"rollup-plugin-terser": "^7.0.2",
|
||||
"ts-lit-plugin": "^1.2.1",
|
||||
"tslib": "^2.3.0",
|
||||
"typescript": "^4.3.2",
|
||||
"typescript": "^4.3.4",
|
||||
"webcomponent-qr-code": "^1.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
},
|
||||
|
|
|
@ -68,7 +68,7 @@ html > form > input {
|
|||
|
||||
/* ensure background on non-flow pages match */
|
||||
.pf-c-background-image::before {
|
||||
background-image: var(--ak-flow-background, url("/static/dist/assets/images/flow_background.jpg"));
|
||||
background-image: var(--ak-flow-background);
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
|
|||
export const ERROR_CLASS = "pf-m-danger";
|
||||
export const PROGRESS_CLASS = "pf-m-in-progress";
|
||||
export const CURRENT_CLASS = "pf-m-current";
|
||||
export const VERSION = "2021.6.1-rc6";
|
||||
export const VERSION = "2021.6.2";
|
||||
export const PAGE_SIZE = 20;
|
||||
export const EVENT_REFRESH = "ak-refresh";
|
||||
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";
|
||||
|
|
|
@ -54,7 +54,9 @@ export class ModalButton extends LitElement {
|
|||
|
||||
resetForms(): void {
|
||||
this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => {
|
||||
if ("resetForm" in form) {
|
||||
form?.resetForm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,9 @@ export abstract class TableModal<T> extends Table<T> {
|
|||
|
||||
resetForms(): void {
|
||||
this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => {
|
||||
if ("resetForm" in form) {
|
||||
form?.resetForm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,27 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
|
|||
${t`Stage-specific settings`}
|
||||
</span>
|
||||
<div slot="body" class="pf-c-form">
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Device classes`}
|
||||
?required=${true}
|
||||
name="deviceClasses">
|
||||
<select name="users" class="pf-c-form-control" multiple>
|
||||
<option value=${DeviceClassesEnum.Static} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Static)}>
|
||||
${t`Static Tokens`}
|
||||
</option>
|
||||
<option value=${DeviceClassesEnum.Totp} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Totp)}>
|
||||
${t`TOTP Authenticators`}
|
||||
</option>
|
||||
<option value=${DeviceClassesEnum.Webauthn} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Webauthn)}>
|
||||
${t`WebAuthn Authenticators`}
|
||||
</option>
|
||||
<option value=${DeviceClassesEnum.Duo} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Duo)}>
|
||||
${t`Duo Authenticators`}
|
||||
</option>
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">${t`Device classes which can be used to authenticate.`}</p>
|
||||
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Not configured action`}
|
||||
?required=${true}
|
||||
|
@ -90,27 +111,6 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
|
|||
</option>
|
||||
</select>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Device classes`}
|
||||
?required=${true}
|
||||
name="deviceClasses">
|
||||
<select name="users" class="pf-c-form-control" multiple>
|
||||
<option value=${DeviceClassesEnum.Static} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Static)}>
|
||||
${t`Static Tokens`}
|
||||
</option>
|
||||
<option value=${DeviceClassesEnum.Totp} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Totp)}>
|
||||
${t`TOTP Authenticators`}
|
||||
</option>
|
||||
<option value=${DeviceClassesEnum.Webauthn} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Webauthn)}>
|
||||
${t`WebAuthn Authenticators`}
|
||||
</option>
|
||||
<option value=${DeviceClassesEnum.Duo} ?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Duo)}>
|
||||
${t`Duo Authenticators`}
|
||||
</option>
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">${t`Device classes which can be used to authenticate.`}</p>
|
||||
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
${this.showConfigurationStage ? html`
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Configuration stage`}
|
||||
|
|
|
@ -49,7 +49,7 @@ export class TenantForm extends ModelForm<Tenant, string> {
|
|||
<input type="text" value="${first(this.instance?.domain, window.location.host)}" class="pf-c-form-control" required>
|
||||
<p class="pf-c-form__helper-text">${t`Matching is done based on domain suffix, so if you enter domain.tld, foo.domain.tld will still match.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="default">
|
||||
<ak-form-element-horizontal name="_default">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?._default, false)}>
|
||||
<label class="pf-c-check__label">
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
title: Frontend-only development environment
|
||||
---
|
||||
|
||||
If you want to only make changes on the UI, you don't need a backend running from source. You can user the docker-compose install with a few customizations.
|
||||
|
||||
1. Clone the git repo from https://github.com/goauthentik/authentik
|
||||
2. In the cloned repository, follow the docker-compose installation instructions [here](../../docs/installation/docker-compose)
|
||||
3. Add the following entry to your `.env` file:
|
||||
|
||||
```
|
||||
AUTHENTIK_IMAGE=beryju.org/authentik/server
|
||||
AUTHENTIK_TAG=gh-next
|
||||
AUTHENTIK_OUTPOSTS__DOCKER_IMAGE_BASE=beryju.org/authentik/outpost-%(type)s:gh-next
|
||||
```
|
||||
|
||||
This will cause authentik to use the beta images.
|
||||
|
||||
4. Create a `local.env.yml` file to tell authentik to use local files instead of the bundled ones:
|
||||
|
||||
```yaml
|
||||
log_level: debug
|
||||
web:
|
||||
load_local_files: true
|
||||
```
|
||||
|
||||
5. Add this volume mapping to your compose file
|
||||
|
||||
```yaml
|
||||
version: '3.2'
|
||||
|
||||
services:
|
||||
# [...]
|
||||
server:
|
||||
# [...]
|
||||
volumes:
|
||||
- ./web:/web
|
||||
- ./local.env.yml:/local.env.yml
|
||||
```
|
||||
|
||||
This makes the local web files and the config file available to the authentik server.
|
||||
|
||||
6. Run `docker-compose up -d` to apply those changes to your containers.
|
||||
7. Run `make gen-web` in the project root directory to generate the API Client used by the web interfaces
|
||||
8. `cd web`
|
||||
9. Run `npm i` and then `npm run watch` to start the build process.
|
||||
|
||||
You can now access authentik on http://localhost:9000 (or https://localhost:9443).
|
||||
|
||||
You might also want to complete the initial setup under `/if/flow/initial-setup/`.
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
title: Getting started
|
||||
slug: /
|
||||
title: Full development environment
|
||||
---
|
||||
|
||||
## Backend
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Developer documentation
|
||||
slug: /
|
||||
---
|
||||
|
||||
Welcome to the authentik developer documentation. authentik is fully open source and can be found here: https://github.com/goauthentik/authentik
|
||||
|
|
@ -29,6 +29,10 @@ All of these variables can be set to values, but you can also use a URI-like for
|
|||
- `AUTHENTIK_REDIS__CACHE_DB`: Database for caching, defaults to 0
|
||||
- `AUTHENTIK_REDIS__MESSAGE_QUEUE_DB`: Database for the message queue, defaults to 1
|
||||
- `AUTHENTIK_REDIS__WS_DB`: Database for websocket connections, defaults to 2
|
||||
- `AUTHENTIK_REDIS__CACHE_TIMEOUT`: Timeout for cached data until it expires in seconds, defaults to 300
|
||||
- `AUTHENTIK_REDIS__CACHE_TIMEOUT_FLOWS`: Timeout for cached flow plans until they expire in seconds, defaults to 300
|
||||
- `AUTHENTIK_REDIS__CACHE_TIMEOUT_POLICIES`: Timeout for cached polices until they expire in seconds, defaults to 300
|
||||
- `AUTHENTIK_REDIS__CACHE_TIMEOUT_REPUTATION`: Timeout for cached reputation until they expire in seconds, defaults to 300
|
||||
|
||||
## authentik Settings
|
||||
|
||||
|
@ -100,16 +104,16 @@ Defaults to `info`.
|
|||
|
||||
Placeholder for outpost docker images. Default: `ghcr.io/goauthentik/%(type)s:%(version)s`.
|
||||
|
||||
### AUTHENTIK_AUTHENTIK
|
||||
### AUTHENTIK_AVATARS
|
||||
|
||||
- `AUTHENTIK_AUTHENTIK__AVATARS`
|
||||
Configure how authentik should show avatars for users. Following values can be set:
|
||||
|
||||
Controls which avatars are shown. Defaults to `gravatar`. Can be set to `none` to disable avatars.
|
||||
- `none`: Disables per-user avatars and just shows a 1x1 pixel transparent picture
|
||||
- `gravatar`: Uses gravatar with the user's email address
|
||||
- Any URL: If you want to use images hosted on another server, you can set any URL.
|
||||
|
||||
- `AUTHENTIK_AUTHENTIK__BRANDING__TITLE`
|
||||
Additionally, these placeholders can be used:
|
||||
|
||||
Branding title used throughout the UI. Defaults to `authentik`.
|
||||
|
||||
- `AUTHENTIK_AUTHENTIK__BRANDING__LOGO`
|
||||
|
||||
Logo shown in the sidebar and flow executions. Defaults to `/static/dist/assets/icons/icon_left_brand.svg`
|
||||
- `%(username)s`: The user's username
|
||||
- `%(mail_hash)s`: The email address, md5 hashed
|
||||
- `%(upn)s`: The user's UPN, if set (otherwise an empty string)
|
||||
|
|
|
@ -12,11 +12,11 @@ This installation method is for test-setups and small-scale productive setups.
|
|||
|
||||
## Preparation
|
||||
|
||||
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.6.1-rc6/docker-compose.yml). Place it in a directory of your choice.
|
||||
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.6.2/docker-compose.yml). Place it in a directory of your choice.
|
||||
|
||||
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
|
||||
|
||||
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.6.1-rc6 >> .env`
|
||||
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.6.2 >> .env`
|
||||
|
||||
If this is a fresh authentik install run the following commands to generate a password:
|
||||
|
||||
|
@ -74,7 +74,6 @@ Afterwards, run these commands to finish
|
|||
```shell
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
docker-compose run --rm server migrate
|
||||
```
|
||||
|
||||
The compose file statically references the latest version available at the time of downloading, which can be overridden with the `SERVER_TAG` environment variable.
|
||||
|
|
|
@ -55,13 +55,19 @@ Under Attribute mapping, set these values:
|
|||
- Attribute to map the email address to.: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`
|
||||
- Attribute to map the users groups to.: `http://schemas.xmlsoap.org/claims/Group`
|
||||
|
||||
:::note
|
||||
If Nextcloud is behind a reverse proxy you may need to force Nextcloud to use HTTPS.
|
||||
To do this you will need to add the line `'overwriteprotocol' => 'https'` to `config.php` in the Nextcloud `config\config.php` file
|
||||
See https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/reverse_proxy_configuration.html#overwrite-parameters for additional information
|
||||
:::
|
||||
|
||||
## Group Quotas
|
||||
|
||||
Create a group for each different level of quota you want users to have. Set a custom attribute, for example called `nextcloud_quota`, to the quota you want, for example `15 GB`.
|
||||
|
||||
Afterwards, create a custom SAML Property Mapping with the name `SAML NextCloud Quota`.
|
||||
Set the *SAML Name* to `nextcloud_quota`.
|
||||
Set the *Expression* to `return user.group_attributes.get("nextcloud_quota", "1 GB")`, where `1 GB` is the default value for users that don't belong to another group (or have another value set).
|
||||
Set the *Expression* to `return user.group_attributes().get("nextcloud_quota", "1 GB")`, where `1 GB` is the default value for users that don't belong to another group (or have another value set).
|
||||
|
||||
## Admin Group
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
title: Wekan
|
||||
---
|
||||
|
||||
## What is Wekan
|
||||
|
||||
From https://github.com/wekan/wekan/wiki
|
||||
|
||||
:::note
|
||||
Wekan is an open-source kanban board which allows a card-based task and to-do management.
|
||||
:::
|
||||
|
||||
## Preparation
|
||||
|
||||
The following placeholders will be used:
|
||||
|
||||
- `wekan.company` is the FQDN of the wekan install.
|
||||
- `authentik.company` is the FQDN of the authentik install.
|
||||
|
||||
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
|
||||
|
||||
- Client Type: `Confidential`
|
||||
- JWT Algorithm: `RS256`
|
||||
- Scopes: OpenID, Email and Profile
|
||||
- RSA Key: Select any available key
|
||||
- Redirect URIs: `https://wekan.company/_oauth/oidc`
|
||||
|
||||
Note the Client ID and Client Secret values. Create an application, using the provider you've created above. Note the slug of the application you've created.
|
||||
|
||||
## Wekan
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
<Tabs
|
||||
defaultValue="docker"
|
||||
values={[
|
||||
{label: 'Docker', value: 'docker'},
|
||||
{label: 'Standalone', value: 'standalone'},
|
||||
]}>
|
||||
<TabItem value="docker">
|
||||
If your Wekan is running in docker, add the following environment variables for Authentik
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
OAUTH2_ENABLED=true
|
||||
OAUTH2_LOGIN_STYLE=redirect
|
||||
OAUTH2_CLIENT_ID=<Client ID from above>
|
||||
OAUTH2_SERVER_URL=https://authentik.company
|
||||
OAUTH2_AUTH_ENDPOINT=/application/o/authorize/
|
||||
OAUTH2_USERINFO_ENDPOINT=/application/o/userinfo/
|
||||
OAUTH2_TOKEN_ENDPOINT=/application/o/token/
|
||||
OAUTH2_SECRET=<Client Secret from above>
|
||||
OAUTH2_ID_MAP=preferred_username
|
||||
OAUTH2_USERNAME_MAP=preferred_username
|
||||
OAUTH2_FULLNAME_MAP=given_name
|
||||
OAUTH2_EMAIL_MAP=email
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="standalone">
|
||||
|
||||
edit `.env` and add the following:
|
||||
|
||||
```ini
|
||||
# Authentik OAUTH Config
|
||||
OAUTH2_ENABLED='true'
|
||||
OAUTH2_LOGIN_STYLE='redirect'
|
||||
OAUTH2_CLIENT_ID='<Client ID from above>'
|
||||
OAUTH2_SERVER_URL='https://authentik.company'
|
||||
OAUTH2_AUTH_ENDPOINT='/application/o/authorize/'
|
||||
OAUTH2_USERINFO_ENDPOINT='/application/o/userinfo/'
|
||||
OAUTH2_TOKEN_ENDPOINT='/application/o/token/'
|
||||
OAUTH2_SECRET='<Client Secret from above>'
|
||||
OAUTH2_ID_MAP='preferred_username'
|
||||
OAUTH2_USERNAME_MAP='preferred_username'
|
||||
OAUTH2_FULLNAME_MAP='given_name'
|
||||
OAUTH2_EMAIL_MAP='email'
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
|
@ -39,6 +39,8 @@ Set the Field `Username attribute` to `http://schemas.goauthentik.io/2021/02/sam
|
|||
|
||||
Set the Field `SP entity ID` to `https://authentik.company/application/saml/zabbix/sso/binding/redirect/`
|
||||
|
||||
Set the Field `SP name ID format` to `urn:oasis:names:tc:SAML:2.0:nameid-format:transient`
|
||||
|
||||
Check the box for `Case sensitive login`.
|
||||
|
||||
For the `SAML Service Provider Certificate` and `SAML Service Provider Private Key`, you can either use custom certificates, or use the self-signed pair generated by authentik.
|
||||
|
|
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 115 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 60 KiB |
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
title: Discord
|
||||
---
|
||||
|
||||
Allows users to authenticate using their Discord credentials
|
||||
|
||||
## Preparation
|
||||
|
||||
The following placeholders will be used:
|
||||
|
||||
- `authentik.company` is the FQDN of the authentik install.
|
||||
|
||||
|
||||
## Discord
|
||||
|
||||
1. Create an application in the Discord Developer Portal (This is Free) https://discord.com/developers/applications
|
||||
|
||||
![New Application Button](discord1.png)
|
||||
|
||||
2. Name the Application
|
||||
|
||||
![Name App](discord2.png)
|
||||
|
||||
3. Select **OAuth2** from the left Menu
|
||||
|
||||
4. Copy the **Client ID** and _save it for later_
|
||||
|
||||
5. **Click to Reveal** the Client Secret and _save it for later_
|
||||
|
||||
6. Click **Add Redirect** and add https://authentik.company/source/oauth/callback/discord
|
||||
|
||||
Here is an example of a completed OAuth2 screen for Discord.
|
||||
|
||||
![Example Screen](discord4.png)
|
||||
|
||||
## Authentik
|
||||
|
||||
8. Under _Resources -> Sources_ Click **Create Discord OAuth Source**
|
||||
|
||||
9. **Name:** Choose a name (For the example I used Discord)
|
||||
10. **Slug:** discord (You can choose a different slug, if you do you will need to update the Discord redirect URLand point it to the correct slug.)
|
||||
11. **Consumer Key:** Client ID from step 4
|
||||
12. **Consumer Secret:** Client Secret from step 5
|
||||
13. **Provider type:** Discord
|
||||
|
||||
Here is an exmple of a complete Authentik Discord OAuth Source
|
||||
|
||||
![Example Screen](discord5.png)
|
||||
|
||||
Save, and you now have Discord as a source.
|
||||
|
||||
:::note
|
||||
For more details on how-to have the new source display on the Login Page see the Sources page
|
||||
:::
|
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 52 KiB |
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
title: Github
|
||||
---
|
||||
|
||||
Allows users to authenticate using their Github credentials
|
||||
|
||||
## Preparation
|
||||
|
||||
The following placeholders will be used:
|
||||
|
||||
- `authentik.company` is the FQDN of the authentik install.
|
||||
- `www.my.company` Homepage URL for your site
|
||||
|
||||
## Github
|
||||
|
||||
1. Create an OAuth app under Developer Settings https://github.com/settings/developers by clicking on the **Register a neww application**
|
||||
|
||||
![Register OAuth App](githubdeveloper1.png)
|
||||
|
||||
2. **Application Name:** Choose a name users will recognize ie: Authentik
|
||||
3. **Homepage URL**:: www.my.company
|
||||
4. **Authorization callback URL**: https://authentik.company/source/oauth/callback/github
|
||||
5. Click **Register Application**
|
||||
|
||||
Example screenshot
|
||||
|
||||
![Example Screen](githubdeveloperexample.png)
|
||||
|
||||
6. Copy the **Client ID** and _save it for later_
|
||||
7. Click **Generate a new client secret** and _save it for later_ You will not be able to see the secret again, so be sure to copy it now.
|
||||
|
||||
## Authentik
|
||||
|
||||
8. Under _Resources -> Sources_ Click **Create Github OAuth Source**
|
||||
|
||||
9. **Name**: Choose a name (For the example I use Github)
|
||||
10. **Slug**: github (If you choose a different slug the URLs will need to be updated to reflect the change)
|
||||
11. **Consumer Key:** Client ID from step 6
|
||||
12. **Consumer Secret:** Client Secret from step 7
|
||||
13. **Provider Type:** Github
|
||||
|
||||
Expand URL settings:
|
||||
|
||||
:::note
|
||||
As of June 20 2021 these URLS are correct. Here is the Github reference URL https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps
|
||||
:::
|
||||
|
||||
14. **Authorization URL:** `https://github.com/login/oauth/authorize`
|
||||
15. **Access token URL:** `https://github.com/login/oauth/access_token`
|
||||
16. **Profile URL:** `https://api.github.com/user`
|
||||
|
||||
Here is an exmple of a complete Authentik Github OAuth Source
|
||||
|
||||
![Example Screen](githubexample2.png)
|
||||
|
||||
Save, and you now have Github as a source.
|
||||
|
||||
:::note
|
||||
For more details on how-to have the new source display on the Login Page see the Sources page
|
||||
:::
|
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 56 KiB |
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
title: Google
|
||||
---
|
||||
|
||||
Allows users to authenticate using their Google credentials
|
||||
|
||||
## Preparation
|
||||
|
||||
The following placeholders will be used:
|
||||
|
||||
- `authentik.company` is the FQDN of the authentik install.
|
||||
|
||||
## Google
|
||||
|
||||
You will need to create a new project, and OAuth credentials in the Google Developer console. The developer console can be overwhelming at first.
|
||||
|
||||
1. Visit https://console.developers.google.com/ to create a new project
|
||||
2. Create a New project.
|
||||
|
||||
![Example Screen](googledeveloper1.png)
|
||||
|
||||
3. **Project Name**: Choose a name
|
||||
4. **Organization**: Leave as defaut if unsure
|
||||
5. **Location**: Leave as default if unsure
|
||||
|
||||
![Example Screen](googledeveloper2.png)
|
||||
|
||||
6. Click **Create**
|
||||
7. Choose your project from the drop down at the top
|
||||
8. Click the **Credentials** menu item on the left. It looks like a key.
|
||||
|
||||
![Example Screen](googledeveloper3.png)
|
||||
|
||||
9. Click on **Configure Consent Screen**
|
||||
|
||||
![Example Screen](googledeveloper4.png)
|
||||
|
||||
|
||||
10. **User Type:** If you do not have a Google Workspace (GSuite) account choose _External_. If you do have a Google Workspace (Gsuite) account and want to limit acces to only users inside of your organization choose _Internal_
|
||||
|
||||
_I'm only going to list the mandatory/important fields to complete._
|
||||
|
||||
11. **App Name:** Choose an Application
|
||||
12. **User Support Email:** Must have a value
|
||||
13. **Authorized Domains:** authentik.company
|
||||
14. **Developer Contact Info:** Must have a value
|
||||
15. Click **Save and Continue**
|
||||
16. If you have special scopes configured for google, enter them on this screen. If not click **Save and Continue**
|
||||
17. If you want to create Test Users enter them here, if not click **Save and Continue**
|
||||
18. From the _Summary Page_ click on the **Credentials* link on the left. Same link as step 8
|
||||
19. Click **Create Credentials** on the top of the screen
|
||||
20. Choose **OAuth Client ID**
|
||||
|
||||
![Example Screen](googledeveloper5.png)
|
||||
|
||||
21. **Application Type:** Web Application
|
||||
22. **Name:** Choose a name
|
||||
23. **Authorized redirect URIs:** `https://authenik.company/source/oauth/callback/google/`
|
||||
|
||||
![Example Screen](googledeveloper6.png)
|
||||
|
||||
24. Click **Create**
|
||||
25. Copy and store _Your Client ID_ and _Your Client Secret_ for later
|
||||
|
||||
## Authentik
|
||||
|
||||
26. Under _Resources -> Sources_ Click **Create Google OAuth Source**
|
||||
|
||||
27. **Name**: Choose a name (For the example I use Google)
|
||||
28. **Slug**: google (If you choose a different slug the URLs will need to be updated to reflect the change)
|
||||
29. **Consumer Key:** Your Client ID from step 25
|
||||
30. **Consumer Secret:** Your Client Secret from step 25
|
||||
31. **Provider Type:** Google
|
||||
|
||||
Here is an exmple of a complete Authentik Google OAuth Source
|
||||
|
||||
![Example Screen](authentiksource.png)
|
||||
|
||||
Save, and you now have Google as a source.
|
||||
|
||||
:::note
|
||||
For more details on how-to have the new source display on the Login Page see the Sources page
|
||||
:::
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
title: Sources
|
||||
---
|
||||
|
||||
Sources allow you to connect authentik to an existing user directory. They can also be used for social logins, using external providers such as Facebook, Twitter, etc.
|
||||
|
||||
### Add Sources to Default Login Page
|
||||
|
||||
To have sources show on the default login screen you will need to add them. This is assuming you have not created or renamed the default stages and flows.
|
||||
1. Access the **Flows** section
|
||||
2. Click on **default-authentication-flow**
|
||||
3. Click the **Stage Bindings** tab
|
||||
4. Chose **Edit Stage** for the _default-authentication-identification_ stage
|
||||
5. Under **Sources** you should see the addtional sources you have configured. Click all applicable sources to have them displayed on the Login Page
|