Compare commits
63 Commits
version/20
...
version/20
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d5c45543b | |||
| 9d476a42d1 | |||
| 2c816e6162 | |||
| dbcb4d46ba | |||
| 6600da7d98 | |||
| a265dd54cc | |||
| a603f42cc0 | |||
| d9a788aac8 | |||
| 7c6185b581 | |||
| 41a1305555 | |||
| 75f252b530 | |||
| a9519a4a68 | |||
| bf4cbb25fe | |||
| a925418f60 | |||
| ffd61d0e60 | |||
| 71d112bdcf | |||
| c58fe18b97 | |||
| 590c7f4c9d | |||
| 56f1204c9b | |||
| 349a5b2d00 | |||
| 63e3667e82 | |||
| 92f2a82c03 | |||
| dcf074650e | |||
| 5a465fbc36 | |||
| 7cd80a903a | |||
| dd00351bc7 | |||
| 5fca7d11b8 | |||
| 0ff59636f7 | |||
| e5ebe390d2 | |||
| b66626f9c4 | |||
| 23123c43ee | |||
| 8ce918d527 | |||
| 45c1a603e7 | |||
| 583271d5ed | |||
| 176360fdd7 | |||
| 8d2a3b67b9 | |||
| d0d3072c50 | |||
| 34e2bbc41d | |||
| ea2dbb2f33 | |||
| c55f2ad10a | |||
| 2cde40aeee | |||
| a30b32fbbf | |||
| 1745306cc6 | |||
| 8925787a13 | |||
| 968b7ec17a | |||
| 6600d5bf69 | |||
| a4278833d8 | |||
| 942905b9b1 | |||
| 81056c3889 | |||
| 36b694fc41 | |||
| 2d9f216658 | |||
| 8d7bb7da17 | |||
| 965db6eaf5 | |||
| 9bdd6f23a4 | |||
| 675ad7710c | |||
| 9939db13c3 | |||
| 03e134b296 | |||
| 465750276c | |||
| 9b13191646 | |||
| 634ea61b50 | |||
| 0fcb4936a2 | |||
| 934e62d5be | |||
| c5e9197b19 |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 2021.5.1
|
||||
current_version = 2021.5.4
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*)
|
||||
@ -31,8 +31,6 @@ values =
|
||||
|
||||
[bumpversion:file:web/src/constants.ts]
|
||||
|
||||
[bumpversion:file:web/nginx.conf]
|
||||
|
||||
[bumpversion:file:website/docs/outposts/manual-deploy-docker-compose.md]
|
||||
|
||||
[bumpversion:file:website/docs/outposts/manual-deploy-kubernetes.md]
|
||||
|
||||
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@ -36,9 +36,9 @@ jobs:
|
||||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik:2021.5.1,
|
||||
beryju/authentik:2021.5.4,
|
||||
beryju/authentik:latest,
|
||||
ghcr.io/goauthentik/server:2021.5.1,
|
||||
ghcr.io/goauthentik/server:2021.5.4,
|
||||
ghcr.io/goauthentik/server:latest
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
@ -75,9 +75,9 @@ jobs:
|
||||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-proxy:2021.5.1,
|
||||
beryju/authentik-proxy:2021.5.4,
|
||||
beryju/authentik-proxy:latest,
|
||||
ghcr.io/goauthentik/proxy:2021.5.1,
|
||||
ghcr.io/goauthentik/proxy:2021.5.4,
|
||||
ghcr.io/goauthentik/proxy:latest
|
||||
context: outpost/
|
||||
file: outpost/proxy.Dockerfile
|
||||
@ -115,9 +115,9 @@ jobs:
|
||||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-ldap:2021.5.1,
|
||||
beryju/authentik-ldap:2021.5.4,
|
||||
beryju/authentik-ldap:latest,
|
||||
ghcr.io/goauthentik/ldap:2021.5.1,
|
||||
ghcr.io/goauthentik/ldap:2021.5.4,
|
||||
ghcr.io/goauthentik/ldap:latest
|
||||
context: outpost/
|
||||
file: outpost/ldap.Dockerfile
|
||||
@ -155,5 +155,5 @@ jobs:
|
||||
SENTRY_PROJECT: authentik
|
||||
SENTRY_URL: https://sentry.beryju.org
|
||||
with:
|
||||
version: authentik@2021.5.1
|
||||
version: authentik@2021.5.4
|
||||
environment: beryjuorg-prod
|
||||
|
||||
120
Pipfile.lock
generated
120
Pipfile.lock
generated
@ -56,7 +56,6 @@
|
||||
"sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a",
|
||||
"sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.7.4.post0"
|
||||
},
|
||||
"aioredis": {
|
||||
@ -71,7 +70,6 @@
|
||||
"sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2",
|
||||
"sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.0.6"
|
||||
},
|
||||
"asgiref": {
|
||||
@ -79,7 +77,6 @@
|
||||
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
|
||||
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.3.4"
|
||||
},
|
||||
"async-timeout": {
|
||||
@ -87,7 +84,6 @@
|
||||
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
|
||||
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
|
||||
],
|
||||
"markers": "python_full_version >= '3.5.3'",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"attrs": {
|
||||
@ -95,7 +91,6 @@
|
||||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==21.2.0"
|
||||
},
|
||||
"autobahn": {
|
||||
@ -103,7 +98,6 @@
|
||||
"sha256:9195df8af03b0ff29ccd4b7f5abbde957ee90273465942205f9a1bad6c3f07ac",
|
||||
"sha256:e126c1f583e872fb59e79d36977cfa1f2d0a8a79f90ae31f406faae7664b8e03"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==21.3.1"
|
||||
},
|
||||
"automat": {
|
||||
@ -122,25 +116,24 @@
|
||||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:3317722a1e9acbfc0d30cdf273d1708c823ceb19309e9cd91cac8a3604762341",
|
||||
"sha256:ee3317fd79b443ef102469fac393a1ffb650ea51ac4fc27464013872c5e1ce31"
|
||||
"sha256:13cfe0e3ae1bdc7baf4272b1814a7e760fbb508b19d6ac3f472a6bbd64baad61",
|
||||
"sha256:ce08b88a2d7a0ad8edb385f84ea4914296fee6813c66ebf0def956d5278de793"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.17.72"
|
||||
"version": "==1.17.73"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:0fa93a2e2daad5791c63ee526ada66896cc483d04cb2d32bfcadfeb881203453"
|
||||
"sha256:4b4aa58c61d4b125bc6ec1597924b2749e19de8f2c9a374ac087aa2561e71828",
|
||||
"sha256:69dc0b6fdc0855f5a4f8b1d29c96b9cec44e71054fea0f968e5904d6ccfd4fd9"
|
||||
],
|
||||
"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.72"
|
||||
"version": "==1.20.73"
|
||||
},
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
"sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001",
|
||||
"sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"
|
||||
],
|
||||
"markers": "python_version ~= '3.5'",
|
||||
"version": "==4.2.2"
|
||||
},
|
||||
"cbor2": {
|
||||
@ -227,7 +220,6 @@
|
||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"click": {
|
||||
@ -235,7 +227,6 @@
|
||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==7.1.2"
|
||||
},
|
||||
"click-didyoumean": {
|
||||
@ -309,7 +300,6 @@
|
||||
"sha256:76ffae916ba3aa66b46996c14fa713e46004788167a4873d647544e750e0e99f",
|
||||
"sha256:a9af943c79717bc52fe64a3c236ae5d3adccc8b5be19c881b442d2c3db233393"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.2"
|
||||
},
|
||||
"defusedxml": {
|
||||
@ -330,9 +320,6 @@
|
||||
},
|
||||
"django-dbbackup": {
|
||||
"git": "https://github.com/django-dbbackup/django-dbbackup.git",
|
||||
"hashes": [
|
||||
"sha256:bb109735cae98b64ad084e5b461b7aca2d7b39992f10c9ed9435e3ebb6fb76c8"
|
||||
],
|
||||
"ref": "9d1909c30a3271c8c9c8450add30d6e0b996e145"
|
||||
},
|
||||
"django-filter": {
|
||||
@ -435,7 +422,6 @@
|
||||
"hashes": [
|
||||
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.18.2"
|
||||
},
|
||||
"geoip2": {
|
||||
@ -451,7 +437,6 @@
|
||||
"sha256:588bdb03a41ecb4978472b847881e5518b5d9ec6153d3d679aa127a55e13b39f",
|
||||
"sha256:9ad25fba07f46a628ad4d0ca09f38dcb262830df2ac95b217f9b0129c9e42206"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.30.0"
|
||||
},
|
||||
"gunicorn": {
|
||||
@ -467,7 +452,6 @@
|
||||
"sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6",
|
||||
"sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.12.0"
|
||||
},
|
||||
"hiredis": {
|
||||
@ -514,7 +498,6 @@
|
||||
"sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0",
|
||||
"sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"httptools": {
|
||||
@ -563,7 +546,6 @@
|
||||
"sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417",
|
||||
"sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"itypes": {
|
||||
@ -578,7 +560,6 @@
|
||||
"sha256:2f2de5285cf37f33d33ecd4a9080b75c87cd0c1994d5a9c6df17131ea1f049c6",
|
||||
"sha256:ea8d7dd814ce9df6de6a761ec7f1cac98afe305b8cdc4aaae4e114b8d8ce24c5"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"jmespath": {
|
||||
@ -586,7 +567,6 @@
|
||||
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
|
||||
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.0"
|
||||
},
|
||||
"jsonschema": {
|
||||
@ -601,7 +581,6 @@
|
||||
"sha256:6dc509178ac4269b0e66ab4881f70a2035c33d3a622e20585f965986a5182006",
|
||||
"sha256:f4965fba0a4718d47d470beeb5d6446e3357a62402b16c510b6a2f251e05ac3c"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.0.2"
|
||||
},
|
||||
"kubernetes": {
|
||||
@ -614,11 +593,8 @@
|
||||
},
|
||||
"ldap3": {
|
||||
"hashes": [
|
||||
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57",
|
||||
"sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91",
|
||||
"sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c",
|
||||
"sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056",
|
||||
"sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59"
|
||||
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.9"
|
||||
@ -712,14 +688,12 @@
|
||||
"sha256:f58b5ba13a5689ca8317b98439fccfbcc673acaaf8241c1869ceea40f5d585bf",
|
||||
"sha256:fef86115fdad7ae774720d7103aa776144cf9b66673b4afa9bcaa7af990ed07b"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"maxminddb": {
|
||||
"hashes": [
|
||||
"sha256:47e86a084dd814fac88c99ea34ba3278a74bc9de5a25f4b815b608798747c7dc"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.3"
|
||||
},
|
||||
"msgpack": {
|
||||
@ -795,7 +769,6 @@
|
||||
"sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281",
|
||||
"sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.1.0"
|
||||
},
|
||||
"oauthlib": {
|
||||
@ -803,7 +776,6 @@
|
||||
"sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
|
||||
"sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"packaging": {
|
||||
@ -819,7 +791,6 @@
|
||||
"sha256:030e4f9df5f53db2292eec37c6255957eb76168c6f974e4176c711cf91ed34aa",
|
||||
"sha256:b6c5a9643e3545bcbfd9451766cbaa5d9c67e7303c7bc32c750b6fa70ecb107d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.1"
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
@ -827,7 +798,6 @@
|
||||
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
|
||||
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.1'",
|
||||
"version": "==3.0.18"
|
||||
},
|
||||
"psycopg2-binary": {
|
||||
@ -873,37 +843,15 @@
|
||||
},
|
||||
"pyasn1": {
|
||||
"hashes": [
|
||||
"sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
|
||||
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
|
||||
"sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
|
||||
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
|
||||
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
|
||||
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
|
||||
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3",
|
||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
|
||||
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
|
||||
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
|
||||
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
|
||||
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
|
||||
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"
|
||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"
|
||||
],
|
||||
"version": "==0.4.8"
|
||||
},
|
||||
"pyasn1-modules": {
|
||||
"hashes": [
|
||||
"sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
|
||||
"sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
|
||||
"sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
|
||||
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
|
||||
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
|
||||
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
|
||||
"sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
|
||||
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
|
||||
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
|
||||
"sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
|
||||
"sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405",
|
||||
"sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
|
||||
"sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199"
|
||||
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"
|
||||
],
|
||||
"version": "==0.2.8"
|
||||
},
|
||||
@ -912,7 +860,6 @@
|
||||
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
|
||||
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.20"
|
||||
},
|
||||
"pycryptodome": {
|
||||
@ -956,7 +903,6 @@
|
||||
"sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316",
|
||||
"sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.0.2"
|
||||
},
|
||||
"pyjwt": {
|
||||
@ -979,14 +925,12 @@
|
||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pyrsistent": {
|
||||
"hashes": [
|
||||
"sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.17.3"
|
||||
},
|
||||
"python-dateutil": {
|
||||
@ -994,7 +938,6 @@
|
||||
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
|
||||
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.8.1"
|
||||
},
|
||||
"python-dotenv": {
|
||||
@ -1051,7 +994,6 @@
|
||||
"sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",
|
||||
"sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==3.5.3"
|
||||
},
|
||||
"requests": {
|
||||
@ -1059,14 +1001,12 @@
|
||||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"requests-oauthlib": {
|
||||
"hashes": [
|
||||
"sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
|
||||
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a",
|
||||
"sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"
|
||||
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.3.0"
|
||||
@ -1084,7 +1024,6 @@
|
||||
"sha256:44bc6b54fddd45e4bc0619059196679f9e8b79c027f4131bb072e6a22f4d5e28",
|
||||
"sha256:ac79fb25f5476e8e9ed1c53b8a2286d2c3f5dde49eb37dbcee5c7eb6a8415a22"
|
||||
],
|
||||
"markers": "python_version >= '3'",
|
||||
"version": "==0.17.4"
|
||||
},
|
||||
"ruamel.yaml.clib": {
|
||||
@ -1121,7 +1060,7 @@
|
||||
"sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2",
|
||||
"sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f"
|
||||
],
|
||||
"markers": "python_version < '3.10' and platform_python_implementation == 'CPython'",
|
||||
"markers": "platform_python_implementation == 'CPython' and python_version < '3.10'",
|
||||
"version": "==0.2.2"
|
||||
},
|
||||
"s3transfer": {
|
||||
@ -1152,7 +1091,6 @@
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"sqlparse": {
|
||||
@ -1160,7 +1098,6 @@
|
||||
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
|
||||
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.4.1"
|
||||
},
|
||||
"structlog": {
|
||||
@ -1216,7 +1153,6 @@
|
||||
"sha256:7d6f89745680233f1c4db9ddb748df5e88d2a7a37962be174c0fd04c8dba1dc8",
|
||||
"sha256:c16b55f9a67b2419cfdf8846576e2ec9ba94fe6978a83080c352a80db31c93fb"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==21.2.1"
|
||||
},
|
||||
"typing-extensions": {
|
||||
@ -1232,7 +1168,6 @@
|
||||
"sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f",
|
||||
"sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"urllib3": {
|
||||
@ -1277,7 +1212,6 @@
|
||||
"sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30",
|
||||
"sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.0.0"
|
||||
},
|
||||
"watchgod": {
|
||||
@ -1307,7 +1241,6 @@
|
||||
"sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32",
|
||||
"sha256:d376bd60eace9d437ab6d7ee16f4ab4e821c9dae591e1b783c58ebd8aaf80c5c"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.59.0"
|
||||
},
|
||||
"websockets": {
|
||||
@ -1394,7 +1327,6 @@
|
||||
"sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a",
|
||||
"sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.6.3"
|
||||
},
|
||||
"zope.interface": {
|
||||
@ -1451,7 +1383,6 @@
|
||||
"sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4",
|
||||
"sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==5.4.0"
|
||||
}
|
||||
},
|
||||
@ -1468,7 +1399,6 @@
|
||||
"sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e",
|
||||
"sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"
|
||||
],
|
||||
"markers": "python_version ~= '3.6'",
|
||||
"version": "==2.5.6"
|
||||
},
|
||||
"attrs": {
|
||||
@ -1476,7 +1406,6 @@
|
||||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==21.2.0"
|
||||
},
|
||||
"bandit": {
|
||||
@ -1515,7 +1444,6 @@
|
||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"click": {
|
||||
@ -1523,7 +1451,6 @@
|
||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==7.1.2"
|
||||
},
|
||||
"colorama": {
|
||||
@ -1597,16 +1524,14 @@
|
||||
"sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0",
|
||||
"sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"
|
||||
],
|
||||
"markers": "python_version >= '3.4'",
|
||||
"version": "==4.0.7"
|
||||
},
|
||||
"gitpython": {
|
||||
"hashes": [
|
||||
"sha256:2bfcd25e6b81fe431fa3ab1f0975986cfddabf7870a323c183f3afbc9447c0c5",
|
||||
"sha256:37ac36cacf2e2be5e88f0810187c5833e71c1a2a8cf81588f5699d1b70183baa"
|
||||
"sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135",
|
||||
"sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==3.1.16"
|
||||
"version": "==3.1.17"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
@ -1627,7 +1552,6 @@
|
||||
"sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
|
||||
"sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
|
||||
],
|
||||
"markers": "python_version >= '3.6' and python_version < '4.0'",
|
||||
"version": "==5.8.0"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
@ -1655,7 +1579,6 @@
|
||||
"sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
|
||||
"sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.6.0"
|
||||
},
|
||||
"mccabe": {
|
||||
@ -1692,7 +1615,6 @@
|
||||
"sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd",
|
||||
"sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"
|
||||
],
|
||||
"markers": "python_version >= '2.6'",
|
||||
"version": "==5.6.0"
|
||||
},
|
||||
"pluggy": {
|
||||
@ -1700,7 +1622,6 @@
|
||||
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
|
||||
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.13.1"
|
||||
},
|
||||
"py": {
|
||||
@ -1708,7 +1629,6 @@
|
||||
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
|
||||
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.10.0"
|
||||
},
|
||||
"pylint": {
|
||||
@ -1739,7 +1659,6 @@
|
||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pytest": {
|
||||
@ -1752,11 +1671,11 @@
|
||||
},
|
||||
"pytest-django": {
|
||||
"hashes": [
|
||||
"sha256:80f8875226ec4dc0b205f0578072034563879d98d9b1bec143a80b9045716cb0",
|
||||
"sha256:a51150d8962200250e850c6adcab670779b9c2aa07271471059d1fb92a843fa9"
|
||||
"sha256:d1c6758a592fb0ef8abaa2fe12dd28858c1dcfc3d466102ffe52aa8934733dca",
|
||||
"sha256:f96c4556f4e7b15d987dd1dcc1d1526df81d40c1548d31ce840d597ed2be8c46"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.2.0"
|
||||
"version": "==4.3.0"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
@ -1844,7 +1763,6 @@
|
||||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"requests-mock": {
|
||||
@ -1868,7 +1786,6 @@
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"smmap": {
|
||||
@ -1876,7 +1793,6 @@
|
||||
"sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182",
|
||||
"sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"stevedore": {
|
||||
@ -1884,7 +1800,6 @@
|
||||
"sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee",
|
||||
"sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.3.0"
|
||||
},
|
||||
"toml": {
|
||||
@ -1892,7 +1807,6 @@
|
||||
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
|
||||
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.2"
|
||||
},
|
||||
"urllib3": {
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
"""authentik"""
|
||||
__version__ = "2021.5.1"
|
||||
__version__ = "2021.5.4"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
||||
@ -42,7 +42,7 @@ def token_from_header(raw_header: bytes) -> Optional[Token]:
|
||||
return tokens.first()
|
||||
|
||||
|
||||
class AuthentikTokenAuthentication(BaseAuthentication):
|
||||
class TokenAuthentication(BaseAuthentication):
|
||||
"""Token-based authentication using HTTP Bearer authentication"""
|
||||
|
||||
def authenticate(self, request: Request) -> Union[tuple[User, Any], None]:
|
||||
35
authentik/api/authorization.py
Normal file
35
authentik/api/authorization.py
Normal file
@ -0,0 +1,35 @@
|
||||
"""API Authorization"""
|
||||
from django.db.models import Model
|
||||
from django.db.models.query import QuerySet
|
||||
from rest_framework.filters import BaseFilterBackend
|
||||
from rest_framework.permissions import BasePermission
|
||||
from rest_framework.request import Request
|
||||
|
||||
|
||||
class OwnerFilter(BaseFilterBackend):
|
||||
"""Filter objects by their owner"""
|
||||
|
||||
owner_key = "user"
|
||||
|
||||
def filter_queryset(self, request: Request, queryset: QuerySet, view) -> QuerySet:
|
||||
return queryset.filter(**{self.owner_key: request.user})
|
||||
|
||||
|
||||
class OwnerPermissions(BasePermission):
|
||||
"""Authorize requests by an object's owner matching the requesting user"""
|
||||
|
||||
owner_key = "user"
|
||||
|
||||
def has_permission(self, request: Request, view) -> bool:
|
||||
"""If the user is authenticated, we allow all requests here. For listing, the
|
||||
object-level permissions are done by the filter backend"""
|
||||
return request.user.is_authenticated
|
||||
|
||||
def has_object_permission(self, request: Request, view, obj: Model) -> bool:
|
||||
"""Check if the object's owner matches the currently logged in user"""
|
||||
if not hasattr(obj, self.owner_key):
|
||||
return False
|
||||
owner = getattr(obj, self.owner_key)
|
||||
if owner != request.user:
|
||||
return False
|
||||
return True
|
||||
@ -5,7 +5,7 @@ from django.test import TestCase
|
||||
from guardian.shortcuts import get_anonymous_user
|
||||
from rest_framework.exceptions import AuthenticationFailed
|
||||
|
||||
from authentik.api.auth import token_from_header
|
||||
from authentik.api.authentication import token_from_header
|
||||
from authentik.core.models import Token, TokenIntents
|
||||
|
||||
|
||||
|
||||
@ -169,9 +169,19 @@ router.register("propertymappings/scope", ScopeMappingViewSet)
|
||||
router.register("authenticators/static", StaticDeviceViewSet)
|
||||
router.register("authenticators/totp", TOTPDeviceViewSet)
|
||||
router.register("authenticators/webauthn", WebAuthnDeviceViewSet)
|
||||
router.register("authenticators/admin/static", StaticAdminDeviceViewSet)
|
||||
router.register("authenticators/admin/totp", TOTPAdminDeviceViewSet)
|
||||
router.register("authenticators/admin/webauthn", WebAuthnAdminDeviceViewSet)
|
||||
router.register(
|
||||
"authenticators/admin/static",
|
||||
StaticAdminDeviceViewSet,
|
||||
basename="admin-staticdevice",
|
||||
)
|
||||
router.register(
|
||||
"authenticators/admin/totp", TOTPAdminDeviceViewSet, basename="admin-totpdevice"
|
||||
)
|
||||
router.register(
|
||||
"authenticators/admin/webauthn",
|
||||
WebAuthnAdminDeviceViewSet,
|
||||
basename="admin-webauthndevice",
|
||||
)
|
||||
|
||||
router.register("stages/all", StageViewSet)
|
||||
router.register("stages/authenticator/static", AuthenticatorStaticStageViewSet)
|
||||
|
||||
@ -23,6 +23,7 @@ from authentik.core.api.providers import ProviderSerializer
|
||||
from authentik.core.models import Application
|
||||
from authentik.events.models import EventAction
|
||||
from authentik.policies.engine import PolicyEngine
|
||||
from authentik.stages.user_login.stage import USER_LOGIN_AUTHENTICATED
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
@ -122,6 +123,7 @@ class ApplicationViewSet(ModelViewSet):
|
||||
)
|
||||
def list(self, request: Request) -> Response:
|
||||
"""Custom list method that checks Policy based access instead of guardian"""
|
||||
self.request.session.pop(USER_LOGIN_AUTHENTICATED, None)
|
||||
queryset = self._filter_queryset_for_list(self.get_queryset())
|
||||
self.paginate_queryset(queryset)
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ class PropertyMappingViewSet(
|
||||
filterset_fields = {"managed": ["isnull"]}
|
||||
ordering = ["name"]
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self): # pragma: no cover
|
||||
return PropertyMapping.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
|
||||
@ -63,7 +63,7 @@ class ProviderViewSet(
|
||||
"application__name",
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self): # pragma: no cover
|
||||
return Provider.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
|
||||
@ -61,7 +61,7 @@ class SourceViewSet(
|
||||
serializer_class = SourceSerializer
|
||||
lookup_field = "slug"
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self): # pragma: no cover
|
||||
return Source.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
|
||||
@ -139,7 +139,7 @@ class UserViewSet(ModelViewSet):
|
||||
search_fields = ["username", "name", "is_active"]
|
||||
filterset_class = UsersFilter
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self): # pragma: no cover
|
||||
return User.objects.all().exclude(pk=get_anonymous_user().pk)
|
||||
|
||||
@swagger_auto_schema(responses={200: SessionUserSerializer(many=False)})
|
||||
|
||||
@ -4,7 +4,7 @@ from channels.generic.websocket import JsonWebsocketConsumer
|
||||
from rest_framework.exceptions import AuthenticationFailed
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.api.auth import token_from_header
|
||||
from authentik.api.authentication import token_from_header
|
||||
from authentik.core.models import User
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
20
authentik/core/migrations/0021_alter_application_slug.py
Normal file
20
authentik/core/migrations/0021_alter_application_slug.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Generated by Django 3.2.3 on 2021-05-14 08:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_core", "0020_source_user_matching_mode"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="application",
|
||||
name="slug",
|
||||
field=models.SlugField(
|
||||
help_text="Internal application name, used in URLs.", unique=True
|
||||
),
|
||||
),
|
||||
]
|
||||
@ -207,7 +207,9 @@ class Application(PolicyBindingModel):
|
||||
add custom fields and other properties"""
|
||||
|
||||
name = models.TextField(help_text=_("Application's display Name."))
|
||||
slug = models.SlugField(help_text=_("Internal application name, used in URLs."))
|
||||
slug = models.SlugField(
|
||||
help_text=_("Internal application name, used in URLs."), unique=True
|
||||
)
|
||||
provider = models.OneToOneField(
|
||||
"Provider", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT
|
||||
)
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
"""Notification API Views"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.fields import ReadOnlyField
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
||||
from authentik.events.api.event import EventSerializer
|
||||
from authentik.events.models import Notification
|
||||
|
||||
@ -49,12 +49,5 @@ class NotificationViewSet(
|
||||
"event",
|
||||
"seen",
|
||||
]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
return Notification.objects.filter(user=user.pk)
|
||||
permission_classes = [OwnerPermissions]
|
||||
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||
|
||||
@ -65,7 +65,7 @@ class StageViewSet(
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self): # pragma: no cover
|
||||
return Stage.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
|
||||
@ -21,7 +21,7 @@ context["user_backend"] = "django.contrib.auth.backends.ModelBackend"
|
||||
return True"""
|
||||
|
||||
|
||||
def create_default_oob_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||
def create_default_oobe_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||
from authentik.stages.prompt.models import FieldTypes
|
||||
|
||||
User = apps.get_model("authentik_core", "User")
|
||||
@ -52,20 +52,20 @@ def create_default_oob_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor)
|
||||
|
||||
# Create a policy that sets the flow's user
|
||||
prefill_policy, _ = ExpressionPolicy.objects.using(db_alias).update_or_create(
|
||||
name="default-oob-prefill-user",
|
||||
name="default-oobe-prefill-user",
|
||||
defaults={"expression": PREFILL_POLICY_EXPRESSION},
|
||||
)
|
||||
password_usable_policy, _ = ExpressionPolicy.objects.using(
|
||||
db_alias
|
||||
).update_or_create(
|
||||
name="default-oob-password-usable",
|
||||
name="default-oobe-password-usable",
|
||||
defaults={"expression": PW_USABLE_POLICY_EXPRESSION},
|
||||
)
|
||||
|
||||
prompt_header, _ = Prompt.objects.using(db_alias).update_or_create(
|
||||
field_key="oob-header-text",
|
||||
field_key="oobe-header-text",
|
||||
defaults={
|
||||
"label": "oob-header-text",
|
||||
"label": "oobe-header-text",
|
||||
"type": FieldTypes.STATIC,
|
||||
"placeholder": "Welcome to authentik! Please set a password for the default admin user, akadmin.",
|
||||
"order": 100,
|
||||
@ -84,7 +84,7 @@ def create_default_oob_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor)
|
||||
password_second = Prompt.objects.using(db_alias).get(field_key="password_repeat")
|
||||
|
||||
prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create(
|
||||
name="default-oob-password",
|
||||
name="default-oobe-password",
|
||||
)
|
||||
prompt_stage.fields.set(
|
||||
[prompt_header, prompt_email, password_first, password_second]
|
||||
@ -102,7 +102,7 @@ def create_default_oob_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor)
|
||||
slug="initial-setup",
|
||||
designation=FlowDesignation.STAGE_CONFIGURATION,
|
||||
defaults={
|
||||
"name": "default-oob-setup",
|
||||
"name": "default-oobe-setup",
|
||||
"title": "Welcome to authentik!",
|
||||
},
|
||||
)
|
||||
@ -146,5 +146,5 @@ class Migration(migrations.Migration):
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(create_default_oob_flow),
|
||||
migrations.RunPython(create_default_oobe_flow),
|
||||
]
|
||||
|
||||
@ -298,7 +298,7 @@ class CancelView(View):
|
||||
if SESSION_KEY_PLAN in request.session:
|
||||
del request.session[SESSION_KEY_PLAN]
|
||||
LOGGER.debug("Canceled current plan")
|
||||
return redirect("authentik_core:default-invalidation")
|
||||
return redirect("authentik_flows:default-invalidation")
|
||||
|
||||
|
||||
class ToDefaultFlow(View):
|
||||
|
||||
@ -88,10 +88,10 @@ class ConfigLoader:
|
||||
value = os.getenv(url.netloc, url.query)
|
||||
if url.scheme == "file":
|
||||
try:
|
||||
with open(url.netloc, "r") as _file:
|
||||
with open(url.path, "r") as _file:
|
||||
value = _file.read()
|
||||
except OSError:
|
||||
self._log("error", f"Failed to read config value from {url.netloc}")
|
||||
self._log("error", f"Failed to read config value from {url.path}")
|
||||
value = url.query
|
||||
return value
|
||||
|
||||
|
||||
@ -8,7 +8,11 @@ from botocore.exceptions import BotoCoreError
|
||||
from celery.exceptions import CeleryError
|
||||
from channels.middleware import BaseMiddleware
|
||||
from channels_redis.core import ChannelFull
|
||||
from django.core.exceptions import SuspiciousOperation, ValidationError
|
||||
from django.core.exceptions import (
|
||||
ImproperlyConfigured,
|
||||
SuspiciousOperation,
|
||||
ValidationError,
|
||||
)
|
||||
from django.db import InternalError, OperationalError, ProgrammingError
|
||||
from django.http.response import Http404
|
||||
from django_redis.exceptions import ConnectionInterrupted
|
||||
@ -51,7 +55,8 @@ def before_send(event: dict, hint: dict) -> Optional[dict]:
|
||||
ConnectionResetError,
|
||||
OSError,
|
||||
PermissionError,
|
||||
# Django DB Errors
|
||||
# Django Errors
|
||||
ImproperlyConfigured,
|
||||
OperationalError,
|
||||
InternalError,
|
||||
ProgrammingError,
|
||||
|
||||
@ -17,7 +17,8 @@ def _get_client_ip_from_meta(meta: dict[str, Any]) -> Optional[str]:
|
||||
)
|
||||
for _header in headers:
|
||||
if _header in meta:
|
||||
return meta.get(_header).split(", ")[0]
|
||||
ips: list[str] = meta.get(_header).split(",")
|
||||
return ips[0].strip()
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@ -2,28 +2,6 @@
|
||||
from django.http import HttpRequest
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import CreateView
|
||||
from guardian.shortcuts import assign_perm
|
||||
|
||||
|
||||
class CreateAssignPermView(CreateView):
|
||||
"""Assign permissions to object after creation"""
|
||||
|
||||
permissions = [
|
||||
"%s.view_%s",
|
||||
"%s.change_%s",
|
||||
"%s.delete_%s",
|
||||
]
|
||||
|
||||
def form_valid(self, form):
|
||||
response = super().form_valid(form)
|
||||
for permission in self.permissions:
|
||||
full_permission = permission % (
|
||||
self.object._meta.app_label,
|
||||
self.object._meta.model_name,
|
||||
)
|
||||
assign_perm(full_permission, self.request.user, self.object)
|
||||
return response
|
||||
|
||||
|
||||
def bad_request_message(
|
||||
|
||||
@ -40,7 +40,7 @@ class WebsocketMessage:
|
||||
class OutpostConsumer(AuthJsonConsumer):
|
||||
"""Handler for Outposts that connect over websockets for health checks and live updates"""
|
||||
|
||||
outpost: Optional[Outpost] = None
|
||||
outpost: Outpost
|
||||
|
||||
last_uid: Optional[str] = None
|
||||
|
||||
@ -64,7 +64,10 @@ class OutpostConsumer(AuthJsonConsumer):
|
||||
# pylint: disable=unused-argument
|
||||
def disconnect(self, close_code):
|
||||
if self.outpost and self.last_uid:
|
||||
OutpostState.for_channel(self.outpost, self.last_uid).delete()
|
||||
state = OutpostState.for_instance_uid(self.outpost, self.last_uid)
|
||||
if self.channel_name in state.channel_ids:
|
||||
state.channel_ids.remove(self.channel_name)
|
||||
state.save()
|
||||
LOGGER.debug(
|
||||
"removed outpost instance from cache",
|
||||
outpost=self.outpost,
|
||||
@ -75,11 +78,10 @@ class OutpostConsumer(AuthJsonConsumer):
|
||||
msg = from_dict(WebsocketMessage, content)
|
||||
uid = msg.args.get("uuid", self.channel_name)
|
||||
self.last_uid = uid
|
||||
state = OutpostState(
|
||||
uid=uid,
|
||||
last_seen=datetime.now(),
|
||||
_outpost=self.outpost,
|
||||
)
|
||||
state = OutpostState.for_instance_uid(self.outpost, uid)
|
||||
if self.channel_name not in state.channel_ids:
|
||||
state.channel_ids.append(self.channel_name)
|
||||
state.last_seen = datetime.now()
|
||||
if msg.instruction == WebsocketMessageInstruction.HELLO:
|
||||
state.version = msg.args.get("version", None)
|
||||
state.build_hash = msg.args.get("buildHash", "")
|
||||
|
||||
@ -409,6 +409,7 @@ class OutpostState:
|
||||
"""Outpost instance state, last_seen and version"""
|
||||
|
||||
uid: str
|
||||
channel_ids: list[str] = field(default_factory=list)
|
||||
last_seen: Optional[datetime] = field(default=None)
|
||||
version: Optional[str] = field(default=None)
|
||||
version_should: Union[Version, LegacyVersion] = field(default=OUR_VERSION)
|
||||
@ -431,21 +432,20 @@ class OutpostState:
|
||||
keys = cache.keys(f"{outpost.state_cache_prefix}_*")
|
||||
states = []
|
||||
for key in keys:
|
||||
channel = key.replace(f"{outpost.state_cache_prefix}_", "")
|
||||
states.append(OutpostState.for_channel(outpost, channel))
|
||||
instance_uid = key.replace(f"{outpost.state_cache_prefix}_", "")
|
||||
states.append(OutpostState.for_instance_uid(outpost, instance_uid))
|
||||
return states
|
||||
|
||||
@staticmethod
|
||||
def for_channel(outpost: Outpost, channel: str) -> "OutpostState":
|
||||
"""Get state for a single channel"""
|
||||
key = f"{outpost.state_cache_prefix}_{channel}"
|
||||
default_data = {"uid": channel}
|
||||
def for_instance_uid(outpost: Outpost, uid: str) -> "OutpostState":
|
||||
"""Get state for a single instance"""
|
||||
key = f"{outpost.state_cache_prefix}_{uid}"
|
||||
default_data = {"uid": uid, "channel_ids": []}
|
||||
data = cache.get(key, default_data)
|
||||
if isinstance(data, str):
|
||||
cache.delete(key)
|
||||
data = default_data
|
||||
state = from_dict(OutpostState, data)
|
||||
state.uid = channel
|
||||
# pylint: disable=protected-access
|
||||
state._outpost = outpost
|
||||
return state
|
||||
|
||||
@ -100,6 +100,8 @@ def outpost_controller(
|
||||
outpost: Outpost = cache.get(CACHE_KEY_OUTPOST_DOWN % outpost_pk)
|
||||
else:
|
||||
outpost: Outpost = Outpost.objects.get(pk=outpost_pk)
|
||||
if not outpost:
|
||||
return
|
||||
self.set_uid(slugify(outpost.name))
|
||||
try:
|
||||
controller = controller_for_outpost(outpost)
|
||||
@ -200,8 +202,11 @@ def _outpost_single_update(outpost: Outpost, layer=None):
|
||||
if not layer: # pragma: no cover
|
||||
layer = get_channel_layer()
|
||||
for state in OutpostState.for_outpost(outpost):
|
||||
LOGGER.debug("sending update", channel=state.uid, outpost=outpost)
|
||||
async_to_sync(layer.send)(state.uid, {"type": "event.update"})
|
||||
for channel in state.channel_ids:
|
||||
LOGGER.debug(
|
||||
"sending update", channel=channel, instance=state.uid, outpost=outpost
|
||||
)
|
||||
async_to_sync(layer.send)(channel, {"type": "event.update"})
|
||||
|
||||
|
||||
@CELERY_APP.task()
|
||||
|
||||
@ -91,7 +91,7 @@ class PolicyViewSet(
|
||||
}
|
||||
search_fields = ["name"]
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self): # pragma: no cover
|
||||
return Policy.objects.select_subclasses().prefetch_related(
|
||||
"bindings", "promptstage_set"
|
||||
)
|
||||
|
||||
@ -105,16 +105,21 @@ class PolicyEngine:
|
||||
if cached_policy and self.use_cache:
|
||||
self.logger.debug(
|
||||
"P_ENG: Taking result from cache",
|
||||
policy=binding.policy,
|
||||
binding=binding,
|
||||
cache_key=key,
|
||||
request=self.request,
|
||||
)
|
||||
self.__cached_policies.append(cached_policy)
|
||||
continue
|
||||
self.logger.debug("P_ENG: Evaluating policy", policy=binding.policy)
|
||||
self.logger.debug(
|
||||
"P_ENG: Evaluating policy", binding=binding, request=self.request
|
||||
)
|
||||
our_end, task_end = Pipe(False)
|
||||
task = PolicyProcess(binding, self.request, task_end)
|
||||
task.daemon = False
|
||||
self.logger.debug("P_ENG: Starting Process", policy=binding.policy)
|
||||
self.logger.debug(
|
||||
"P_ENG: Starting Process", binding=binding, request=self.request
|
||||
)
|
||||
if not CURRENT_PROCESS._config.get("daemon"):
|
||||
task.run()
|
||||
else:
|
||||
|
||||
@ -51,7 +51,12 @@ class PolicyRequest:
|
||||
LOGGER.warning("failed to get geoip data", exc=exc)
|
||||
|
||||
def __str__(self):
|
||||
return f"<PolicyRequest user={self.user}>"
|
||||
text = f"<PolicyRequest user={self.user}"
|
||||
if self.obj:
|
||||
text += f" obj={self.obj}"
|
||||
if self.http_request:
|
||||
text += f" http_request={self.http_request}"
|
||||
return text + ">"
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@ -6,13 +6,11 @@ import time
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import datetime
|
||||
from hashlib import sha256
|
||||
from typing import Any, Optional, Type, Union
|
||||
from typing import Any, Optional, Type
|
||||
from urllib.parse import urlparse
|
||||
from uuid import uuid4
|
||||
|
||||
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
|
||||
from dacite import from_dict
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.http import HttpRequest
|
||||
from django.utils import dateformat, timezone
|
||||
@ -239,7 +237,7 @@ class OAuth2Provider(Provider):
|
||||
token.access_token = token.create_access_token(user, request)
|
||||
return token
|
||||
|
||||
def get_jwt_keys(self) -> Union[RSAPrivateKey, str]:
|
||||
def get_jwt_key(self) -> str:
|
||||
"""
|
||||
Takes a provider and returns the set of keys associated with it.
|
||||
Returns a list of keys.
|
||||
@ -256,7 +254,7 @@ class OAuth2Provider(Provider):
|
||||
self.jwt_alg = JWTAlgorithms.HS256
|
||||
self.save()
|
||||
else:
|
||||
return self.rsa_key.private_key
|
||||
return self.rsa_key.key_data
|
||||
|
||||
if self.jwt_alg == JWTAlgorithms.HS256:
|
||||
return self.client_secret
|
||||
@ -300,11 +298,14 @@ class OAuth2Provider(Provider):
|
||||
|
||||
def encode(self, payload: dict[str, Any]) -> str:
|
||||
"""Represent the ID Token as a JSON Web Token (JWT)."""
|
||||
key = self.get_jwt_keys()
|
||||
headers = {}
|
||||
if self.rsa_key:
|
||||
headers["kid"] = self.rsa_key.kid
|
||||
key = self.get_jwt_key()
|
||||
# If the provider does not have an RSA Key assigned, it was switched to Symmetric
|
||||
self.refresh_from_db()
|
||||
# pyright: reportGeneralTypeIssues=false
|
||||
return encode(payload, key, algorithm=self.jwt_alg)
|
||||
return encode(payload, key, algorithm=self.jwt_alg, headers=headers)
|
||||
|
||||
class Meta:
|
||||
|
||||
@ -457,7 +458,7 @@ class RefreshToken(ExpiringModel, BaseGrantModel):
|
||||
See: http://openid.net/specs/openid-connect-core-1_0.html#IDToken"""
|
||||
sub = ""
|
||||
if self.provider.sub_mode == SubModes.HASHED_USER_ID:
|
||||
sub = sha256(f"{user.id}-{settings.SECRET_KEY}".encode("ascii")).hexdigest()
|
||||
sub = user.uid
|
||||
elif self.provider.sub_mode == SubModes.USER_EMAIL:
|
||||
sub = user.email
|
||||
elif self.provider.sub_mode == SubModes.USER_USERNAME:
|
||||
|
||||
@ -4,6 +4,7 @@ from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
from authentik.core.models import Application, User
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.providers.oauth2.errors import (
|
||||
@ -207,6 +208,7 @@ class TestAuthorize(OAuthTestCase):
|
||||
client_secret=generate_client_secret(),
|
||||
authorization_flow=flow,
|
||||
redirect_uris="http://localhost",
|
||||
rsa_key=CertificateKeyPair.objects.first(),
|
||||
)
|
||||
Application.objects.create(name="app", slug="app", provider=provider)
|
||||
state = generate_client_id()
|
||||
|
||||
@ -2,7 +2,11 @@
|
||||
from django.test import TestCase
|
||||
from jwt import decode
|
||||
|
||||
from authentik.providers.oauth2.models import OAuth2Provider, RefreshToken
|
||||
from authentik.providers.oauth2.models import (
|
||||
JWTAlgorithms,
|
||||
OAuth2Provider,
|
||||
RefreshToken,
|
||||
)
|
||||
|
||||
|
||||
class OAuthTestCase(TestCase):
|
||||
@ -19,9 +23,12 @@ class OAuthTestCase(TestCase):
|
||||
|
||||
def validate_jwt(self, token: RefreshToken, provider: OAuth2Provider):
|
||||
"""Validate that all required fields are set"""
|
||||
key = provider.client_secret
|
||||
if provider.jwt_alg == JWTAlgorithms.RS256:
|
||||
key = provider.rsa_key.public_key
|
||||
jwt = decode(
|
||||
token.access_token,
|
||||
provider.client_secret,
|
||||
key,
|
||||
algorithms=[provider.jwt_alg],
|
||||
audience=provider.client_id,
|
||||
)
|
||||
|
||||
@ -54,6 +54,7 @@ from authentik.stages.consent.stage import (
|
||||
PLAN_CONTEXT_CONSENT_PERMISSIONS,
|
||||
ConsentStageView,
|
||||
)
|
||||
from authentik.stages.user_login.stage import USER_LOGIN_AUTHENTICATED
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
@ -437,6 +438,10 @@ class AuthorizationFlowInitView(PolicyAccessView):
|
||||
if (
|
||||
PROMPT_LOGIN in self.params.prompt
|
||||
and SESSION_NEEDS_LOGIN not in self.request.session
|
||||
# To prevent the user from having to double login when prompt is set to login
|
||||
# and the user has just signed it. This session variable is set in the UserLoginStage
|
||||
# and is (quite hackily) removed from the session in applications's API's List method
|
||||
and USER_LOGIN_AUTHENTICATED not in self.request.session
|
||||
):
|
||||
self.request.session[SESSION_NEEDS_LOGIN] = True
|
||||
return self.handle_no_permission()
|
||||
|
||||
@ -53,8 +53,10 @@ class ProxyProviderSerializer(ProviderSerializer):
|
||||
return instance
|
||||
|
||||
def update(self, instance: ProxyProvider, validated_data):
|
||||
instance = super().update(instance, validated_data)
|
||||
instance.set_oauth_defaults()
|
||||
return super().update(instance, validated_data)
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
|
||||
|
||||
@ -127,7 +127,7 @@ class ProxyProvider(OutpostModel, OAuth2Provider):
|
||||
"""Ensure all OAuth2-related settings are correct"""
|
||||
self.client_type = ClientTypes.CONFIDENTIAL
|
||||
self.jwt_alg = JWTAlgorithms.RS256
|
||||
self.rsa_key = CertificateKeyPair.objects.first()
|
||||
self.rsa_key = CertificateKeyPair.objects.exclude(key_data__iexact="").first()
|
||||
scopes = ScopeMapping.objects.filter(
|
||||
scope_name__in=[
|
||||
SCOPE_OPENID,
|
||||
|
||||
@ -20,6 +20,7 @@ from time import time
|
||||
import structlog
|
||||
from celery.schedules import crontab
|
||||
from sentry_sdk import init as sentry_init
|
||||
from sentry_sdk.api import set_tag
|
||||
from sentry_sdk.integrations.celery import CeleryIntegration
|
||||
from sentry_sdk.integrations.django import DjangoIntegration
|
||||
from sentry_sdk.integrations.redis import RedisIntegration
|
||||
@ -52,11 +53,9 @@ STATIC_ROOT = BASE_DIR + "/static"
|
||||
STATICFILES_DIRS = [BASE_DIR + "/web"]
|
||||
MEDIA_ROOT = BASE_DIR + "/media"
|
||||
|
||||
SECRET_KEY = CONFIG.y(
|
||||
"secret_key", "9$@r!d^1^jrn#fk#1#@ks#9&i$^s#1)_13%$rwjrhd=e8jfi_s"
|
||||
) # noqa Debug
|
||||
|
||||
DEBUG = CONFIG.y_bool("debug")
|
||||
SECRET_KEY = CONFIG.y("secret_key")
|
||||
|
||||
INTERNAL_IPS = ["127.0.0.1"]
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
@ -162,7 +161,7 @@ REST_FRAMEWORK = {
|
||||
"rest_framework.permissions.DjangoObjectPermissions",
|
||||
),
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"authentik.api.auth.AuthentikTokenAuthentication",
|
||||
"authentik.api.authentication.TokenAuthentication",
|
||||
"rest_framework.authentication.SessionAuthentication",
|
||||
),
|
||||
"DEFAULT_RENDERER_CLASSES": [
|
||||
@ -354,6 +353,11 @@ if _ERROR_REPORTING:
|
||||
environment=CONFIG.y("error_reporting.environment", "customer"),
|
||||
send_default_pii=CONFIG.y_bool("error_reporting.send_pii", False),
|
||||
)
|
||||
set_tag("authentik:build_hash", os.environ.get(ENV_GIT_HASH_KEY, "tagged"))
|
||||
set_tag(
|
||||
"authentik:env", "kubernetes" if "KUBERNETES_PORT" in os.environ else "compose"
|
||||
)
|
||||
set_tag("authentik:component", "backend")
|
||||
j_print(
|
||||
"Error reporting is enabled",
|
||||
env=CONFIG.y("error_reporting.environment", "customer"),
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
"""OAuth Source Serializer"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.sources.oauth.models import UserOAuthSourceConnection
|
||||
|
||||
@ -21,20 +22,17 @@ class UserOAuthSourceConnectionSerializer(SourceSerializer):
|
||||
]
|
||||
|
||||
|
||||
class UserOAuthSourceConnectionViewSet(ModelViewSet):
|
||||
class UserOAuthSourceConnectionViewSet(
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""Source Viewset"""
|
||||
|
||||
queryset = UserOAuthSourceConnection.objects.all()
|
||||
serializer_class = UserOAuthSourceConnectionSerializer
|
||||
filterset_fields = ["source__slug"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
if user.is_superuser:
|
||||
return super().get_queryset()
|
||||
return super().get_queryset().filter(user=user.pk)
|
||||
permission_classes = [OwnerPermissions]
|
||||
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.3 on 2021-05-20 17:04
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_sources_plex", "0002_auto_20210505_1717"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="plexsource",
|
||||
name="plex_token",
|
||||
field=models.TextField(help_text="Plex token used to check firends"),
|
||||
),
|
||||
]
|
||||
@ -41,9 +41,7 @@ class PlexSource(Source):
|
||||
default=True,
|
||||
help_text=_("Allow friends to authenticate, even if you don't share a server."),
|
||||
)
|
||||
plex_token = models.TextField(
|
||||
default="", help_text=_("Plex token used to check firends")
|
||||
)
|
||||
plex_token = models.TextField(help_text=_("Plex token used to check firends"))
|
||||
|
||||
@property
|
||||
def component(self) -> str:
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
"""AuthenticatorStaticStage API Views"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django_otp.plugins.otp_static.models import StaticDevice
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
|
||||
|
||||
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_static.models import AuthenticatorStaticStage
|
||||
|
||||
@ -37,23 +38,22 @@ class StaticDeviceSerializer(ModelSerializer):
|
||||
depth = 2
|
||||
|
||||
|
||||
class StaticDeviceViewSet(ModelViewSet):
|
||||
class StaticDeviceViewSet(
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""Viewset for static authenticator devices"""
|
||||
|
||||
queryset = StaticDevice.objects.none()
|
||||
queryset = StaticDevice.objects.all()
|
||||
serializer_class = StaticDeviceSerializer
|
||||
permission_classes = [OwnerPermissions]
|
||||
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
return StaticDevice.objects.filter(user=user.pk)
|
||||
|
||||
|
||||
class StaticAdminDeviceViewSet(ReadOnlyModelViewSet):
|
||||
|
||||
20
authentik/stages/authenticator_static/tests.py
Normal file
20
authentik/stages/authenticator_static/tests.py
Normal file
@ -0,0 +1,20 @@
|
||||
"""Test Static API"""
|
||||
from django.urls import reverse
|
||||
from django_otp.plugins.otp_static.models import StaticDevice
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
|
||||
|
||||
class AuthenticatorStaticStage(APITestCase):
|
||||
"""Test Static API"""
|
||||
|
||||
def test_api_delete(self):
|
||||
"""Test api delete"""
|
||||
user = User.objects.create(username="foo")
|
||||
self.client.force_login(user)
|
||||
dev = StaticDevice.objects.create(user=user)
|
||||
response = self.client.delete(
|
||||
reverse("authentik_api:staticdevice-detail", kwargs={"pk": dev.pk})
|
||||
)
|
||||
self.assertEqual(response.status_code, 204)
|
||||
@ -1,12 +1,13 @@
|
||||
"""AuthenticatorTOTPStage API Views"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django_filters.rest_framework.backends import DjangoFilterBackend
|
||||
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
|
||||
|
||||
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_totp.models import AuthenticatorTOTPStage
|
||||
|
||||
@ -40,23 +41,22 @@ class TOTPDeviceSerializer(ModelSerializer):
|
||||
depth = 2
|
||||
|
||||
|
||||
class TOTPDeviceViewSet(ModelViewSet):
|
||||
class TOTPDeviceViewSet(
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""Viewset for totp authenticator devices"""
|
||||
|
||||
queryset = TOTPDevice.objects.none()
|
||||
queryset = TOTPDevice.objects.all()
|
||||
serializer_class = TOTPDeviceSerializer
|
||||
permission_classes = [OwnerPermissions]
|
||||
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
return TOTPDevice.objects.filter(user=user.pk)
|
||||
|
||||
|
||||
class TOTPAdminDeviceViewSet(ReadOnlyModelViewSet):
|
||||
|
||||
20
authentik/stages/authenticator_totp/tests.py
Normal file
20
authentik/stages/authenticator_totp/tests.py
Normal file
@ -0,0 +1,20 @@
|
||||
"""Test TOTP API"""
|
||||
from django.urls import reverse
|
||||
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
|
||||
|
||||
class AuthenticatorTOTPStage(APITestCase):
|
||||
"""Test TOTP API"""
|
||||
|
||||
def test_api_delete(self):
|
||||
"""Test api delete"""
|
||||
user = User.objects.create(username="foo")
|
||||
self.client.force_login(user)
|
||||
dev = TOTPDevice.objects.create(user=user)
|
||||
response = self.client.delete(
|
||||
reverse("authentik_api:totpdevice-detail", kwargs={"pk": dev.pk})
|
||||
)
|
||||
self.assertEqual(response.status_code, 204)
|
||||
@ -1,11 +1,12 @@
|
||||
"""AuthenticateWebAuthnStage API Views"""
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from guardian.utils import get_anonymous_user
|
||||
from django_filters.rest_framework.backends import DjangoFilterBackend
|
||||
from rest_framework import mixins
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
|
||||
|
||||
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_webauthn.models import (
|
||||
AuthenticateWebAuthnStage,
|
||||
@ -39,23 +40,22 @@ class WebAuthnDeviceSerializer(ModelSerializer):
|
||||
depth = 2
|
||||
|
||||
|
||||
class WebAuthnDeviceViewSet(ModelViewSet):
|
||||
class WebAuthnDeviceViewSet(
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""Viewset for WebAuthn authenticator devices"""
|
||||
|
||||
queryset = WebAuthnDevice.objects.none()
|
||||
queryset = WebAuthnDevice.objects.all()
|
||||
serializer_class = WebAuthnDeviceSerializer
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
OrderingFilter,
|
||||
SearchFilter,
|
||||
]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user if self.request else get_anonymous_user()
|
||||
return WebAuthnDevice.objects.filter(user=user.pk)
|
||||
permission_classes = [OwnerPermissions]
|
||||
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||
|
||||
|
||||
class WebAuthnAdminDeviceViewSet(ReadOnlyModelViewSet):
|
||||
|
||||
20
authentik/stages/authenticator_webauthn/tests.py
Normal file
20
authentik/stages/authenticator_webauthn/tests.py
Normal file
@ -0,0 +1,20 @@
|
||||
"""Test WebAuthn API"""
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
||||
|
||||
|
||||
class AuthenticatorWebAuthnStage(APITestCase):
|
||||
"""Test WebAuthn API"""
|
||||
|
||||
def test_api_delete(self):
|
||||
"""Test api delete"""
|
||||
user = User.objects.create(username="foo")
|
||||
self.client.force_login(user)
|
||||
dev = WebAuthnDevice.objects.create(user=user)
|
||||
response = self.client.delete(
|
||||
reverse("authentik_api:webauthndevice-detail", kwargs={"pk": dev.pk})
|
||||
)
|
||||
self.assertEqual(response.status_code, 204)
|
||||
@ -1,5 +1,5 @@
|
||||
"""dummy tests"""
|
||||
from django.test import Client, TestCase
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
@ -14,7 +14,6 @@ class TestDummyStage(TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-dummy",
|
||||
|
||||
@ -12,6 +12,7 @@ from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||
|
||||
LOGGER = get_logger()
|
||||
DEFAULT_BACKEND = "django.contrib.auth.backends.ModelBackend"
|
||||
USER_LOGIN_AUTHENTICATED = "user_login_authenticated"
|
||||
|
||||
|
||||
class UserLoginStageView(StageView):
|
||||
@ -43,5 +44,6 @@ class UserLoginStageView(StageView):
|
||||
flow_slug=self.executor.flow.slug,
|
||||
session_duration=self.executor.current_stage.session_duration,
|
||||
)
|
||||
self.request.session[USER_LOGIN_AUTHENTICATED] = True
|
||||
messages.success(self.request, _("Successfully logged in!"))
|
||||
return self.executor.stage_ok()
|
||||
|
||||
@ -43,7 +43,9 @@ stages:
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: pipenv run pylint authentik tests lifecycle
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run pylint authentik tests lifecycle
|
||||
- job: black
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
@ -140,7 +142,9 @@ stages:
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: pipenv run ./manage.py migrate
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run ./manage.py migrate
|
||||
- job: migrations_from_previous_release
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
@ -171,8 +175,9 @@ stages:
|
||||
- task: CmdLine@2
|
||||
displayName: Migrate to last tagged release
|
||||
inputs:
|
||||
script:
|
||||
pipenv run ./manage.py migrate
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run python -m lifecycle.migrate
|
||||
- task: CmdLine@2
|
||||
displayName: Install current branch
|
||||
inputs:
|
||||
@ -184,8 +189,8 @@ stages:
|
||||
displayName: Migrate to current branch
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run python -m lifecycle.migrate
|
||||
pipenv run ./manage.py migrate
|
||||
- job: coverage_unittest
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
@ -210,6 +215,7 @@ stages:
|
||||
displayName: Run full test suite
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run make test
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
@ -253,6 +259,7 @@ stages:
|
||||
displayName: Run full test suite
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run make test-integration
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
@ -308,6 +315,7 @@ stages:
|
||||
displayName: Run full test suite
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run make test-e2e
|
||||
- task: CmdLine@2
|
||||
condition: always()
|
||||
|
||||
@ -21,7 +21,7 @@ services:
|
||||
networks:
|
||||
- internal
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.5.1}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.5.4}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
@ -52,7 +52,7 @@ services:
|
||||
- "0.0.0.0:9000:9000"
|
||||
- "0.0.0.0:9443:9443"
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.5.1}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.5.4}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
networks:
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
package constants
|
||||
|
||||
const VERSION = "2021.5.1"
|
||||
const VERSION = "2021.5.4"
|
||||
|
||||
@ -9,7 +9,18 @@ import (
|
||||
func (ws *WebServer) configureProxy() {
|
||||
// Reverse proxy to the application server
|
||||
u, _ := url.Parse("http://localhost:8000")
|
||||
rp := httputil.NewSingleHostReverseProxy(u)
|
||||
director := func(req *http.Request) {
|
||||
req.URL.Scheme = u.Scheme
|
||||
req.URL.Host = u.Host
|
||||
if _, ok := req.Header["User-Agent"]; !ok {
|
||||
// explicitly disable User-Agent so it's not set to default value
|
||||
req.Header.Set("User-Agent", "")
|
||||
}
|
||||
if req.TLS != nil {
|
||||
req.Header.Set("X-Forwarded-Proto", "https")
|
||||
}
|
||||
}
|
||||
rp := &httputil.ReverseProxy{Director: director}
|
||||
rp.ErrorHandler = ws.proxyErrorHandler
|
||||
rp.ModifyResponse = ws.proxyModifyResponse
|
||||
ws.m.PathPrefix("/").Handler(rp)
|
||||
|
||||
@ -4,16 +4,19 @@ import (
|
||||
"net/http"
|
||||
|
||||
"goauthentik.io/internal/config"
|
||||
"goauthentik.io/internal/constants"
|
||||
staticWeb "goauthentik.io/web"
|
||||
)
|
||||
|
||||
func (ws *WebServer) configureStatic() {
|
||||
statRouter := ws.lh.NewRoute().Subrouter()
|
||||
if config.G.Debug {
|
||||
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"))))
|
||||
} else {
|
||||
ws.log.Debug("Using packaged static files")
|
||||
statRouter.Use(ws.staticHeaderMiddleware)
|
||||
ws.log.Debug("Using packaged static files with aggressive caching")
|
||||
ws.lh.PathPrefix("/static/dist").Handler(http.StripPrefix("/static", http.FileServer(http.FS(staticWeb.StaticDist))))
|
||||
ws.lh.PathPrefix("/static/authentik").Handler(http.StripPrefix("/static", http.FileServer(http.FS(staticWeb.StaticAuthentik))))
|
||||
}
|
||||
@ -41,3 +44,12 @@ func (ws *WebServer) configureStatic() {
|
||||
// Media files, always local
|
||||
ws.lh.PathPrefix("/media").Handler(http.StripPrefix("/media", http.FileServer(http.Dir(config.G.Paths.Media))))
|
||||
}
|
||||
|
||||
func (ws *WebServer) staticHeaderMiddleware(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Cache-Control", "\"public, no-transform\"")
|
||||
w.Header().Set("X-authentik-version", constants.VERSION)
|
||||
w.Header().Set("Vary", "X-authentik-version")
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ printf '{"event": "Bootstrap completed", "level": "info", "logger": "bootstrap",
|
||||
function check_if_root {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
printf '{"event": "Not running as root, disabling permission fixes", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr
|
||||
$1
|
||||
return
|
||||
fi
|
||||
SOCKET="/var/run/docker.sock"
|
||||
@ -12,18 +13,19 @@ function check_if_root {
|
||||
# Get group ID of the docker socket, so we can create a matching group and
|
||||
# add ourselves to it
|
||||
DOCKER_GID=$(stat -c '%g' $SOCKET)
|
||||
getent group $DOCKER_GID || groupadd -f -g $DOCKER_GID docker
|
||||
usermod -a -G $DOCKER_GID authentik
|
||||
fi
|
||||
# Fix permissions of backups and media
|
||||
chown -R authentik:authentik /media /backups
|
||||
chpst -u authentik env HOME=/authentik $1
|
||||
}
|
||||
|
||||
if [[ "$1" == "server" ]]; then
|
||||
python -m lifecycle.migrate
|
||||
/authentik-proxy
|
||||
elif [[ "$1" == "worker" ]]; then
|
||||
check_if_root
|
||||
chpst -u authentik env HOME=/authentik celery -A authentik.root.celery worker --autoscale 3,1 -E -B -s /tmp/celerybeat-schedule -Q authentik,authentik_scheduled,authentik_events
|
||||
check_if_root "celery -A authentik.root.celery worker --autoscale 3,1 -E -B -s /tmp/celerybeat-schedule -Q authentik,authentik_scheduled,authentik_events"
|
||||
elif [[ "$1" == "backup" ]]; then
|
||||
python -m manage dbbackup --clean
|
||||
elif [[ "$1" == "restore" ]]; then
|
||||
|
||||
@ -42,7 +42,7 @@ type APIController struct {
|
||||
// NewAPIController initialise new API Controller instance from URL and API token
|
||||
func NewAPIController(akURL url.URL, token string) *APIController {
|
||||
transport := httptransport.New(akURL.Host, client.DefaultBasePath, []string{akURL.Scheme})
|
||||
transport.Transport = SetUserAgent(getTLSTransport(), pkg.UserAgent())
|
||||
transport.Transport = SetUserAgent(GetTLSTransport(), pkg.UserAgent())
|
||||
|
||||
// create the transport
|
||||
auth := httptransport.BearerToken(token)
|
||||
|
||||
@ -52,7 +52,8 @@ func doGlobalSetup(config map[string]interface{}) {
|
||||
defer sentry.Flush(2 * time.Second)
|
||||
}
|
||||
|
||||
func getTLSTransport() http.RoundTripper {
|
||||
// GetTLSTransport Get a TLS transport instance, that skips verification if configured via environment variables.
|
||||
func GetTLSTransport() http.RoundTripper {
|
||||
value, set := os.LookupEnv("AUTHENTIK_INSECURE")
|
||||
if !set {
|
||||
value = "false"
|
||||
|
||||
@ -55,14 +55,18 @@ func (ls *LDAPServer) Start() error {
|
||||
|
||||
type transport struct {
|
||||
headers map[string]string
|
||||
inner http.RoundTripper
|
||||
}
|
||||
|
||||
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
for key, value := range t.headers {
|
||||
req.Header.Add(key, value)
|
||||
}
|
||||
return http.DefaultTransport.RoundTrip(req)
|
||||
return t.inner.RoundTrip(req)
|
||||
}
|
||||
func newTransport(headers map[string]string) *transport {
|
||||
return &transport{headers}
|
||||
func newTransport(inner http.RoundTripper, headers map[string]string) *transport {
|
||||
return &transport{
|
||||
inner: inner,
|
||||
headers: headers,
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,8 @@ import (
|
||||
goldap "github.com/go-ldap/ldap/v3"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/nmcclain/ldap"
|
||||
"goauthentik.io/outpost/pkg"
|
||||
"goauthentik.io/outpost/pkg/ak"
|
||||
"goauthentik.io/outpost/pkg/client/core"
|
||||
"goauthentik.io/outpost/pkg/client/flows"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
@ -61,7 +63,7 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne
|
||||
// Create new http client that also sets the correct ip
|
||||
client := &http.Client{
|
||||
Jar: jar,
|
||||
Transport: newTransport(map[string]string{
|
||||
Transport: newTransport(ak.SetUserAgent(ak.GetTLSTransport(), pkg.UserAgent()), map[string]string{
|
||||
"X-authentik-remote-ip": host,
|
||||
}),
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest,
|
||||
|
||||
attrs = append(attrs, AKAttrsToLDAP(u.Attributes)...)
|
||||
|
||||
dn := fmt.Sprintf("cn=%s,%s", *u.Name, pi.UserDN)
|
||||
dn := fmt.Sprintf("cn=%s,%s", *u.Username, pi.UserDN)
|
||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,19 +80,19 @@ func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *opti
|
||||
ID: "default",
|
||||
URI: provider.InternalHost,
|
||||
Path: "/",
|
||||
InsecureSkipTLSVerify: provider.InternalHostSslValidation,
|
||||
InsecureSkipTLSVerify: !provider.InternalHostSslValidation,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if provider.Certificate != nil {
|
||||
pb.log.WithField("provider", provider.ClientID).Debug("Enabling TLS")
|
||||
pb.log.WithField("provider", provider.Name).Debug("Enabling TLS")
|
||||
cert, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewCertificate(&crypto.CryptoCertificatekeypairsViewCertificateParams{
|
||||
Context: context.Background(),
|
||||
KpUUID: *provider.Certificate,
|
||||
}, pb.s.ak.Auth)
|
||||
if err != nil {
|
||||
pb.log.WithField("provider", provider.ClientID).WithError(err).Warning("Failed to fetch certificate")
|
||||
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch certificate")
|
||||
return providerOpts
|
||||
}
|
||||
key, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewPrivateKey(&crypto.CryptoCertificatekeypairsViewPrivateKeyParams{
|
||||
@ -100,17 +100,17 @@ func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *opti
|
||||
KpUUID: *provider.Certificate,
|
||||
}, pb.s.ak.Auth)
|
||||
if err != nil {
|
||||
pb.log.WithField("provider", provider.ClientID).WithError(err).Warning("Failed to fetch private key")
|
||||
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch private key")
|
||||
return providerOpts
|
||||
}
|
||||
|
||||
x509cert, err := tls.X509KeyPair([]byte(cert.Payload.Data), []byte(key.Payload.Data))
|
||||
if err != nil {
|
||||
pb.log.WithField("provider", provider.ClientID).WithError(err).Warning("Failed to parse certificate")
|
||||
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to parse certificate")
|
||||
return providerOpts
|
||||
}
|
||||
pb.cert = &x509cert
|
||||
pb.log.WithField("provider", provider.ClientID).Debug("Loaded certificates")
|
||||
pb.log.WithField("provider", provider.Name).Debug("Loaded certificates")
|
||||
}
|
||||
return providerOpts
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
session, err := p.redeemCode(req.Context(), getHost(req), req.Form.Get("code"))
|
||||
session, err := p.redeemCode(req.Context(), req.Host, req.Form.Get("code"))
|
||||
if err != nil {
|
||||
p.logger.Errorf("Error redeeming code during OAuth2 callback: %v", err)
|
||||
p.ErrorPage(rw, http.StatusInternalServerError, "Internal Server Error", "Internal Error")
|
||||
@ -207,7 +207,7 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
p.ClearCSRFCookie(rw, req)
|
||||
if c.Value != nonce {
|
||||
p.logger.WithField("user", session.Email).WithField("status", "AuthFailure").Info("Invalid authentication via OAuth2: CSRF token mismatch, potential attack")
|
||||
p.logger.WithField("is", c.Value).WithField("should", nonce).WithField("user", session.Email).WithField("status", "AuthFailure").Info("Invalid authentication via OAuth2: CSRF token mismatch, potential attack")
|
||||
p.ErrorPage(rw, http.StatusForbidden, "Permission Denied", "CSRF Failed")
|
||||
return
|
||||
}
|
||||
|
||||
@ -13,12 +13,14 @@ func getTemplates() *template.Template {
|
||||
<head>
|
||||
<title>{{.Title}}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<style>* { font-family: sans-serif; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>{{.Title}}</h2>
|
||||
<p>{{.Message}}</p>
|
||||
<hr>
|
||||
<p><a href="{{.ProxyPrefix}}/sign_in">Sign In</a></p>
|
||||
<p>Powered by <a href="https://goauthentik.io">authentik</a></p>
|
||||
</body>
|
||||
</html>{{end}}`)
|
||||
if err != nil {
|
||||
|
||||
@ -5,7 +5,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
const VERSION = "2021.5.1"
|
||||
const VERSION = "2021.5.4"
|
||||
|
||||
func BUILD() string {
|
||||
return os.Getenv("GIT_BUILD_HASH")
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
#!/bin/bash -xe
|
||||
wget -q -O - https://raw.githubusercontent.com/rancher/k3d/main/install.sh | bash
|
||||
|
||||
VERSION=3.9.0
|
||||
|
||||
wget https://www.python.org/ftp/python/$VERSION/Python-$VERSION.tgz
|
||||
tar xvzf Python-$VERSION.tgz
|
||||
cd Python-$VERSION/
|
||||
|
||||
./configure --prefix=$HOME/_work/_tool/Python/$VERSION/x64/ --enable-optimizations --with-ensurepip=install
|
||||
make -j 8
|
||||
sudo make altinstall
|
||||
touch $HOME/_work/_tool/Python/$VERSION/x64.complete
|
||||
|
||||
ln -s $HOME/_work/_tool/Python/3.9.5/x64 $HOME/_work/_tool/Python/3/x64
|
||||
ln -s $HOME/_work/_tool/Python/3.9.5/x64 $HOME/_work/_tool/Python/3.9/x64
|
||||
8
scripts/generate_ci_config.py
Normal file
8
scripts/generate_ci_config.py
Normal file
@ -0,0 +1,8 @@
|
||||
"""Utility script to generate a config for CI runs"""
|
||||
from authentik.providers.oauth2.generators import generate_client_id
|
||||
from yaml import safe_dump
|
||||
|
||||
with open("local.env.yml", "w") as _config:
|
||||
safe_dump({
|
||||
"secret_key": generate_client_id()
|
||||
}, _config, default_flow_style=False)
|
||||
102
swagger.yaml
102
swagger.yaml
@ -531,6 +531,11 @@ paths:
|
||||
description: ''
|
||||
required: false
|
||||
type: string
|
||||
- name: ordering
|
||||
in: query
|
||||
description: Which field to use when ordering the results.
|
||||
required: false
|
||||
type: string
|
||||
- name: search
|
||||
in: query
|
||||
description: A search term.
|
||||
@ -590,30 +595,6 @@ paths:
|
||||
$ref: '#/definitions/GenericError'
|
||||
tags:
|
||||
- authenticators
|
||||
post:
|
||||
operationId: authenticators_static_create
|
||||
description: Viewset for static authenticator devices
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/StaticDevice'
|
||||
responses:
|
||||
'201':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/StaticDevice'
|
||||
'400':
|
||||
description: Invalid input.
|
||||
schema:
|
||||
$ref: '#/definitions/ValidationError'
|
||||
'403':
|
||||
description: Authentication credentials were invalid, absent or insufficient.
|
||||
schema:
|
||||
$ref: '#/definitions/GenericError'
|
||||
tags:
|
||||
- authenticators
|
||||
parameters: []
|
||||
/authenticators/static/{id}/:
|
||||
get:
|
||||
@ -792,30 +773,6 @@ paths:
|
||||
$ref: '#/definitions/GenericError'
|
||||
tags:
|
||||
- authenticators
|
||||
post:
|
||||
operationId: authenticators_totp_create
|
||||
description: Viewset for totp authenticator devices
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/TOTPDevice'
|
||||
responses:
|
||||
'201':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/TOTPDevice'
|
||||
'400':
|
||||
description: Invalid input.
|
||||
schema:
|
||||
$ref: '#/definitions/ValidationError'
|
||||
'403':
|
||||
description: Authentication credentials were invalid, absent or insufficient.
|
||||
schema:
|
||||
$ref: '#/definitions/GenericError'
|
||||
tags:
|
||||
- authenticators
|
||||
parameters: []
|
||||
/authenticators/totp/{id}/:
|
||||
get:
|
||||
@ -994,30 +951,6 @@ paths:
|
||||
$ref: '#/definitions/GenericError'
|
||||
tags:
|
||||
- authenticators
|
||||
post:
|
||||
operationId: authenticators_webauthn_create
|
||||
description: Viewset for WebAuthn authenticator devices
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/WebAuthnDevice'
|
||||
responses:
|
||||
'201':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/WebAuthnDevice'
|
||||
'400':
|
||||
description: Invalid input.
|
||||
schema:
|
||||
$ref: '#/definitions/ValidationError'
|
||||
'403':
|
||||
description: Authentication credentials were invalid, absent or insufficient.
|
||||
schema:
|
||||
$ref: '#/definitions/GenericError'
|
||||
tags:
|
||||
- authenticators
|
||||
parameters: []
|
||||
/authenticators/webauthn/{id}/:
|
||||
get:
|
||||
@ -10420,30 +10353,6 @@ paths:
|
||||
$ref: '#/definitions/GenericError'
|
||||
tags:
|
||||
- sources
|
||||
post:
|
||||
operationId: sources_oauth_user_connections_create
|
||||
description: Source Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/UserOAuthSourceConnection'
|
||||
responses:
|
||||
'201':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/UserOAuthSourceConnection'
|
||||
'400':
|
||||
description: Invalid input.
|
||||
schema:
|
||||
$ref: '#/definitions/ValidationError'
|
||||
'403':
|
||||
description: Authentication credentials were invalid, absent or insufficient.
|
||||
schema:
|
||||
$ref: '#/definitions/GenericError'
|
||||
tags:
|
||||
- sources
|
||||
parameters: []
|
||||
/sources/oauth_user_connections/{id}/:
|
||||
get:
|
||||
@ -18040,6 +17949,7 @@ definitions:
|
||||
required:
|
||||
- name
|
||||
- slug
|
||||
- plex_token
|
||||
type: object
|
||||
properties:
|
||||
pk:
|
||||
|
||||
@ -46,7 +46,7 @@ class TestProviderProxy(SeleniumTestCase):
|
||||
"""Start proxy container based on outpost created"""
|
||||
client: DockerClient = from_env()
|
||||
container = client.containers.run(
|
||||
image=f"beryju/authentik-proxy:{__version__}",
|
||||
image=f"ghcr.io/goauthentik/proxy:{__version__}",
|
||||
detach=True,
|
||||
network_mode="host",
|
||||
auto_remove=True,
|
||||
|
||||
@ -1,98 +0,0 @@
|
||||
worker_processes auto;
|
||||
pid /tmp/nginx.pid;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
error_log /dev/stdout;
|
||||
user www-data;
|
||||
|
||||
events {
|
||||
worker_connections 768;
|
||||
# multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
|
||||
##
|
||||
# Basic Settings
|
||||
##
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
# server_tokens off;
|
||||
|
||||
# server_names_hash_bucket_size 64;
|
||||
# server_name_in_redirect off;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
##
|
||||
# SSL Settings
|
||||
##
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
##
|
||||
# Logging Settings
|
||||
##
|
||||
log_format json_combined escape=json
|
||||
'{'
|
||||
'"timestamp":"$time_local",'
|
||||
'"host":"$remote_addr",'
|
||||
'"request_username":"$remote_user",'
|
||||
'"event":"$request",'
|
||||
'"status": "$status",'
|
||||
'"size":"$body_bytes_sent",'
|
||||
'"runtime":"$request_time",'
|
||||
'"logger":"nginx",'
|
||||
'"request_useragent":"$http_user_agent"'
|
||||
'}';
|
||||
access_log /dev/null json_combined;
|
||||
|
||||
##
|
||||
# Gzip Settings
|
||||
##
|
||||
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_buffers 16 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
##
|
||||
# Virtual Host Configs
|
||||
##
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
charset utf-8;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
access_log /dev/stdout json_combined;
|
||||
}
|
||||
location /static/ {
|
||||
expires 31d;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
add_header X-authentik-version "2021.5.1";
|
||||
add_header Vary X-authentik-version;
|
||||
}
|
||||
|
||||
location /if/admin {
|
||||
root /usr/share/nginx/html/static/dist;
|
||||
try_files $uri /static/dist/if/admin/index.html;
|
||||
}
|
||||
location /if/flow {
|
||||
root /usr/share/nginx/html/static/dist;
|
||||
try_files $uri /static/dist/if/flow/index.html;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
28
web/package-lock.json
generated
28
web/package-lock.json
generated
@ -42,13 +42,13 @@
|
||||
"eslint": "^7.26.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.2",
|
||||
"eslint-plugin-lit": "^1.4.0",
|
||||
"eslint-plugin-lit": "^1.4.1",
|
||||
"flowchart.js": "^1.15.0",
|
||||
"lit-element": "^2.5.1",
|
||||
"lit-html": "^1.4.1",
|
||||
"moment": "^2.29.1",
|
||||
"rapidoc": "^9.0.0",
|
||||
"rollup": "^2.47.0",
|
||||
"rollup": "^2.48.0",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-cssimport": "^1.0.2",
|
||||
@ -3601,9 +3601,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-lit": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.0.tgz",
|
||||
"integrity": "sha512-3PJCC1p4pvDBKtFmg1g2cGzAgJF4IDqhb9NJUh95nYc+QXExa/O/0fILF4WB6X7qdNQKm+gW6nYtSKTyYPHtXw==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.1.tgz",
|
||||
"integrity": "sha512-7UIbjSa1DGH7ZaDhmGZPHWm17kOjCrGP4VAKNjR0wZVdQLuRKXE+LqXysQ1L3O12hBnExkMG2J9swXpQvuCuXA==",
|
||||
"dependencies": {
|
||||
"parse5": "^6.0.1",
|
||||
"parse5-htmlparser2-tree-adapter": "^6.0.1",
|
||||
@ -6408,9 +6408,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.47.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.47.0.tgz",
|
||||
"integrity": "sha512-rqBjgq9hQfW0vRmz+0S062ORRNJXvwRpzxhFXORvar/maZqY6za3rgQ/p1Glg+j1hnc1GtYyQCPiAei95uTElg==",
|
||||
"version": "2.48.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.48.0.tgz",
|
||||
"integrity": "sha512-wl9ZSSSsi5579oscSDYSzGn092tCS076YB+TQrzsGuSfYyJeep8eEWj0eaRjuC5McuMNmcnR8icBqiE/FWNB1A==",
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
@ -10751,9 +10751,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-lit": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.0.tgz",
|
||||
"integrity": "sha512-3PJCC1p4pvDBKtFmg1g2cGzAgJF4IDqhb9NJUh95nYc+QXExa/O/0fILF4WB6X7qdNQKm+gW6nYtSKTyYPHtXw==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.1.tgz",
|
||||
"integrity": "sha512-7UIbjSa1DGH7ZaDhmGZPHWm17kOjCrGP4VAKNjR0wZVdQLuRKXE+LqXysQ1L3O12hBnExkMG2J9swXpQvuCuXA==",
|
||||
"requires": {
|
||||
"parse5": "^6.0.1",
|
||||
"parse5-htmlparser2-tree-adapter": "^6.0.1",
|
||||
@ -12917,9 +12917,9 @@
|
||||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.47.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.47.0.tgz",
|
||||
"integrity": "sha512-rqBjgq9hQfW0vRmz+0S062ORRNJXvwRpzxhFXORvar/maZqY6za3rgQ/p1Glg+j1hnc1GtYyQCPiAei95uTElg==",
|
||||
"version": "2.48.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.48.0.tgz",
|
||||
"integrity": "sha512-wl9ZSSSsi5579oscSDYSzGn092tCS076YB+TQrzsGuSfYyJeep8eEWj0eaRjuC5McuMNmcnR8icBqiE/FWNB1A==",
|
||||
"requires": {
|
||||
"fsevents": "~2.3.1"
|
||||
}
|
||||
|
||||
@ -68,13 +68,13 @@
|
||||
"eslint": "^7.26.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.2",
|
||||
"eslint-plugin-lit": "^1.4.0",
|
||||
"eslint-plugin-lit": "^1.4.1",
|
||||
"flowchart.js": "^1.15.0",
|
||||
"lit-element": "^2.5.1",
|
||||
"lit-html": "^1.4.1",
|
||||
"moment": "^2.29.1",
|
||||
"rapidoc": "^9.0.0",
|
||||
"rollup": "^2.47.0",
|
||||
"rollup": "^2.48.0",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-cssimport": "^1.0.2",
|
||||
|
||||
@ -104,6 +104,7 @@ export default [
|
||||
dir: "dist",
|
||||
sourcemap: true,
|
||||
manualChunks: manualChunks,
|
||||
chunkFileNames: "admin-[name].js"
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
@ -135,6 +136,7 @@ export default [
|
||||
dir: "dist",
|
||||
sourcemap: true,
|
||||
manualChunks: manualChunks,
|
||||
chunkFileNames: "flow-[name].js"
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
|
||||
@ -6,7 +6,9 @@ import { me } from "./Users";
|
||||
import { config } from "./Config";
|
||||
import { Config } from "authentik-api";
|
||||
|
||||
export function configureSentry(canDoPpi: boolean = false): Promise<Config> {
|
||||
export const TAG_SENTRY_COMPONENT = "authentik:component";
|
||||
|
||||
export function configureSentry(canDoPpi: boolean = false, tags: { [key: string]: string; } = {}): Promise<Config> {
|
||||
return config().then((config) => {
|
||||
if (config.errorReportingEnabled) {
|
||||
Sentry.init({
|
||||
@ -51,6 +53,12 @@ export function configureSentry(canDoPpi: boolean = false): Promise<Config> {
|
||||
return event;
|
||||
},
|
||||
});
|
||||
Sentry.setTags(tags);
|
||||
if (window.location.pathname.includes("if/")) {
|
||||
// Get the interface name from URL
|
||||
const intf = window.location.pathname.replace(/.+if\/(.+)\//, "$1");
|
||||
Sentry.setTag(TAG_SENTRY_COMPONENT, `web/${intf}`);
|
||||
}
|
||||
console.debug("authentik/config: Sentry enabled.");
|
||||
if (config.errorReportingSendPii && canDoPpi) {
|
||||
me().then(user => {
|
||||
|
||||
@ -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.5.1";
|
||||
export const VERSION = "2021.5.4";
|
||||
export const PAGE_SIZE = 20;
|
||||
export const EVENT_REFRESH = "ak-refresh";
|
||||
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";
|
||||
|
||||
@ -55,7 +55,7 @@ export class ModalButton extends LitElement {
|
||||
|
||||
resetForms(): void {
|
||||
this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => {
|
||||
form.reset();
|
||||
form?.reset();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -29,8 +29,8 @@ export class TokenCopyButton extends ActionButton {
|
||||
this.buttonClass = PRIMARY_CLASS;
|
||||
}, 1500);
|
||||
});
|
||||
}).catch((err: Response) => {
|
||||
return err.json().then(errResp => {
|
||||
}).catch((err: Response | undefined) => {
|
||||
return err?.json().then(errResp => {
|
||||
throw new Error(errResp["detail"]);
|
||||
});
|
||||
});
|
||||
|
||||
@ -76,10 +76,7 @@ export class Form<T> extends LitElement {
|
||||
*/
|
||||
reset(): void {
|
||||
const ironForm = this.shadowRoot?.querySelector("iron-form");
|
||||
if (!ironForm) {
|
||||
return;
|
||||
}
|
||||
ironForm.reset();
|
||||
ironForm?.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -23,7 +23,7 @@ export class ModalForm extends ModalButton {
|
||||
return formPromise.then(() => {
|
||||
if (this.closeAfterSuccessfulSubmit) {
|
||||
this.open = false;
|
||||
form.reset();
|
||||
form?.reset();
|
||||
}
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EVENT_REFRESH, {
|
||||
|
||||
@ -34,7 +34,7 @@ export abstract class TableModal<T> extends Table<T> {
|
||||
|
||||
resetForms(): void {
|
||||
this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => {
|
||||
form.reset();
|
||||
form?.reset();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -10,9 +10,8 @@
|
||||
<link rel="stylesheet" type="text/css" href="/static/dist/empty-state.css">
|
||||
<link rel="stylesheet" type="text/css" href="/static/dist/spinner.css">
|
||||
<link rel="stylesheet" type="text/css" href="/static/dist/authentik.css">
|
||||
<script>ShadyDOM = { force: !navigator.webdriver };</script>
|
||||
<script>ShadyDOM = { force: !navigator.webdriver }; window["polymerSkipLoadingFontRoboto"] = true;</script>
|
||||
<script src="/static/dist/poly.js" type="module"></script>
|
||||
<script>window["polymerSkipLoadingFontRoboto"] = true;</script>
|
||||
<script src="/static/dist/FlowInterface.js" type="module"></script>
|
||||
<title>authentik</title>
|
||||
</head>
|
||||
|
||||
@ -144,7 +144,7 @@ msgstr "Algorithm used to sign the JWT Tokens."
|
||||
msgid "Allow IDP-initiated logins"
|
||||
msgstr "Allow IDP-initiated logins"
|
||||
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:150
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:103
|
||||
msgid "Allow friends to authenticate via Plex, even if you don't share any servers"
|
||||
msgstr "Allow friends to authenticate via Plex, even if you don't share any servers"
|
||||
|
||||
@ -152,7 +152,7 @@ msgstr "Allow friends to authenticate via Plex, even if you don't share any serv
|
||||
msgid "Allow up to N occurrences in the HIBP database."
|
||||
msgstr "Allow up to N occurrences in the HIBP database."
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:41
|
||||
#: src/pages/policies/PolicyListPage.ts:42
|
||||
msgid "Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Stages."
|
||||
msgstr "Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Stages."
|
||||
|
||||
@ -164,7 +164,7 @@ msgstr "Allowed Redirect URIs"
|
||||
msgid "Allowed count"
|
||||
msgstr "Allowed count"
|
||||
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:155
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:108
|
||||
msgid "Allowed servers"
|
||||
msgstr "Allowed servers"
|
||||
|
||||
@ -218,6 +218,22 @@ msgstr "Applications"
|
||||
msgid "Apps with most usage"
|
||||
msgstr "Apps with most usage"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:146
|
||||
msgid ""
|
||||
"Are you sure you want to clear the flow cache?\n"
|
||||
"This will cause all flows to be re-evaluated on their next usage."
|
||||
msgstr ""
|
||||
"Are you sure you want to clear the flow cache?\n"
|
||||
"This will cause all flows to be re-evaluated on their next usage."
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:165
|
||||
msgid ""
|
||||
"Are you sure you want to clear the policy cache?\n"
|
||||
"This will cause all policies to be re-evaluated on their next usage."
|
||||
msgstr ""
|
||||
"Are you sure you want to clear the policy cache?\n"
|
||||
"This will cause all policies to be re-evaluated on their next usage."
|
||||
|
||||
#: src/elements/forms/DeleteForm.ts:69
|
||||
msgid "Are you sure you want to delete {0} {objName} ?"
|
||||
msgstr "Are you sure you want to delete {0} {objName} ?"
|
||||
@ -250,7 +266,7 @@ msgstr "Assertions is empty"
|
||||
msgid "Assigned to application"
|
||||
msgstr "Assigned to application"
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:68
|
||||
#: src/pages/policies/PolicyListPage.ts:69
|
||||
msgid "Assigned to {0} objects."
|
||||
msgstr "Assigned to {0} objects."
|
||||
|
||||
@ -282,7 +298,7 @@ msgid "Authentication"
|
||||
msgstr "Authentication"
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:231
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:185
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:190
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:243
|
||||
msgid "Authentication flow"
|
||||
msgstr "Authentication flow"
|
||||
@ -530,6 +546,21 @@ msgstr "Checks if the request's user's password has been changed in the last x d
|
||||
msgid "Checks the value from the policy request against several rules, mostly used to ensure password strength."
|
||||
msgstr "Checks the value from the policy request against several rules, mostly used to ensure password strength."
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:143
|
||||
msgid "Clear Flow cache"
|
||||
msgstr "Clear Flow cache"
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:162
|
||||
msgid "Clear Policy cache"
|
||||
msgstr "Clear Policy cache"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:138
|
||||
#: src/pages/flows/FlowListPage.ts:150
|
||||
#: src/pages/policies/PolicyListPage.ts:157
|
||||
#: src/pages/policies/PolicyListPage.ts:169
|
||||
msgid "Clear cache"
|
||||
msgstr "Clear cache"
|
||||
|
||||
#: src/elements/forms/HorizontalFormElement.ts:82
|
||||
msgid "Click to change value"
|
||||
msgstr "Click to change value"
|
||||
@ -540,7 +571,7 @@ msgstr "Click to copy token"
|
||||
|
||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts:107
|
||||
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts:99
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:141
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:176
|
||||
msgid "Client ID"
|
||||
msgstr "Client ID"
|
||||
|
||||
@ -726,8 +757,8 @@ msgstr "Copy download URL"
|
||||
#: src/pages/flows/BoundStagesList.ts:119
|
||||
#: src/pages/flows/BoundStagesList.ts:146
|
||||
#: src/pages/flows/BoundStagesList.ts:167
|
||||
#: src/pages/flows/FlowListPage.ts:109
|
||||
#: src/pages/flows/FlowListPage.ts:117
|
||||
#: src/pages/flows/FlowListPage.ts:110
|
||||
#: src/pages/flows/FlowListPage.ts:118
|
||||
#: src/pages/groups/GroupListPage.ts:90
|
||||
#: src/pages/groups/GroupListPage.ts:98
|
||||
#: src/pages/outposts/OutpostListPage.ts:101
|
||||
@ -737,8 +768,8 @@ msgstr "Copy download URL"
|
||||
#: src/pages/policies/BoundPoliciesList.ts:162
|
||||
#: src/pages/policies/BoundPoliciesList.ts:189
|
||||
#: src/pages/policies/BoundPoliciesList.ts:210
|
||||
#: src/pages/policies/PolicyListPage.ts:124
|
||||
#: src/pages/policies/PolicyListPage.ts:133
|
||||
#: src/pages/policies/PolicyListPage.ts:125
|
||||
#: src/pages/policies/PolicyListPage.ts:134
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:113
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:122
|
||||
#: src/pages/providers/ProviderListPage.ts:108
|
||||
@ -778,7 +809,7 @@ msgstr "Create Binding"
|
||||
msgid "Create Certificate-Key Pair"
|
||||
msgstr "Create Certificate-Key Pair"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:112
|
||||
#: src/pages/flows/FlowListPage.ts:113
|
||||
msgid "Create Flow"
|
||||
msgstr "Create Flow"
|
||||
|
||||
@ -840,7 +871,7 @@ msgstr "Create provider"
|
||||
#: src/pages/flows/BoundStagesList.ts:149
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:122
|
||||
#: src/pages/policies/BoundPoliciesList.ts:192
|
||||
#: src/pages/policies/PolicyListPage.ts:136
|
||||
#: src/pages/policies/PolicyListPage.ts:137
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:125
|
||||
#: src/pages/providers/ProviderListPage.ts:120
|
||||
#: src/pages/sources/SourcesListPage.ts:126
|
||||
@ -892,11 +923,11 @@ msgstr "Define how notifications are sent to users, like Email or Webhook."
|
||||
#: src/pages/crypto/CertificateKeyPairListPage.ts:86
|
||||
#: src/pages/events/RuleListPage.ts:82
|
||||
#: src/pages/events/TransportListPage.ts:86
|
||||
#: src/pages/flows/FlowListPage.ts:86
|
||||
#: src/pages/flows/FlowListPage.ts:87
|
||||
#: src/pages/groups/GroupListPage.ts:81
|
||||
#: src/pages/outposts/OutpostListPage.ts:87
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:101
|
||||
#: src/pages/policies/PolicyListPage.ts:115
|
||||
#: src/pages/policies/PolicyListPage.ts:116
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:104
|
||||
#: src/pages/providers/ProviderListPage.ts:99
|
||||
#: src/pages/sources/SourcesListPage.ts:95
|
||||
@ -967,7 +998,7 @@ msgid "Designates whether this user should be treated as active. Unselect this i
|
||||
msgstr "Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
|
||||
#: src/pages/flows/FlowForm.ts:119
|
||||
#: src/pages/flows/FlowListPage.ts:48
|
||||
#: src/pages/flows/FlowListPage.ts:49
|
||||
msgid "Designation"
|
||||
msgstr "Designation"
|
||||
|
||||
@ -1049,11 +1080,11 @@ msgstr "Each provider has a different issuer, based on the application slug."
|
||||
#: src/pages/crypto/CertificateKeyPairListPage.ts:74
|
||||
#: src/pages/events/RuleListPage.ts:70
|
||||
#: src/pages/events/TransportListPage.ts:74
|
||||
#: src/pages/flows/FlowListPage.ts:74
|
||||
#: src/pages/flows/FlowListPage.ts:75
|
||||
#: src/pages/groups/GroupListPage.ts:69
|
||||
#: src/pages/outposts/OutpostListPage.ts:75
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:89
|
||||
#: src/pages/policies/PolicyListPage.ts:90
|
||||
#: src/pages/policies/PolicyListPage.ts:91
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:79
|
||||
#: src/pages/providers/ProviderListPage.ts:87
|
||||
#: src/pages/providers/ldap/LDAPProviderViewPage.ts:103
|
||||
@ -1148,7 +1179,7 @@ msgstr "Enable this if you don't want to use this provider as a proxy, and want
|
||||
#: src/pages/policies/PolicyBindingForm.ts:199
|
||||
#: src/pages/sources/ldap/LDAPSourceForm.ts:67
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:134
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:108
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:143
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:67
|
||||
msgid "Enabled"
|
||||
msgstr "Enabled"
|
||||
@ -1158,7 +1189,7 @@ msgid "Enrollment"
|
||||
msgstr "Enrollment"
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:252
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:206
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:211
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:264
|
||||
#: src/pages/stages/identification/IdentificationStageForm.ts:104
|
||||
msgid "Enrollment flow"
|
||||
@ -1225,12 +1256,12 @@ msgstr "Events"
|
||||
msgid "Exception"
|
||||
msgstr "Exception"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:98
|
||||
#: src/pages/flows/FlowViewPage.ts:83
|
||||
#: src/pages/flows/FlowListPage.ts:99
|
||||
#: src/pages/flows/FlowViewPage.ts:75
|
||||
msgid "Execute"
|
||||
msgstr "Execute"
|
||||
|
||||
#: src/pages/flows/FlowViewPage.ts:69
|
||||
#: src/pages/flows/FlowViewPage.ts:61
|
||||
msgid "Execute flow"
|
||||
msgstr "Execute flow"
|
||||
|
||||
@ -1277,7 +1308,7 @@ msgstr "Expiry date"
|
||||
msgid "Explicit Consent"
|
||||
msgstr "Explicit Consent"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:101
|
||||
#: src/pages/flows/FlowListPage.ts:102
|
||||
msgid "Export"
|
||||
msgstr "Export"
|
||||
|
||||
@ -1316,6 +1347,14 @@ msgstr "Failed attempts before cancel"
|
||||
msgid "Failed sources"
|
||||
msgstr "Failed sources"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:137
|
||||
msgid "Failed to delete flow cache"
|
||||
msgstr "Failed to delete flow cache"
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:156
|
||||
msgid "Failed to delete policy cache"
|
||||
msgstr "Failed to delete policy cache"
|
||||
|
||||
#: src/elements/forms/DeleteForm.ts:46
|
||||
msgid "Failed to delete {0}: {1}"
|
||||
msgstr "Failed to delete {0}: {1}"
|
||||
@ -1358,7 +1397,7 @@ msgid "Fields a user can identify themselves with. If no fields are selected, th
|
||||
msgstr "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
|
||||
|
||||
#: src/pages/flows/FlowImportForm.ts:34
|
||||
#: src/pages/flows/FlowListPage.ts:79
|
||||
#: src/pages/flows/FlowListPage.ts:80
|
||||
msgid "Flow"
|
||||
msgstr "Flow"
|
||||
|
||||
@ -1367,19 +1406,19 @@ msgid "Flow Overview"
|
||||
msgstr "Flow Overview"
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:227
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:181
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:186
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:218
|
||||
msgid "Flow settings"
|
||||
msgstr "Flow settings"
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:249
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:203
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:208
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:261
|
||||
msgid "Flow to use when authenticating existing users."
|
||||
msgstr "Flow to use when authenticating existing users."
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:270
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:224
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:229
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:282
|
||||
msgid "Flow to use when enrolling new users."
|
||||
msgstr "Flow to use when enrolling new users."
|
||||
@ -1411,12 +1450,12 @@ msgstr "Flow used when authorizing this provider."
|
||||
#: src/interfaces/AdminInterface.ts:82
|
||||
#: src/interfaces/AdminInterface.ts:84
|
||||
#: src/pages/admin-overview/AdminOverviewPage.ts:61
|
||||
#: src/pages/flows/FlowListPage.ts:28
|
||||
#: src/pages/flows/FlowListPage.ts:29
|
||||
#: src/pages/stages/StageListPage.ts:66
|
||||
msgid "Flows"
|
||||
msgstr "Flows"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:31
|
||||
#: src/pages/flows/FlowListPage.ts:32
|
||||
msgid "Flows describe a chain of Stages to authenticate, enroll or recover a user. Stages are chosen based on policies applied to them."
|
||||
msgstr "Flows describe a chain of Stages to authenticate, enroll or recover a user. Stages are chosen based on policies applied to them."
|
||||
|
||||
@ -1546,7 +1585,7 @@ msgstr "Hide service-accounts"
|
||||
#: src/pages/providers/saml/SAMLProviderForm.ts:176
|
||||
#: src/pages/sources/ldap/LDAPSourceForm.ts:165
|
||||
#: src/pages/sources/ldap/LDAPSourceForm.ts:191
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:168
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:121
|
||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts:114
|
||||
#: src/pages/stages/identification/IdentificationStageForm.ts:83
|
||||
#: src/pages/stages/password/PasswordStageForm.ts:84
|
||||
@ -1567,7 +1606,7 @@ msgstr "ID"
|
||||
msgid "Icon"
|
||||
msgstr "Icon"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:46
|
||||
#: src/pages/flows/FlowListPage.ts:47
|
||||
#: src/pages/system-tasks/SystemTaskListPage.ts:54
|
||||
#: src/pages/tokens/TokenListPage.ts:44
|
||||
#: src/pages/user-settings/tokens/UserTokenForm.ts:49
|
||||
@ -1600,12 +1639,12 @@ msgstr "If your authentik Instance is using a self-signed certificate, set this
|
||||
msgid "Impersonate"
|
||||
msgstr "Impersonate"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:122
|
||||
#: src/pages/flows/FlowListPage.ts:130
|
||||
#: src/pages/flows/FlowListPage.ts:123
|
||||
#: src/pages/flows/FlowListPage.ts:131
|
||||
msgid "Import"
|
||||
msgstr "Import"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:125
|
||||
#: src/pages/flows/FlowListPage.ts:126
|
||||
msgid "Import Flow"
|
||||
msgstr "Import Flow"
|
||||
|
||||
@ -1716,7 +1755,7 @@ msgstr "Last login"
|
||||
msgid "Last run"
|
||||
msgstr "Last run"
|
||||
|
||||
#: src/pages/outposts/OutpostHealth.ts:54
|
||||
#: src/pages/outposts/OutpostHealth.ts:53
|
||||
msgid "Last seen: {0}"
|
||||
msgstr "Last seen: {0}"
|
||||
|
||||
@ -1742,21 +1781,21 @@ msgid "Library"
|
||||
msgstr "Library"
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:147
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:121
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:156
|
||||
msgid "Link to a user with identical email address. Can have security implications when a source doesn't validate email addresses"
|
||||
msgstr "Link to a user with identical email address. Can have security implications when a source doesn't validate email addresses"
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:153
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:127
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:162
|
||||
msgid "Link to a user with identical username address. Can have security implications when a username is used with another source."
|
||||
msgstr "Link to a user with identical username address. Can have security implications when a username is used with another source."
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:144
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:118
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:153
|
||||
msgid "Link users on unique identifier"
|
||||
msgstr "Link users on unique identifier"
|
||||
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:173
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:96
|
||||
msgid "Load servers"
|
||||
msgstr "Load servers"
|
||||
|
||||
@ -1821,8 +1860,8 @@ msgstr "Loading"
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:219
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:247
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:268
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:201
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:222
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:206
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:227
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:124
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:238
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:259
|
||||
@ -1961,7 +2000,7 @@ msgstr "My Applications"
|
||||
#: src/pages/events/TransportListPage.ts:46
|
||||
#: src/pages/flows/BoundStagesList.ts:39
|
||||
#: src/pages/flows/FlowForm.ts:86
|
||||
#: src/pages/flows/FlowListPage.ts:47
|
||||
#: src/pages/flows/FlowListPage.ts:48
|
||||
#: src/pages/groups/GroupForm.ts:58
|
||||
#: src/pages/groups/GroupListPage.ts:45
|
||||
#: src/pages/groups/MemberSelectModal.ts:45
|
||||
@ -1970,7 +2009,7 @@ msgstr "My Applications"
|
||||
#: src/pages/outposts/ServiceConnectionDockerForm.ts:51
|
||||
#: src/pages/outposts/ServiceConnectionKubernetesForm.ts:52
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:53
|
||||
#: src/pages/policies/PolicyListPage.ts:56
|
||||
#: src/pages/policies/PolicyListPage.ts:57
|
||||
#: src/pages/policies/dummy/DummyPolicyForm.ts:54
|
||||
#: src/pages/policies/event_matcher/EventMatcherPolicyForm.ts:55
|
||||
#: src/pages/policies/expiry/ExpiryPolicyForm.ts:54
|
||||
@ -1997,7 +2036,7 @@ msgstr "My Applications"
|
||||
#: src/pages/sources/ldap/LDAPSourceViewPage.ts:64
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:108
|
||||
#: src/pages/sources/oauth/OAuthSourceViewPage.ts:64
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:93
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:128
|
||||
#: src/pages/sources/plex/PlexSourceViewPage.ts:63
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:52
|
||||
#: src/pages/sources/saml/SAMLSourceViewPage.ts:66
|
||||
@ -2359,15 +2398,15 @@ msgstr "Please enter your password"
|
||||
|
||||
#: src/interfaces/AdminInterface.ts:74
|
||||
#: src/pages/admin-overview/AdminOverviewPage.ts:56
|
||||
#: src/pages/flows/FlowListPage.ts:50
|
||||
#: src/pages/policies/PolicyListPage.ts:38
|
||||
#: src/pages/flows/FlowListPage.ts:51
|
||||
#: src/pages/policies/PolicyListPage.ts:39
|
||||
msgid "Policies"
|
||||
msgstr "Policies"
|
||||
|
||||
#: src/pages/policies/PolicyBindingForm.ts:108
|
||||
#: src/pages/policies/PolicyBindingForm.ts:117
|
||||
#: src/pages/policies/PolicyBindingForm.ts:148
|
||||
#: src/pages/policies/PolicyListPage.ts:108
|
||||
#: src/pages/policies/PolicyListPage.ts:109
|
||||
msgid "Policy"
|
||||
msgstr "Policy"
|
||||
|
||||
@ -2492,7 +2531,7 @@ msgstr "Protocol Settings"
|
||||
#: src/pages/providers/proxy/ProxyProviderForm.ts:123
|
||||
#: src/pages/providers/saml/SAMLProviderForm.ts:77
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:163
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:137
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:172
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:74
|
||||
msgid "Protocol settings"
|
||||
msgstr "Protocol settings"
|
||||
@ -2623,7 +2662,7 @@ msgid "Regular expressions for which authentication is not required. Each new li
|
||||
msgstr "Regular expressions for which authentication is not required. Each new line is interpreted as a new Regular Expression."
|
||||
|
||||
#: src/pages/applications/ApplicationViewPage.ts:62
|
||||
#: src/pages/flows/FlowViewPage.ts:64
|
||||
#: src/pages/flows/FlowViewPage.ts:56
|
||||
msgid "Related"
|
||||
msgstr "Related"
|
||||
|
||||
@ -2800,7 +2839,7 @@ msgstr "Select users to add"
|
||||
msgid "Select which scopes can be used by the client. The client stil has to specify the scope to access the data."
|
||||
msgstr "Select which scopes can be used by the client. The client stil has to specify the scope to access the data."
|
||||
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:167
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:120
|
||||
msgid "Select which server a user has to be a member of to be allowed to authenticate."
|
||||
msgstr "Select which server a user has to be a member of to be allowed to authenticate."
|
||||
|
||||
@ -2940,7 +2979,7 @@ msgstr "Skip path regex"
|
||||
#: src/pages/flows/FlowForm.ts:99
|
||||
#: src/pages/sources/ldap/LDAPSourceForm.ts:58
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:114
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:99
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:134
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:58
|
||||
msgid "Slug"
|
||||
msgstr "Slug"
|
||||
@ -3017,7 +3056,7 @@ msgid "Stage-specific settings"
|
||||
msgstr "Stage-specific settings"
|
||||
|
||||
#: src/interfaces/AdminInterface.ts:87
|
||||
#: src/pages/flows/FlowListPage.ts:49
|
||||
#: src/pages/flows/FlowListPage.ts:50
|
||||
#: src/pages/stages/StageListPage.ts:44
|
||||
#: src/pages/stages/prompt/PromptListPage.ts:50
|
||||
msgid "Stages"
|
||||
@ -3081,6 +3120,14 @@ msgstr "Subject-alt name"
|
||||
msgid "Successful"
|
||||
msgstr "Successful"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:136
|
||||
msgid "Successfully cleared flow cache"
|
||||
msgstr "Successfully cleared flow cache"
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:155
|
||||
msgid "Successfully cleared policy cache"
|
||||
msgstr "Successfully cleared policy cache"
|
||||
|
||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts:63
|
||||
msgid "Successfully copied TOTP Config."
|
||||
msgstr "Successfully copied TOTP Config."
|
||||
@ -3405,14 +3452,14 @@ msgid "Template"
|
||||
msgstr "Template"
|
||||
|
||||
#: src/pages/events/TransportListPage.ts:62
|
||||
#: src/pages/policies/PolicyListPage.ts:95
|
||||
#: src/pages/policies/PolicyListPage.ts:103
|
||||
#: src/pages/policies/PolicyListPage.ts:96
|
||||
#: src/pages/policies/PolicyListPage.ts:104
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:84
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:92
|
||||
msgid "Test"
|
||||
msgstr "Test"
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:98
|
||||
#: src/pages/policies/PolicyListPage.ts:99
|
||||
msgid "Test Policy"
|
||||
msgstr "Test Policy"
|
||||
|
||||
@ -3429,8 +3476,8 @@ msgid "The URL \"{0}\" was not found."
|
||||
msgstr "The URL \"{0}\" was not found."
|
||||
|
||||
#: src/pages/providers/proxy/ProxyProviderForm.ts:131
|
||||
msgid "The external URL you'll access the application at"
|
||||
msgstr "The external URL you'll access the application at"
|
||||
msgid "The external URL you'll access the application at. Include any non-standard port."
|
||||
msgstr "The external URL you'll access the application at. Include any non-standard port."
|
||||
|
||||
#: src/pages/policies/dummy/DummyPolicyForm.ts:88
|
||||
msgid "The policy takes a random time to execute. This controls the minimum time it will take."
|
||||
@ -3564,7 +3611,7 @@ msgstr "Transports"
|
||||
#: src/pages/flows/BoundStagesList.ts:40
|
||||
#: src/pages/outposts/OutpostForm.ts:58
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:54
|
||||
#: src/pages/policies/PolicyListPage.ts:57
|
||||
#: src/pages/policies/PolicyListPage.ts:58
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:55
|
||||
#: src/pages/providers/ProviderListPage.ts:55
|
||||
#: src/pages/sources/SourcesListPage.ts:53
|
||||
@ -3640,7 +3687,7 @@ msgstr "Up-to-date!"
|
||||
#: src/pages/events/TransportListPage.ts:66
|
||||
#: src/pages/flows/BoundStagesList.ts:53
|
||||
#: src/pages/flows/BoundStagesList.ts:71
|
||||
#: src/pages/flows/FlowListPage.ts:66
|
||||
#: src/pages/flows/FlowListPage.ts:67
|
||||
#: src/pages/groups/GroupListPage.ts:61
|
||||
#: src/pages/outposts/OutpostListPage.ts:67
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:76
|
||||
@ -3648,7 +3695,7 @@ msgstr "Up-to-date!"
|
||||
#: src/pages/policies/BoundPoliciesList.ts:88
|
||||
#: src/pages/policies/BoundPoliciesList.ts:103
|
||||
#: src/pages/policies/BoundPoliciesList.ts:129
|
||||
#: src/pages/policies/PolicyListPage.ts:77
|
||||
#: src/pages/policies/PolicyListPage.ts:78
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:66
|
||||
#: src/pages/providers/ProviderListPage.ts:74
|
||||
#: src/pages/providers/ldap/LDAPProviderViewPage.ts:93
|
||||
@ -3686,7 +3733,7 @@ msgstr "Update Binding"
|
||||
msgid "Update Certificate-Key Pair"
|
||||
msgstr "Update Certificate-Key Pair"
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:69
|
||||
#: src/pages/flows/FlowListPage.ts:70
|
||||
msgid "Update Flow"
|
||||
msgstr "Update Flow"
|
||||
|
||||
@ -3764,7 +3811,7 @@ msgstr "Update details"
|
||||
#: src/pages/flows/BoundStagesList.ts:56
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:79
|
||||
#: src/pages/policies/BoundPoliciesList.ts:71
|
||||
#: src/pages/policies/PolicyListPage.ts:80
|
||||
#: src/pages/policies/PolicyListPage.ts:81
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:69
|
||||
#: src/pages/providers/ProviderListPage.ts:77
|
||||
#: src/pages/sources/SourcesListPage.ts:73
|
||||
@ -3798,12 +3845,12 @@ msgid "Use global settings"
|
||||
msgstr "Use global settings"
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:150
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:124
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:159
|
||||
msgid "Use the user's email address, but deny enrollment when the email address already exists."
|
||||
msgstr "Use the user's email address, but deny enrollment when the email address already exists."
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:156
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:130
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:165
|
||||
msgid "Use the user's username, but deny enrollment when the username already exists."
|
||||
msgstr "Use the user's username, but deny enrollment when the username already exists."
|
||||
|
||||
@ -3852,7 +3899,7 @@ msgid "User fields"
|
||||
msgstr "User fields"
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:139
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:113
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:148
|
||||
msgid "User matching mode"
|
||||
msgstr "User matching mode"
|
||||
|
||||
@ -3913,8 +3960,8 @@ msgid "Users added to this group will be superusers."
|
||||
msgstr "Users added to this group will be superusers."
|
||||
|
||||
#: src/pages/providers/ldap/LDAPProviderForm.ts:86
|
||||
msgid "Users in the selected group can do search queries."
|
||||
msgstr "Users in the selected group can do search queries."
|
||||
msgid "Users in the selected group can do search queries. If no group is selected, no LDAP Searches are allowed."
|
||||
msgstr "Users in the selected group can do search queries. If no group is selected, no LDAP Searches are allowed."
|
||||
|
||||
#: src/pages/events/EventInfo.ts:108
|
||||
msgid "Using flow"
|
||||
@ -3956,7 +4003,7 @@ msgstr "Verify the user's email address by sending them a one-time-link. Can als
|
||||
msgid "Version"
|
||||
msgstr "Version"
|
||||
|
||||
#: src/pages/outposts/OutpostHealth.ts:60
|
||||
#: src/pages/outposts/OutpostHealth.ts:59
|
||||
msgid "Version: {0}"
|
||||
msgstr "Version: {0}"
|
||||
|
||||
@ -3985,7 +4032,7 @@ msgstr "Wait (min)"
|
||||
msgid "Warning"
|
||||
msgstr "Warning"
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:71
|
||||
#: src/pages/policies/PolicyListPage.ts:72
|
||||
msgid "Warning: Policy is not assigned."
|
||||
msgstr "Warning: Policy is not assigned."
|
||||
|
||||
@ -4122,7 +4169,7 @@ msgstr "{0} is available!"
|
||||
msgid "{0} unread"
|
||||
msgstr "{0} unread"
|
||||
|
||||
#: src/pages/outposts/OutpostHealth.ts:59
|
||||
#: src/pages/outposts/OutpostHealth.ts:58
|
||||
msgid "{0}, should be {1}"
|
||||
msgstr "{0}, should be {1}"
|
||||
|
||||
|
||||
@ -144,7 +144,7 @@ msgstr ""
|
||||
msgid "Allow IDP-initiated logins"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:150
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:103
|
||||
msgid "Allow friends to authenticate via Plex, even if you don't share any servers"
|
||||
msgstr ""
|
||||
|
||||
@ -152,7 +152,7 @@ msgstr ""
|
||||
msgid "Allow up to N occurrences in the HIBP database."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:41
|
||||
#: src/pages/policies/PolicyListPage.ts:42
|
||||
msgid "Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Stages."
|
||||
msgstr ""
|
||||
|
||||
@ -164,7 +164,7 @@ msgstr ""
|
||||
msgid "Allowed count"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:155
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:108
|
||||
msgid "Allowed servers"
|
||||
msgstr ""
|
||||
|
||||
@ -218,6 +218,18 @@ msgstr ""
|
||||
msgid "Apps with most usage"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:146
|
||||
msgid ""
|
||||
"Are you sure you want to clear the flow cache?\n"
|
||||
"This will cause all flows to be re-evaluated on their next usage."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:165
|
||||
msgid ""
|
||||
"Are you sure you want to clear the policy cache?\n"
|
||||
"This will cause all policies to be re-evaluated on their next usage."
|
||||
msgstr ""
|
||||
|
||||
#: src/elements/forms/DeleteForm.ts:69
|
||||
msgid "Are you sure you want to delete {0} {objName} ?"
|
||||
msgstr ""
|
||||
@ -250,7 +262,7 @@ msgstr ""
|
||||
msgid "Assigned to application"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:68
|
||||
#: src/pages/policies/PolicyListPage.ts:69
|
||||
msgid "Assigned to {0} objects."
|
||||
msgstr ""
|
||||
|
||||
@ -282,7 +294,7 @@ msgid "Authentication"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:231
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:185
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:190
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:243
|
||||
msgid "Authentication flow"
|
||||
msgstr ""
|
||||
@ -528,6 +540,21 @@ msgstr ""
|
||||
msgid "Checks the value from the policy request against several rules, mostly used to ensure password strength."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:143
|
||||
msgid "Clear Flow cache"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:162
|
||||
msgid "Clear Policy cache"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:138
|
||||
#: src/pages/flows/FlowListPage.ts:150
|
||||
#: src/pages/policies/PolicyListPage.ts:157
|
||||
#: src/pages/policies/PolicyListPage.ts:169
|
||||
msgid "Clear cache"
|
||||
msgstr ""
|
||||
|
||||
#: src/elements/forms/HorizontalFormElement.ts:82
|
||||
msgid "Click to change value"
|
||||
msgstr ""
|
||||
@ -538,7 +565,7 @@ msgstr ""
|
||||
|
||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts:107
|
||||
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts:99
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:141
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:176
|
||||
msgid "Client ID"
|
||||
msgstr ""
|
||||
|
||||
@ -724,8 +751,8 @@ msgstr ""
|
||||
#: src/pages/flows/BoundStagesList.ts:119
|
||||
#: src/pages/flows/BoundStagesList.ts:146
|
||||
#: src/pages/flows/BoundStagesList.ts:167
|
||||
#: src/pages/flows/FlowListPage.ts:109
|
||||
#: src/pages/flows/FlowListPage.ts:117
|
||||
#: src/pages/flows/FlowListPage.ts:110
|
||||
#: src/pages/flows/FlowListPage.ts:118
|
||||
#: src/pages/groups/GroupListPage.ts:90
|
||||
#: src/pages/groups/GroupListPage.ts:98
|
||||
#: src/pages/outposts/OutpostListPage.ts:101
|
||||
@ -735,8 +762,8 @@ msgstr ""
|
||||
#: src/pages/policies/BoundPoliciesList.ts:162
|
||||
#: src/pages/policies/BoundPoliciesList.ts:189
|
||||
#: src/pages/policies/BoundPoliciesList.ts:210
|
||||
#: src/pages/policies/PolicyListPage.ts:124
|
||||
#: src/pages/policies/PolicyListPage.ts:133
|
||||
#: src/pages/policies/PolicyListPage.ts:125
|
||||
#: src/pages/policies/PolicyListPage.ts:134
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:113
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:122
|
||||
#: src/pages/providers/ProviderListPage.ts:108
|
||||
@ -776,7 +803,7 @@ msgstr ""
|
||||
msgid "Create Certificate-Key Pair"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:112
|
||||
#: src/pages/flows/FlowListPage.ts:113
|
||||
msgid "Create Flow"
|
||||
msgstr ""
|
||||
|
||||
@ -838,7 +865,7 @@ msgstr ""
|
||||
#: src/pages/flows/BoundStagesList.ts:149
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:122
|
||||
#: src/pages/policies/BoundPoliciesList.ts:192
|
||||
#: src/pages/policies/PolicyListPage.ts:136
|
||||
#: src/pages/policies/PolicyListPage.ts:137
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:125
|
||||
#: src/pages/providers/ProviderListPage.ts:120
|
||||
#: src/pages/sources/SourcesListPage.ts:126
|
||||
@ -890,11 +917,11 @@ msgstr ""
|
||||
#: src/pages/crypto/CertificateKeyPairListPage.ts:86
|
||||
#: src/pages/events/RuleListPage.ts:82
|
||||
#: src/pages/events/TransportListPage.ts:86
|
||||
#: src/pages/flows/FlowListPage.ts:86
|
||||
#: src/pages/flows/FlowListPage.ts:87
|
||||
#: src/pages/groups/GroupListPage.ts:81
|
||||
#: src/pages/outposts/OutpostListPage.ts:87
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:101
|
||||
#: src/pages/policies/PolicyListPage.ts:115
|
||||
#: src/pages/policies/PolicyListPage.ts:116
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:104
|
||||
#: src/pages/providers/ProviderListPage.ts:99
|
||||
#: src/pages/sources/SourcesListPage.ts:95
|
||||
@ -963,7 +990,7 @@ msgid "Designates whether this user should be treated as active. Unselect this i
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowForm.ts:119
|
||||
#: src/pages/flows/FlowListPage.ts:48
|
||||
#: src/pages/flows/FlowListPage.ts:49
|
||||
msgid "Designation"
|
||||
msgstr ""
|
||||
|
||||
@ -1045,11 +1072,11 @@ msgstr ""
|
||||
#: src/pages/crypto/CertificateKeyPairListPage.ts:74
|
||||
#: src/pages/events/RuleListPage.ts:70
|
||||
#: src/pages/events/TransportListPage.ts:74
|
||||
#: src/pages/flows/FlowListPage.ts:74
|
||||
#: src/pages/flows/FlowListPage.ts:75
|
||||
#: src/pages/groups/GroupListPage.ts:69
|
||||
#: src/pages/outposts/OutpostListPage.ts:75
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:89
|
||||
#: src/pages/policies/PolicyListPage.ts:90
|
||||
#: src/pages/policies/PolicyListPage.ts:91
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:79
|
||||
#: src/pages/providers/ProviderListPage.ts:87
|
||||
#: src/pages/providers/ldap/LDAPProviderViewPage.ts:103
|
||||
@ -1144,7 +1171,7 @@ msgstr ""
|
||||
#: src/pages/policies/PolicyBindingForm.ts:199
|
||||
#: src/pages/sources/ldap/LDAPSourceForm.ts:67
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:134
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:108
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:143
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:67
|
||||
msgid "Enabled"
|
||||
msgstr ""
|
||||
@ -1154,7 +1181,7 @@ msgid "Enrollment"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:252
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:206
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:211
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:264
|
||||
#: src/pages/stages/identification/IdentificationStageForm.ts:104
|
||||
msgid "Enrollment flow"
|
||||
@ -1221,12 +1248,12 @@ msgstr ""
|
||||
msgid "Exception"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:98
|
||||
#: src/pages/flows/FlowViewPage.ts:83
|
||||
#: src/pages/flows/FlowListPage.ts:99
|
||||
#: src/pages/flows/FlowViewPage.ts:75
|
||||
msgid "Execute"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowViewPage.ts:69
|
||||
#: src/pages/flows/FlowViewPage.ts:61
|
||||
msgid "Execute flow"
|
||||
msgstr ""
|
||||
|
||||
@ -1273,7 +1300,7 @@ msgstr ""
|
||||
msgid "Explicit Consent"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:101
|
||||
#: src/pages/flows/FlowListPage.ts:102
|
||||
msgid "Export"
|
||||
msgstr ""
|
||||
|
||||
@ -1312,6 +1339,14 @@ msgstr ""
|
||||
msgid "Failed sources"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:137
|
||||
msgid "Failed to delete flow cache"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:156
|
||||
msgid "Failed to delete policy cache"
|
||||
msgstr ""
|
||||
|
||||
#: src/elements/forms/DeleteForm.ts:46
|
||||
msgid "Failed to delete {0}: {1}"
|
||||
msgstr ""
|
||||
@ -1354,7 +1389,7 @@ msgid "Fields a user can identify themselves with. If no fields are selected, th
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowImportForm.ts:34
|
||||
#: src/pages/flows/FlowListPage.ts:79
|
||||
#: src/pages/flows/FlowListPage.ts:80
|
||||
msgid "Flow"
|
||||
msgstr ""
|
||||
|
||||
@ -1363,19 +1398,19 @@ msgid "Flow Overview"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:227
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:181
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:186
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:218
|
||||
msgid "Flow settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:249
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:203
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:208
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:261
|
||||
msgid "Flow to use when authenticating existing users."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:270
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:224
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:229
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:282
|
||||
msgid "Flow to use when enrolling new users."
|
||||
msgstr ""
|
||||
@ -1407,12 +1442,12 @@ msgstr ""
|
||||
#: src/interfaces/AdminInterface.ts:82
|
||||
#: src/interfaces/AdminInterface.ts:84
|
||||
#: src/pages/admin-overview/AdminOverviewPage.ts:61
|
||||
#: src/pages/flows/FlowListPage.ts:28
|
||||
#: src/pages/flows/FlowListPage.ts:29
|
||||
#: src/pages/stages/StageListPage.ts:66
|
||||
msgid "Flows"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:31
|
||||
#: src/pages/flows/FlowListPage.ts:32
|
||||
msgid "Flows describe a chain of Stages to authenticate, enroll or recover a user. Stages are chosen based on policies applied to them."
|
||||
msgstr ""
|
||||
|
||||
@ -1542,7 +1577,7 @@ msgstr ""
|
||||
#: src/pages/providers/saml/SAMLProviderForm.ts:176
|
||||
#: src/pages/sources/ldap/LDAPSourceForm.ts:165
|
||||
#: src/pages/sources/ldap/LDAPSourceForm.ts:191
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:168
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:121
|
||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts:114
|
||||
#: src/pages/stages/identification/IdentificationStageForm.ts:83
|
||||
#: src/pages/stages/password/PasswordStageForm.ts:84
|
||||
@ -1563,7 +1598,7 @@ msgstr ""
|
||||
msgid "Icon"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:46
|
||||
#: src/pages/flows/FlowListPage.ts:47
|
||||
#: src/pages/system-tasks/SystemTaskListPage.ts:54
|
||||
#: src/pages/tokens/TokenListPage.ts:44
|
||||
#: src/pages/user-settings/tokens/UserTokenForm.ts:49
|
||||
@ -1596,12 +1631,12 @@ msgstr ""
|
||||
msgid "Impersonate"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:122
|
||||
#: src/pages/flows/FlowListPage.ts:130
|
||||
#: src/pages/flows/FlowListPage.ts:123
|
||||
#: src/pages/flows/FlowListPage.ts:131
|
||||
msgid "Import"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:125
|
||||
#: src/pages/flows/FlowListPage.ts:126
|
||||
msgid "Import Flow"
|
||||
msgstr ""
|
||||
|
||||
@ -1712,7 +1747,7 @@ msgstr ""
|
||||
msgid "Last run"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/outposts/OutpostHealth.ts:54
|
||||
#: src/pages/outposts/OutpostHealth.ts:53
|
||||
msgid "Last seen: {0}"
|
||||
msgstr ""
|
||||
|
||||
@ -1738,21 +1773,21 @@ msgid "Library"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:147
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:121
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:156
|
||||
msgid "Link to a user with identical email address. Can have security implications when a source doesn't validate email addresses"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:153
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:127
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:162
|
||||
msgid "Link to a user with identical username address. Can have security implications when a username is used with another source."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:144
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:118
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:153
|
||||
msgid "Link users on unique identifier"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:173
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:96
|
||||
msgid "Load servers"
|
||||
msgstr ""
|
||||
|
||||
@ -1817,8 +1852,8 @@ msgstr ""
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:219
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:247
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:268
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:201
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:222
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:206
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:227
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:124
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:238
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:259
|
||||
@ -1957,7 +1992,7 @@ msgstr ""
|
||||
#: src/pages/events/TransportListPage.ts:46
|
||||
#: src/pages/flows/BoundStagesList.ts:39
|
||||
#: src/pages/flows/FlowForm.ts:86
|
||||
#: src/pages/flows/FlowListPage.ts:47
|
||||
#: src/pages/flows/FlowListPage.ts:48
|
||||
#: src/pages/groups/GroupForm.ts:58
|
||||
#: src/pages/groups/GroupListPage.ts:45
|
||||
#: src/pages/groups/MemberSelectModal.ts:45
|
||||
@ -1966,7 +2001,7 @@ msgstr ""
|
||||
#: src/pages/outposts/ServiceConnectionDockerForm.ts:51
|
||||
#: src/pages/outposts/ServiceConnectionKubernetesForm.ts:52
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:53
|
||||
#: src/pages/policies/PolicyListPage.ts:56
|
||||
#: src/pages/policies/PolicyListPage.ts:57
|
||||
#: src/pages/policies/dummy/DummyPolicyForm.ts:54
|
||||
#: src/pages/policies/event_matcher/EventMatcherPolicyForm.ts:55
|
||||
#: src/pages/policies/expiry/ExpiryPolicyForm.ts:54
|
||||
@ -1993,7 +2028,7 @@ msgstr ""
|
||||
#: src/pages/sources/ldap/LDAPSourceViewPage.ts:64
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:108
|
||||
#: src/pages/sources/oauth/OAuthSourceViewPage.ts:64
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:93
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:128
|
||||
#: src/pages/sources/plex/PlexSourceViewPage.ts:63
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:52
|
||||
#: src/pages/sources/saml/SAMLSourceViewPage.ts:66
|
||||
@ -2355,15 +2390,15 @@ msgstr ""
|
||||
|
||||
#: src/interfaces/AdminInterface.ts:74
|
||||
#: src/pages/admin-overview/AdminOverviewPage.ts:56
|
||||
#: src/pages/flows/FlowListPage.ts:50
|
||||
#: src/pages/policies/PolicyListPage.ts:38
|
||||
#: src/pages/flows/FlowListPage.ts:51
|
||||
#: src/pages/policies/PolicyListPage.ts:39
|
||||
msgid "Policies"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/PolicyBindingForm.ts:108
|
||||
#: src/pages/policies/PolicyBindingForm.ts:117
|
||||
#: src/pages/policies/PolicyBindingForm.ts:148
|
||||
#: src/pages/policies/PolicyListPage.ts:108
|
||||
#: src/pages/policies/PolicyListPage.ts:109
|
||||
msgid "Policy"
|
||||
msgstr ""
|
||||
|
||||
@ -2488,7 +2523,7 @@ msgstr ""
|
||||
#: src/pages/providers/proxy/ProxyProviderForm.ts:123
|
||||
#: src/pages/providers/saml/SAMLProviderForm.ts:77
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:163
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:137
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:172
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:74
|
||||
msgid "Protocol settings"
|
||||
msgstr ""
|
||||
@ -2619,7 +2654,7 @@ msgid "Regular expressions for which authentication is not required. Each new li
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/applications/ApplicationViewPage.ts:62
|
||||
#: src/pages/flows/FlowViewPage.ts:64
|
||||
#: src/pages/flows/FlowViewPage.ts:56
|
||||
msgid "Related"
|
||||
msgstr ""
|
||||
|
||||
@ -2796,7 +2831,7 @@ msgstr ""
|
||||
msgid "Select which scopes can be used by the client. The client stil has to specify the scope to access the data."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:167
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:120
|
||||
msgid "Select which server a user has to be a member of to be allowed to authenticate."
|
||||
msgstr ""
|
||||
|
||||
@ -2936,7 +2971,7 @@ msgstr ""
|
||||
#: src/pages/flows/FlowForm.ts:99
|
||||
#: src/pages/sources/ldap/LDAPSourceForm.ts:58
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:114
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:99
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:134
|
||||
#: src/pages/sources/saml/SAMLSourceForm.ts:58
|
||||
msgid "Slug"
|
||||
msgstr ""
|
||||
@ -3013,7 +3048,7 @@ msgid "Stage-specific settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/interfaces/AdminInterface.ts:87
|
||||
#: src/pages/flows/FlowListPage.ts:49
|
||||
#: src/pages/flows/FlowListPage.ts:50
|
||||
#: src/pages/stages/StageListPage.ts:44
|
||||
#: src/pages/stages/prompt/PromptListPage.ts:50
|
||||
msgid "Stages"
|
||||
@ -3077,6 +3112,14 @@ msgstr ""
|
||||
msgid "Successful"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:136
|
||||
msgid "Successfully cleared flow cache"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:155
|
||||
msgid "Successfully cleared policy cache"
|
||||
msgstr ""
|
||||
|
||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts:63
|
||||
msgid "Successfully copied TOTP Config."
|
||||
msgstr ""
|
||||
@ -3401,14 +3444,14 @@ msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/events/TransportListPage.ts:62
|
||||
#: src/pages/policies/PolicyListPage.ts:95
|
||||
#: src/pages/policies/PolicyListPage.ts:103
|
||||
#: src/pages/policies/PolicyListPage.ts:96
|
||||
#: src/pages/policies/PolicyListPage.ts:104
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:84
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:92
|
||||
msgid "Test"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:98
|
||||
#: src/pages/policies/PolicyListPage.ts:99
|
||||
msgid "Test Policy"
|
||||
msgstr ""
|
||||
|
||||
@ -3425,7 +3468,7 @@ msgid "The URL \"{0}\" was not found."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/providers/proxy/ProxyProviderForm.ts:131
|
||||
msgid "The external URL you'll access the application at"
|
||||
msgid "The external URL you'll access the application at. Include any non-standard port."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/dummy/DummyPolicyForm.ts:88
|
||||
@ -3556,7 +3599,7 @@ msgstr ""
|
||||
#: src/pages/flows/BoundStagesList.ts:40
|
||||
#: src/pages/outposts/OutpostForm.ts:58
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:54
|
||||
#: src/pages/policies/PolicyListPage.ts:57
|
||||
#: src/pages/policies/PolicyListPage.ts:58
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:55
|
||||
#: src/pages/providers/ProviderListPage.ts:55
|
||||
#: src/pages/sources/SourcesListPage.ts:53
|
||||
@ -3632,7 +3675,7 @@ msgstr ""
|
||||
#: src/pages/events/TransportListPage.ts:66
|
||||
#: src/pages/flows/BoundStagesList.ts:53
|
||||
#: src/pages/flows/BoundStagesList.ts:71
|
||||
#: src/pages/flows/FlowListPage.ts:66
|
||||
#: src/pages/flows/FlowListPage.ts:67
|
||||
#: src/pages/groups/GroupListPage.ts:61
|
||||
#: src/pages/outposts/OutpostListPage.ts:67
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:76
|
||||
@ -3640,7 +3683,7 @@ msgstr ""
|
||||
#: src/pages/policies/BoundPoliciesList.ts:88
|
||||
#: src/pages/policies/BoundPoliciesList.ts:103
|
||||
#: src/pages/policies/BoundPoliciesList.ts:129
|
||||
#: src/pages/policies/PolicyListPage.ts:77
|
||||
#: src/pages/policies/PolicyListPage.ts:78
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:66
|
||||
#: src/pages/providers/ProviderListPage.ts:74
|
||||
#: src/pages/providers/ldap/LDAPProviderViewPage.ts:93
|
||||
@ -3678,7 +3721,7 @@ msgstr ""
|
||||
msgid "Update Certificate-Key Pair"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts:69
|
||||
#: src/pages/flows/FlowListPage.ts:70
|
||||
msgid "Update Flow"
|
||||
msgstr ""
|
||||
|
||||
@ -3756,7 +3799,7 @@ msgstr ""
|
||||
#: src/pages/flows/BoundStagesList.ts:56
|
||||
#: src/pages/outposts/ServiceConnectionListPage.ts:79
|
||||
#: src/pages/policies/BoundPoliciesList.ts:71
|
||||
#: src/pages/policies/PolicyListPage.ts:80
|
||||
#: src/pages/policies/PolicyListPage.ts:81
|
||||
#: src/pages/property-mappings/PropertyMappingListPage.ts:69
|
||||
#: src/pages/providers/ProviderListPage.ts:77
|
||||
#: src/pages/sources/SourcesListPage.ts:73
|
||||
@ -3790,12 +3833,12 @@ msgid "Use global settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:150
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:124
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:159
|
||||
msgid "Use the user's email address, but deny enrollment when the email address already exists."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:156
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:130
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:165
|
||||
msgid "Use the user's username, but deny enrollment when the username already exists."
|
||||
msgstr ""
|
||||
|
||||
@ -3844,7 +3887,7 @@ msgid "User fields"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/sources/oauth/OAuthSourceForm.ts:139
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:113
|
||||
#: src/pages/sources/plex/PlexSourceForm.ts:148
|
||||
msgid "User matching mode"
|
||||
msgstr ""
|
||||
|
||||
@ -3905,7 +3948,7 @@ msgid "Users added to this group will be superusers."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/providers/ldap/LDAPProviderForm.ts:86
|
||||
msgid "Users in the selected group can do search queries."
|
||||
msgid "Users in the selected group can do search queries. If no group is selected, no LDAP Searches are allowed."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/events/EventInfo.ts:108
|
||||
@ -3948,7 +3991,7 @@ msgstr ""
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/outposts/OutpostHealth.ts:60
|
||||
#: src/pages/outposts/OutpostHealth.ts:59
|
||||
msgid "Version: {0}"
|
||||
msgstr ""
|
||||
|
||||
@ -3977,7 +4020,7 @@ msgstr ""
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/policies/PolicyListPage.ts:71
|
||||
#: src/pages/policies/PolicyListPage.ts:72
|
||||
msgid "Warning: Policy is not assigned."
|
||||
msgstr ""
|
||||
|
||||
@ -4112,7 +4155,7 @@ msgstr ""
|
||||
msgid "{0} unread"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/outposts/OutpostHealth.ts:59
|
||||
#: src/pages/outposts/OutpostHealth.ts:58
|
||||
msgid "{0}, should be {1}"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import { TablePage } from "../../elements/table/TablePage";
|
||||
import "../../elements/buttons/SpinnerButton";
|
||||
import "../../elements/forms/DeleteForm";
|
||||
import "../../elements/forms/ModalForm";
|
||||
import "../../elements/forms/ConfirmationForm";
|
||||
import "./FlowForm";
|
||||
import "./FlowImportForm";
|
||||
import { TableColumn } from "../../elements/table/Table";
|
||||
@ -68,7 +69,7 @@ export class FlowListPage extends TablePage<Flow> {
|
||||
<span slot="header">
|
||||
${t`Update Flow`}
|
||||
</span>
|
||||
<ak-flow-form slot="form" .instancePk=${item.pk}>
|
||||
<ak-flow-form slot="form" .instancePk=${item.slug}>
|
||||
</ak-flow-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
${t`Edit`}
|
||||
@ -132,6 +133,24 @@ export class FlowListPage extends TablePage<Flow> {
|
||||
</button>
|
||||
</ak-forms-modal>
|
||||
${super.renderToolbar()}
|
||||
`;
|
||||
<ak-forms-confirm
|
||||
successMessage=${t`Successfully cleared flow cache`}
|
||||
errorMessage=${t`Failed to delete flow cache`}
|
||||
action=${t`Clear cache`}
|
||||
.onConfirm=${() => {
|
||||
return new FlowsApi(DEFAULT_CONFIG).flowsInstancesCacheClear();
|
||||
}}>
|
||||
<span slot="header">
|
||||
${t`Clear Flow cache`}
|
||||
</span>
|
||||
<p slot="body">
|
||||
${t`Are you sure you want to clear the flow cache?
|
||||
This will cause all flows to be re-evaluated on their next usage.`}
|
||||
</p>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary" type="button">
|
||||
${t`Clear cache`}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</ak-forms-confirm>`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import "../../elements/buttons/SpinnerButton";
|
||||
import "../../elements/forms/DeleteForm";
|
||||
import "../../elements/forms/ModalForm";
|
||||
import "../../elements/forms/ProxyForm";
|
||||
import "../../elements/forms/ConfirmationForm";
|
||||
import "./PolicyTestForm";
|
||||
import { TableColumn } from "../../elements/table/Table";
|
||||
import { until } from "lit-html/directives/until";
|
||||
@ -150,7 +151,26 @@ export class PolicyListPage extends TablePage<Policy> {
|
||||
}), html`<ak-spinner></ak-spinner>`)}
|
||||
</ul>
|
||||
</ak-dropdown>
|
||||
${super.renderToolbar()}`;
|
||||
${super.renderToolbar()}
|
||||
<ak-forms-confirm
|
||||
successMessage=${t`Successfully cleared policy cache`}
|
||||
errorMessage=${t`Failed to delete policy cache`}
|
||||
action=${t`Clear cache`}
|
||||
.onConfirm=${() => {
|
||||
return new PoliciesApi(DEFAULT_CONFIG).policiesAllCacheClear();
|
||||
}}>
|
||||
<span slot="header">
|
||||
${t`Clear Policy cache`}
|
||||
</span>
|
||||
<p slot="body">
|
||||
${t`Are you sure you want to clear the policy cache?
|
||||
This will cause all policies to be re-evaluated on their next usage.`}
|
||||
</p>
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary" type="button">
|
||||
${t`Clear cache`}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</ak-forms-confirm>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
|
||||
<ak-proxy-form
|
||||
slot="form"
|
||||
.args=${{
|
||||
"mappingUUID": item.pk
|
||||
"instancePk": item.pk
|
||||
}}
|
||||
type=${ifDefined(item.component)}>
|
||||
</ak-proxy-form>
|
||||
|
||||
@ -75,7 +75,7 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">${t`Users in the selected group can do search queries.`}</p>
|
||||
<p class="pf-c-form__helper-text">${t`Users in the selected group can do search queries. If no group is selected, no LDAP Searches are allowed.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
||||
<ak-form-group .expanded=${true}>
|
||||
|
||||
@ -125,7 +125,7 @@ export class ProxyProviderFormPage extends ModelForm<ProxyProvider, number> {
|
||||
?required=${true}
|
||||
name="externalHost">
|
||||
<input type="text" value="${ifDefined(this.instance?.externalHost)}" class="pf-c-form-control" required>
|
||||
<p class="pf-c-form__helper-text">${t`The external URL you'll access the application at`}</p>
|
||||
<p class="pf-c-form__helper-text">${t`The external URL you'll access the application at. Include any non-standard port.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="forwardAuthMode">
|
||||
<div class="pf-c-check">
|
||||
|
||||
@ -46,7 +46,7 @@ export class PlexSourceForm extends ModelForm<PlexSource, string> {
|
||||
}
|
||||
|
||||
send = (data: PlexSource): Promise<PlexSource> => {
|
||||
data.plexToken = this.plexToken;
|
||||
data.plexToken = this.plexToken || "";
|
||||
if (this.instance?.slug) {
|
||||
return new SourcesApi(DEFAULT_CONFIG).sourcesPlexUpdate({
|
||||
slug: this.instance.slug,
|
||||
|
||||
@ -22,6 +22,7 @@ postgresql:
|
||||
user: postgres
|
||||
|
||||
log_level: debug
|
||||
secret_key: "A long key you can generate with `pwgen 40 1` for example"
|
||||
```
|
||||
|
||||
Afterwards, you can start authentik by running `./manage.py runserver`. Generally speaking, authentik is a Django application.
|
||||
|
||||
@ -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.4/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.5.4/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.5.1 >> .env`
|
||||
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.5.4 >> .env`
|
||||
|
||||
If this is a fresh authentik install run the following commands to generate a password:
|
||||
|
||||
|
||||
@ -16,7 +16,18 @@ You can configure under which base DN the information should be available. For t
|
||||
|
||||
Users are available under `ou=users,<base DN>` and groups under `ou=groups,<base DN>`.
|
||||
|
||||
You can bind using the DN `cn=<username>,ou=users,<base DN>`.
|
||||
You can bind using the DN `cn=<username>,ou=users,<base DN>`, or using the following ldapsearch command for example:
|
||||
|
||||
```
|
||||
ldapsearch \
|
||||
-x \ # Only simple binds are currently supported
|
||||
-h *ip* \
|
||||
-p 3389 \
|
||||
-D 'cn=*user*,ou=users,DC=ldap,DC=goauthentik,DC=io' \ # Bind user and password
|
||||
-w '*password*' \
|
||||
-b 'ou=users,DC=ldap,DC=goauthentik,DC=io' \ # The search base
|
||||
'(objectClass=user)'
|
||||
```
|
||||
|
||||
The following fields are currently sent for users:
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ version: "3.5"
|
||||
|
||||
services:
|
||||
authentik_proxy:
|
||||
image: beryju/authentik-proxy:2021.5.1
|
||||
image: ghcr.io/goauthentik/proxy:2021.5.4
|
||||
ports:
|
||||
- 4180:4180
|
||||
- 4443:4443
|
||||
@ -19,4 +19,13 @@ services:
|
||||
AUTHENTIK_HOST: https://your-authentik.tld
|
||||
AUTHENTIK_INSECURE: "false"
|
||||
AUTHENTIK_TOKEN: token-generated-by-authentik
|
||||
# Or, for the LDAP Outpost
|
||||
authentik_proxy:
|
||||
image: ghcr.io/goauthentik/ldap:2021.5.4
|
||||
ports:
|
||||
- 389:3389
|
||||
environment:
|
||||
AUTHENTIK_HOST: https://your-authentik.tld
|
||||
AUTHENTIK_INSECURE: "false"
|
||||
AUTHENTIK_TOKEN: token-generated-by-authentik
|
||||
```
|
||||
|
||||
@ -14,7 +14,7 @@ metadata:
|
||||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.5.1
|
||||
app.kubernetes.io/version: 2021.5.4
|
||||
name: authentik-outpost-api
|
||||
stringData:
|
||||
authentik_host: "__AUTHENTIK_URL__"
|
||||
@ -29,7 +29,7 @@ metadata:
|
||||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.5.1
|
||||
app.kubernetes.io/version: 2021.5.4
|
||||
name: authentik-outpost
|
||||
spec:
|
||||
ports:
|
||||
@ -54,7 +54,7 @@ metadata:
|
||||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.5.1
|
||||
app.kubernetes.io/version: 2021.5.4
|
||||
name: authentik-outpost
|
||||
spec:
|
||||
selector:
|
||||
@ -62,14 +62,14 @@ spec:
|
||||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.5.1
|
||||
app.kubernetes.io/version: 2021.5.4
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.5.1
|
||||
app.kubernetes.io/version: 2021.5.4
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
@ -88,7 +88,7 @@ spec:
|
||||
secretKeyRef:
|
||||
key: authentik_host_insecure
|
||||
name: authentik-outpost-api
|
||||
image: beryju/authentik-proxy:2021.5.1
|
||||
image: ghcr.io/goauthentik/proxy:2021.5.4
|
||||
name: proxy
|
||||
ports:
|
||||
- containerPort: 4180
|
||||
@ -110,7 +110,7 @@ metadata:
|
||||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.5.1
|
||||
app.kubernetes.io/version: 2021.5.4
|
||||
name: authentik-outpost
|
||||
spec:
|
||||
rules:
|
||||
|
||||
@ -15,6 +15,14 @@ Additionally, you can set `additionalHeaders` on groups or users to set addition
|
||||
|
||||
If you enable *Set HTTP-Basic Authentication* option, the HTTP Authorization header is being set.
|
||||
|
||||
# HTTPS
|
||||
|
||||
The outpost listens on both 4180 for HTTP and 4443 for HTTPS.
|
||||
|
||||
:::warning
|
||||
If your upstream host is HTTPS, and you're not using forward auth, you need to access the outpost over HTTPS too.
|
||||
:::
|
||||
|
||||
# Forward auth
|
||||
|
||||
To use forward auth instead of proxying, you have to change a couple of settings. In the Proxy Provider, make sure to enable `Enable forward-auth mode` on the provider.
|
||||
@ -35,8 +43,10 @@ import TabItem from '@theme/TabItem';
|
||||
```
|
||||
location /akprox {
|
||||
proxy_pass http://*ip of your outpost*:4180;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
error_page 401 = @akprox_signin;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
}
|
||||
|
||||
location @akprox_signin {
|
||||
@ -157,7 +167,7 @@ services:
|
||||
- '--entrypoints.https.address=:443'
|
||||
|
||||
authentik_proxy:
|
||||
image: beryju/authentik-proxy:2021.4.4
|
||||
image: ghcr.io/goauthentik/proxy:2021.5.1
|
||||
ports:
|
||||
- 4180:4180
|
||||
- 4443:4443
|
||||
|
||||
@ -51,7 +51,7 @@ This release does not introduce any new requirements.
|
||||
|
||||
### docker-compose
|
||||
|
||||
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-0.14/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
|
||||
Download the docker-compose file for 0.14 from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-0.14/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
|
||||
|
||||
### Kubernetes
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@ This release does not introduce any new requirements.
|
||||
|
||||
### docker-compose
|
||||
|
||||
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.1/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
|
||||
Download the docker-compose file for 2021.1 from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.1/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
|
||||
|
||||
### Kubernetes
|
||||
|
||||
|
||||
@ -124,7 +124,7 @@ The integrations affected are:
|
||||
|
||||
### docker-compose
|
||||
|
||||
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.2/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
|
||||
Download the docker-compose file for 2021.2 from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.2/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
|
||||
|
||||
### Kubernetes
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ This release does not introduce any new requirements.
|
||||
|
||||
### docker-compose
|
||||
|
||||
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.3/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
|
||||
Download the docker-compose file for 2021.3 from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.3/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
|
||||
|
||||
### Kubernetes
|
||||
|
||||
|
||||
@ -133,7 +133,7 @@ This release does not introduce any new requirements.
|
||||
|
||||
### docker-compose
|
||||
|
||||
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.4/docker-compose.yml). Afterwards, simply run `docker-compose up -d`.
|
||||
Download the docker-compose file for 2021.4 from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.4/docker-compose.yml). Afterwards, simply run `docker-compose up -d`.
|
||||
|
||||
### Kubernetes
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ This feature is still in technical preview, so please report any Bugs you run in
|
||||
|
||||
- Docker images for ARM
|
||||
|
||||
Docker images are now built for amd64, arm64, arm v7 and arm v8.
|
||||
Docker images are now built for amd64 and arm64.
|
||||
|
||||
- Reduced setup complexity
|
||||
|
||||
@ -58,13 +58,35 @@ This feature is still in technical preview, so please report any Bugs you run in
|
||||
- Add single-use flag for invitations to delete token after use.
|
||||
- Fix sidebar not collapsible on mobile.
|
||||
|
||||
## Fixed in 2021.5.2
|
||||
|
||||
- core: fix application's slug field not being set to unique
|
||||
- flows: fix error when using cancel flow
|
||||
- lib: Fix config loading of secrets from files (#887)
|
||||
- lib: fix parsing of remote IP header when behind multiple reverse proxies
|
||||
- lifecycle: check if group of docker socket exists
|
||||
- lifecycle: fix error when worker is not running as root
|
||||
- outposts: fix error when controller loads from cache but cache has expired
|
||||
- outposts: fix missing default for OutpostState.for_channel
|
||||
- outposts: fix reload notification not working due to wrong ID being cached
|
||||
- outposts/ldap: fix AUTHENTIK_INSECURE not being respected for API client during bind
|
||||
- outposts/proxy: fix error redeeming code when using non-standard ports
|
||||
- outposts/proxy: fix insecure TLS Skip
|
||||
- providers/ldap: use username instead of name for user dn (#883)
|
||||
- providers/proxy: connect ingress to https instead of http
|
||||
- root: only load debug secret key when debug is enabled
|
||||
- web: fix chunks overwriting each other
|
||||
- web/admin: add notice for LDAP Provider's group selection
|
||||
- web/admin: fix PropertyMappings not loading correctly
|
||||
- website/docs: add example ldapsearch command
|
||||
|
||||
## Upgrading
|
||||
|
||||
This release does not introduce any new requirements.
|
||||
|
||||
### docker-compose
|
||||
|
||||
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.5/docker-compose.yml). Afterwards, simply run `docker-compose up -d`.
|
||||
Download the docker-compose file for 2021.5 from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.5/docker-compose.yml). Afterwards, simply run `docker-compose up -d`.
|
||||
|
||||
:::warning
|
||||
The public port of the compose stack has been changed from 443 to 9000 and 9443 to prevent port contention.
|
||||
|
||||
Reference in New Issue
Block a user