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] | [bumpversion] | ||||||
| current_version = 2021.5.1 | current_version = 2021.5.4 | ||||||
| tag = True | tag = True | ||||||
| commit = True | commit = True | ||||||
| parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*) | 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/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-docker-compose.md] | ||||||
|  |  | ||||||
| [bumpversion:file:website/docs/outposts/manual-deploy-kubernetes.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: |         with: | ||||||
|           push: ${{ github.event_name == 'release' }} |           push: ${{ github.event_name == 'release' }} | ||||||
|           tags: | |           tags: | | ||||||
|             beryju/authentik:2021.5.1, |             beryju/authentik:2021.5.4, | ||||||
|             beryju/authentik:latest, |             beryju/authentik:latest, | ||||||
|             ghcr.io/goauthentik/server:2021.5.1, |             ghcr.io/goauthentik/server:2021.5.4, | ||||||
|             ghcr.io/goauthentik/server:latest |             ghcr.io/goauthentik/server:latest | ||||||
|           platforms: linux/amd64,linux/arm64 |           platforms: linux/amd64,linux/arm64 | ||||||
|           context: . |           context: . | ||||||
| @ -75,9 +75,9 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           push: ${{ github.event_name == 'release' }} |           push: ${{ github.event_name == 'release' }} | ||||||
|           tags: | |           tags: | | ||||||
|             beryju/authentik-proxy:2021.5.1, |             beryju/authentik-proxy:2021.5.4, | ||||||
|             beryju/authentik-proxy:latest, |             beryju/authentik-proxy:latest, | ||||||
|             ghcr.io/goauthentik/proxy:2021.5.1, |             ghcr.io/goauthentik/proxy:2021.5.4, | ||||||
|             ghcr.io/goauthentik/proxy:latest |             ghcr.io/goauthentik/proxy:latest | ||||||
|           context: outpost/ |           context: outpost/ | ||||||
|           file: outpost/proxy.Dockerfile |           file: outpost/proxy.Dockerfile | ||||||
| @ -115,9 +115,9 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           push: ${{ github.event_name == 'release' }} |           push: ${{ github.event_name == 'release' }} | ||||||
|           tags: | |           tags: | | ||||||
|             beryju/authentik-ldap:2021.5.1, |             beryju/authentik-ldap:2021.5.4, | ||||||
|             beryju/authentik-ldap:latest, |             beryju/authentik-ldap:latest, | ||||||
|             ghcr.io/goauthentik/ldap:2021.5.1, |             ghcr.io/goauthentik/ldap:2021.5.4, | ||||||
|             ghcr.io/goauthentik/ldap:latest |             ghcr.io/goauthentik/ldap:latest | ||||||
|           context: outpost/ |           context: outpost/ | ||||||
|           file: outpost/ldap.Dockerfile |           file: outpost/ldap.Dockerfile | ||||||
| @ -155,5 +155,5 @@ jobs: | |||||||
|           SENTRY_PROJECT: authentik |           SENTRY_PROJECT: authentik | ||||||
|           SENTRY_URL: https://sentry.beryju.org |           SENTRY_URL: https://sentry.beryju.org | ||||||
|         with: |         with: | ||||||
|           version: authentik@2021.5.1 |           version: authentik@2021.5.4 | ||||||
|           environment: beryjuorg-prod |           environment: beryjuorg-prod | ||||||
|  | |||||||
							
								
								
									
										120
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										120
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							| @ -56,7 +56,6 @@ | |||||||
|                 "sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a", |                 "sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a", | ||||||
|                 "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95" |                 "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==3.7.4.post0" |             "version": "==3.7.4.post0" | ||||||
|         }, |         }, | ||||||
|         "aioredis": { |         "aioredis": { | ||||||
| @ -71,7 +70,6 @@ | |||||||
|                 "sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2", |                 "sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2", | ||||||
|                 "sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb" |                 "sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==5.0.6" |             "version": "==5.0.6" | ||||||
|         }, |         }, | ||||||
|         "asgiref": { |         "asgiref": { | ||||||
| @ -79,7 +77,6 @@ | |||||||
|                 "sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee", |                 "sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee", | ||||||
|                 "sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78" |                 "sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==3.3.4" |             "version": "==3.3.4" | ||||||
|         }, |         }, | ||||||
|         "async-timeout": { |         "async-timeout": { | ||||||
| @ -87,7 +84,6 @@ | |||||||
|                 "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", |                 "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", | ||||||
|                 "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" |                 "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_full_version >= '3.5.3'", |  | ||||||
|             "version": "==3.0.1" |             "version": "==3.0.1" | ||||||
|         }, |         }, | ||||||
|         "attrs": { |         "attrs": { | ||||||
| @ -95,7 +91,6 @@ | |||||||
|                 "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", |                 "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", | ||||||
|                 "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" |                 "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" |             "version": "==21.2.0" | ||||||
|         }, |         }, | ||||||
|         "autobahn": { |         "autobahn": { | ||||||
| @ -103,7 +98,6 @@ | |||||||
|                 "sha256:9195df8af03b0ff29ccd4b7f5abbde957ee90273465942205f9a1bad6c3f07ac", |                 "sha256:9195df8af03b0ff29ccd4b7f5abbde957ee90273465942205f9a1bad6c3f07ac", | ||||||
|                 "sha256:e126c1f583e872fb59e79d36977cfa1f2d0a8a79f90ae31f406faae7664b8e03" |                 "sha256:e126c1f583e872fb59e79d36977cfa1f2d0a8a79f90ae31f406faae7664b8e03" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.7'", |  | ||||||
|             "version": "==21.3.1" |             "version": "==21.3.1" | ||||||
|         }, |         }, | ||||||
|         "automat": { |         "automat": { | ||||||
| @ -122,25 +116,24 @@ | |||||||
|         }, |         }, | ||||||
|         "boto3": { |         "boto3": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:3317722a1e9acbfc0d30cdf273d1708c823ceb19309e9cd91cac8a3604762341", |                 "sha256:13cfe0e3ae1bdc7baf4272b1814a7e760fbb508b19d6ac3f472a6bbd64baad61", | ||||||
|                 "sha256:ee3317fd79b443ef102469fac393a1ffb650ea51ac4fc27464013872c5e1ce31" |                 "sha256:ce08b88a2d7a0ad8edb385f84ea4914296fee6813c66ebf0def956d5278de793" | ||||||
|             ], |             ], | ||||||
|             "index": "pypi", |             "index": "pypi", | ||||||
|             "version": "==1.17.72" |             "version": "==1.17.73" | ||||||
|         }, |         }, | ||||||
|         "botocore": { |         "botocore": { | ||||||
|             "hashes": [ |             "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.73" | ||||||
|             "version": "==1.20.72" |  | ||||||
|         }, |         }, | ||||||
|         "cachetools": { |         "cachetools": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001", |                 "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001", | ||||||
|                 "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff" |                 "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version ~= '3.5'", |  | ||||||
|             "version": "==4.2.2" |             "version": "==4.2.2" | ||||||
|         }, |         }, | ||||||
|         "cbor2": { |         "cbor2": { | ||||||
| @ -227,7 +220,6 @@ | |||||||
|                 "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", |                 "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", | ||||||
|                 "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" |                 "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" |             "version": "==4.0.0" | ||||||
|         }, |         }, | ||||||
|         "click": { |         "click": { | ||||||
| @ -235,7 +227,6 @@ | |||||||
|                 "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", |                 "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", | ||||||
|                 "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" |                 "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" |             "version": "==7.1.2" | ||||||
|         }, |         }, | ||||||
|         "click-didyoumean": { |         "click-didyoumean": { | ||||||
| @ -309,7 +300,6 @@ | |||||||
|                 "sha256:76ffae916ba3aa66b46996c14fa713e46004788167a4873d647544e750e0e99f", |                 "sha256:76ffae916ba3aa66b46996c14fa713e46004788167a4873d647544e750e0e99f", | ||||||
|                 "sha256:a9af943c79717bc52fe64a3c236ae5d3adccc8b5be19c881b442d2c3db233393" |                 "sha256:a9af943c79717bc52fe64a3c236ae5d3adccc8b5be19c881b442d2c3db233393" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==3.0.2" |             "version": "==3.0.2" | ||||||
|         }, |         }, | ||||||
|         "defusedxml": { |         "defusedxml": { | ||||||
| @ -330,9 +320,6 @@ | |||||||
|         }, |         }, | ||||||
|         "django-dbbackup": { |         "django-dbbackup": { | ||||||
|             "git": "https://github.com/django-dbbackup/django-dbbackup.git", |             "git": "https://github.com/django-dbbackup/django-dbbackup.git", | ||||||
|             "hashes": [ |  | ||||||
|                 "sha256:bb109735cae98b64ad084e5b461b7aca2d7b39992f10c9ed9435e3ebb6fb76c8" |  | ||||||
|             ], |  | ||||||
|             "ref": "9d1909c30a3271c8c9c8450add30d6e0b996e145" |             "ref": "9d1909c30a3271c8c9c8450add30d6e0b996e145" | ||||||
|         }, |         }, | ||||||
|         "django-filter": { |         "django-filter": { | ||||||
| @ -435,7 +422,6 @@ | |||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d" |                 "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==0.18.2" |             "version": "==0.18.2" | ||||||
|         }, |         }, | ||||||
|         "geoip2": { |         "geoip2": { | ||||||
| @ -451,7 +437,6 @@ | |||||||
|                 "sha256:588bdb03a41ecb4978472b847881e5518b5d9ec6153d3d679aa127a55e13b39f", |                 "sha256:588bdb03a41ecb4978472b847881e5518b5d9ec6153d3d679aa127a55e13b39f", | ||||||
|                 "sha256:9ad25fba07f46a628ad4d0ca09f38dcb262830df2ac95b217f9b0129c9e42206" |                 "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" |             "version": "==1.30.0" | ||||||
|         }, |         }, | ||||||
|         "gunicorn": { |         "gunicorn": { | ||||||
| @ -467,7 +452,6 @@ | |||||||
|                 "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6", |                 "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6", | ||||||
|                 "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042" |                 "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==0.12.0" |             "version": "==0.12.0" | ||||||
|         }, |         }, | ||||||
|         "hiredis": { |         "hiredis": { | ||||||
| @ -514,7 +498,6 @@ | |||||||
|                 "sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0", |                 "sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0", | ||||||
|                 "sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a" |                 "sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==2.0.0" |             "version": "==2.0.0" | ||||||
|         }, |         }, | ||||||
|         "httptools": { |         "httptools": { | ||||||
| @ -563,7 +546,6 @@ | |||||||
|                 "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", |                 "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", | ||||||
|                 "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2" |                 "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.5'", |  | ||||||
|             "version": "==0.5.1" |             "version": "==0.5.1" | ||||||
|         }, |         }, | ||||||
|         "itypes": { |         "itypes": { | ||||||
| @ -578,7 +560,6 @@ | |||||||
|                 "sha256:2f2de5285cf37f33d33ecd4a9080b75c87cd0c1994d5a9c6df17131ea1f049c6", |                 "sha256:2f2de5285cf37f33d33ecd4a9080b75c87cd0c1994d5a9c6df17131ea1f049c6", | ||||||
|                 "sha256:ea8d7dd814ce9df6de6a761ec7f1cac98afe305b8cdc4aaae4e114b8d8ce24c5" |                 "sha256:ea8d7dd814ce9df6de6a761ec7f1cac98afe305b8cdc4aaae4e114b8d8ce24c5" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==3.0.0" |             "version": "==3.0.0" | ||||||
|         }, |         }, | ||||||
|         "jmespath": { |         "jmespath": { | ||||||
| @ -586,7 +567,6 @@ | |||||||
|                 "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9", |                 "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9", | ||||||
|                 "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f" |                 "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==0.10.0" |             "version": "==0.10.0" | ||||||
|         }, |         }, | ||||||
|         "jsonschema": { |         "jsonschema": { | ||||||
| @ -601,7 +581,6 @@ | |||||||
|                 "sha256:6dc509178ac4269b0e66ab4881f70a2035c33d3a622e20585f965986a5182006", |                 "sha256:6dc509178ac4269b0e66ab4881f70a2035c33d3a622e20585f965986a5182006", | ||||||
|                 "sha256:f4965fba0a4718d47d470beeb5d6446e3357a62402b16c510b6a2f251e05ac3c" |                 "sha256:f4965fba0a4718d47d470beeb5d6446e3357a62402b16c510b6a2f251e05ac3c" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==5.0.2" |             "version": "==5.0.2" | ||||||
|         }, |         }, | ||||||
|         "kubernetes": { |         "kubernetes": { | ||||||
| @ -614,11 +593,8 @@ | |||||||
|         }, |         }, | ||||||
|         "ldap3": { |         "ldap3": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57", |  | ||||||
|                 "sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91", |                 "sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91", | ||||||
|                 "sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c", |                 "sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57" | ||||||
|                 "sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056", |  | ||||||
|                 "sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59" |  | ||||||
|             ], |             ], | ||||||
|             "index": "pypi", |             "index": "pypi", | ||||||
|             "version": "==2.9" |             "version": "==2.9" | ||||||
| @ -712,14 +688,12 @@ | |||||||
|                 "sha256:f58b5ba13a5689ca8317b98439fccfbcc673acaaf8241c1869ceea40f5d585bf", |                 "sha256:f58b5ba13a5689ca8317b98439fccfbcc673acaaf8241c1869ceea40f5d585bf", | ||||||
|                 "sha256:fef86115fdad7ae774720d7103aa776144cf9b66673b4afa9bcaa7af990ed07b" |                 "sha256:fef86115fdad7ae774720d7103aa776144cf9b66673b4afa9bcaa7af990ed07b" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==2.0.0" |             "version": "==2.0.0" | ||||||
|         }, |         }, | ||||||
|         "maxminddb": { |         "maxminddb": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:47e86a084dd814fac88c99ea34ba3278a74bc9de5a25f4b815b608798747c7dc" |                 "sha256:47e86a084dd814fac88c99ea34ba3278a74bc9de5a25f4b815b608798747c7dc" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==2.0.3" |             "version": "==2.0.3" | ||||||
|         }, |         }, | ||||||
|         "msgpack": { |         "msgpack": { | ||||||
| @ -795,7 +769,6 @@ | |||||||
|                 "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281", |                 "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281", | ||||||
|                 "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80" |                 "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==5.1.0" |             "version": "==5.1.0" | ||||||
|         }, |         }, | ||||||
|         "oauthlib": { |         "oauthlib": { | ||||||
| @ -803,7 +776,6 @@ | |||||||
|                 "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889", |                 "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889", | ||||||
|                 "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea" |                 "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==3.1.0" |             "version": "==3.1.0" | ||||||
|         }, |         }, | ||||||
|         "packaging": { |         "packaging": { | ||||||
| @ -819,7 +791,6 @@ | |||||||
|                 "sha256:030e4f9df5f53db2292eec37c6255957eb76168c6f974e4176c711cf91ed34aa", |                 "sha256:030e4f9df5f53db2292eec37c6255957eb76168c6f974e4176c711cf91ed34aa", | ||||||
|                 "sha256:b6c5a9643e3545bcbfd9451766cbaa5d9c67e7303c7bc32c750b6fa70ecb107d" |                 "sha256:b6c5a9643e3545bcbfd9451766cbaa5d9c67e7303c7bc32c750b6fa70ecb107d" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==0.10.1" |             "version": "==0.10.1" | ||||||
|         }, |         }, | ||||||
|         "prompt-toolkit": { |         "prompt-toolkit": { | ||||||
| @ -827,7 +798,6 @@ | |||||||
|                 "sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04", |                 "sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04", | ||||||
|                 "sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc" |                 "sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_full_version >= '3.6.1'", |  | ||||||
|             "version": "==3.0.18" |             "version": "==3.0.18" | ||||||
|         }, |         }, | ||||||
|         "psycopg2-binary": { |         "psycopg2-binary": { | ||||||
| @ -873,37 +843,15 @@ | |||||||
|         }, |         }, | ||||||
|         "pyasn1": { |         "pyasn1": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", |  | ||||||
|                 "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", |                 "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", | ||||||
|                 "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", |                 "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba" | ||||||
|                 "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", |  | ||||||
|                 "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", |  | ||||||
|                 "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", |  | ||||||
|                 "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3", |  | ||||||
|                 "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", |  | ||||||
|                 "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", |  | ||||||
|                 "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", |  | ||||||
|                 "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", |  | ||||||
|                 "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", |  | ||||||
|                 "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2" |  | ||||||
|             ], |             ], | ||||||
|             "version": "==0.4.8" |             "version": "==0.4.8" | ||||||
|         }, |         }, | ||||||
|         "pyasn1-modules": { |         "pyasn1-modules": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd", |  | ||||||
|                 "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45", |  | ||||||
|                 "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4", |  | ||||||
|                 "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d", |  | ||||||
|                 "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0", |  | ||||||
|                 "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811", |  | ||||||
|                 "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8", |  | ||||||
|                 "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", |                 "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", | ||||||
|                 "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74", |                 "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74" | ||||||
|                 "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb", |  | ||||||
|                 "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405", |  | ||||||
|                 "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed", |  | ||||||
|                 "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199" |  | ||||||
|             ], |             ], | ||||||
|             "version": "==0.2.8" |             "version": "==0.2.8" | ||||||
|         }, |         }, | ||||||
| @ -912,7 +860,6 @@ | |||||||
|                 "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", |                 "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", | ||||||
|                 "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" |                 "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==2.20" |             "version": "==2.20" | ||||||
|         }, |         }, | ||||||
|         "pycryptodome": { |         "pycryptodome": { | ||||||
| @ -956,7 +903,6 @@ | |||||||
|                 "sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316", |                 "sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316", | ||||||
|                 "sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29" |                 "sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.5'", |  | ||||||
|             "version": "==2.0.2" |             "version": "==2.0.2" | ||||||
|         }, |         }, | ||||||
|         "pyjwt": { |         "pyjwt": { | ||||||
| @ -979,14 +925,12 @@ | |||||||
|                 "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", |                 "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", | ||||||
|                 "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" |                 "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==2.4.7" |             "version": "==2.4.7" | ||||||
|         }, |         }, | ||||||
|         "pyrsistent": { |         "pyrsistent": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e" |                 "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.5'", |  | ||||||
|             "version": "==0.17.3" |             "version": "==0.17.3" | ||||||
|         }, |         }, | ||||||
|         "python-dateutil": { |         "python-dateutil": { | ||||||
| @ -994,7 +938,6 @@ | |||||||
|                 "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", |                 "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", | ||||||
|                 "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" |                 "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==2.8.1" |             "version": "==2.8.1" | ||||||
|         }, |         }, | ||||||
|         "python-dotenv": { |         "python-dotenv": { | ||||||
| @ -1051,7 +994,6 @@ | |||||||
|                 "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2", |                 "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2", | ||||||
|                 "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24" |                 "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" |             "version": "==3.5.3" | ||||||
|         }, |         }, | ||||||
|         "requests": { |         "requests": { | ||||||
| @ -1059,14 +1001,12 @@ | |||||||
|                 "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", |                 "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", | ||||||
|                 "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" |                 "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" |             "version": "==2.25.1" | ||||||
|         }, |         }, | ||||||
|         "requests-oauthlib": { |         "requests-oauthlib": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d", |                 "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d", | ||||||
|                 "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a", |                 "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a" | ||||||
|                 "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc" |  | ||||||
|             ], |             ], | ||||||
|             "index": "pypi", |             "index": "pypi", | ||||||
|             "version": "==1.3.0" |             "version": "==1.3.0" | ||||||
| @ -1084,7 +1024,6 @@ | |||||||
|                 "sha256:44bc6b54fddd45e4bc0619059196679f9e8b79c027f4131bb072e6a22f4d5e28", |                 "sha256:44bc6b54fddd45e4bc0619059196679f9e8b79c027f4131bb072e6a22f4d5e28", | ||||||
|                 "sha256:ac79fb25f5476e8e9ed1c53b8a2286d2c3f5dde49eb37dbcee5c7eb6a8415a22" |                 "sha256:ac79fb25f5476e8e9ed1c53b8a2286d2c3f5dde49eb37dbcee5c7eb6a8415a22" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3'", |  | ||||||
|             "version": "==0.17.4" |             "version": "==0.17.4" | ||||||
|         }, |         }, | ||||||
|         "ruamel.yaml.clib": { |         "ruamel.yaml.clib": { | ||||||
| @ -1121,7 +1060,7 @@ | |||||||
|                 "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2", |                 "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2", | ||||||
|                 "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f" |                 "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" |             "version": "==0.2.2" | ||||||
|         }, |         }, | ||||||
|         "s3transfer": { |         "s3transfer": { | ||||||
| @ -1152,7 +1091,6 @@ | |||||||
|                 "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", |                 "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", | ||||||
|                 "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" |                 "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==1.16.0" |             "version": "==1.16.0" | ||||||
|         }, |         }, | ||||||
|         "sqlparse": { |         "sqlparse": { | ||||||
| @ -1160,7 +1098,6 @@ | |||||||
|                 "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0", |                 "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0", | ||||||
|                 "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8" |                 "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.5'", |  | ||||||
|             "version": "==0.4.1" |             "version": "==0.4.1" | ||||||
|         }, |         }, | ||||||
|         "structlog": { |         "structlog": { | ||||||
| @ -1216,7 +1153,6 @@ | |||||||
|                 "sha256:7d6f89745680233f1c4db9ddb748df5e88d2a7a37962be174c0fd04c8dba1dc8", |                 "sha256:7d6f89745680233f1c4db9ddb748df5e88d2a7a37962be174c0fd04c8dba1dc8", | ||||||
|                 "sha256:c16b55f9a67b2419cfdf8846576e2ec9ba94fe6978a83080c352a80db31c93fb" |                 "sha256:c16b55f9a67b2419cfdf8846576e2ec9ba94fe6978a83080c352a80db31c93fb" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==21.2.1" |             "version": "==21.2.1" | ||||||
|         }, |         }, | ||||||
|         "typing-extensions": { |         "typing-extensions": { | ||||||
| @ -1232,7 +1168,6 @@ | |||||||
|                 "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f", |                 "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f", | ||||||
|                 "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae" |                 "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==3.0.1" |             "version": "==3.0.1" | ||||||
|         }, |         }, | ||||||
|         "urllib3": { |         "urllib3": { | ||||||
| @ -1277,7 +1212,6 @@ | |||||||
|                 "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30", |                 "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30", | ||||||
|                 "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e" |                 "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==5.0.0" |             "version": "==5.0.0" | ||||||
|         }, |         }, | ||||||
|         "watchgod": { |         "watchgod": { | ||||||
| @ -1307,7 +1241,6 @@ | |||||||
|                 "sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32", |                 "sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32", | ||||||
|                 "sha256:d376bd60eace9d437ab6d7ee16f4ab4e821c9dae591e1b783c58ebd8aaf80c5c" |                 "sha256:d376bd60eace9d437ab6d7ee16f4ab4e821c9dae591e1b783c58ebd8aaf80c5c" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==0.59.0" |             "version": "==0.59.0" | ||||||
|         }, |         }, | ||||||
|         "websockets": { |         "websockets": { | ||||||
| @ -1394,7 +1327,6 @@ | |||||||
|                 "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a", |                 "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a", | ||||||
|                 "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71" |                 "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==1.6.3" |             "version": "==1.6.3" | ||||||
|         }, |         }, | ||||||
|         "zope.interface": { |         "zope.interface": { | ||||||
| @ -1451,7 +1383,6 @@ | |||||||
|                 "sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4", |                 "sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4", | ||||||
|                 "sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263" |                 "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" |             "version": "==5.4.0" | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
| @ -1468,7 +1399,6 @@ | |||||||
|                 "sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e", |                 "sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e", | ||||||
|                 "sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975" |                 "sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version ~= '3.6'", |  | ||||||
|             "version": "==2.5.6" |             "version": "==2.5.6" | ||||||
|         }, |         }, | ||||||
|         "attrs": { |         "attrs": { | ||||||
| @ -1476,7 +1406,6 @@ | |||||||
|                 "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", |                 "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", | ||||||
|                 "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" |                 "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" |             "version": "==21.2.0" | ||||||
|         }, |         }, | ||||||
|         "bandit": { |         "bandit": { | ||||||
| @ -1515,7 +1444,6 @@ | |||||||
|                 "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", |                 "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", | ||||||
|                 "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" |                 "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" |             "version": "==4.0.0" | ||||||
|         }, |         }, | ||||||
|         "click": { |         "click": { | ||||||
| @ -1523,7 +1451,6 @@ | |||||||
|                 "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", |                 "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", | ||||||
|                 "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc" |                 "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" |             "version": "==7.1.2" | ||||||
|         }, |         }, | ||||||
|         "colorama": { |         "colorama": { | ||||||
| @ -1597,16 +1524,14 @@ | |||||||
|                 "sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0", |                 "sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0", | ||||||
|                 "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005" |                 "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.4'", |  | ||||||
|             "version": "==4.0.7" |             "version": "==4.0.7" | ||||||
|         }, |         }, | ||||||
|         "gitpython": { |         "gitpython": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:2bfcd25e6b81fe431fa3ab1f0975986cfddabf7870a323c183f3afbc9447c0c5", |                 "sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135", | ||||||
|                 "sha256:37ac36cacf2e2be5e88f0810187c5833e71c1a2a8cf81588f5699d1b70183baa" |                 "sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.5'", |             "version": "==3.1.17" | ||||||
|             "version": "==3.1.16" |  | ||||||
|         }, |         }, | ||||||
|         "idna": { |         "idna": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
| @ -1627,7 +1552,6 @@ | |||||||
|                 "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6", |                 "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6", | ||||||
|                 "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d" |                 "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6' and python_version < '4.0'", |  | ||||||
|             "version": "==5.8.0" |             "version": "==5.8.0" | ||||||
|         }, |         }, | ||||||
|         "lazy-object-proxy": { |         "lazy-object-proxy": { | ||||||
| @ -1655,7 +1579,6 @@ | |||||||
|                 "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93", |                 "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93", | ||||||
|                 "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b" |                 "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" |             "version": "==1.6.0" | ||||||
|         }, |         }, | ||||||
|         "mccabe": { |         "mccabe": { | ||||||
| @ -1692,7 +1615,6 @@ | |||||||
|                 "sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd", |                 "sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd", | ||||||
|                 "sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4" |                 "sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.6'", |  | ||||||
|             "version": "==5.6.0" |             "version": "==5.6.0" | ||||||
|         }, |         }, | ||||||
|         "pluggy": { |         "pluggy": { | ||||||
| @ -1700,7 +1622,6 @@ | |||||||
|                 "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", |                 "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", | ||||||
|                 "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" |                 "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==0.13.1" |             "version": "==0.13.1" | ||||||
|         }, |         }, | ||||||
|         "py": { |         "py": { | ||||||
| @ -1708,7 +1629,6 @@ | |||||||
|                 "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", |                 "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", | ||||||
|                 "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" |                 "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==1.10.0" |             "version": "==1.10.0" | ||||||
|         }, |         }, | ||||||
|         "pylint": { |         "pylint": { | ||||||
| @ -1739,7 +1659,6 @@ | |||||||
|                 "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", |                 "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", | ||||||
|                 "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" |                 "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==2.4.7" |             "version": "==2.4.7" | ||||||
|         }, |         }, | ||||||
|         "pytest": { |         "pytest": { | ||||||
| @ -1752,11 +1671,11 @@ | |||||||
|         }, |         }, | ||||||
|         "pytest-django": { |         "pytest-django": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
|                 "sha256:80f8875226ec4dc0b205f0578072034563879d98d9b1bec143a80b9045716cb0", |                 "sha256:d1c6758a592fb0ef8abaa2fe12dd28858c1dcfc3d466102ffe52aa8934733dca", | ||||||
|                 "sha256:a51150d8962200250e850c6adcab670779b9c2aa07271471059d1fb92a843fa9" |                 "sha256:f96c4556f4e7b15d987dd1dcc1d1526df81d40c1548d31ce840d597ed2be8c46" | ||||||
|             ], |             ], | ||||||
|             "index": "pypi", |             "index": "pypi", | ||||||
|             "version": "==4.2.0" |             "version": "==4.3.0" | ||||||
|         }, |         }, | ||||||
|         "pyyaml": { |         "pyyaml": { | ||||||
|             "hashes": [ |             "hashes": [ | ||||||
| @ -1844,7 +1763,6 @@ | |||||||
|                 "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", |                 "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", | ||||||
|                 "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" |                 "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" |             "version": "==2.25.1" | ||||||
|         }, |         }, | ||||||
|         "requests-mock": { |         "requests-mock": { | ||||||
| @ -1868,7 +1786,6 @@ | |||||||
|                 "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", |                 "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", | ||||||
|                 "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" |                 "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==1.16.0" |             "version": "==1.16.0" | ||||||
|         }, |         }, | ||||||
|         "smmap": { |         "smmap": { | ||||||
| @ -1876,7 +1793,6 @@ | |||||||
|                 "sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182", |                 "sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182", | ||||||
|                 "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2" |                 "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.5'", |  | ||||||
|             "version": "==4.0.0" |             "version": "==4.0.0" | ||||||
|         }, |         }, | ||||||
|         "stevedore": { |         "stevedore": { | ||||||
| @ -1884,7 +1800,6 @@ | |||||||
|                 "sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee", |                 "sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee", | ||||||
|                 "sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a" |                 "sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '3.6'", |  | ||||||
|             "version": "==3.3.0" |             "version": "==3.3.0" | ||||||
|         }, |         }, | ||||||
|         "toml": { |         "toml": { | ||||||
| @ -1892,7 +1807,6 @@ | |||||||
|                 "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", |                 "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", | ||||||
|                 "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" |                 "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" | ||||||
|             ], |             ], | ||||||
|             "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", |  | ||||||
|             "version": "==0.10.2" |             "version": "==0.10.2" | ||||||
|         }, |         }, | ||||||
|         "urllib3": { |         "urllib3": { | ||||||
|  | |||||||
| @ -1,3 +1,3 @@ | |||||||
| """authentik""" | """authentik""" | ||||||
| __version__ = "2021.5.1" | __version__ = "2021.5.4" | ||||||
| ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" | ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ def token_from_header(raw_header: bytes) -> Optional[Token]: | |||||||
|     return tokens.first() |     return tokens.first() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class AuthentikTokenAuthentication(BaseAuthentication): | class TokenAuthentication(BaseAuthentication): | ||||||
|     """Token-based authentication using HTTP Bearer authentication""" |     """Token-based authentication using HTTP Bearer authentication""" | ||||||
| 
 | 
 | ||||||
|     def authenticate(self, request: Request) -> Union[tuple[User, Any], None]: |     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 guardian.shortcuts import get_anonymous_user | ||||||
| from rest_framework.exceptions import AuthenticationFailed | 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 | from authentik.core.models import Token, TokenIntents | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -169,9 +169,19 @@ router.register("propertymappings/scope", ScopeMappingViewSet) | |||||||
| router.register("authenticators/static", StaticDeviceViewSet) | router.register("authenticators/static", StaticDeviceViewSet) | ||||||
| router.register("authenticators/totp", TOTPDeviceViewSet) | router.register("authenticators/totp", TOTPDeviceViewSet) | ||||||
| router.register("authenticators/webauthn", WebAuthnDeviceViewSet) | router.register("authenticators/webauthn", WebAuthnDeviceViewSet) | ||||||
| router.register("authenticators/admin/static", StaticAdminDeviceViewSet) | router.register( | ||||||
| router.register("authenticators/admin/totp", TOTPAdminDeviceViewSet) |     "authenticators/admin/static", | ||||||
| router.register("authenticators/admin/webauthn", WebAuthnAdminDeviceViewSet) |     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/all", StageViewSet) | ||||||
| router.register("stages/authenticator/static", AuthenticatorStaticStageViewSet) | 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.core.models import Application | ||||||
| from authentik.events.models import EventAction | from authentik.events.models import EventAction | ||||||
| from authentik.policies.engine import PolicyEngine | from authentik.policies.engine import PolicyEngine | ||||||
|  | from authentik.stages.user_login.stage import USER_LOGIN_AUTHENTICATED | ||||||
|  |  | ||||||
| LOGGER = get_logger() | LOGGER = get_logger() | ||||||
|  |  | ||||||
| @ -122,6 +123,7 @@ class ApplicationViewSet(ModelViewSet): | |||||||
|     ) |     ) | ||||||
|     def list(self, request: Request) -> Response: |     def list(self, request: Request) -> Response: | ||||||
|         """Custom list method that checks Policy based access instead of guardian""" |         """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()) |         queryset = self._filter_queryset_for_list(self.get_queryset()) | ||||||
|         self.paginate_queryset(queryset) |         self.paginate_queryset(queryset) | ||||||
|  |  | ||||||
|  | |||||||
| @ -78,7 +78,7 @@ class PropertyMappingViewSet( | |||||||
|     filterset_fields = {"managed": ["isnull"]} |     filterset_fields = {"managed": ["isnull"]} | ||||||
|     ordering = ["name"] |     ordering = ["name"] | ||||||
|  |  | ||||||
|     def get_queryset(self): |     def get_queryset(self):  # pragma: no cover | ||||||
|         return PropertyMapping.objects.select_subclasses() |         return PropertyMapping.objects.select_subclasses() | ||||||
|  |  | ||||||
|     @swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)}) |     @swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)}) | ||||||
|  | |||||||
| @ -63,7 +63,7 @@ class ProviderViewSet( | |||||||
|         "application__name", |         "application__name", | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|     def get_queryset(self): |     def get_queryset(self):  # pragma: no cover | ||||||
|         return Provider.objects.select_subclasses() |         return Provider.objects.select_subclasses() | ||||||
|  |  | ||||||
|     @swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)}) |     @swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)}) | ||||||
|  | |||||||
| @ -61,7 +61,7 @@ class SourceViewSet( | |||||||
|     serializer_class = SourceSerializer |     serializer_class = SourceSerializer | ||||||
|     lookup_field = "slug" |     lookup_field = "slug" | ||||||
|  |  | ||||||
|     def get_queryset(self): |     def get_queryset(self):  # pragma: no cover | ||||||
|         return Source.objects.select_subclasses() |         return Source.objects.select_subclasses() | ||||||
|  |  | ||||||
|     @swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)}) |     @swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)}) | ||||||
|  | |||||||
| @ -139,7 +139,7 @@ class UserViewSet(ModelViewSet): | |||||||
|     search_fields = ["username", "name", "is_active"] |     search_fields = ["username", "name", "is_active"] | ||||||
|     filterset_class = UsersFilter |     filterset_class = UsersFilter | ||||||
|  |  | ||||||
|     def get_queryset(self): |     def get_queryset(self):  # pragma: no cover | ||||||
|         return User.objects.all().exclude(pk=get_anonymous_user().pk) |         return User.objects.all().exclude(pk=get_anonymous_user().pk) | ||||||
|  |  | ||||||
|     @swagger_auto_schema(responses={200: SessionUserSerializer(many=False)}) |     @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 rest_framework.exceptions import AuthenticationFailed | ||||||
| from structlog.stdlib import get_logger | 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 | from authentik.core.models import User | ||||||
|  |  | ||||||
| LOGGER = get_logger() | 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""" |     add custom fields and other properties""" | ||||||
|  |  | ||||||
|     name = models.TextField(help_text=_("Application's display Name.")) |     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 = models.OneToOneField( | ||||||
|         "Provider", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT |         "Provider", null=True, blank=True, default=None, on_delete=models.SET_DEFAULT | ||||||
|     ) |     ) | ||||||
|  | |||||||
| @ -1,12 +1,12 @@ | |||||||
| """Notification API Views""" | """Notification API Views""" | ||||||
| from django_filters.rest_framework import DjangoFilterBackend | from django_filters.rest_framework import DjangoFilterBackend | ||||||
| from guardian.utils import get_anonymous_user |  | ||||||
| from rest_framework import mixins | from rest_framework import mixins | ||||||
| from rest_framework.fields import ReadOnlyField | from rest_framework.fields import ReadOnlyField | ||||||
| from rest_framework.filters import OrderingFilter, SearchFilter | from rest_framework.filters import OrderingFilter, SearchFilter | ||||||
| from rest_framework.serializers import ModelSerializer | from rest_framework.serializers import ModelSerializer | ||||||
| from rest_framework.viewsets import GenericViewSet | from rest_framework.viewsets import GenericViewSet | ||||||
|  |  | ||||||
|  | from authentik.api.authorization import OwnerFilter, OwnerPermissions | ||||||
| from authentik.events.api.event import EventSerializer | from authentik.events.api.event import EventSerializer | ||||||
| from authentik.events.models import Notification | from authentik.events.models import Notification | ||||||
|  |  | ||||||
| @ -49,12 +49,5 @@ class NotificationViewSet( | |||||||
|         "event", |         "event", | ||||||
|         "seen", |         "seen", | ||||||
|     ] |     ] | ||||||
|     filter_backends = [ |     permission_classes = [OwnerPermissions] | ||||||
|         DjangoFilterBackend, |     filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter] | ||||||
|         OrderingFilter, |  | ||||||
|         SearchFilter, |  | ||||||
|     ] |  | ||||||
|  |  | ||||||
|     def get_queryset(self): |  | ||||||
|         user = self.request.user if self.request else get_anonymous_user() |  | ||||||
|         return Notification.objects.filter(user=user.pk) |  | ||||||
|  | |||||||
| @ -65,7 +65,7 @@ class StageViewSet( | |||||||
|     search_fields = ["name"] |     search_fields = ["name"] | ||||||
|     filterset_fields = ["name"] |     filterset_fields = ["name"] | ||||||
|  |  | ||||||
|     def get_queryset(self): |     def get_queryset(self):  # pragma: no cover | ||||||
|         return Stage.objects.select_subclasses() |         return Stage.objects.select_subclasses() | ||||||
|  |  | ||||||
|     @swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)}) |     @swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)}) | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ context["user_backend"] = "django.contrib.auth.backends.ModelBackend" | |||||||
| return True""" | 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 |     from authentik.stages.prompt.models import FieldTypes | ||||||
|  |  | ||||||
|     User = apps.get_model("authentik_core", "User") |     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 |     # Create a policy that sets the flow's user | ||||||
|     prefill_policy, _ = ExpressionPolicy.objects.using(db_alias).update_or_create( |     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}, |         defaults={"expression": PREFILL_POLICY_EXPRESSION}, | ||||||
|     ) |     ) | ||||||
|     password_usable_policy, _ = ExpressionPolicy.objects.using( |     password_usable_policy, _ = ExpressionPolicy.objects.using( | ||||||
|         db_alias |         db_alias | ||||||
|     ).update_or_create( |     ).update_or_create( | ||||||
|         name="default-oob-password-usable", |         name="default-oobe-password-usable", | ||||||
|         defaults={"expression": PW_USABLE_POLICY_EXPRESSION}, |         defaults={"expression": PW_USABLE_POLICY_EXPRESSION}, | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     prompt_header, _ = Prompt.objects.using(db_alias).update_or_create( |     prompt_header, _ = Prompt.objects.using(db_alias).update_or_create( | ||||||
|         field_key="oob-header-text", |         field_key="oobe-header-text", | ||||||
|         defaults={ |         defaults={ | ||||||
|             "label": "oob-header-text", |             "label": "oobe-header-text", | ||||||
|             "type": FieldTypes.STATIC, |             "type": FieldTypes.STATIC, | ||||||
|             "placeholder": "Welcome to authentik! Please set a password for the default admin user, akadmin.", |             "placeholder": "Welcome to authentik! Please set a password for the default admin user, akadmin.", | ||||||
|             "order": 100, |             "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") |     password_second = Prompt.objects.using(db_alias).get(field_key="password_repeat") | ||||||
|  |  | ||||||
|     prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create( |     prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create( | ||||||
|         name="default-oob-password", |         name="default-oobe-password", | ||||||
|     ) |     ) | ||||||
|     prompt_stage.fields.set( |     prompt_stage.fields.set( | ||||||
|         [prompt_header, prompt_email, password_first, password_second] |         [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", |         slug="initial-setup", | ||||||
|         designation=FlowDesignation.STAGE_CONFIGURATION, |         designation=FlowDesignation.STAGE_CONFIGURATION, | ||||||
|         defaults={ |         defaults={ | ||||||
|             "name": "default-oob-setup", |             "name": "default-oobe-setup", | ||||||
|             "title": "Welcome to authentik!", |             "title": "Welcome to authentik!", | ||||||
|         }, |         }, | ||||||
|     ) |     ) | ||||||
| @ -146,5 +146,5 @@ class Migration(migrations.Migration): | |||||||
|     ] |     ] | ||||||
|  |  | ||||||
|     operations = [ |     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: |         if SESSION_KEY_PLAN in request.session: | ||||||
|             del request.session[SESSION_KEY_PLAN] |             del request.session[SESSION_KEY_PLAN] | ||||||
|             LOGGER.debug("Canceled current plan") |             LOGGER.debug("Canceled current plan") | ||||||
|         return redirect("authentik_core:default-invalidation") |         return redirect("authentik_flows:default-invalidation") | ||||||
|  |  | ||||||
|  |  | ||||||
| class ToDefaultFlow(View): | class ToDefaultFlow(View): | ||||||
|  | |||||||
| @ -88,10 +88,10 @@ class ConfigLoader: | |||||||
|             value = os.getenv(url.netloc, url.query) |             value = os.getenv(url.netloc, url.query) | ||||||
|         if url.scheme == "file": |         if url.scheme == "file": | ||||||
|             try: |             try: | ||||||
|                 with open(url.netloc, "r") as _file: |                 with open(url.path, "r") as _file: | ||||||
|                     value = _file.read() |                     value = _file.read() | ||||||
|             except OSError: |             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 |                 value = url.query | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|  | |||||||
| @ -8,7 +8,11 @@ from botocore.exceptions import BotoCoreError | |||||||
| from celery.exceptions import CeleryError | from celery.exceptions import CeleryError | ||||||
| from channels.middleware import BaseMiddleware | from channels.middleware import BaseMiddleware | ||||||
| from channels_redis.core import ChannelFull | 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.db import InternalError, OperationalError, ProgrammingError | ||||||
| from django.http.response import Http404 | from django.http.response import Http404 | ||||||
| from django_redis.exceptions import ConnectionInterrupted | from django_redis.exceptions import ConnectionInterrupted | ||||||
| @ -51,7 +55,8 @@ def before_send(event: dict, hint: dict) -> Optional[dict]: | |||||||
|         ConnectionResetError, |         ConnectionResetError, | ||||||
|         OSError, |         OSError, | ||||||
|         PermissionError, |         PermissionError, | ||||||
|         # Django DB Errors |         # Django Errors | ||||||
|  |         ImproperlyConfigured, | ||||||
|         OperationalError, |         OperationalError, | ||||||
|         InternalError, |         InternalError, | ||||||
|         ProgrammingError, |         ProgrammingError, | ||||||
|  | |||||||
| @ -17,7 +17,8 @@ def _get_client_ip_from_meta(meta: dict[str, Any]) -> Optional[str]: | |||||||
|     ) |     ) | ||||||
|     for _header in headers: |     for _header in headers: | ||||||
|         if _header in meta: |         if _header in meta: | ||||||
|             return meta.get(_header).split(", ")[0] |             ips: list[str] = meta.get(_header).split(",") | ||||||
|  |             return ips[0].strip() | ||||||
|     return None |     return None | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -2,28 +2,6 @@ | |||||||
| from django.http import HttpRequest | from django.http import HttpRequest | ||||||
| from django.template.response import TemplateResponse | from django.template.response import TemplateResponse | ||||||
| from django.utils.translation import gettext_lazy as _ | 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( | def bad_request_message( | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ class WebsocketMessage: | |||||||
| class OutpostConsumer(AuthJsonConsumer): | class OutpostConsumer(AuthJsonConsumer): | ||||||
|     """Handler for Outposts that connect over websockets for health checks and live updates""" |     """Handler for Outposts that connect over websockets for health checks and live updates""" | ||||||
|  |  | ||||||
|     outpost: Optional[Outpost] = None |     outpost: Outpost | ||||||
|  |  | ||||||
|     last_uid: Optional[str] = None |     last_uid: Optional[str] = None | ||||||
|  |  | ||||||
| @ -64,7 +64,10 @@ class OutpostConsumer(AuthJsonConsumer): | |||||||
|     # pylint: disable=unused-argument |     # pylint: disable=unused-argument | ||||||
|     def disconnect(self, close_code): |     def disconnect(self, close_code): | ||||||
|         if self.outpost and self.last_uid: |         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( |         LOGGER.debug( | ||||||
|             "removed outpost instance from cache", |             "removed outpost instance from cache", | ||||||
|             outpost=self.outpost, |             outpost=self.outpost, | ||||||
| @ -75,11 +78,10 @@ class OutpostConsumer(AuthJsonConsumer): | |||||||
|         msg = from_dict(WebsocketMessage, content) |         msg = from_dict(WebsocketMessage, content) | ||||||
|         uid = msg.args.get("uuid", self.channel_name) |         uid = msg.args.get("uuid", self.channel_name) | ||||||
|         self.last_uid = uid |         self.last_uid = uid | ||||||
|         state = OutpostState( |         state = OutpostState.for_instance_uid(self.outpost, uid) | ||||||
|             uid=uid, |         if self.channel_name not in state.channel_ids: | ||||||
|             last_seen=datetime.now(), |             state.channel_ids.append(self.channel_name) | ||||||
|             _outpost=self.outpost, |         state.last_seen = datetime.now() | ||||||
|         ) |  | ||||||
|         if msg.instruction == WebsocketMessageInstruction.HELLO: |         if msg.instruction == WebsocketMessageInstruction.HELLO: | ||||||
|             state.version = msg.args.get("version", None) |             state.version = msg.args.get("version", None) | ||||||
|             state.build_hash = msg.args.get("buildHash", "") |             state.build_hash = msg.args.get("buildHash", "") | ||||||
|  | |||||||
| @ -409,6 +409,7 @@ class OutpostState: | |||||||
|     """Outpost instance state, last_seen and version""" |     """Outpost instance state, last_seen and version""" | ||||||
|  |  | ||||||
|     uid: str |     uid: str | ||||||
|  |     channel_ids: list[str] = field(default_factory=list) | ||||||
|     last_seen: Optional[datetime] = field(default=None) |     last_seen: Optional[datetime] = field(default=None) | ||||||
|     version: Optional[str] = field(default=None) |     version: Optional[str] = field(default=None) | ||||||
|     version_should: Union[Version, LegacyVersion] = field(default=OUR_VERSION) |     version_should: Union[Version, LegacyVersion] = field(default=OUR_VERSION) | ||||||
| @ -431,21 +432,20 @@ class OutpostState: | |||||||
|         keys = cache.keys(f"{outpost.state_cache_prefix}_*") |         keys = cache.keys(f"{outpost.state_cache_prefix}_*") | ||||||
|         states = [] |         states = [] | ||||||
|         for key in keys: |         for key in keys: | ||||||
|             channel = key.replace(f"{outpost.state_cache_prefix}_", "") |             instance_uid = key.replace(f"{outpost.state_cache_prefix}_", "") | ||||||
|             states.append(OutpostState.for_channel(outpost, channel)) |             states.append(OutpostState.for_instance_uid(outpost, instance_uid)) | ||||||
|         return states |         return states | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def for_channel(outpost: Outpost, channel: str) -> "OutpostState": |     def for_instance_uid(outpost: Outpost, uid: str) -> "OutpostState": | ||||||
|         """Get state for a single channel""" |         """Get state for a single instance""" | ||||||
|         key = f"{outpost.state_cache_prefix}_{channel}" |         key = f"{outpost.state_cache_prefix}_{uid}" | ||||||
|         default_data = {"uid": channel} |         default_data = {"uid": uid, "channel_ids": []} | ||||||
|         data = cache.get(key, default_data) |         data = cache.get(key, default_data) | ||||||
|         if isinstance(data, str): |         if isinstance(data, str): | ||||||
|             cache.delete(key) |             cache.delete(key) | ||||||
|             data = default_data |             data = default_data | ||||||
|         state = from_dict(OutpostState, data) |         state = from_dict(OutpostState, data) | ||||||
|         state.uid = channel |  | ||||||
|         # pylint: disable=protected-access |         # pylint: disable=protected-access | ||||||
|         state._outpost = outpost |         state._outpost = outpost | ||||||
|         return state |         return state | ||||||
|  | |||||||
| @ -100,6 +100,8 @@ def outpost_controller( | |||||||
|         outpost: Outpost = cache.get(CACHE_KEY_OUTPOST_DOWN % outpost_pk) |         outpost: Outpost = cache.get(CACHE_KEY_OUTPOST_DOWN % outpost_pk) | ||||||
|     else: |     else: | ||||||
|         outpost: Outpost = Outpost.objects.get(pk=outpost_pk) |         outpost: Outpost = Outpost.objects.get(pk=outpost_pk) | ||||||
|  |     if not outpost: | ||||||
|  |         return | ||||||
|     self.set_uid(slugify(outpost.name)) |     self.set_uid(slugify(outpost.name)) | ||||||
|     try: |     try: | ||||||
|         controller = controller_for_outpost(outpost) |         controller = controller_for_outpost(outpost) | ||||||
| @ -200,8 +202,11 @@ def _outpost_single_update(outpost: Outpost, layer=None): | |||||||
|     if not layer:  # pragma: no cover |     if not layer:  # pragma: no cover | ||||||
|         layer = get_channel_layer() |         layer = get_channel_layer() | ||||||
|     for state in OutpostState.for_outpost(outpost): |     for state in OutpostState.for_outpost(outpost): | ||||||
|         LOGGER.debug("sending update", channel=state.uid, outpost=outpost) |         for channel in state.channel_ids: | ||||||
|         async_to_sync(layer.send)(state.uid, {"type": "event.update"}) |             LOGGER.debug( | ||||||
|  |                 "sending update", channel=channel, instance=state.uid, outpost=outpost | ||||||
|  |             ) | ||||||
|  |             async_to_sync(layer.send)(channel, {"type": "event.update"}) | ||||||
|  |  | ||||||
|  |  | ||||||
| @CELERY_APP.task() | @CELERY_APP.task() | ||||||
|  | |||||||
| @ -91,7 +91,7 @@ class PolicyViewSet( | |||||||
|     } |     } | ||||||
|     search_fields = ["name"] |     search_fields = ["name"] | ||||||
|  |  | ||||||
|     def get_queryset(self): |     def get_queryset(self):  # pragma: no cover | ||||||
|         return Policy.objects.select_subclasses().prefetch_related( |         return Policy.objects.select_subclasses().prefetch_related( | ||||||
|             "bindings", "promptstage_set" |             "bindings", "promptstage_set" | ||||||
|         ) |         ) | ||||||
|  | |||||||
| @ -105,16 +105,21 @@ class PolicyEngine: | |||||||
|                 if cached_policy and self.use_cache: |                 if cached_policy and self.use_cache: | ||||||
|                     self.logger.debug( |                     self.logger.debug( | ||||||
|                         "P_ENG: Taking result from cache", |                         "P_ENG: Taking result from cache", | ||||||
|                         policy=binding.policy, |                         binding=binding, | ||||||
|                         cache_key=key, |                         cache_key=key, | ||||||
|  |                         request=self.request, | ||||||
|                     ) |                     ) | ||||||
|                     self.__cached_policies.append(cached_policy) |                     self.__cached_policies.append(cached_policy) | ||||||
|                     continue |                     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) |                 our_end, task_end = Pipe(False) | ||||||
|                 task = PolicyProcess(binding, self.request, task_end) |                 task = PolicyProcess(binding, self.request, task_end) | ||||||
|                 task.daemon = False |                 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"): |                 if not CURRENT_PROCESS._config.get("daemon"): | ||||||
|                     task.run() |                     task.run() | ||||||
|                 else: |                 else: | ||||||
|  | |||||||
| @ -51,7 +51,12 @@ class PolicyRequest: | |||||||
|             LOGGER.warning("failed to get geoip data", exc=exc) |             LOGGER.warning("failed to get geoip data", exc=exc) | ||||||
|  |  | ||||||
|     def __str__(self): |     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 | @dataclass | ||||||
|  | |||||||
| @ -6,13 +6,11 @@ import time | |||||||
| from dataclasses import asdict, dataclass, field | from dataclasses import asdict, dataclass, field | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| from hashlib import sha256 | from hashlib import sha256 | ||||||
| from typing import Any, Optional, Type, Union | from typing import Any, Optional, Type | ||||||
| from urllib.parse import urlparse | from urllib.parse import urlparse | ||||||
| from uuid import uuid4 | from uuid import uuid4 | ||||||
|  |  | ||||||
| from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey |  | ||||||
| from dacite import from_dict | from dacite import from_dict | ||||||
| from django.conf import settings |  | ||||||
| from django.db import models | from django.db import models | ||||||
| from django.http import HttpRequest | from django.http import HttpRequest | ||||||
| from django.utils import dateformat, timezone | from django.utils import dateformat, timezone | ||||||
| @ -239,7 +237,7 @@ class OAuth2Provider(Provider): | |||||||
|         token.access_token = token.create_access_token(user, request) |         token.access_token = token.create_access_token(user, request) | ||||||
|         return token |         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. |         Takes a provider and returns the set of keys associated with it. | ||||||
|         Returns a list of keys. |         Returns a list of keys. | ||||||
| @ -256,7 +254,7 @@ class OAuth2Provider(Provider): | |||||||
|                 self.jwt_alg = JWTAlgorithms.HS256 |                 self.jwt_alg = JWTAlgorithms.HS256 | ||||||
|                 self.save() |                 self.save() | ||||||
|             else: |             else: | ||||||
|                 return self.rsa_key.private_key |                 return self.rsa_key.key_data | ||||||
|  |  | ||||||
|         if self.jwt_alg == JWTAlgorithms.HS256: |         if self.jwt_alg == JWTAlgorithms.HS256: | ||||||
|             return self.client_secret |             return self.client_secret | ||||||
| @ -300,11 +298,14 @@ class OAuth2Provider(Provider): | |||||||
|  |  | ||||||
|     def encode(self, payload: dict[str, Any]) -> str: |     def encode(self, payload: dict[str, Any]) -> str: | ||||||
|         """Represent the ID Token as a JSON Web Token (JWT).""" |         """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 |         # If the provider does not have an RSA Key assigned, it was switched to Symmetric | ||||||
|         self.refresh_from_db() |         self.refresh_from_db() | ||||||
|         # pyright: reportGeneralTypeIssues=false |         # pyright: reportGeneralTypeIssues=false | ||||||
|         return encode(payload, key, algorithm=self.jwt_alg) |         return encode(payload, key, algorithm=self.jwt_alg, headers=headers) | ||||||
|  |  | ||||||
|     class Meta: |     class Meta: | ||||||
|  |  | ||||||
| @ -457,7 +458,7 @@ class RefreshToken(ExpiringModel, BaseGrantModel): | |||||||
|         See: http://openid.net/specs/openid-connect-core-1_0.html#IDToken""" |         See: http://openid.net/specs/openid-connect-core-1_0.html#IDToken""" | ||||||
|         sub = "" |         sub = "" | ||||||
|         if self.provider.sub_mode == SubModes.HASHED_USER_ID: |         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: |         elif self.provider.sub_mode == SubModes.USER_EMAIL: | ||||||
|             sub = user.email |             sub = user.email | ||||||
|         elif self.provider.sub_mode == SubModes.USER_USERNAME: |         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 django.utils.encoding import force_str | ||||||
|  |  | ||||||
| from authentik.core.models import Application, User | from authentik.core.models import Application, User | ||||||
|  | from authentik.crypto.models import CertificateKeyPair | ||||||
| from authentik.flows.challenge import ChallengeTypes | from authentik.flows.challenge import ChallengeTypes | ||||||
| from authentik.flows.models import Flow | from authentik.flows.models import Flow | ||||||
| from authentik.providers.oauth2.errors import ( | from authentik.providers.oauth2.errors import ( | ||||||
| @ -207,6 +208,7 @@ class TestAuthorize(OAuthTestCase): | |||||||
|             client_secret=generate_client_secret(), |             client_secret=generate_client_secret(), | ||||||
|             authorization_flow=flow, |             authorization_flow=flow, | ||||||
|             redirect_uris="http://localhost", |             redirect_uris="http://localhost", | ||||||
|  |             rsa_key=CertificateKeyPair.objects.first(), | ||||||
|         ) |         ) | ||||||
|         Application.objects.create(name="app", slug="app", provider=provider) |         Application.objects.create(name="app", slug="app", provider=provider) | ||||||
|         state = generate_client_id() |         state = generate_client_id() | ||||||
|  | |||||||
| @ -2,7 +2,11 @@ | |||||||
| from django.test import TestCase | from django.test import TestCase | ||||||
| from jwt import decode | from jwt import decode | ||||||
|  |  | ||||||
| from authentik.providers.oauth2.models import OAuth2Provider, RefreshToken | from authentik.providers.oauth2.models import ( | ||||||
|  |     JWTAlgorithms, | ||||||
|  |     OAuth2Provider, | ||||||
|  |     RefreshToken, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class OAuthTestCase(TestCase): | class OAuthTestCase(TestCase): | ||||||
| @ -19,9 +23,12 @@ class OAuthTestCase(TestCase): | |||||||
|  |  | ||||||
|     def validate_jwt(self, token: RefreshToken, provider: OAuth2Provider): |     def validate_jwt(self, token: RefreshToken, provider: OAuth2Provider): | ||||||
|         """Validate that all required fields are set""" |         """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( |         jwt = decode( | ||||||
|             token.access_token, |             token.access_token, | ||||||
|             provider.client_secret, |             key, | ||||||
|             algorithms=[provider.jwt_alg], |             algorithms=[provider.jwt_alg], | ||||||
|             audience=provider.client_id, |             audience=provider.client_id, | ||||||
|         ) |         ) | ||||||
|  | |||||||
| @ -54,6 +54,7 @@ from authentik.stages.consent.stage import ( | |||||||
|     PLAN_CONTEXT_CONSENT_PERMISSIONS, |     PLAN_CONTEXT_CONSENT_PERMISSIONS, | ||||||
|     ConsentStageView, |     ConsentStageView, | ||||||
| ) | ) | ||||||
|  | from authentik.stages.user_login.stage import USER_LOGIN_AUTHENTICATED | ||||||
|  |  | ||||||
| LOGGER = get_logger() | LOGGER = get_logger() | ||||||
|  |  | ||||||
| @ -437,6 +438,10 @@ class AuthorizationFlowInitView(PolicyAccessView): | |||||||
|         if ( |         if ( | ||||||
|             PROMPT_LOGIN in self.params.prompt |             PROMPT_LOGIN in self.params.prompt | ||||||
|             and SESSION_NEEDS_LOGIN not in self.request.session |             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 |             self.request.session[SESSION_NEEDS_LOGIN] = True | ||||||
|             return self.handle_no_permission() |             return self.handle_no_permission() | ||||||
|  | |||||||
| @ -53,8 +53,10 @@ class ProxyProviderSerializer(ProviderSerializer): | |||||||
|         return instance |         return instance | ||||||
|  |  | ||||||
|     def update(self, instance: ProxyProvider, validated_data): |     def update(self, instance: ProxyProvider, validated_data): | ||||||
|  |         instance = super().update(instance, validated_data) | ||||||
|         instance.set_oauth_defaults() |         instance.set_oauth_defaults() | ||||||
|         return super().update(instance, validated_data) |         instance.save() | ||||||
|  |         return instance | ||||||
|  |  | ||||||
|     class Meta: |     class Meta: | ||||||
|  |  | ||||||
|  | |||||||
| @ -127,7 +127,7 @@ class ProxyProvider(OutpostModel, OAuth2Provider): | |||||||
|         """Ensure all OAuth2-related settings are correct""" |         """Ensure all OAuth2-related settings are correct""" | ||||||
|         self.client_type = ClientTypes.CONFIDENTIAL |         self.client_type = ClientTypes.CONFIDENTIAL | ||||||
|         self.jwt_alg = JWTAlgorithms.RS256 |         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( |         scopes = ScopeMapping.objects.filter( | ||||||
|             scope_name__in=[ |             scope_name__in=[ | ||||||
|                 SCOPE_OPENID, |                 SCOPE_OPENID, | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ from time import time | |||||||
| import structlog | import structlog | ||||||
| from celery.schedules import crontab | from celery.schedules import crontab | ||||||
| from sentry_sdk import init as sentry_init | 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.celery import CeleryIntegration | ||||||
| from sentry_sdk.integrations.django import DjangoIntegration | from sentry_sdk.integrations.django import DjangoIntegration | ||||||
| from sentry_sdk.integrations.redis import RedisIntegration | from sentry_sdk.integrations.redis import RedisIntegration | ||||||
| @ -52,11 +53,9 @@ STATIC_ROOT = BASE_DIR + "/static" | |||||||
| STATICFILES_DIRS = [BASE_DIR + "/web"] | STATICFILES_DIRS = [BASE_DIR + "/web"] | ||||||
| MEDIA_ROOT = BASE_DIR + "/media" | 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") | DEBUG = CONFIG.y_bool("debug") | ||||||
|  | SECRET_KEY = CONFIG.y("secret_key") | ||||||
|  |  | ||||||
| INTERNAL_IPS = ["127.0.0.1"] | INTERNAL_IPS = ["127.0.0.1"] | ||||||
| ALLOWED_HOSTS = ["*"] | ALLOWED_HOSTS = ["*"] | ||||||
| SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") | SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") | ||||||
| @ -162,7 +161,7 @@ REST_FRAMEWORK = { | |||||||
|         "rest_framework.permissions.DjangoObjectPermissions", |         "rest_framework.permissions.DjangoObjectPermissions", | ||||||
|     ), |     ), | ||||||
|     "DEFAULT_AUTHENTICATION_CLASSES": ( |     "DEFAULT_AUTHENTICATION_CLASSES": ( | ||||||
|         "authentik.api.auth.AuthentikTokenAuthentication", |         "authentik.api.authentication.TokenAuthentication", | ||||||
|         "rest_framework.authentication.SessionAuthentication", |         "rest_framework.authentication.SessionAuthentication", | ||||||
|     ), |     ), | ||||||
|     "DEFAULT_RENDERER_CLASSES": [ |     "DEFAULT_RENDERER_CLASSES": [ | ||||||
| @ -354,6 +353,11 @@ if _ERROR_REPORTING: | |||||||
|         environment=CONFIG.y("error_reporting.environment", "customer"), |         environment=CONFIG.y("error_reporting.environment", "customer"), | ||||||
|         send_default_pii=CONFIG.y_bool("error_reporting.send_pii", False), |         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( |     j_print( | ||||||
|         "Error reporting is enabled", |         "Error reporting is enabled", | ||||||
|         env=CONFIG.y("error_reporting.environment", "customer"), |         env=CONFIG.y("error_reporting.environment", "customer"), | ||||||
|  | |||||||
| @ -1,9 +1,10 @@ | |||||||
| """OAuth Source Serializer""" | """OAuth Source Serializer""" | ||||||
| from django_filters.rest_framework import DjangoFilterBackend | 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.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.core.api.sources import SourceSerializer | ||||||
| from authentik.sources.oauth.models import UserOAuthSourceConnection | 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""" |     """Source Viewset""" | ||||||
|  |  | ||||||
|     queryset = UserOAuthSourceConnection.objects.all() |     queryset = UserOAuthSourceConnection.objects.all() | ||||||
|     serializer_class = UserOAuthSourceConnectionSerializer |     serializer_class = UserOAuthSourceConnectionSerializer | ||||||
|     filterset_fields = ["source__slug"] |     filterset_fields = ["source__slug"] | ||||||
|     filter_backends = [ |     permission_classes = [OwnerPermissions] | ||||||
|         DjangoFilterBackend, |     filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter] | ||||||
|         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) |  | ||||||
|  | |||||||
| @ -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, |         default=True, | ||||||
|         help_text=_("Allow friends to authenticate, even if you don't share a server."), |         help_text=_("Allow friends to authenticate, even if you don't share a server."), | ||||||
|     ) |     ) | ||||||
|     plex_token = models.TextField( |     plex_token = models.TextField(help_text=_("Plex token used to check firends")) | ||||||
|         default="", help_text=_("Plex token used to check firends") |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def component(self) -> str: |     def component(self) -> str: | ||||||
|  | |||||||
| @ -1,12 +1,13 @@ | |||||||
| """AuthenticatorStaticStage API Views""" | """AuthenticatorStaticStage API Views""" | ||||||
| from django_filters.rest_framework import DjangoFilterBackend | from django_filters.rest_framework import DjangoFilterBackend | ||||||
| from django_otp.plugins.otp_static.models import StaticDevice | 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.filters import OrderingFilter, SearchFilter | ||||||
| from rest_framework.permissions import IsAdminUser | from rest_framework.permissions import IsAdminUser | ||||||
| from rest_framework.serializers import ModelSerializer | 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.flows.api.stages import StageSerializer | ||||||
| from authentik.stages.authenticator_static.models import AuthenticatorStaticStage | from authentik.stages.authenticator_static.models import AuthenticatorStaticStage | ||||||
|  |  | ||||||
| @ -37,23 +38,22 @@ class StaticDeviceSerializer(ModelSerializer): | |||||||
|         depth = 2 |         depth = 2 | ||||||
|  |  | ||||||
|  |  | ||||||
| class StaticDeviceViewSet(ModelViewSet): | class StaticDeviceViewSet( | ||||||
|  |     mixins.RetrieveModelMixin, | ||||||
|  |     mixins.UpdateModelMixin, | ||||||
|  |     mixins.DestroyModelMixin, | ||||||
|  |     mixins.ListModelMixin, | ||||||
|  |     GenericViewSet, | ||||||
|  | ): | ||||||
|     """Viewset for static authenticator devices""" |     """Viewset for static authenticator devices""" | ||||||
|  |  | ||||||
|     queryset = StaticDevice.objects.none() |     queryset = StaticDevice.objects.all() | ||||||
|     serializer_class = StaticDeviceSerializer |     serializer_class = StaticDeviceSerializer | ||||||
|  |     permission_classes = [OwnerPermissions] | ||||||
|  |     filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter] | ||||||
|     search_fields = ["name"] |     search_fields = ["name"] | ||||||
|     filterset_fields = ["name"] |     filterset_fields = ["name"] | ||||||
|     ordering = ["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): | 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""" | """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 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.filters import OrderingFilter, SearchFilter | ||||||
| from rest_framework.permissions import IsAdminUser | from rest_framework.permissions import IsAdminUser | ||||||
| from rest_framework.serializers import ModelSerializer | 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.flows.api.stages import StageSerializer | ||||||
| from authentik.stages.authenticator_totp.models import AuthenticatorTOTPStage | from authentik.stages.authenticator_totp.models import AuthenticatorTOTPStage | ||||||
|  |  | ||||||
| @ -40,23 +41,22 @@ class TOTPDeviceSerializer(ModelSerializer): | |||||||
|         depth = 2 |         depth = 2 | ||||||
|  |  | ||||||
|  |  | ||||||
| class TOTPDeviceViewSet(ModelViewSet): | class TOTPDeviceViewSet( | ||||||
|  |     mixins.RetrieveModelMixin, | ||||||
|  |     mixins.UpdateModelMixin, | ||||||
|  |     mixins.DestroyModelMixin, | ||||||
|  |     mixins.ListModelMixin, | ||||||
|  |     GenericViewSet, | ||||||
|  | ): | ||||||
|     """Viewset for totp authenticator devices""" |     """Viewset for totp authenticator devices""" | ||||||
|  |  | ||||||
|     queryset = TOTPDevice.objects.none() |     queryset = TOTPDevice.objects.all() | ||||||
|     serializer_class = TOTPDeviceSerializer |     serializer_class = TOTPDeviceSerializer | ||||||
|  |     permission_classes = [OwnerPermissions] | ||||||
|  |     filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter] | ||||||
|     search_fields = ["name"] |     search_fields = ["name"] | ||||||
|     filterset_fields = ["name"] |     filterset_fields = ["name"] | ||||||
|     ordering = ["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): | 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""" | """AuthenticateWebAuthnStage API Views""" | ||||||
| from django_filters.rest_framework import DjangoFilterBackend | from django_filters.rest_framework.backends import DjangoFilterBackend | ||||||
| from guardian.utils import get_anonymous_user | from rest_framework import mixins | ||||||
| from rest_framework.filters import OrderingFilter, SearchFilter | from rest_framework.filters import OrderingFilter, SearchFilter | ||||||
| from rest_framework.permissions import IsAdminUser | from rest_framework.permissions import IsAdminUser | ||||||
| from rest_framework.serializers import ModelSerializer | 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.flows.api.stages import StageSerializer | ||||||
| from authentik.stages.authenticator_webauthn.models import ( | from authentik.stages.authenticator_webauthn.models import ( | ||||||
|     AuthenticateWebAuthnStage, |     AuthenticateWebAuthnStage, | ||||||
| @ -39,23 +40,22 @@ class WebAuthnDeviceSerializer(ModelSerializer): | |||||||
|         depth = 2 |         depth = 2 | ||||||
|  |  | ||||||
|  |  | ||||||
| class WebAuthnDeviceViewSet(ModelViewSet): | class WebAuthnDeviceViewSet( | ||||||
|  |     mixins.RetrieveModelMixin, | ||||||
|  |     mixins.UpdateModelMixin, | ||||||
|  |     mixins.DestroyModelMixin, | ||||||
|  |     mixins.ListModelMixin, | ||||||
|  |     GenericViewSet, | ||||||
|  | ): | ||||||
|     """Viewset for WebAuthn authenticator devices""" |     """Viewset for WebAuthn authenticator devices""" | ||||||
|  |  | ||||||
|     queryset = WebAuthnDevice.objects.none() |     queryset = WebAuthnDevice.objects.all() | ||||||
|     serializer_class = WebAuthnDeviceSerializer |     serializer_class = WebAuthnDeviceSerializer | ||||||
|     search_fields = ["name"] |     search_fields = ["name"] | ||||||
|     filterset_fields = ["name"] |     filterset_fields = ["name"] | ||||||
|     ordering = ["name"] |     ordering = ["name"] | ||||||
|     filter_backends = [ |     permission_classes = [OwnerPermissions] | ||||||
|         DjangoFilterBackend, |     filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter] | ||||||
|         OrderingFilter, |  | ||||||
|         SearchFilter, |  | ||||||
|     ] |  | ||||||
|  |  | ||||||
|     def get_queryset(self): |  | ||||||
|         user = self.request.user if self.request else get_anonymous_user() |  | ||||||
|         return WebAuthnDevice.objects.filter(user=user.pk) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class WebAuthnAdminDeviceViewSet(ReadOnlyModelViewSet): | 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""" | """dummy tests""" | ||||||
| from django.test import Client, TestCase | from django.test import TestCase | ||||||
| from django.urls import reverse | from django.urls import reverse | ||||||
| from django.utils.encoding import force_str | from django.utils.encoding import force_str | ||||||
|  |  | ||||||
| @ -14,7 +14,6 @@ class TestDummyStage(TestCase): | |||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super().setUp() |         super().setUp() | ||||||
|         self.user = User.objects.create(username="unittest", email="test@beryju.org") |         self.user = User.objects.create(username="unittest", email="test@beryju.org") | ||||||
|         self.client = Client() |  | ||||||
|  |  | ||||||
|         self.flow = Flow.objects.create( |         self.flow = Flow.objects.create( | ||||||
|             name="test-dummy", |             name="test-dummy", | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND | |||||||
|  |  | ||||||
| LOGGER = get_logger() | LOGGER = get_logger() | ||||||
| DEFAULT_BACKEND = "django.contrib.auth.backends.ModelBackend" | DEFAULT_BACKEND = "django.contrib.auth.backends.ModelBackend" | ||||||
|  | USER_LOGIN_AUTHENTICATED = "user_login_authenticated" | ||||||
|  |  | ||||||
|  |  | ||||||
| class UserLoginStageView(StageView): | class UserLoginStageView(StageView): | ||||||
| @ -43,5 +44,6 @@ class UserLoginStageView(StageView): | |||||||
|             flow_slug=self.executor.flow.slug, |             flow_slug=self.executor.flow.slug, | ||||||
|             session_duration=self.executor.current_stage.session_duration, |             session_duration=self.executor.current_stage.session_duration, | ||||||
|         ) |         ) | ||||||
|  |         self.request.session[USER_LOGIN_AUTHENTICATED] = True | ||||||
|         messages.success(self.request, _("Successfully logged in!")) |         messages.success(self.request, _("Successfully logged in!")) | ||||||
|         return self.executor.stage_ok() |         return self.executor.stage_ok() | ||||||
|  | |||||||
| @ -43,7 +43,9 @@ stages: | |||||||
|                 pipenv install --dev |                 pipenv install --dev | ||||||
|           - task: CmdLine@2 |           - task: CmdLine@2 | ||||||
|             inputs: |             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 |       - job: black | ||||||
|         pool: |         pool: | ||||||
|           vmImage: 'ubuntu-latest' |           vmImage: 'ubuntu-latest' | ||||||
| @ -140,7 +142,9 @@ stages: | |||||||
|                 pipenv install --dev |                 pipenv install --dev | ||||||
|           - task: CmdLine@2 |           - task: CmdLine@2 | ||||||
|             inputs: |             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 |       - job: migrations_from_previous_release | ||||||
|         pool: |         pool: | ||||||
|           vmImage: 'ubuntu-latest' |           vmImage: 'ubuntu-latest' | ||||||
| @ -171,8 +175,9 @@ stages: | |||||||
|           - task: CmdLine@2 |           - task: CmdLine@2 | ||||||
|             displayName: Migrate to last tagged release |             displayName: Migrate to last tagged release | ||||||
|             inputs: |             inputs: | ||||||
|               script: |               script: | | ||||||
|                 pipenv run ./manage.py migrate |                 pipenv run python -m scripts.generate_ci_config | ||||||
|  |                 pipenv run python -m lifecycle.migrate | ||||||
|           - task: CmdLine@2 |           - task: CmdLine@2 | ||||||
|             displayName: Install current branch |             displayName: Install current branch | ||||||
|             inputs: |             inputs: | ||||||
| @ -184,8 +189,8 @@ stages: | |||||||
|             displayName: Migrate to current branch |             displayName: Migrate to current branch | ||||||
|             inputs: |             inputs: | ||||||
|               script: | |               script: | | ||||||
|  |                 pipenv run python -m scripts.generate_ci_config | ||||||
|                 pipenv run python -m lifecycle.migrate |                 pipenv run python -m lifecycle.migrate | ||||||
|                 pipenv run ./manage.py migrate |  | ||||||
|       - job: coverage_unittest |       - job: coverage_unittest | ||||||
|         pool: |         pool: | ||||||
|           vmImage: 'ubuntu-latest' |           vmImage: 'ubuntu-latest' | ||||||
| @ -210,6 +215,7 @@ stages: | |||||||
|             displayName: Run full test suite |             displayName: Run full test suite | ||||||
|             inputs: |             inputs: | ||||||
|               script: | |               script: | | ||||||
|  |                 pipenv run python -m scripts.generate_ci_config | ||||||
|                 pipenv run make test |                 pipenv run make test | ||||||
|           - task: CmdLine@2 |           - task: CmdLine@2 | ||||||
|             inputs: |             inputs: | ||||||
| @ -253,6 +259,7 @@ stages: | |||||||
|             displayName: Run full test suite |             displayName: Run full test suite | ||||||
|             inputs: |             inputs: | ||||||
|               script: | |               script: | | ||||||
|  |                 pipenv run python -m scripts.generate_ci_config | ||||||
|                 pipenv run make test-integration |                 pipenv run make test-integration | ||||||
|           - task: CmdLine@2 |           - task: CmdLine@2 | ||||||
|             inputs: |             inputs: | ||||||
| @ -308,6 +315,7 @@ stages: | |||||||
|             displayName: Run full test suite |             displayName: Run full test suite | ||||||
|             inputs: |             inputs: | ||||||
|               script: | |               script: | | ||||||
|  |                 pipenv run python -m scripts.generate_ci_config | ||||||
|                 pipenv run make test-e2e |                 pipenv run make test-e2e | ||||||
|           - task: CmdLine@2 |           - task: CmdLine@2 | ||||||
|             condition: always() |             condition: always() | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ services: | |||||||
|     networks: |     networks: | ||||||
|       - internal |       - internal | ||||||
|   server: |   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 |     restart: unless-stopped | ||||||
|     command: server |     command: server | ||||||
|     environment: |     environment: | ||||||
| @ -52,7 +52,7 @@ services: | |||||||
|       - "0.0.0.0:9000:9000" |       - "0.0.0.0:9000:9000" | ||||||
|       - "0.0.0.0:9443:9443" |       - "0.0.0.0:9443:9443" | ||||||
|   worker: |   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 |     restart: unless-stopped | ||||||
|     command: worker |     command: worker | ||||||
|     networks: |     networks: | ||||||
|  | |||||||
| @ -1,3 +1,3 @@ | |||||||
| package constants | package constants | ||||||
|  |  | ||||||
| const VERSION = "2021.5.1" | const VERSION = "2021.5.4" | ||||||
|  | |||||||
| @ -9,7 +9,18 @@ import ( | |||||||
| func (ws *WebServer) configureProxy() { | func (ws *WebServer) configureProxy() { | ||||||
| 	// Reverse proxy to the application server | 	// Reverse proxy to the application server | ||||||
| 	u, _ := url.Parse("http://localhost:8000") | 	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.ErrorHandler = ws.proxyErrorHandler | ||||||
| 	rp.ModifyResponse = ws.proxyModifyResponse | 	rp.ModifyResponse = ws.proxyModifyResponse | ||||||
| 	ws.m.PathPrefix("/").Handler(rp) | 	ws.m.PathPrefix("/").Handler(rp) | ||||||
|  | |||||||
| @ -4,16 +4,19 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
| 	"goauthentik.io/internal/config" | 	"goauthentik.io/internal/config" | ||||||
|  | 	"goauthentik.io/internal/constants" | ||||||
| 	staticWeb "goauthentik.io/web" | 	staticWeb "goauthentik.io/web" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func (ws *WebServer) configureStatic() { | func (ws *WebServer) configureStatic() { | ||||||
|  | 	statRouter := ws.lh.NewRoute().Subrouter() | ||||||
| 	if config.G.Debug { | 	if config.G.Debug { | ||||||
| 		ws.log.Debug("Using local static files") | 		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/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")))) | 		ws.lh.PathPrefix("/static/authentik").Handler(http.StripPrefix("/static/authentik", http.FileServer(http.Dir("./web/authentik")))) | ||||||
| 	} else { | 	} 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/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)))) | 		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 | 	// Media files, always local | ||||||
| 	ws.lh.PathPrefix("/media").Handler(http.StripPrefix("/media", http.FileServer(http.Dir(config.G.Paths.Media)))) | 	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 { | function check_if_root { | ||||||
|     if [[ $EUID -ne 0 ]]; then |     if [[ $EUID -ne 0 ]]; then | ||||||
|         printf '{"event": "Not running as root, disabling permission fixes", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr |         printf '{"event": "Not running as root, disabling permission fixes", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr | ||||||
|  |         $1 | ||||||
|         return |         return | ||||||
|     fi |     fi | ||||||
|     SOCKET="/var/run/docker.sock" |     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 |         # Get group ID of the docker socket, so we can create a matching group and | ||||||
|         # add ourselves to it |         # add ourselves to it | ||||||
|         DOCKER_GID=$(stat -c '%g' $SOCKET) |         DOCKER_GID=$(stat -c '%g' $SOCKET) | ||||||
|  |         getent group $DOCKER_GID || groupadd -f -g $DOCKER_GID docker | ||||||
|         usermod -a -G $DOCKER_GID authentik |         usermod -a -G $DOCKER_GID authentik | ||||||
|     fi |     fi | ||||||
|     # Fix permissions of backups and media |     # Fix permissions of backups and media | ||||||
|     chown -R authentik:authentik /media /backups |     chown -R authentik:authentik /media /backups | ||||||
|  |     chpst -u authentik env HOME=/authentik $1 | ||||||
| } | } | ||||||
|  |  | ||||||
| if [[ "$1" == "server" ]]; then | if [[ "$1" == "server" ]]; then | ||||||
|     python -m lifecycle.migrate |     python -m lifecycle.migrate | ||||||
|     /authentik-proxy |     /authentik-proxy | ||||||
| elif [[ "$1" == "worker" ]]; then | elif [[ "$1" == "worker" ]]; then | ||||||
|     check_if_root |     check_if_root "celery -A authentik.root.celery worker --autoscale 3,1 -E -B -s /tmp/celerybeat-schedule -Q authentik,authentik_scheduled,authentik_events" | ||||||
|     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 |  | ||||||
| elif [[ "$1" == "backup" ]]; then | elif [[ "$1" == "backup" ]]; then | ||||||
|     python -m manage dbbackup --clean |     python -m manage dbbackup --clean | ||||||
| elif [[ "$1" == "restore" ]]; then | elif [[ "$1" == "restore" ]]; then | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ type APIController struct { | |||||||
| // NewAPIController initialise new API Controller instance from URL and API token | // NewAPIController initialise new API Controller instance from URL and API token | ||||||
| func NewAPIController(akURL url.URL, token string) *APIController { | func NewAPIController(akURL url.URL, token string) *APIController { | ||||||
| 	transport := httptransport.New(akURL.Host, client.DefaultBasePath, []string{akURL.Scheme}) | 	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 | 	// create the transport | ||||||
| 	auth := httptransport.BearerToken(token) | 	auth := httptransport.BearerToken(token) | ||||||
|  | |||||||
| @ -52,7 +52,8 @@ func doGlobalSetup(config map[string]interface{}) { | |||||||
| 	defer sentry.Flush(2 * time.Second) | 	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") | 	value, set := os.LookupEnv("AUTHENTIK_INSECURE") | ||||||
| 	if !set { | 	if !set { | ||||||
| 		value = "false" | 		value = "false" | ||||||
|  | |||||||
| @ -55,14 +55,18 @@ func (ls *LDAPServer) Start() error { | |||||||
|  |  | ||||||
| type transport struct { | type transport struct { | ||||||
| 	headers map[string]string | 	headers map[string]string | ||||||
|  | 	inner   http.RoundTripper | ||||||
| } | } | ||||||
|  |  | ||||||
| func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { | func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { | ||||||
| 	for key, value := range t.headers { | 	for key, value := range t.headers { | ||||||
| 		req.Header.Add(key, value) | 		req.Header.Add(key, value) | ||||||
| 	} | 	} | ||||||
| 	return http.DefaultTransport.RoundTrip(req) | 	return t.inner.RoundTrip(req) | ||||||
|  | } | ||||||
|  | func newTransport(inner http.RoundTripper, headers map[string]string) *transport { | ||||||
|  | 	return &transport{ | ||||||
|  | 		inner:   inner, | ||||||
|  | 		headers: headers, | ||||||
| 	} | 	} | ||||||
| func newTransport(headers map[string]string) *transport { |  | ||||||
| 	return &transport{headers} |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,6 +14,8 @@ import ( | |||||||
| 	goldap "github.com/go-ldap/ldap/v3" | 	goldap "github.com/go-ldap/ldap/v3" | ||||||
| 	httptransport "github.com/go-openapi/runtime/client" | 	httptransport "github.com/go-openapi/runtime/client" | ||||||
| 	"github.com/nmcclain/ldap" | 	"github.com/nmcclain/ldap" | ||||||
|  | 	"goauthentik.io/outpost/pkg" | ||||||
|  | 	"goauthentik.io/outpost/pkg/ak" | ||||||
| 	"goauthentik.io/outpost/pkg/client/core" | 	"goauthentik.io/outpost/pkg/client/core" | ||||||
| 	"goauthentik.io/outpost/pkg/client/flows" | 	"goauthentik.io/outpost/pkg/client/flows" | ||||||
| 	"goauthentik.io/outpost/pkg/models" | 	"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 | 	// Create new http client that also sets the correct ip | ||||||
| 	client := &http.Client{ | 	client := &http.Client{ | ||||||
| 		Jar: jar, | 		Jar: jar, | ||||||
| 		Transport: newTransport(map[string]string{ | 		Transport: newTransport(ak.SetUserAgent(ak.GetTLSTransport(), pkg.UserAgent()), map[string]string{ | ||||||
| 			"X-authentik-remote-ip": host, | 			"X-authentik-remote-ip": host, | ||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -117,7 +117,7 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest, | |||||||
|  |  | ||||||
| 			attrs = append(attrs, AKAttrsToLDAP(u.Attributes)...) | 			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}) | 			entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs}) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -80,19 +80,19 @@ func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *opti | |||||||
| 				ID:                    "default", | 				ID:                    "default", | ||||||
| 				URI:                   provider.InternalHost, | 				URI:                   provider.InternalHost, | ||||||
| 				Path:                  "/", | 				Path:                  "/", | ||||||
| 				InsecureSkipTLSVerify: provider.InternalHostSslValidation, | 				InsecureSkipTLSVerify: !provider.InternalHostSslValidation, | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if provider.Certificate != nil { | 	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{ | 		cert, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewCertificate(&crypto.CryptoCertificatekeypairsViewCertificateParams{ | ||||||
| 			Context: context.Background(), | 			Context: context.Background(), | ||||||
| 			KpUUID:  *provider.Certificate, | 			KpUUID:  *provider.Certificate, | ||||||
| 		}, pb.s.ak.Auth) | 		}, pb.s.ak.Auth) | ||||||
| 		if err != nil { | 		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 | 			return providerOpts | ||||||
| 		} | 		} | ||||||
| 		key, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewPrivateKey(&crypto.CryptoCertificatekeypairsViewPrivateKeyParams{ | 		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, | 			KpUUID:  *provider.Certificate, | ||||||
| 		}, pb.s.ak.Auth) | 		}, pb.s.ak.Auth) | ||||||
| 		if err != nil { | 		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 | 			return providerOpts | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		x509cert, err := tls.X509KeyPair([]byte(cert.Payload.Data), []byte(key.Payload.Data)) | 		x509cert, err := tls.X509KeyPair([]byte(cert.Payload.Data), []byte(key.Payload.Data)) | ||||||
| 		if err != nil { | 		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 | 			return providerOpts | ||||||
| 		} | 		} | ||||||
| 		pb.cert = &x509cert | 		pb.cert = &x509cert | ||||||
| 		pb.log.WithField("provider", provider.ClientID).Debug("Loaded certificates") | 		pb.log.WithField("provider", provider.Name).Debug("Loaded certificates") | ||||||
| 	} | 	} | ||||||
| 	return providerOpts | 	return providerOpts | ||||||
| } | } | ||||||
|  | |||||||
| @ -184,7 +184,7 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) { | |||||||
| 		return | 		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 { | 	if err != nil { | ||||||
| 		p.logger.Errorf("Error redeeming code during OAuth2 callback: %v", err) | 		p.logger.Errorf("Error redeeming code during OAuth2 callback: %v", err) | ||||||
| 		p.ErrorPage(rw, http.StatusInternalServerError, "Internal Server Error", "Internal Error") | 		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) | 	p.ClearCSRFCookie(rw, req) | ||||||
| 	if c.Value != nonce { | 	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") | 		p.ErrorPage(rw, http.StatusForbidden, "Permission Denied", "CSRF Failed") | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -13,12 +13,14 @@ func getTemplates() *template.Template { | |||||||
| <head> | <head> | ||||||
| 	<title>{{.Title}}</title> | 	<title>{{.Title}}</title> | ||||||
| 	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> | 	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> | ||||||
|  | 	<style>* { font-family: sans-serif; }</style> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| 	<h2>{{.Title}}</h2> | 	<h2>{{.Title}}</h2> | ||||||
| 	<p>{{.Message}}</p> | 	<p>{{.Message}}</p> | ||||||
| 	<hr> | 	<hr> | ||||||
| 	<p><a href="{{.ProxyPrefix}}/sign_in">Sign In</a></p> | 	<p><a href="{{.ProxyPrefix}}/sign_in">Sign In</a></p> | ||||||
|  | 	<p>Powered by <a href="https://goauthentik.io">authentik</a></p> | ||||||
| </body> | </body> | ||||||
| </html>{{end}}`) | </html>{{end}}`) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const VERSION = "2021.5.1" | const VERSION = "2021.5.4" | ||||||
|  |  | ||||||
| func BUILD() string { | func BUILD() string { | ||||||
| 	return os.Getenv("GIT_BUILD_HASH") | 	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: '' |           description: '' | ||||||
|           required: false |           required: false | ||||||
|           type: string |           type: string | ||||||
|  |         - name: ordering | ||||||
|  |           in: query | ||||||
|  |           description: Which field to use when ordering the results. | ||||||
|  |           required: false | ||||||
|  |           type: string | ||||||
|         - name: search |         - name: search | ||||||
|           in: query |           in: query | ||||||
|           description: A search term. |           description: A search term. | ||||||
| @ -590,30 +595,6 @@ paths: | |||||||
|             $ref: '#/definitions/GenericError' |             $ref: '#/definitions/GenericError' | ||||||
|       tags: |       tags: | ||||||
|         - authenticators |         - 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: [] |     parameters: [] | ||||||
|   /authenticators/static/{id}/: |   /authenticators/static/{id}/: | ||||||
|     get: |     get: | ||||||
| @ -792,30 +773,6 @@ paths: | |||||||
|             $ref: '#/definitions/GenericError' |             $ref: '#/definitions/GenericError' | ||||||
|       tags: |       tags: | ||||||
|         - authenticators |         - 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: [] |     parameters: [] | ||||||
|   /authenticators/totp/{id}/: |   /authenticators/totp/{id}/: | ||||||
|     get: |     get: | ||||||
| @ -994,30 +951,6 @@ paths: | |||||||
|             $ref: '#/definitions/GenericError' |             $ref: '#/definitions/GenericError' | ||||||
|       tags: |       tags: | ||||||
|         - authenticators |         - 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: [] |     parameters: [] | ||||||
|   /authenticators/webauthn/{id}/: |   /authenticators/webauthn/{id}/: | ||||||
|     get: |     get: | ||||||
| @ -10420,30 +10353,6 @@ paths: | |||||||
|             $ref: '#/definitions/GenericError' |             $ref: '#/definitions/GenericError' | ||||||
|       tags: |       tags: | ||||||
|         - sources |         - 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: [] |     parameters: [] | ||||||
|   /sources/oauth_user_connections/{id}/: |   /sources/oauth_user_connections/{id}/: | ||||||
|     get: |     get: | ||||||
| @ -18040,6 +17949,7 @@ definitions: | |||||||
|     required: |     required: | ||||||
|       - name |       - name | ||||||
|       - slug |       - slug | ||||||
|  |       - plex_token | ||||||
|     type: object |     type: object | ||||||
|     properties: |     properties: | ||||||
|       pk: |       pk: | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ class TestProviderProxy(SeleniumTestCase): | |||||||
|         """Start proxy container based on outpost created""" |         """Start proxy container based on outpost created""" | ||||||
|         client: DockerClient = from_env() |         client: DockerClient = from_env() | ||||||
|         container = client.containers.run( |         container = client.containers.run( | ||||||
|             image=f"beryju/authentik-proxy:{__version__}", |             image=f"ghcr.io/goauthentik/proxy:{__version__}", | ||||||
|             detach=True, |             detach=True, | ||||||
|             network_mode="host", |             network_mode="host", | ||||||
|             auto_remove=True, |             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": "^7.26.0", | ||||||
|                 "eslint-config-google": "^0.14.0", |                 "eslint-config-google": "^0.14.0", | ||||||
|                 "eslint-plugin-custom-elements": "0.0.2", |                 "eslint-plugin-custom-elements": "0.0.2", | ||||||
|                 "eslint-plugin-lit": "^1.4.0", |                 "eslint-plugin-lit": "^1.4.1", | ||||||
|                 "flowchart.js": "^1.15.0", |                 "flowchart.js": "^1.15.0", | ||||||
|                 "lit-element": "^2.5.1", |                 "lit-element": "^2.5.1", | ||||||
|                 "lit-html": "^1.4.1", |                 "lit-html": "^1.4.1", | ||||||
|                 "moment": "^2.29.1", |                 "moment": "^2.29.1", | ||||||
|                 "rapidoc": "^9.0.0", |                 "rapidoc": "^9.0.0", | ||||||
|                 "rollup": "^2.47.0", |                 "rollup": "^2.48.0", | ||||||
|                 "rollup-plugin-commonjs": "^10.1.0", |                 "rollup-plugin-commonjs": "^10.1.0", | ||||||
|                 "rollup-plugin-copy": "^3.4.0", |                 "rollup-plugin-copy": "^3.4.0", | ||||||
|                 "rollup-plugin-cssimport": "^1.0.2", |                 "rollup-plugin-cssimport": "^1.0.2", | ||||||
| @ -3601,9 +3601,9 @@ | |||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "node_modules/eslint-plugin-lit": { |         "node_modules/eslint-plugin-lit": { | ||||||
|             "version": "1.4.0", |             "version": "1.4.1", | ||||||
|             "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.0.tgz", |             "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.1.tgz", | ||||||
|             "integrity": "sha512-3PJCC1p4pvDBKtFmg1g2cGzAgJF4IDqhb9NJUh95nYc+QXExa/O/0fILF4WB6X7qdNQKm+gW6nYtSKTyYPHtXw==", |             "integrity": "sha512-7UIbjSa1DGH7ZaDhmGZPHWm17kOjCrGP4VAKNjR0wZVdQLuRKXE+LqXysQ1L3O12hBnExkMG2J9swXpQvuCuXA==", | ||||||
|             "dependencies": { |             "dependencies": { | ||||||
|                 "parse5": "^6.0.1", |                 "parse5": "^6.0.1", | ||||||
|                 "parse5-htmlparser2-tree-adapter": "^6.0.1", |                 "parse5-htmlparser2-tree-adapter": "^6.0.1", | ||||||
| @ -6408,9 +6408,9 @@ | |||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "node_modules/rollup": { |         "node_modules/rollup": { | ||||||
|             "version": "2.47.0", |             "version": "2.48.0", | ||||||
|             "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.47.0.tgz", |             "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.48.0.tgz", | ||||||
|             "integrity": "sha512-rqBjgq9hQfW0vRmz+0S062ORRNJXvwRpzxhFXORvar/maZqY6za3rgQ/p1Glg+j1hnc1GtYyQCPiAei95uTElg==", |             "integrity": "sha512-wl9ZSSSsi5579oscSDYSzGn092tCS076YB+TQrzsGuSfYyJeep8eEWj0eaRjuC5McuMNmcnR8icBqiE/FWNB1A==", | ||||||
|             "bin": { |             "bin": { | ||||||
|                 "rollup": "dist/bin/rollup" |                 "rollup": "dist/bin/rollup" | ||||||
|             }, |             }, | ||||||
| @ -10751,9 +10751,9 @@ | |||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "eslint-plugin-lit": { |         "eslint-plugin-lit": { | ||||||
|             "version": "1.4.0", |             "version": "1.4.1", | ||||||
|             "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.0.tgz", |             "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.4.1.tgz", | ||||||
|             "integrity": "sha512-3PJCC1p4pvDBKtFmg1g2cGzAgJF4IDqhb9NJUh95nYc+QXExa/O/0fILF4WB6X7qdNQKm+gW6nYtSKTyYPHtXw==", |             "integrity": "sha512-7UIbjSa1DGH7ZaDhmGZPHWm17kOjCrGP4VAKNjR0wZVdQLuRKXE+LqXysQ1L3O12hBnExkMG2J9swXpQvuCuXA==", | ||||||
|             "requires": { |             "requires": { | ||||||
|                 "parse5": "^6.0.1", |                 "parse5": "^6.0.1", | ||||||
|                 "parse5-htmlparser2-tree-adapter": "^6.0.1", |                 "parse5-htmlparser2-tree-adapter": "^6.0.1", | ||||||
| @ -12917,9 +12917,9 @@ | |||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         "rollup": { |         "rollup": { | ||||||
|             "version": "2.47.0", |             "version": "2.48.0", | ||||||
|             "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.47.0.tgz", |             "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.48.0.tgz", | ||||||
|             "integrity": "sha512-rqBjgq9hQfW0vRmz+0S062ORRNJXvwRpzxhFXORvar/maZqY6za3rgQ/p1Glg+j1hnc1GtYyQCPiAei95uTElg==", |             "integrity": "sha512-wl9ZSSSsi5579oscSDYSzGn092tCS076YB+TQrzsGuSfYyJeep8eEWj0eaRjuC5McuMNmcnR8icBqiE/FWNB1A==", | ||||||
|             "requires": { |             "requires": { | ||||||
|                 "fsevents": "~2.3.1" |                 "fsevents": "~2.3.1" | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -68,13 +68,13 @@ | |||||||
|         "eslint": "^7.26.0", |         "eslint": "^7.26.0", | ||||||
|         "eslint-config-google": "^0.14.0", |         "eslint-config-google": "^0.14.0", | ||||||
|         "eslint-plugin-custom-elements": "0.0.2", |         "eslint-plugin-custom-elements": "0.0.2", | ||||||
|         "eslint-plugin-lit": "^1.4.0", |         "eslint-plugin-lit": "^1.4.1", | ||||||
|         "flowchart.js": "^1.15.0", |         "flowchart.js": "^1.15.0", | ||||||
|         "lit-element": "^2.5.1", |         "lit-element": "^2.5.1", | ||||||
|         "lit-html": "^1.4.1", |         "lit-html": "^1.4.1", | ||||||
|         "moment": "^2.29.1", |         "moment": "^2.29.1", | ||||||
|         "rapidoc": "^9.0.0", |         "rapidoc": "^9.0.0", | ||||||
|         "rollup": "^2.47.0", |         "rollup": "^2.48.0", | ||||||
|         "rollup-plugin-commonjs": "^10.1.0", |         "rollup-plugin-commonjs": "^10.1.0", | ||||||
|         "rollup-plugin-copy": "^3.4.0", |         "rollup-plugin-copy": "^3.4.0", | ||||||
|         "rollup-plugin-cssimport": "^1.0.2", |         "rollup-plugin-cssimport": "^1.0.2", | ||||||
|  | |||||||
| @ -104,6 +104,7 @@ export default [ | |||||||
|                 dir: "dist", |                 dir: "dist", | ||||||
|                 sourcemap: true, |                 sourcemap: true, | ||||||
|                 manualChunks: manualChunks, |                 manualChunks: manualChunks, | ||||||
|  |                 chunkFileNames: "admin-[name].js" | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|         plugins: [ |         plugins: [ | ||||||
| @ -135,6 +136,7 @@ export default [ | |||||||
|                 dir: "dist", |                 dir: "dist", | ||||||
|                 sourcemap: true, |                 sourcemap: true, | ||||||
|                 manualChunks: manualChunks, |                 manualChunks: manualChunks, | ||||||
|  |                 chunkFileNames: "flow-[name].js" | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|         plugins: [ |         plugins: [ | ||||||
|  | |||||||
| @ -6,7 +6,9 @@ import { me } from "./Users"; | |||||||
| import { config } from "./Config"; | import { config } from "./Config"; | ||||||
| import { Config } from "authentik-api"; | 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) => { |     return config().then((config) => { | ||||||
|         if (config.errorReportingEnabled) { |         if (config.errorReportingEnabled) { | ||||||
|             Sentry.init({ |             Sentry.init({ | ||||||
| @ -51,6 +53,12 @@ export function configureSentry(canDoPpi: boolean = false): Promise<Config> { | |||||||
|                     return event; |                     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."); |             console.debug("authentik/config: Sentry enabled."); | ||||||
|             if (config.errorReportingSendPii && canDoPpi) { |             if (config.errorReportingSendPii && canDoPpi) { | ||||||
|                 me().then(user => { |                 me().then(user => { | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success"; | |||||||
| export const ERROR_CLASS = "pf-m-danger"; | export const ERROR_CLASS = "pf-m-danger"; | ||||||
| export const PROGRESS_CLASS = "pf-m-in-progress"; | export const PROGRESS_CLASS = "pf-m-in-progress"; | ||||||
| export const CURRENT_CLASS = "pf-m-current"; | 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 PAGE_SIZE = 20; | ||||||
| export const EVENT_REFRESH = "ak-refresh"; | export const EVENT_REFRESH = "ak-refresh"; | ||||||
| export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle"; | export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle"; | ||||||
|  | |||||||
| @ -55,7 +55,7 @@ export class ModalButton extends LitElement { | |||||||
|  |  | ||||||
|     resetForms(): void { |     resetForms(): void { | ||||||
|         this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => { |         this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => { | ||||||
|             form.reset(); |             form?.reset(); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -29,8 +29,8 @@ export class TokenCopyButton extends ActionButton { | |||||||
|                     this.buttonClass = PRIMARY_CLASS; |                     this.buttonClass = PRIMARY_CLASS; | ||||||
|                 }, 1500); |                 }, 1500); | ||||||
|             }); |             }); | ||||||
|         }).catch((err: Response) => { |         }).catch((err: Response | undefined) => { | ||||||
|             return err.json().then(errResp => { |             return err?.json().then(errResp => { | ||||||
|                 throw new Error(errResp["detail"]); |                 throw new Error(errResp["detail"]); | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|  | |||||||
| @ -76,10 +76,7 @@ export class Form<T> extends LitElement { | |||||||
|      */ |      */ | ||||||
|     reset(): void { |     reset(): void { | ||||||
|         const ironForm = this.shadowRoot?.querySelector("iron-form"); |         const ironForm = this.shadowRoot?.querySelector("iron-form"); | ||||||
|         if (!ironForm) { |         ironForm?.reset(); | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         ironForm.reset(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ export class ModalForm extends ModalButton { | |||||||
|         return formPromise.then(() => { |         return formPromise.then(() => { | ||||||
|             if (this.closeAfterSuccessfulSubmit) { |             if (this.closeAfterSuccessfulSubmit) { | ||||||
|                 this.open = false; |                 this.open = false; | ||||||
|                 form.reset(); |                 form?.reset(); | ||||||
|             } |             } | ||||||
|             this.dispatchEvent( |             this.dispatchEvent( | ||||||
|                 new CustomEvent(EVENT_REFRESH, { |                 new CustomEvent(EVENT_REFRESH, { | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ export abstract class TableModal<T> extends Table<T> { | |||||||
|  |  | ||||||
|     resetForms(): void { |     resetForms(): void { | ||||||
|         this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => { |         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/empty-state.css"> | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/spinner.css"> |         <link rel="stylesheet" type="text/css" href="/static/dist/spinner.css"> | ||||||
|         <link rel="stylesheet" type="text/css" href="/static/dist/authentik.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 src="/static/dist/poly.js" type="module"></script> | ||||||
|         <script>window["polymerSkipLoadingFontRoboto"] = true;</script> |  | ||||||
|         <script src="/static/dist/FlowInterface.js" type="module"></script> |         <script src="/static/dist/FlowInterface.js" type="module"></script> | ||||||
|         <title>authentik</title> |         <title>authentik</title> | ||||||
|     </head> |     </head> | ||||||
|  | |||||||
| @ -144,7 +144,7 @@ msgstr "Algorithm used to sign the JWT Tokens." | |||||||
| msgid "Allow IDP-initiated logins" | msgid "Allow IDP-initiated logins" | ||||||
| msgstr "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" | 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" | 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." | msgid "Allow up to N occurrences in the HIBP database." | ||||||
| msgstr "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." | 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." | 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" | msgid "Allowed count" | ||||||
| msgstr "Allowed count" | msgstr "Allowed count" | ||||||
|  |  | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:155 | #: src/pages/sources/plex/PlexSourceForm.ts:108 | ||||||
| msgid "Allowed servers" | msgid "Allowed servers" | ||||||
| msgstr "Allowed servers" | msgstr "Allowed servers" | ||||||
|  |  | ||||||
| @ -218,6 +218,22 @@ msgstr "Applications" | |||||||
| msgid "Apps with most usage" | msgid "Apps with most usage" | ||||||
| msgstr "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 | #: src/elements/forms/DeleteForm.ts:69 | ||||||
| msgid "Are you sure you want to delete {0} {objName} ?" | msgid "Are you sure you want to delete {0} {objName} ?" | ||||||
| msgstr "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" | msgid "Assigned to application" | ||||||
| msgstr "Assigned to application" | msgstr "Assigned to application" | ||||||
|  |  | ||||||
| #: src/pages/policies/PolicyListPage.ts:68 | #: src/pages/policies/PolicyListPage.ts:69 | ||||||
| msgid "Assigned to {0} objects." | msgid "Assigned to {0} objects." | ||||||
| msgstr "Assigned to {0} objects." | msgstr "Assigned to {0} objects." | ||||||
|  |  | ||||||
| @ -282,7 +298,7 @@ msgid "Authentication" | |||||||
| msgstr "Authentication" | msgstr "Authentication" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:231 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:243 | ||||||
| msgid "Authentication flow" | msgid "Authentication flow" | ||||||
| msgstr "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." | 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." | 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 | #: src/elements/forms/HorizontalFormElement.ts:82 | ||||||
| msgid "Click to change value" | msgid "Click to change value" | ||||||
| msgstr "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/OAuth2ProviderForm.ts:107 | ||||||
| #: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts:99 | #: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts:99 | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:141 | #: src/pages/sources/plex/PlexSourceForm.ts:176 | ||||||
| msgid "Client ID" | msgid "Client ID" | ||||||
| msgstr "Client ID" | msgstr "Client ID" | ||||||
|  |  | ||||||
| @ -726,8 +757,8 @@ msgstr "Copy download URL" | |||||||
| #: src/pages/flows/BoundStagesList.ts:119 | #: src/pages/flows/BoundStagesList.ts:119 | ||||||
| #: src/pages/flows/BoundStagesList.ts:146 | #: src/pages/flows/BoundStagesList.ts:146 | ||||||
| #: src/pages/flows/BoundStagesList.ts:167 | #: src/pages/flows/BoundStagesList.ts:167 | ||||||
| #: src/pages/flows/FlowListPage.ts:109 | #: src/pages/flows/FlowListPage.ts:110 | ||||||
| #: src/pages/flows/FlowListPage.ts:117 | #: src/pages/flows/FlowListPage.ts:118 | ||||||
| #: src/pages/groups/GroupListPage.ts:90 | #: src/pages/groups/GroupListPage.ts:90 | ||||||
| #: src/pages/groups/GroupListPage.ts:98 | #: src/pages/groups/GroupListPage.ts:98 | ||||||
| #: src/pages/outposts/OutpostListPage.ts:101 | #: 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:162 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:189 | #: src/pages/policies/BoundPoliciesList.ts:189 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:210 | #: src/pages/policies/BoundPoliciesList.ts:210 | ||||||
| #: src/pages/policies/PolicyListPage.ts:124 | #: src/pages/policies/PolicyListPage.ts:125 | ||||||
| #: src/pages/policies/PolicyListPage.ts:133 | #: src/pages/policies/PolicyListPage.ts:134 | ||||||
| #: src/pages/property-mappings/PropertyMappingListPage.ts:113 | #: src/pages/property-mappings/PropertyMappingListPage.ts:113 | ||||||
| #: src/pages/property-mappings/PropertyMappingListPage.ts:122 | #: src/pages/property-mappings/PropertyMappingListPage.ts:122 | ||||||
| #: src/pages/providers/ProviderListPage.ts:108 | #: src/pages/providers/ProviderListPage.ts:108 | ||||||
| @ -778,7 +809,7 @@ msgstr "Create Binding" | |||||||
| msgid "Create Certificate-Key Pair" | msgid "Create Certificate-Key Pair" | ||||||
| msgstr "Create Certificate-Key Pair" | msgstr "Create Certificate-Key Pair" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:112 | #: src/pages/flows/FlowListPage.ts:113 | ||||||
| msgid "Create Flow" | msgid "Create Flow" | ||||||
| msgstr "Create Flow" | msgstr "Create Flow" | ||||||
|  |  | ||||||
| @ -840,7 +871,7 @@ msgstr "Create provider" | |||||||
| #: src/pages/flows/BoundStagesList.ts:149 | #: src/pages/flows/BoundStagesList.ts:149 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:122 | #: src/pages/outposts/ServiceConnectionListPage.ts:122 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:192 | #: 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/property-mappings/PropertyMappingListPage.ts:125 | ||||||
| #: src/pages/providers/ProviderListPage.ts:120 | #: src/pages/providers/ProviderListPage.ts:120 | ||||||
| #: src/pages/sources/SourcesListPage.ts:126 | #: 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/crypto/CertificateKeyPairListPage.ts:86 | ||||||
| #: src/pages/events/RuleListPage.ts:82 | #: src/pages/events/RuleListPage.ts:82 | ||||||
| #: src/pages/events/TransportListPage.ts:86 | #: 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/groups/GroupListPage.ts:81 | ||||||
| #: src/pages/outposts/OutpostListPage.ts:87 | #: src/pages/outposts/OutpostListPage.ts:87 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:101 | #: 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/property-mappings/PropertyMappingListPage.ts:104 | ||||||
| #: src/pages/providers/ProviderListPage.ts:99 | #: src/pages/providers/ProviderListPage.ts:99 | ||||||
| #: src/pages/sources/SourcesListPage.ts:95 | #: 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." | 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/FlowForm.ts:119 | ||||||
| #: src/pages/flows/FlowListPage.ts:48 | #: src/pages/flows/FlowListPage.ts:49 | ||||||
| msgid "Designation" | msgid "Designation" | ||||||
| msgstr "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/crypto/CertificateKeyPairListPage.ts:74 | ||||||
| #: src/pages/events/RuleListPage.ts:70 | #: src/pages/events/RuleListPage.ts:70 | ||||||
| #: src/pages/events/TransportListPage.ts:74 | #: 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/groups/GroupListPage.ts:69 | ||||||
| #: src/pages/outposts/OutpostListPage.ts:75 | #: src/pages/outposts/OutpostListPage.ts:75 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:89 | #: 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/property-mappings/PropertyMappingListPage.ts:79 | ||||||
| #: src/pages/providers/ProviderListPage.ts:87 | #: src/pages/providers/ProviderListPage.ts:87 | ||||||
| #: src/pages/providers/ldap/LDAPProviderViewPage.ts:103 | #: 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/policies/PolicyBindingForm.ts:199 | ||||||
| #: src/pages/sources/ldap/LDAPSourceForm.ts:67 | #: src/pages/sources/ldap/LDAPSourceForm.ts:67 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:134 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:67 | ||||||
| msgid "Enabled" | msgid "Enabled" | ||||||
| msgstr "Enabled" | msgstr "Enabled" | ||||||
| @ -1158,7 +1189,7 @@ msgid "Enrollment" | |||||||
| msgstr "Enrollment" | msgstr "Enrollment" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:252 | #: 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/sources/saml/SAMLSourceForm.ts:264 | ||||||
| #: src/pages/stages/identification/IdentificationStageForm.ts:104 | #: src/pages/stages/identification/IdentificationStageForm.ts:104 | ||||||
| msgid "Enrollment flow" | msgid "Enrollment flow" | ||||||
| @ -1225,12 +1256,12 @@ msgstr "Events" | |||||||
| msgid "Exception" | msgid "Exception" | ||||||
| msgstr "Exception" | msgstr "Exception" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:98 | #: src/pages/flows/FlowListPage.ts:99 | ||||||
| #: src/pages/flows/FlowViewPage.ts:83 | #: src/pages/flows/FlowViewPage.ts:75 | ||||||
| msgid "Execute" | msgid "Execute" | ||||||
| msgstr "Execute" | msgstr "Execute" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowViewPage.ts:69 | #: src/pages/flows/FlowViewPage.ts:61 | ||||||
| msgid "Execute flow" | msgid "Execute flow" | ||||||
| msgstr "Execute flow" | msgstr "Execute flow" | ||||||
|  |  | ||||||
| @ -1277,7 +1308,7 @@ msgstr "Expiry date" | |||||||
| msgid "Explicit Consent" | msgid "Explicit Consent" | ||||||
| msgstr "Explicit Consent" | msgstr "Explicit Consent" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:101 | #: src/pages/flows/FlowListPage.ts:102 | ||||||
| msgid "Export" | msgid "Export" | ||||||
| msgstr "Export" | msgstr "Export" | ||||||
|  |  | ||||||
| @ -1316,6 +1347,14 @@ msgstr "Failed attempts before cancel" | |||||||
| msgid "Failed sources" | msgid "Failed sources" | ||||||
| msgstr "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 | #: src/elements/forms/DeleteForm.ts:46 | ||||||
| msgid "Failed to delete {0}: {1}" | msgid "Failed to delete {0}: {1}" | ||||||
| msgstr "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." | 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/FlowImportForm.ts:34 | ||||||
| #: src/pages/flows/FlowListPage.ts:79 | #: src/pages/flows/FlowListPage.ts:80 | ||||||
| msgid "Flow" | msgid "Flow" | ||||||
| msgstr "Flow" | msgstr "Flow" | ||||||
|  |  | ||||||
| @ -1367,19 +1406,19 @@ msgid "Flow Overview" | |||||||
| msgstr "Flow Overview" | msgstr "Flow Overview" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:227 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:218 | ||||||
| msgid "Flow settings" | msgid "Flow settings" | ||||||
| msgstr "Flow settings" | msgstr "Flow settings" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:249 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:261 | ||||||
| msgid "Flow to use when authenticating existing users." | msgid "Flow to use when authenticating existing users." | ||||||
| msgstr "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/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 | #: src/pages/sources/saml/SAMLSourceForm.ts:282 | ||||||
| msgid "Flow to use when enrolling new users." | msgid "Flow to use when enrolling new users." | ||||||
| msgstr "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:82 | ||||||
| #: src/interfaces/AdminInterface.ts:84 | #: src/interfaces/AdminInterface.ts:84 | ||||||
| #: src/pages/admin-overview/AdminOverviewPage.ts:61 | #: 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 | #: src/pages/stages/StageListPage.ts:66 | ||||||
| msgid "Flows" | msgid "Flows" | ||||||
| msgstr "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." | 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." | 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/providers/saml/SAMLProviderForm.ts:176 | ||||||
| #: src/pages/sources/ldap/LDAPSourceForm.ts:165 | #: src/pages/sources/ldap/LDAPSourceForm.ts:165 | ||||||
| #: src/pages/sources/ldap/LDAPSourceForm.ts:191 | #: 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/authenticator_validate/AuthenticatorValidateStageForm.ts:114 | ||||||
| #: src/pages/stages/identification/IdentificationStageForm.ts:83 | #: src/pages/stages/identification/IdentificationStageForm.ts:83 | ||||||
| #: src/pages/stages/password/PasswordStageForm.ts:84 | #: src/pages/stages/password/PasswordStageForm.ts:84 | ||||||
| @ -1567,7 +1606,7 @@ msgstr "ID" | |||||||
| msgid "Icon" | msgid "Icon" | ||||||
| msgstr "Icon" | msgstr "Icon" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:46 | #: src/pages/flows/FlowListPage.ts:47 | ||||||
| #: src/pages/system-tasks/SystemTaskListPage.ts:54 | #: src/pages/system-tasks/SystemTaskListPage.ts:54 | ||||||
| #: src/pages/tokens/TokenListPage.ts:44 | #: src/pages/tokens/TokenListPage.ts:44 | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts:49 | #: 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" | msgid "Impersonate" | ||||||
| msgstr "Impersonate" | msgstr "Impersonate" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:122 | #: src/pages/flows/FlowListPage.ts:123 | ||||||
| #: src/pages/flows/FlowListPage.ts:130 | #: src/pages/flows/FlowListPage.ts:131 | ||||||
| msgid "Import" | msgid "Import" | ||||||
| msgstr "Import" | msgstr "Import" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:125 | #: src/pages/flows/FlowListPage.ts:126 | ||||||
| msgid "Import Flow" | msgid "Import Flow" | ||||||
| msgstr "Import Flow" | msgstr "Import Flow" | ||||||
|  |  | ||||||
| @ -1716,7 +1755,7 @@ msgstr "Last login" | |||||||
| msgid "Last run" | msgid "Last run" | ||||||
| msgstr "Last run" | msgstr "Last run" | ||||||
|  |  | ||||||
| #: src/pages/outposts/OutpostHealth.ts:54 | #: src/pages/outposts/OutpostHealth.ts:53 | ||||||
| msgid "Last seen: {0}" | msgid "Last seen: {0}" | ||||||
| msgstr "Last seen: {0}" | msgstr "Last seen: {0}" | ||||||
|  |  | ||||||
| @ -1742,21 +1781,21 @@ msgid "Library" | |||||||
| msgstr "Library" | msgstr "Library" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:147 | #: 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" | 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" | 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/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." | 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." | 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/oauth/OAuthSourceForm.ts:144 | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:118 | #: src/pages/sources/plex/PlexSourceForm.ts:153 | ||||||
| msgid "Link users on unique identifier" | msgid "Link users on unique identifier" | ||||||
| msgstr "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" | msgid "Load servers" | ||||||
| msgstr "Load servers" | msgstr "Load servers" | ||||||
|  |  | ||||||
| @ -1821,8 +1860,8 @@ msgstr "Loading" | |||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:219 | #: src/pages/sources/oauth/OAuthSourceForm.ts:219 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:247 | #: src/pages/sources/oauth/OAuthSourceForm.ts:247 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:268 | #: src/pages/sources/oauth/OAuthSourceForm.ts:268 | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:201 | #: src/pages/sources/plex/PlexSourceForm.ts:206 | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:222 | #: src/pages/sources/plex/PlexSourceForm.ts:227 | ||||||
| #: src/pages/sources/saml/SAMLSourceForm.ts:124 | #: src/pages/sources/saml/SAMLSourceForm.ts:124 | ||||||
| #: src/pages/sources/saml/SAMLSourceForm.ts:238 | #: src/pages/sources/saml/SAMLSourceForm.ts:238 | ||||||
| #: src/pages/sources/saml/SAMLSourceForm.ts:259 | #: src/pages/sources/saml/SAMLSourceForm.ts:259 | ||||||
| @ -1961,7 +2000,7 @@ msgstr "My Applications" | |||||||
| #: src/pages/events/TransportListPage.ts:46 | #: src/pages/events/TransportListPage.ts:46 | ||||||
| #: src/pages/flows/BoundStagesList.ts:39 | #: src/pages/flows/BoundStagesList.ts:39 | ||||||
| #: src/pages/flows/FlowForm.ts:86 | #: 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/GroupForm.ts:58 | ||||||
| #: src/pages/groups/GroupListPage.ts:45 | #: src/pages/groups/GroupListPage.ts:45 | ||||||
| #: src/pages/groups/MemberSelectModal.ts:45 | #: src/pages/groups/MemberSelectModal.ts:45 | ||||||
| @ -1970,7 +2009,7 @@ msgstr "My Applications" | |||||||
| #: src/pages/outposts/ServiceConnectionDockerForm.ts:51 | #: src/pages/outposts/ServiceConnectionDockerForm.ts:51 | ||||||
| #: src/pages/outposts/ServiceConnectionKubernetesForm.ts:52 | #: src/pages/outposts/ServiceConnectionKubernetesForm.ts:52 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:53 | #: 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/dummy/DummyPolicyForm.ts:54 | ||||||
| #: src/pages/policies/event_matcher/EventMatcherPolicyForm.ts:55 | #: src/pages/policies/event_matcher/EventMatcherPolicyForm.ts:55 | ||||||
| #: src/pages/policies/expiry/ExpiryPolicyForm.ts:54 | #: src/pages/policies/expiry/ExpiryPolicyForm.ts:54 | ||||||
| @ -1997,7 +2036,7 @@ msgstr "My Applications" | |||||||
| #: src/pages/sources/ldap/LDAPSourceViewPage.ts:64 | #: src/pages/sources/ldap/LDAPSourceViewPage.ts:64 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:108 | #: src/pages/sources/oauth/OAuthSourceForm.ts:108 | ||||||
| #: src/pages/sources/oauth/OAuthSourceViewPage.ts:64 | #: 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/plex/PlexSourceViewPage.ts:63 | ||||||
| #: src/pages/sources/saml/SAMLSourceForm.ts:52 | #: src/pages/sources/saml/SAMLSourceForm.ts:52 | ||||||
| #: src/pages/sources/saml/SAMLSourceViewPage.ts:66 | #: src/pages/sources/saml/SAMLSourceViewPage.ts:66 | ||||||
| @ -2359,15 +2398,15 @@ msgstr "Please enter your password" | |||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts:74 | #: src/interfaces/AdminInterface.ts:74 | ||||||
| #: src/pages/admin-overview/AdminOverviewPage.ts:56 | #: src/pages/admin-overview/AdminOverviewPage.ts:56 | ||||||
| #: src/pages/flows/FlowListPage.ts:50 | #: src/pages/flows/FlowListPage.ts:51 | ||||||
| #: src/pages/policies/PolicyListPage.ts:38 | #: src/pages/policies/PolicyListPage.ts:39 | ||||||
| msgid "Policies" | msgid "Policies" | ||||||
| msgstr "Policies" | msgstr "Policies" | ||||||
|  |  | ||||||
| #: src/pages/policies/PolicyBindingForm.ts:108 | #: src/pages/policies/PolicyBindingForm.ts:108 | ||||||
| #: src/pages/policies/PolicyBindingForm.ts:117 | #: src/pages/policies/PolicyBindingForm.ts:117 | ||||||
| #: src/pages/policies/PolicyBindingForm.ts:148 | #: src/pages/policies/PolicyBindingForm.ts:148 | ||||||
| #: src/pages/policies/PolicyListPage.ts:108 | #: src/pages/policies/PolicyListPage.ts:109 | ||||||
| msgid "Policy" | msgid "Policy" | ||||||
| msgstr "Policy" | msgstr "Policy" | ||||||
|  |  | ||||||
| @ -2492,7 +2531,7 @@ msgstr "Protocol Settings" | |||||||
| #: src/pages/providers/proxy/ProxyProviderForm.ts:123 | #: src/pages/providers/proxy/ProxyProviderForm.ts:123 | ||||||
| #: src/pages/providers/saml/SAMLProviderForm.ts:77 | #: src/pages/providers/saml/SAMLProviderForm.ts:77 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:163 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:74 | ||||||
| msgid "Protocol settings" | msgid "Protocol settings" | ||||||
| msgstr "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." | 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/applications/ApplicationViewPage.ts:62 | ||||||
| #: src/pages/flows/FlowViewPage.ts:64 | #: src/pages/flows/FlowViewPage.ts:56 | ||||||
| msgid "Related" | msgid "Related" | ||||||
| msgstr "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." | 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." | 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." | 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." | 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/flows/FlowForm.ts:99 | ||||||
| #: src/pages/sources/ldap/LDAPSourceForm.ts:58 | #: src/pages/sources/ldap/LDAPSourceForm.ts:58 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:114 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:58 | ||||||
| msgid "Slug" | msgid "Slug" | ||||||
| msgstr "Slug" | msgstr "Slug" | ||||||
| @ -3017,7 +3056,7 @@ msgid "Stage-specific settings" | |||||||
| msgstr "Stage-specific settings" | msgstr "Stage-specific settings" | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts:87 | #: 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/StageListPage.ts:44 | ||||||
| #: src/pages/stages/prompt/PromptListPage.ts:50 | #: src/pages/stages/prompt/PromptListPage.ts:50 | ||||||
| msgid "Stages" | msgid "Stages" | ||||||
| @ -3081,6 +3120,14 @@ msgstr "Subject-alt name" | |||||||
| msgid "Successful" | msgid "Successful" | ||||||
| msgstr "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 | #: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts:63 | ||||||
| msgid "Successfully copied TOTP Config." | msgid "Successfully copied TOTP Config." | ||||||
| msgstr "Successfully copied TOTP Config." | msgstr "Successfully copied TOTP Config." | ||||||
| @ -3405,14 +3452,14 @@ msgid "Template" | |||||||
| msgstr "Template" | msgstr "Template" | ||||||
|  |  | ||||||
| #: src/pages/events/TransportListPage.ts:62 | #: src/pages/events/TransportListPage.ts:62 | ||||||
| #: src/pages/policies/PolicyListPage.ts:95 | #: src/pages/policies/PolicyListPage.ts:96 | ||||||
| #: src/pages/policies/PolicyListPage.ts:103 | #: src/pages/policies/PolicyListPage.ts:104 | ||||||
| #: src/pages/property-mappings/PropertyMappingListPage.ts:84 | #: src/pages/property-mappings/PropertyMappingListPage.ts:84 | ||||||
| #: src/pages/property-mappings/PropertyMappingListPage.ts:92 | #: src/pages/property-mappings/PropertyMappingListPage.ts:92 | ||||||
| msgid "Test" | msgid "Test" | ||||||
| msgstr "Test" | msgstr "Test" | ||||||
|  |  | ||||||
| #: src/pages/policies/PolicyListPage.ts:98 | #: src/pages/policies/PolicyListPage.ts:99 | ||||||
| msgid "Test Policy" | msgid "Test Policy" | ||||||
| msgstr "Test Policy" | msgstr "Test Policy" | ||||||
|  |  | ||||||
| @ -3429,8 +3476,8 @@ msgid "The URL \"{0}\" was not found." | |||||||
| msgstr "The URL \"{0}\" was not found." | msgstr "The URL \"{0}\" was not found." | ||||||
|  |  | ||||||
| #: src/pages/providers/proxy/ProxyProviderForm.ts:131 | #: 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 "The external URL you'll access the application at" | msgstr "The external URL you'll access the application at. Include any non-standard port." | ||||||
|  |  | ||||||
| #: src/pages/policies/dummy/DummyPolicyForm.ts:88 | #: src/pages/policies/dummy/DummyPolicyForm.ts:88 | ||||||
| msgid "The policy takes a random time to execute. This controls the minimum time it will take." | 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/flows/BoundStagesList.ts:40 | ||||||
| #: src/pages/outposts/OutpostForm.ts:58 | #: src/pages/outposts/OutpostForm.ts:58 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:54 | #: 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/property-mappings/PropertyMappingListPage.ts:55 | ||||||
| #: src/pages/providers/ProviderListPage.ts:55 | #: src/pages/providers/ProviderListPage.ts:55 | ||||||
| #: src/pages/sources/SourcesListPage.ts:53 | #: src/pages/sources/SourcesListPage.ts:53 | ||||||
| @ -3640,7 +3687,7 @@ msgstr "Up-to-date!" | |||||||
| #: src/pages/events/TransportListPage.ts:66 | #: src/pages/events/TransportListPage.ts:66 | ||||||
| #: src/pages/flows/BoundStagesList.ts:53 | #: src/pages/flows/BoundStagesList.ts:53 | ||||||
| #: src/pages/flows/BoundStagesList.ts:71 | #: 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/groups/GroupListPage.ts:61 | ||||||
| #: src/pages/outposts/OutpostListPage.ts:67 | #: src/pages/outposts/OutpostListPage.ts:67 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:76 | #: 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:88 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:103 | #: src/pages/policies/BoundPoliciesList.ts:103 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:129 | #: 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/property-mappings/PropertyMappingListPage.ts:66 | ||||||
| #: src/pages/providers/ProviderListPage.ts:74 | #: src/pages/providers/ProviderListPage.ts:74 | ||||||
| #: src/pages/providers/ldap/LDAPProviderViewPage.ts:93 | #: src/pages/providers/ldap/LDAPProviderViewPage.ts:93 | ||||||
| @ -3686,7 +3733,7 @@ msgstr "Update Binding" | |||||||
| msgid "Update Certificate-Key Pair" | msgid "Update Certificate-Key Pair" | ||||||
| msgstr "Update Certificate-Key Pair" | msgstr "Update Certificate-Key Pair" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:69 | #: src/pages/flows/FlowListPage.ts:70 | ||||||
| msgid "Update Flow" | msgid "Update Flow" | ||||||
| msgstr "Update Flow" | msgstr "Update Flow" | ||||||
|  |  | ||||||
| @ -3764,7 +3811,7 @@ msgstr "Update details" | |||||||
| #: src/pages/flows/BoundStagesList.ts:56 | #: src/pages/flows/BoundStagesList.ts:56 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:79 | #: src/pages/outposts/ServiceConnectionListPage.ts:79 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:71 | #: 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/property-mappings/PropertyMappingListPage.ts:69 | ||||||
| #: src/pages/providers/ProviderListPage.ts:77 | #: src/pages/providers/ProviderListPage.ts:77 | ||||||
| #: src/pages/sources/SourcesListPage.ts:73 | #: src/pages/sources/SourcesListPage.ts:73 | ||||||
| @ -3798,12 +3845,12 @@ msgid "Use global settings" | |||||||
| msgstr "Use global settings" | msgstr "Use global settings" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:150 | #: 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." | 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." | 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/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." | 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." | msgstr "Use the user's username, but deny enrollment when the username already exists." | ||||||
|  |  | ||||||
| @ -3852,7 +3899,7 @@ msgid "User fields" | |||||||
| msgstr "User fields" | msgstr "User fields" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:139 | #: 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" | msgid "User matching mode" | ||||||
| msgstr "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." | msgstr "Users added to this group will be superusers." | ||||||
|  |  | ||||||
| #: src/pages/providers/ldap/LDAPProviderForm.ts:86 | #: 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 "Users in the selected group can do search queries." | 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 | #: src/pages/events/EventInfo.ts:108 | ||||||
| msgid "Using flow" | 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" | msgid "Version" | ||||||
| msgstr "Version" | msgstr "Version" | ||||||
|  |  | ||||||
| #: src/pages/outposts/OutpostHealth.ts:60 | #: src/pages/outposts/OutpostHealth.ts:59 | ||||||
| msgid "Version: {0}" | msgid "Version: {0}" | ||||||
| msgstr "Version: {0}" | msgstr "Version: {0}" | ||||||
|  |  | ||||||
| @ -3985,7 +4032,7 @@ msgstr "Wait (min)" | |||||||
| msgid "Warning" | msgid "Warning" | ||||||
| msgstr "Warning" | msgstr "Warning" | ||||||
|  |  | ||||||
| #: src/pages/policies/PolicyListPage.ts:71 | #: src/pages/policies/PolicyListPage.ts:72 | ||||||
| msgid "Warning: Policy is not assigned." | msgid "Warning: Policy is not assigned." | ||||||
| msgstr "Warning: Policy is not assigned." | msgstr "Warning: Policy is not assigned." | ||||||
|  |  | ||||||
| @ -4122,7 +4169,7 @@ msgstr "{0} is available!" | |||||||
| msgid "{0} unread" | msgid "{0} unread" | ||||||
| msgstr "{0} unread" | msgstr "{0} unread" | ||||||
|  |  | ||||||
| #: src/pages/outposts/OutpostHealth.ts:59 | #: src/pages/outposts/OutpostHealth.ts:58 | ||||||
| msgid "{0}, should be {1}" | msgid "{0}, should be {1}" | ||||||
| msgstr "{0}, should be {1}" | msgstr "{0}, should be {1}" | ||||||
|  |  | ||||||
|  | |||||||
| @ -144,7 +144,7 @@ msgstr "" | |||||||
| msgid "Allow IDP-initiated logins" | msgid "Allow IDP-initiated logins" | ||||||
| msgstr "" | 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" | msgid "Allow friends to authenticate via Plex, even if you don't share any servers" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -152,7 +152,7 @@ msgstr "" | |||||||
| msgid "Allow up to N occurrences in the HIBP database." | msgid "Allow up to N occurrences in the HIBP database." | ||||||
| msgstr "" | 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." | msgid "Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Stages." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -164,7 +164,7 @@ msgstr "" | |||||||
| msgid "Allowed count" | msgid "Allowed count" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:155 | #: src/pages/sources/plex/PlexSourceForm.ts:108 | ||||||
| msgid "Allowed servers" | msgid "Allowed servers" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -218,6 +218,18 @@ msgstr "" | |||||||
| msgid "Apps with most usage" | msgid "Apps with most usage" | ||||||
| msgstr "" | 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 | #: src/elements/forms/DeleteForm.ts:69 | ||||||
| msgid "Are you sure you want to delete {0} {objName} ?" | msgid "Are you sure you want to delete {0} {objName} ?" | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -250,7 +262,7 @@ msgstr "" | |||||||
| msgid "Assigned to application" | msgid "Assigned to application" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/policies/PolicyListPage.ts:68 | #: src/pages/policies/PolicyListPage.ts:69 | ||||||
| msgid "Assigned to {0} objects." | msgid "Assigned to {0} objects." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -282,7 +294,7 @@ msgid "Authentication" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:231 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:243 | ||||||
| msgid "Authentication flow" | msgid "Authentication flow" | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -528,6 +540,21 @@ msgstr "" | |||||||
| msgid "Checks the value from the policy request against several rules, mostly used to ensure password strength." | msgid "Checks the value from the policy request against several rules, mostly used to ensure password strength." | ||||||
| msgstr "" | 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 | #: src/elements/forms/HorizontalFormElement.ts:82 | ||||||
| msgid "Click to change value" | msgid "Click to change value" | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -538,7 +565,7 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/pages/providers/oauth2/OAuth2ProviderForm.ts:107 | #: src/pages/providers/oauth2/OAuth2ProviderForm.ts:107 | ||||||
| #: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts:99 | #: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts:99 | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:141 | #: src/pages/sources/plex/PlexSourceForm.ts:176 | ||||||
| msgid "Client ID" | msgid "Client ID" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -724,8 +751,8 @@ msgstr "" | |||||||
| #: src/pages/flows/BoundStagesList.ts:119 | #: src/pages/flows/BoundStagesList.ts:119 | ||||||
| #: src/pages/flows/BoundStagesList.ts:146 | #: src/pages/flows/BoundStagesList.ts:146 | ||||||
| #: src/pages/flows/BoundStagesList.ts:167 | #: src/pages/flows/BoundStagesList.ts:167 | ||||||
| #: src/pages/flows/FlowListPage.ts:109 | #: src/pages/flows/FlowListPage.ts:110 | ||||||
| #: src/pages/flows/FlowListPage.ts:117 | #: src/pages/flows/FlowListPage.ts:118 | ||||||
| #: src/pages/groups/GroupListPage.ts:90 | #: src/pages/groups/GroupListPage.ts:90 | ||||||
| #: src/pages/groups/GroupListPage.ts:98 | #: src/pages/groups/GroupListPage.ts:98 | ||||||
| #: src/pages/outposts/OutpostListPage.ts:101 | #: src/pages/outposts/OutpostListPage.ts:101 | ||||||
| @ -735,8 +762,8 @@ msgstr "" | |||||||
| #: src/pages/policies/BoundPoliciesList.ts:162 | #: src/pages/policies/BoundPoliciesList.ts:162 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:189 | #: src/pages/policies/BoundPoliciesList.ts:189 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:210 | #: src/pages/policies/BoundPoliciesList.ts:210 | ||||||
| #: src/pages/policies/PolicyListPage.ts:124 | #: src/pages/policies/PolicyListPage.ts:125 | ||||||
| #: src/pages/policies/PolicyListPage.ts:133 | #: src/pages/policies/PolicyListPage.ts:134 | ||||||
| #: src/pages/property-mappings/PropertyMappingListPage.ts:113 | #: src/pages/property-mappings/PropertyMappingListPage.ts:113 | ||||||
| #: src/pages/property-mappings/PropertyMappingListPage.ts:122 | #: src/pages/property-mappings/PropertyMappingListPage.ts:122 | ||||||
| #: src/pages/providers/ProviderListPage.ts:108 | #: src/pages/providers/ProviderListPage.ts:108 | ||||||
| @ -776,7 +803,7 @@ msgstr "" | |||||||
| msgid "Create Certificate-Key Pair" | msgid "Create Certificate-Key Pair" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:112 | #: src/pages/flows/FlowListPage.ts:113 | ||||||
| msgid "Create Flow" | msgid "Create Flow" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -838,7 +865,7 @@ msgstr "" | |||||||
| #: src/pages/flows/BoundStagesList.ts:149 | #: src/pages/flows/BoundStagesList.ts:149 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:122 | #: src/pages/outposts/ServiceConnectionListPage.ts:122 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:192 | #: 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/property-mappings/PropertyMappingListPage.ts:125 | ||||||
| #: src/pages/providers/ProviderListPage.ts:120 | #: src/pages/providers/ProviderListPage.ts:120 | ||||||
| #: src/pages/sources/SourcesListPage.ts:126 | #: src/pages/sources/SourcesListPage.ts:126 | ||||||
| @ -890,11 +917,11 @@ msgstr "" | |||||||
| #: src/pages/crypto/CertificateKeyPairListPage.ts:86 | #: src/pages/crypto/CertificateKeyPairListPage.ts:86 | ||||||
| #: src/pages/events/RuleListPage.ts:82 | #: src/pages/events/RuleListPage.ts:82 | ||||||
| #: src/pages/events/TransportListPage.ts:86 | #: 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/groups/GroupListPage.ts:81 | ||||||
| #: src/pages/outposts/OutpostListPage.ts:87 | #: src/pages/outposts/OutpostListPage.ts:87 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:101 | #: 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/property-mappings/PropertyMappingListPage.ts:104 | ||||||
| #: src/pages/providers/ProviderListPage.ts:99 | #: src/pages/providers/ProviderListPage.ts:99 | ||||||
| #: src/pages/sources/SourcesListPage.ts:95 | #: src/pages/sources/SourcesListPage.ts:95 | ||||||
| @ -963,7 +990,7 @@ msgid "Designates whether this user should be treated as active. Unselect this i | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowForm.ts:119 | #: src/pages/flows/FlowForm.ts:119 | ||||||
| #: src/pages/flows/FlowListPage.ts:48 | #: src/pages/flows/FlowListPage.ts:49 | ||||||
| msgid "Designation" | msgid "Designation" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1045,11 +1072,11 @@ msgstr "" | |||||||
| #: src/pages/crypto/CertificateKeyPairListPage.ts:74 | #: src/pages/crypto/CertificateKeyPairListPage.ts:74 | ||||||
| #: src/pages/events/RuleListPage.ts:70 | #: src/pages/events/RuleListPage.ts:70 | ||||||
| #: src/pages/events/TransportListPage.ts:74 | #: 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/groups/GroupListPage.ts:69 | ||||||
| #: src/pages/outposts/OutpostListPage.ts:75 | #: src/pages/outposts/OutpostListPage.ts:75 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:89 | #: 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/property-mappings/PropertyMappingListPage.ts:79 | ||||||
| #: src/pages/providers/ProviderListPage.ts:87 | #: src/pages/providers/ProviderListPage.ts:87 | ||||||
| #: src/pages/providers/ldap/LDAPProviderViewPage.ts:103 | #: src/pages/providers/ldap/LDAPProviderViewPage.ts:103 | ||||||
| @ -1144,7 +1171,7 @@ msgstr "" | |||||||
| #: src/pages/policies/PolicyBindingForm.ts:199 | #: src/pages/policies/PolicyBindingForm.ts:199 | ||||||
| #: src/pages/sources/ldap/LDAPSourceForm.ts:67 | #: src/pages/sources/ldap/LDAPSourceForm.ts:67 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:134 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:67 | ||||||
| msgid "Enabled" | msgid "Enabled" | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -1154,7 +1181,7 @@ msgid "Enrollment" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:252 | #: 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/sources/saml/SAMLSourceForm.ts:264 | ||||||
| #: src/pages/stages/identification/IdentificationStageForm.ts:104 | #: src/pages/stages/identification/IdentificationStageForm.ts:104 | ||||||
| msgid "Enrollment flow" | msgid "Enrollment flow" | ||||||
| @ -1221,12 +1248,12 @@ msgstr "" | |||||||
| msgid "Exception" | msgid "Exception" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:98 | #: src/pages/flows/FlowListPage.ts:99 | ||||||
| #: src/pages/flows/FlowViewPage.ts:83 | #: src/pages/flows/FlowViewPage.ts:75 | ||||||
| msgid "Execute" | msgid "Execute" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowViewPage.ts:69 | #: src/pages/flows/FlowViewPage.ts:61 | ||||||
| msgid "Execute flow" | msgid "Execute flow" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1273,7 +1300,7 @@ msgstr "" | |||||||
| msgid "Explicit Consent" | msgid "Explicit Consent" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:101 | #: src/pages/flows/FlowListPage.ts:102 | ||||||
| msgid "Export" | msgid "Export" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1312,6 +1339,14 @@ msgstr "" | |||||||
| msgid "Failed sources" | msgid "Failed sources" | ||||||
| msgstr "" | 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 | #: src/elements/forms/DeleteForm.ts:46 | ||||||
| msgid "Failed to delete {0}: {1}" | msgid "Failed to delete {0}: {1}" | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -1354,7 +1389,7 @@ msgid "Fields a user can identify themselves with. If no fields are selected, th | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowImportForm.ts:34 | #: src/pages/flows/FlowImportForm.ts:34 | ||||||
| #: src/pages/flows/FlowListPage.ts:79 | #: src/pages/flows/FlowListPage.ts:80 | ||||||
| msgid "Flow" | msgid "Flow" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1363,19 +1398,19 @@ msgid "Flow Overview" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:227 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:218 | ||||||
| msgid "Flow settings" | msgid "Flow settings" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:249 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:261 | ||||||
| msgid "Flow to use when authenticating existing users." | msgid "Flow to use when authenticating existing users." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:270 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:282 | ||||||
| msgid "Flow to use when enrolling new users." | msgid "Flow to use when enrolling new users." | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -1407,12 +1442,12 @@ msgstr "" | |||||||
| #: src/interfaces/AdminInterface.ts:82 | #: src/interfaces/AdminInterface.ts:82 | ||||||
| #: src/interfaces/AdminInterface.ts:84 | #: src/interfaces/AdminInterface.ts:84 | ||||||
| #: src/pages/admin-overview/AdminOverviewPage.ts:61 | #: 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 | #: src/pages/stages/StageListPage.ts:66 | ||||||
| msgid "Flows" | msgid "Flows" | ||||||
| msgstr "" | 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." | msgid "Flows describe a chain of Stages to authenticate, enroll or recover a user. Stages are chosen based on policies applied to them." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1542,7 +1577,7 @@ msgstr "" | |||||||
| #: src/pages/providers/saml/SAMLProviderForm.ts:176 | #: src/pages/providers/saml/SAMLProviderForm.ts:176 | ||||||
| #: src/pages/sources/ldap/LDAPSourceForm.ts:165 | #: src/pages/sources/ldap/LDAPSourceForm.ts:165 | ||||||
| #: src/pages/sources/ldap/LDAPSourceForm.ts:191 | #: 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/authenticator_validate/AuthenticatorValidateStageForm.ts:114 | ||||||
| #: src/pages/stages/identification/IdentificationStageForm.ts:83 | #: src/pages/stages/identification/IdentificationStageForm.ts:83 | ||||||
| #: src/pages/stages/password/PasswordStageForm.ts:84 | #: src/pages/stages/password/PasswordStageForm.ts:84 | ||||||
| @ -1563,7 +1598,7 @@ msgstr "" | |||||||
| msgid "Icon" | msgid "Icon" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:46 | #: src/pages/flows/FlowListPage.ts:47 | ||||||
| #: src/pages/system-tasks/SystemTaskListPage.ts:54 | #: src/pages/system-tasks/SystemTaskListPage.ts:54 | ||||||
| #: src/pages/tokens/TokenListPage.ts:44 | #: src/pages/tokens/TokenListPage.ts:44 | ||||||
| #: src/pages/user-settings/tokens/UserTokenForm.ts:49 | #: src/pages/user-settings/tokens/UserTokenForm.ts:49 | ||||||
| @ -1596,12 +1631,12 @@ msgstr "" | |||||||
| msgid "Impersonate" | msgid "Impersonate" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:122 | #: src/pages/flows/FlowListPage.ts:123 | ||||||
| #: src/pages/flows/FlowListPage.ts:130 | #: src/pages/flows/FlowListPage.ts:131 | ||||||
| msgid "Import" | msgid "Import" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:125 | #: src/pages/flows/FlowListPage.ts:126 | ||||||
| msgid "Import Flow" | msgid "Import Flow" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1712,7 +1747,7 @@ msgstr "" | |||||||
| msgid "Last run" | msgid "Last run" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/outposts/OutpostHealth.ts:54 | #: src/pages/outposts/OutpostHealth.ts:53 | ||||||
| msgid "Last seen: {0}" | msgid "Last seen: {0}" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1738,21 +1773,21 @@ msgid "Library" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:147 | #: 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" | msgid "Link to a user with identical email address. Can have security implications when a source doesn't validate email addresses" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:153 | #: 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." | msgid "Link to a user with identical username address. Can have security implications when a username is used with another source." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:144 | #: 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" | msgid "Link users on unique identifier" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:173 | #: src/pages/sources/plex/PlexSourceForm.ts:96 | ||||||
| msgid "Load servers" | msgid "Load servers" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -1817,8 +1852,8 @@ msgstr "" | |||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:219 | #: src/pages/sources/oauth/OAuthSourceForm.ts:219 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:247 | #: src/pages/sources/oauth/OAuthSourceForm.ts:247 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:268 | #: src/pages/sources/oauth/OAuthSourceForm.ts:268 | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:201 | #: src/pages/sources/plex/PlexSourceForm.ts:206 | ||||||
| #: src/pages/sources/plex/PlexSourceForm.ts:222 | #: src/pages/sources/plex/PlexSourceForm.ts:227 | ||||||
| #: src/pages/sources/saml/SAMLSourceForm.ts:124 | #: src/pages/sources/saml/SAMLSourceForm.ts:124 | ||||||
| #: src/pages/sources/saml/SAMLSourceForm.ts:238 | #: src/pages/sources/saml/SAMLSourceForm.ts:238 | ||||||
| #: src/pages/sources/saml/SAMLSourceForm.ts:259 | #: src/pages/sources/saml/SAMLSourceForm.ts:259 | ||||||
| @ -1957,7 +1992,7 @@ msgstr "" | |||||||
| #: src/pages/events/TransportListPage.ts:46 | #: src/pages/events/TransportListPage.ts:46 | ||||||
| #: src/pages/flows/BoundStagesList.ts:39 | #: src/pages/flows/BoundStagesList.ts:39 | ||||||
| #: src/pages/flows/FlowForm.ts:86 | #: 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/GroupForm.ts:58 | ||||||
| #: src/pages/groups/GroupListPage.ts:45 | #: src/pages/groups/GroupListPage.ts:45 | ||||||
| #: src/pages/groups/MemberSelectModal.ts:45 | #: src/pages/groups/MemberSelectModal.ts:45 | ||||||
| @ -1966,7 +2001,7 @@ msgstr "" | |||||||
| #: src/pages/outposts/ServiceConnectionDockerForm.ts:51 | #: src/pages/outposts/ServiceConnectionDockerForm.ts:51 | ||||||
| #: src/pages/outposts/ServiceConnectionKubernetesForm.ts:52 | #: src/pages/outposts/ServiceConnectionKubernetesForm.ts:52 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:53 | #: 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/dummy/DummyPolicyForm.ts:54 | ||||||
| #: src/pages/policies/event_matcher/EventMatcherPolicyForm.ts:55 | #: src/pages/policies/event_matcher/EventMatcherPolicyForm.ts:55 | ||||||
| #: src/pages/policies/expiry/ExpiryPolicyForm.ts:54 | #: src/pages/policies/expiry/ExpiryPolicyForm.ts:54 | ||||||
| @ -1993,7 +2028,7 @@ msgstr "" | |||||||
| #: src/pages/sources/ldap/LDAPSourceViewPage.ts:64 | #: src/pages/sources/ldap/LDAPSourceViewPage.ts:64 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:108 | #: src/pages/sources/oauth/OAuthSourceForm.ts:108 | ||||||
| #: src/pages/sources/oauth/OAuthSourceViewPage.ts:64 | #: 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/plex/PlexSourceViewPage.ts:63 | ||||||
| #: src/pages/sources/saml/SAMLSourceForm.ts:52 | #: src/pages/sources/saml/SAMLSourceForm.ts:52 | ||||||
| #: src/pages/sources/saml/SAMLSourceViewPage.ts:66 | #: src/pages/sources/saml/SAMLSourceViewPage.ts:66 | ||||||
| @ -2355,15 +2390,15 @@ msgstr "" | |||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts:74 | #: src/interfaces/AdminInterface.ts:74 | ||||||
| #: src/pages/admin-overview/AdminOverviewPage.ts:56 | #: src/pages/admin-overview/AdminOverviewPage.ts:56 | ||||||
| #: src/pages/flows/FlowListPage.ts:50 | #: src/pages/flows/FlowListPage.ts:51 | ||||||
| #: src/pages/policies/PolicyListPage.ts:38 | #: src/pages/policies/PolicyListPage.ts:39 | ||||||
| msgid "Policies" | msgid "Policies" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/policies/PolicyBindingForm.ts:108 | #: src/pages/policies/PolicyBindingForm.ts:108 | ||||||
| #: src/pages/policies/PolicyBindingForm.ts:117 | #: src/pages/policies/PolicyBindingForm.ts:117 | ||||||
| #: src/pages/policies/PolicyBindingForm.ts:148 | #: src/pages/policies/PolicyBindingForm.ts:148 | ||||||
| #: src/pages/policies/PolicyListPage.ts:108 | #: src/pages/policies/PolicyListPage.ts:109 | ||||||
| msgid "Policy" | msgid "Policy" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -2488,7 +2523,7 @@ msgstr "" | |||||||
| #: src/pages/providers/proxy/ProxyProviderForm.ts:123 | #: src/pages/providers/proxy/ProxyProviderForm.ts:123 | ||||||
| #: src/pages/providers/saml/SAMLProviderForm.ts:77 | #: src/pages/providers/saml/SAMLProviderForm.ts:77 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:163 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:74 | ||||||
| msgid "Protocol settings" | msgid "Protocol settings" | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -2619,7 +2654,7 @@ msgid "Regular expressions for which authentication is not required. Each new li | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/applications/ApplicationViewPage.ts:62 | #: src/pages/applications/ApplicationViewPage.ts:62 | ||||||
| #: src/pages/flows/FlowViewPage.ts:64 | #: src/pages/flows/FlowViewPage.ts:56 | ||||||
| msgid "Related" | msgid "Related" | ||||||
| msgstr "" | 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." | msgid "Select which scopes can be used by the client. The client stil has to specify the scope to access the data." | ||||||
| msgstr "" | 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." | msgid "Select which server a user has to be a member of to be allowed to authenticate." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -2936,7 +2971,7 @@ msgstr "" | |||||||
| #: src/pages/flows/FlowForm.ts:99 | #: src/pages/flows/FlowForm.ts:99 | ||||||
| #: src/pages/sources/ldap/LDAPSourceForm.ts:58 | #: src/pages/sources/ldap/LDAPSourceForm.ts:58 | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:114 | #: 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 | #: src/pages/sources/saml/SAMLSourceForm.ts:58 | ||||||
| msgid "Slug" | msgid "Slug" | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -3013,7 +3048,7 @@ msgid "Stage-specific settings" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/interfaces/AdminInterface.ts:87 | #: 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/StageListPage.ts:44 | ||||||
| #: src/pages/stages/prompt/PromptListPage.ts:50 | #: src/pages/stages/prompt/PromptListPage.ts:50 | ||||||
| msgid "Stages" | msgid "Stages" | ||||||
| @ -3077,6 +3112,14 @@ msgstr "" | |||||||
| msgid "Successful" | msgid "Successful" | ||||||
| msgstr "" | 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 | #: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts:63 | ||||||
| msgid "Successfully copied TOTP Config." | msgid "Successfully copied TOTP Config." | ||||||
| msgstr "" | msgstr "" | ||||||
| @ -3401,14 +3444,14 @@ msgid "Template" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/events/TransportListPage.ts:62 | #: src/pages/events/TransportListPage.ts:62 | ||||||
| #: src/pages/policies/PolicyListPage.ts:95 | #: src/pages/policies/PolicyListPage.ts:96 | ||||||
| #: src/pages/policies/PolicyListPage.ts:103 | #: src/pages/policies/PolicyListPage.ts:104 | ||||||
| #: src/pages/property-mappings/PropertyMappingListPage.ts:84 | #: src/pages/property-mappings/PropertyMappingListPage.ts:84 | ||||||
| #: src/pages/property-mappings/PropertyMappingListPage.ts:92 | #: src/pages/property-mappings/PropertyMappingListPage.ts:92 | ||||||
| msgid "Test" | msgid "Test" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/policies/PolicyListPage.ts:98 | #: src/pages/policies/PolicyListPage.ts:99 | ||||||
| msgid "Test Policy" | msgid "Test Policy" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -3425,7 +3468,7 @@ msgid "The URL \"{0}\" was not found." | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/providers/proxy/ProxyProviderForm.ts:131 | #: 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 "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/policies/dummy/DummyPolicyForm.ts:88 | #: src/pages/policies/dummy/DummyPolicyForm.ts:88 | ||||||
| @ -3556,7 +3599,7 @@ msgstr "" | |||||||
| #: src/pages/flows/BoundStagesList.ts:40 | #: src/pages/flows/BoundStagesList.ts:40 | ||||||
| #: src/pages/outposts/OutpostForm.ts:58 | #: src/pages/outposts/OutpostForm.ts:58 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:54 | #: 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/property-mappings/PropertyMappingListPage.ts:55 | ||||||
| #: src/pages/providers/ProviderListPage.ts:55 | #: src/pages/providers/ProviderListPage.ts:55 | ||||||
| #: src/pages/sources/SourcesListPage.ts:53 | #: src/pages/sources/SourcesListPage.ts:53 | ||||||
| @ -3632,7 +3675,7 @@ msgstr "" | |||||||
| #: src/pages/events/TransportListPage.ts:66 | #: src/pages/events/TransportListPage.ts:66 | ||||||
| #: src/pages/flows/BoundStagesList.ts:53 | #: src/pages/flows/BoundStagesList.ts:53 | ||||||
| #: src/pages/flows/BoundStagesList.ts:71 | #: 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/groups/GroupListPage.ts:61 | ||||||
| #: src/pages/outposts/OutpostListPage.ts:67 | #: src/pages/outposts/OutpostListPage.ts:67 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:76 | #: src/pages/outposts/ServiceConnectionListPage.ts:76 | ||||||
| @ -3640,7 +3683,7 @@ msgstr "" | |||||||
| #: src/pages/policies/BoundPoliciesList.ts:88 | #: src/pages/policies/BoundPoliciesList.ts:88 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:103 | #: src/pages/policies/BoundPoliciesList.ts:103 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:129 | #: 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/property-mappings/PropertyMappingListPage.ts:66 | ||||||
| #: src/pages/providers/ProviderListPage.ts:74 | #: src/pages/providers/ProviderListPage.ts:74 | ||||||
| #: src/pages/providers/ldap/LDAPProviderViewPage.ts:93 | #: src/pages/providers/ldap/LDAPProviderViewPage.ts:93 | ||||||
| @ -3678,7 +3721,7 @@ msgstr "" | |||||||
| msgid "Update Certificate-Key Pair" | msgid "Update Certificate-Key Pair" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/flows/FlowListPage.ts:69 | #: src/pages/flows/FlowListPage.ts:70 | ||||||
| msgid "Update Flow" | msgid "Update Flow" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -3756,7 +3799,7 @@ msgstr "" | |||||||
| #: src/pages/flows/BoundStagesList.ts:56 | #: src/pages/flows/BoundStagesList.ts:56 | ||||||
| #: src/pages/outposts/ServiceConnectionListPage.ts:79 | #: src/pages/outposts/ServiceConnectionListPage.ts:79 | ||||||
| #: src/pages/policies/BoundPoliciesList.ts:71 | #: 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/property-mappings/PropertyMappingListPage.ts:69 | ||||||
| #: src/pages/providers/ProviderListPage.ts:77 | #: src/pages/providers/ProviderListPage.ts:77 | ||||||
| #: src/pages/sources/SourcesListPage.ts:73 | #: src/pages/sources/SourcesListPage.ts:73 | ||||||
| @ -3790,12 +3833,12 @@ msgid "Use global settings" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:150 | #: 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." | msgid "Use the user's email address, but deny enrollment when the email address already exists." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:156 | #: 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." | msgid "Use the user's username, but deny enrollment when the username already exists." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -3844,7 +3887,7 @@ msgid "User fields" | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/sources/oauth/OAuthSourceForm.ts:139 | #: 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" | msgid "User matching mode" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -3905,7 +3948,7 @@ msgid "Users added to this group will be superusers." | |||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/providers/ldap/LDAPProviderForm.ts:86 | #: 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 "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/events/EventInfo.ts:108 | #: src/pages/events/EventInfo.ts:108 | ||||||
| @ -3948,7 +3991,7 @@ msgstr "" | |||||||
| msgid "Version" | msgid "Version" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/outposts/OutpostHealth.ts:60 | #: src/pages/outposts/OutpostHealth.ts:59 | ||||||
| msgid "Version: {0}" | msgid "Version: {0}" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -3977,7 +4020,7 @@ msgstr "" | |||||||
| msgid "Warning" | msgid "Warning" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/policies/PolicyListPage.ts:71 | #: src/pages/policies/PolicyListPage.ts:72 | ||||||
| msgid "Warning: Policy is not assigned." | msgid "Warning: Policy is not assigned." | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @ -4112,7 +4155,7 @@ msgstr "" | |||||||
| msgid "{0} unread" | msgid "{0} unread" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| #: src/pages/outposts/OutpostHealth.ts:59 | #: src/pages/outposts/OutpostHealth.ts:58 | ||||||
| msgid "{0}, should be {1}" | msgid "{0}, should be {1}" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import { TablePage } from "../../elements/table/TablePage"; | |||||||
| import "../../elements/buttons/SpinnerButton"; | import "../../elements/buttons/SpinnerButton"; | ||||||
| import "../../elements/forms/DeleteForm"; | import "../../elements/forms/DeleteForm"; | ||||||
| import "../../elements/forms/ModalForm"; | import "../../elements/forms/ModalForm"; | ||||||
|  | import "../../elements/forms/ConfirmationForm"; | ||||||
| import "./FlowForm"; | import "./FlowForm"; | ||||||
| import "./FlowImportForm"; | import "./FlowImportForm"; | ||||||
| import { TableColumn } from "../../elements/table/Table"; | import { TableColumn } from "../../elements/table/Table"; | ||||||
| @ -68,7 +69,7 @@ export class FlowListPage extends TablePage<Flow> { | |||||||
|                 <span slot="header"> |                 <span slot="header"> | ||||||
|                     ${t`Update Flow`} |                     ${t`Update Flow`} | ||||||
|                 </span> |                 </span> | ||||||
|                 <ak-flow-form slot="form" .instancePk=${item.pk}> |                 <ak-flow-form slot="form" .instancePk=${item.slug}> | ||||||
|                 </ak-flow-form> |                 </ak-flow-form> | ||||||
|                 <button slot="trigger" class="pf-c-button pf-m-secondary"> |                 <button slot="trigger" class="pf-c-button pf-m-secondary"> | ||||||
|                     ${t`Edit`} |                     ${t`Edit`} | ||||||
| @ -132,6 +133,24 @@ export class FlowListPage extends TablePage<Flow> { | |||||||
|             </button> |             </button> | ||||||
|         </ak-forms-modal> |         </ak-forms-modal> | ||||||
|         ${super.renderToolbar()} |         ${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/DeleteForm"; | ||||||
| import "../../elements/forms/ModalForm"; | import "../../elements/forms/ModalForm"; | ||||||
| import "../../elements/forms/ProxyForm"; | import "../../elements/forms/ProxyForm"; | ||||||
|  | import "../../elements/forms/ConfirmationForm"; | ||||||
| import "./PolicyTestForm"; | import "./PolicyTestForm"; | ||||||
| import { TableColumn } from "../../elements/table/Table"; | import { TableColumn } from "../../elements/table/Table"; | ||||||
| import { until } from "lit-html/directives/until"; | import { until } from "lit-html/directives/until"; | ||||||
| @ -150,7 +151,26 @@ export class PolicyListPage extends TablePage<Policy> { | |||||||
|                     }), html`<ak-spinner></ak-spinner>`)} |                     }), html`<ak-spinner></ak-spinner>`)} | ||||||
|             </ul> |             </ul> | ||||||
|         </ak-dropdown> |         </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 |                 <ak-proxy-form | ||||||
|                     slot="form" |                     slot="form" | ||||||
|                     .args=${{ |                     .args=${{ | ||||||
|                         "mappingUUID": item.pk |                         "instancePk": item.pk | ||||||
|                     }} |                     }} | ||||||
|                     type=${ifDefined(item.component)}> |                     type=${ifDefined(item.component)}> | ||||||
|                 </ak-proxy-form> |                 </ak-proxy-form> | ||||||
|  | |||||||
| @ -75,7 +75,7 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> { | |||||||
|                         }); |                         }); | ||||||
|                     }), html`<option>${t`Loading...`}</option>`)} |                     }), html`<option>${t`Loading...`}</option>`)} | ||||||
|                 </select> |                 </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-element-horizontal> | ||||||
|  |  | ||||||
|             <ak-form-group .expanded=${true}> |             <ak-form-group .expanded=${true}> | ||||||
|  | |||||||
| @ -125,7 +125,7 @@ export class ProxyProviderFormPage extends ModelForm<ProxyProvider, number> { | |||||||
|                         ?required=${true} |                         ?required=${true} | ||||||
|                         name="externalHost"> |                         name="externalHost"> | ||||||
|                         <input type="text" value="${ifDefined(this.instance?.externalHost)}" class="pf-c-form-control" required> |                         <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> | ||||||
|                     <ak-form-element-horizontal name="forwardAuthMode"> |                     <ak-form-element-horizontal name="forwardAuthMode"> | ||||||
|                         <div class="pf-c-check"> |                         <div class="pf-c-check"> | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ export class PlexSourceForm extends ModelForm<PlexSource, string> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     send = (data: PlexSource): Promise<PlexSource> => { |     send = (data: PlexSource): Promise<PlexSource> => { | ||||||
|         data.plexToken = this.plexToken; |         data.plexToken = this.plexToken || ""; | ||||||
|         if (this.instance?.slug) { |         if (this.instance?.slug) { | ||||||
|             return new SourcesApi(DEFAULT_CONFIG).sourcesPlexUpdate({ |             return new SourcesApi(DEFAULT_CONFIG).sourcesPlexUpdate({ | ||||||
|                 slug: this.instance.slug, |                 slug: this.instance.slug, | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ postgresql: | |||||||
|   user: postgres |   user: postgres | ||||||
|  |  | ||||||
| log_level: debug | 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. | 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 | ## 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 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: | 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>`. | 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: | The following fields are currently sent for users: | ||||||
|  |  | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ version: "3.5" | |||||||
|  |  | ||||||
| services: | services: | ||||||
|   authentik_proxy: |   authentik_proxy: | ||||||
|     image: beryju/authentik-proxy:2021.5.1 |     image: ghcr.io/goauthentik/proxy:2021.5.4 | ||||||
|     ports: |     ports: | ||||||
|       - 4180:4180 |       - 4180:4180 | ||||||
|       - 4443:4443 |       - 4443:4443 | ||||||
| @ -19,4 +19,13 @@ services: | |||||||
|       AUTHENTIK_HOST: https://your-authentik.tld |       AUTHENTIK_HOST: https://your-authentik.tld | ||||||
|       AUTHENTIK_INSECURE: "false" |       AUTHENTIK_INSECURE: "false" | ||||||
|       AUTHENTIK_TOKEN: token-generated-by-authentik |       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/instance: __OUTPOST_NAME__ | ||||||
|     app.kubernetes.io/managed-by: goauthentik.io |     app.kubernetes.io/managed-by: goauthentik.io | ||||||
|     app.kubernetes.io/name: authentik-proxy |     app.kubernetes.io/name: authentik-proxy | ||||||
|     app.kubernetes.io/version: 2021.5.1 |     app.kubernetes.io/version: 2021.5.4 | ||||||
|   name: authentik-outpost-api |   name: authentik-outpost-api | ||||||
| stringData: | stringData: | ||||||
|   authentik_host: "__AUTHENTIK_URL__" |   authentik_host: "__AUTHENTIK_URL__" | ||||||
| @ -29,7 +29,7 @@ metadata: | |||||||
|     app.kubernetes.io/instance: __OUTPOST_NAME__ |     app.kubernetes.io/instance: __OUTPOST_NAME__ | ||||||
|     app.kubernetes.io/managed-by: goauthentik.io |     app.kubernetes.io/managed-by: goauthentik.io | ||||||
|     app.kubernetes.io/name: authentik-proxy |     app.kubernetes.io/name: authentik-proxy | ||||||
|     app.kubernetes.io/version: 2021.5.1 |     app.kubernetes.io/version: 2021.5.4 | ||||||
|   name: authentik-outpost |   name: authentik-outpost | ||||||
| spec: | spec: | ||||||
|   ports: |   ports: | ||||||
| @ -54,7 +54,7 @@ metadata: | |||||||
|     app.kubernetes.io/instance: __OUTPOST_NAME__ |     app.kubernetes.io/instance: __OUTPOST_NAME__ | ||||||
|     app.kubernetes.io/managed-by: goauthentik.io |     app.kubernetes.io/managed-by: goauthentik.io | ||||||
|     app.kubernetes.io/name: authentik-proxy |     app.kubernetes.io/name: authentik-proxy | ||||||
|     app.kubernetes.io/version: 2021.5.1 |     app.kubernetes.io/version: 2021.5.4 | ||||||
|   name: authentik-outpost |   name: authentik-outpost | ||||||
| spec: | spec: | ||||||
|   selector: |   selector: | ||||||
| @ -62,14 +62,14 @@ spec: | |||||||
|       app.kubernetes.io/instance: __OUTPOST_NAME__ |       app.kubernetes.io/instance: __OUTPOST_NAME__ | ||||||
|       app.kubernetes.io/managed-by: goauthentik.io |       app.kubernetes.io/managed-by: goauthentik.io | ||||||
|       app.kubernetes.io/name: authentik-proxy |       app.kubernetes.io/name: authentik-proxy | ||||||
|       app.kubernetes.io/version: 2021.5.1 |       app.kubernetes.io/version: 2021.5.4 | ||||||
|   template: |   template: | ||||||
|     metadata: |     metadata: | ||||||
|       labels: |       labels: | ||||||
|         app.kubernetes.io/instance: __OUTPOST_NAME__ |         app.kubernetes.io/instance: __OUTPOST_NAME__ | ||||||
|         app.kubernetes.io/managed-by: goauthentik.io |         app.kubernetes.io/managed-by: goauthentik.io | ||||||
|         app.kubernetes.io/name: authentik-proxy |         app.kubernetes.io/name: authentik-proxy | ||||||
|         app.kubernetes.io/version: 2021.5.1 |         app.kubernetes.io/version: 2021.5.4 | ||||||
|     spec: |     spec: | ||||||
|       containers: |       containers: | ||||||
|         - env: |         - env: | ||||||
| @ -88,7 +88,7 @@ spec: | |||||||
|               secretKeyRef: |               secretKeyRef: | ||||||
|                 key: authentik_host_insecure |                 key: authentik_host_insecure | ||||||
|                 name: authentik-outpost-api |                 name: authentik-outpost-api | ||||||
|         image: beryju/authentik-proxy:2021.5.1 |         image: ghcr.io/goauthentik/proxy:2021.5.4 | ||||||
|         name: proxy |         name: proxy | ||||||
|         ports: |         ports: | ||||||
|           - containerPort: 4180 |           - containerPort: 4180 | ||||||
| @ -110,7 +110,7 @@ metadata: | |||||||
|     app.kubernetes.io/instance: __OUTPOST_NAME__ |     app.kubernetes.io/instance: __OUTPOST_NAME__ | ||||||
|     app.kubernetes.io/managed-by: goauthentik.io |     app.kubernetes.io/managed-by: goauthentik.io | ||||||
|     app.kubernetes.io/name: authentik-proxy |     app.kubernetes.io/name: authentik-proxy | ||||||
|     app.kubernetes.io/version: 2021.5.1 |     app.kubernetes.io/version: 2021.5.4 | ||||||
|   name: authentik-outpost |   name: authentik-outpost | ||||||
| spec: | spec: | ||||||
|   rules: |   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. | 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 | # 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. | 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 { |     location /akprox { | ||||||
|         proxy_pass http://*ip of your outpost*:4180; |         proxy_pass http://*ip of your outpost*:4180; | ||||||
|         proxy_set_header X-Forwarded-Host $http_host; |  | ||||||
|         error_page 401 = @akprox_signin; |         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 { |     location @akprox_signin { | ||||||
| @ -157,7 +167,7 @@ services: | |||||||
|       - '--entrypoints.https.address=:443' |       - '--entrypoints.https.address=:443' | ||||||
|  |  | ||||||
|   authentik_proxy: |   authentik_proxy: | ||||||
|     image: beryju/authentik-proxy:2021.4.4 |     image: ghcr.io/goauthentik/proxy:2021.5.1 | ||||||
|     ports: |     ports: | ||||||
|       - 4180:4180 |       - 4180:4180 | ||||||
|       - 4443:4443 |       - 4443:4443 | ||||||
|  | |||||||
| @ -51,7 +51,7 @@ This release does not introduce any new requirements. | |||||||
|  |  | ||||||
| ### docker-compose | ### 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 | ### Kubernetes | ||||||
|  |  | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ This release does not introduce any new requirements. | |||||||
|  |  | ||||||
| ### docker-compose | ### 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 | ### Kubernetes | ||||||
|  |  | ||||||
|  | |||||||
| @ -124,7 +124,7 @@ The integrations affected are: | |||||||
|  |  | ||||||
| ### docker-compose | ### 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 | ### Kubernetes | ||||||
|  |  | ||||||
|  | |||||||
| @ -87,7 +87,7 @@ This release does not introduce any new requirements. | |||||||
|  |  | ||||||
| ### docker-compose | ### 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 | ### Kubernetes | ||||||
|  |  | ||||||
|  | |||||||
| @ -133,7 +133,7 @@ This release does not introduce any new requirements. | |||||||
|  |  | ||||||
| ### docker-compose | ### 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 | ### 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 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 | - 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. | - Add single-use flag for invitations to delete token after use. | ||||||
| - Fix sidebar not collapsible on mobile. | - 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 | ## Upgrading | ||||||
|  |  | ||||||
| This release does not introduce any new requirements. | This release does not introduce any new requirements. | ||||||
|  |  | ||||||
| ### docker-compose | ### 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 | :::warning | ||||||
| The public port of the compose stack has been changed from 443 to 9000 and 9443 to prevent port contention. | 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
	