Merge branch 'master' into inbuilt-proxy
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> # Conflicts: # internal/constants/constants.go # outpost/pkg/version.go
This commit is contained in:
commit
3dc9e247d5
|
@ -1,5 +1,5 @@
|
|||
[bumpversion]
|
||||
current_version = 2021.6.2
|
||||
current_version = 2021.6.3
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*)
|
||||
|
@ -21,6 +21,8 @@ values =
|
|||
|
||||
[bumpversion:file:docker-compose.yml]
|
||||
|
||||
[bumpversion:file:schema.yml]
|
||||
|
||||
[bumpversion:file:.github/workflows/release.yml]
|
||||
|
||||
[bumpversion:file:authentik/__init__.py]
|
||||
|
|
23
.github/workflows/release.yml
vendored
23
.github/workflows/release.yml
vendored
|
@ -33,14 +33,14 @@ jobs:
|
|||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik:2021.6.2,
|
||||
beryju/authentik:2021.6.3,
|
||||
beryju/authentik:latest,
|
||||
ghcr.io/goauthentik/server:2021.6.2,
|
||||
ghcr.io/goauthentik/server:2021.6.3,
|
||||
ghcr.io/goauthentik/server:latest
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
- name: Building Docker Image (stable)
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.2', 'rc') }}
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.3', 'rc') }}
|
||||
run: |
|
||||
docker pull beryju/authentik:latest
|
||||
docker tag beryju/authentik:latest beryju/authentik:stable
|
||||
|
@ -75,14 +75,14 @@ jobs:
|
|||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-proxy:2021.6.2,
|
||||
beryju/authentik-proxy:2021.6.3,
|
||||
beryju/authentik-proxy:latest,
|
||||
ghcr.io/goauthentik/proxy:2021.6.2,
|
||||
ghcr.io/goauthentik/proxy:2021.6.3,
|
||||
ghcr.io/goauthentik/proxy:latest
|
||||
file: proxy.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: Building Docker Image (stable)
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.2', 'rc') }}
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.3', 'rc') }}
|
||||
run: |
|
||||
docker pull beryju/authentik-proxy:latest
|
||||
docker tag beryju/authentik-proxy:latest beryju/authentik-proxy:stable
|
||||
|
@ -117,14 +117,14 @@ jobs:
|
|||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-ldap:2021.6.2,
|
||||
beryju/authentik-ldap:2021.6.3,
|
||||
beryju/authentik-ldap:latest,
|
||||
ghcr.io/goauthentik/ldap:2021.6.2,
|
||||
ghcr.io/goauthentik/ldap:2021.6.3,
|
||||
ghcr.io/goauthentik/ldap:latest
|
||||
file: ldap.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: Building Docker Image (stable)
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.2', 'rc') }}
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.6.3', 'rc') }}
|
||||
run: |
|
||||
docker pull beryju/authentik-ldap:latest
|
||||
docker tag beryju/authentik-ldap:latest beryju/authentik-ldap:stable
|
||||
|
@ -157,7 +157,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v2.1.5
|
||||
uses: actions/setup-node@v2.2.0
|
||||
with:
|
||||
node-version: 12.x
|
||||
- name: Build web api client and web ui
|
||||
|
@ -176,6 +176,7 @@ jobs:
|
|||
SENTRY_PROJECT: authentik
|
||||
SENTRY_URL: https://sentry.beryju.org
|
||||
with:
|
||||
version: authentik@2021.6.2
|
||||
version: authentik@2021.6.3
|
||||
environment: beryjuorg-prod
|
||||
sourcemaps: './web/dist'
|
||||
finalize: false
|
||||
|
|
128
Pipfile.lock
generated
128
Pipfile.lock
generated
|
@ -76,11 +76,11 @@
|
|||
},
|
||||
"asgiref": {
|
||||
"hashes": [
|
||||
"sha256:05914d0fa65a21711e732adc6572edad6c8da5f1435c3f0c060689ced5e85195",
|
||||
"sha256:d36fa91dd90e3aa3c81a6bd426ccc8fb20bd3d22b0cf14a12800289e9c3e2563"
|
||||
"sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9",
|
||||
"sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.4.0"
|
||||
"version": "==3.4.1"
|
||||
},
|
||||
"async-timeout": {
|
||||
"hashes": [
|
||||
|
@ -122,19 +122,19 @@
|
|||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:6300e9ee9a404038113250bd218e2c4827f5e676efb14e77de2ad2dcb67679bc",
|
||||
"sha256:be4714f0475c1f5183eea09ddbf568ced6fa41b0fc9976f2698b8442e1b17303"
|
||||
"sha256:055f9dc07f95f202a4dc25196a3a9f1e2f137171ee364cf980e4673de75fb529",
|
||||
"sha256:bc9b278e362ec9b531511a498262297f074c4f5ca9560455919a0af1a4698615"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.17.102"
|
||||
"version": "==1.17.104"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:2f57f7ceed1598d96cc497aeb45317db5d3b21a5aafea4732d0e561d0fc2a8fa",
|
||||
"sha256:bdf08a4f7f01ead00d386848f089c08270499711447569c18d0db60023619c06"
|
||||
"sha256:23aa3238c004319f78423eb8cbba2813b62ee64d0e3bab04e0a00e067f99542a",
|
||||
"sha256:95ab472c8254b8d2cfa6d719b433e511fbcf80895b4cd18e4219c1efa0b78270"
|
||||
],
|
||||
"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.102"
|
||||
"version": "==1.20.104"
|
||||
},
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
|
@ -242,11 +242,11 @@
|
|||
},
|
||||
"channels-redis": {
|
||||
"hashes": [
|
||||
"sha256:18d63f6462a58011740dc8eeb57ea4b31ec220eb551cb71b27de9c6779a549de",
|
||||
"sha256:2fb31a63b05373f6402da2e6a91a22b9e66eb8b56626c6bfc93e156c734c5ae6"
|
||||
"sha256:0a18ce279c15ba79b7985bb12b2d6dd0ac8a14e4ad6952681f4422a4cc4a5ea9",
|
||||
"sha256:1abd5820ff1ed4ac627f8a219ad389e4c87e52e47a230929a7a474e95dd2c6c2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.2.0"
|
||||
"version": "==3.3.0"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
|
@ -342,11 +342,11 @@
|
|||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:66c9d8db8cc6fe938a28b7887c1596e42d522e27618562517cc8929eb7e7f296",
|
||||
"sha256:ea735cbbbb3b2fba6d4da4784a0043d84c67c92f1fdf15ad6db69900e792c10f"
|
||||
"sha256:3da05fea54fdec2315b54a563d5b59f3b4e2b1e69c3a5841dda35019c01855cd",
|
||||
"sha256:c58b5f19c5ae0afe6d75cbdd7df561e6eb929339985dbbda2565e1cabb19a62e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.2.4"
|
||||
"version": "==3.2.5"
|
||||
},
|
||||
"django-dbbackup": {
|
||||
"git": "https://github.com/django-dbbackup/django-dbbackup.git",
|
||||
|
@ -473,11 +473,11 @@
|
|||
},
|
||||
"google-auth": {
|
||||
"hashes": [
|
||||
"sha256:b3a67fa9ba5b768861dacf374c2135eb09fa14a0e40c851c3b8ea7abe6fc8fef",
|
||||
"sha256:e34e5f5de5610b202f9b40ebd9f8b27571d5c5537db9afed3a72b2db5a345039"
|
||||
"sha256:9266252e11393943410354cf14a77bcca24dd2ccd9c4e1aef23034fe0fbae630",
|
||||
"sha256:c7c215c74348ef24faef2f7b62f6d8e6b38824fe08b1e7b7b09a02d397eda7b3"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.32.0"
|
||||
"version": "==1.32.1"
|
||||
},
|
||||
"gunicorn": {
|
||||
"hashes": [
|
||||
|
@ -1423,11 +1423,11 @@
|
|||
},
|
||||
"astroid": {
|
||||
"hashes": [
|
||||
"sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e",
|
||||
"sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"
|
||||
"sha256:38b95085e9d92e2ca06cf8b35c12a74fa81da395a6f9e65803742e6509c05892",
|
||||
"sha256:606b2911d10c3dcf35e58d2ee5c97360e8477d7b9f3efc3f24811c93e6fc2cd9"
|
||||
],
|
||||
"markers": "python_version ~= '3.6'",
|
||||
"version": "==2.5.6"
|
||||
"version": "==2.6.2"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
|
@ -1671,11 +1671,11 @@
|
|||
},
|
||||
"pylint": {
|
||||
"hashes": [
|
||||
"sha256:0a049c5d47b629d9070c3932d13bff482b12119b6a241a93bc460b0be16953c8",
|
||||
"sha256:792b38ff30903884e4a9eab814ee3523731abd3c463f3ba48d7b627e87013484"
|
||||
"sha256:23a1dc8b30459d78e9ff25942c61bb936108ccbe29dd9e71c01dc8274961709a",
|
||||
"sha256:5d46330e6b8886c31b5e3aba5ff48c10f4aa5e76cbf9002c6544306221e63fbc"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.8.3"
|
||||
"version": "==2.9.3"
|
||||
},
|
||||
"pylint-django": {
|
||||
"hashes": [
|
||||
|
@ -1753,49 +1753,45 @@
|
|||
},
|
||||
"regex": {
|
||||
"hashes": [
|
||||
"sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5",
|
||||
"sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79",
|
||||
"sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31",
|
||||
"sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500",
|
||||
"sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11",
|
||||
"sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14",
|
||||
"sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3",
|
||||
"sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439",
|
||||
"sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c",
|
||||
"sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82",
|
||||
"sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711",
|
||||
"sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093",
|
||||
"sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a",
|
||||
"sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb",
|
||||
"sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8",
|
||||
"sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17",
|
||||
"sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000",
|
||||
"sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d",
|
||||
"sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480",
|
||||
"sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc",
|
||||
"sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0",
|
||||
"sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9",
|
||||
"sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765",
|
||||
"sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e",
|
||||
"sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a",
|
||||
"sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07",
|
||||
"sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f",
|
||||
"sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac",
|
||||
"sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7",
|
||||
"sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed",
|
||||
"sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968",
|
||||
"sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7",
|
||||
"sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2",
|
||||
"sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4",
|
||||
"sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87",
|
||||
"sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8",
|
||||
"sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10",
|
||||
"sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29",
|
||||
"sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605",
|
||||
"sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6",
|
||||
"sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"
|
||||
"sha256:0e46c1191b2eb293a6912269ed08b4512e7e241bbf591f97e527492e04c77e93",
|
||||
"sha256:18040755606b0c21281493ec309214bd61e41a170509e5014f41d6a5a586e161",
|
||||
"sha256:1806370b2bef4d4193eebe8ee59a9fd7547836a34917b7badbe6561a8594d9cb",
|
||||
"sha256:1ccbd41dbee3a31e18938096510b7d4ee53aa9fce2ee3dcc8ec82ae264f6acfd",
|
||||
"sha256:1d386402ae7f3c9b107ae5863f7ecccb0167762c82a687ae6526b040feaa5ac6",
|
||||
"sha256:210c359e6ee5b83f7d8c529ba3c75ba405481d50f35a420609b0db827e2e3bb5",
|
||||
"sha256:268fe9dd1deb4a30c8593cabd63f7a241dfdc5bd9dd0233906c718db22cdd49a",
|
||||
"sha256:361be4d311ac995a8c7ad577025a3ae3a538531b1f2cf32efd8b7e5d33a13e5a",
|
||||
"sha256:3f7a92e60930f8fca2623d9e326c173b7cf2c8b7e4fdcf984b75a1d2fb08114d",
|
||||
"sha256:444723ebaeb7fa8125f29c01a31101a3854ac3de293e317944022ae5effa53a4",
|
||||
"sha256:494d0172774dc0beeea984b94c95389143db029575f7ca908edd74469321ea99",
|
||||
"sha256:4b1999ef60c45357598935c12508abf56edbbb9c380df6f336de38a6c3a294ae",
|
||||
"sha256:4fc86b729ab88fe8ac3ec92287df253c64aa71560d76da5acd8a2e245839c629",
|
||||
"sha256:5049d00dbb78f9d166d1c704e93934d42cce0570842bb1a61695123d6b01de09",
|
||||
"sha256:56bef6b414949e2c9acf96cb5d78de8b529c7b99752619494e78dc76f99fd005",
|
||||
"sha256:59845101de68fd5d3a1145df9ea022e85ecd1b49300ea68307ad4302320f6f61",
|
||||
"sha256:6b8b629f93246e507287ee07e26744beaffb4c56ed520576deac8b615bd76012",
|
||||
"sha256:6c72ebb72e64e9bd195cb35a9b9bbfb955fd953b295255b8ae3e4ad4a146b615",
|
||||
"sha256:7743798dfb573d006f1143d745bf17efad39775a5190b347da5d83079646be56",
|
||||
"sha256:78a2a885345a2d60b5e68099e877757d5ed12e46ba1e87507175f14f80892af3",
|
||||
"sha256:849802379a660206277675aa5a5c327f5c910c690649535863ddf329b0ba8c87",
|
||||
"sha256:8cf6728f89b071bd3ab37cb8a0e306f4de897553a0ed07442015ee65fbf53d62",
|
||||
"sha256:a1b6a3f600d6aff97e3f28c34192c9ed93fee293bd96ef327b64adb51a74b2f6",
|
||||
"sha256:a548bb51c4476332ce4139df8e637386730f79a92652a907d12c696b6252b64d",
|
||||
"sha256:a8a5826d8a1b64e2ff9af488cc179e1a4d0f144d11ce486a9f34ea38ccedf4ef",
|
||||
"sha256:b024ee43ee6b310fad5acaee23e6485b21468718cb792a9d1693eecacc3f0b7e",
|
||||
"sha256:b092754c06852e8a8b022004aff56c24b06310189186805800d09313c37ce1f8",
|
||||
"sha256:b1dbeef938281f240347d50f28ae53c4b046a23389cd1fc4acec5ea0eae646a1",
|
||||
"sha256:bf819c5b77ff44accc9a24e31f1f7ceaaf6c960816913ed3ef8443b9d20d81b6",
|
||||
"sha256:c11f2fca544b5e30a0e813023196a63b1cb9869106ef9a26e9dae28bce3e4e26",
|
||||
"sha256:ce269e903b00d1ab4746793e9c50a57eec5d5388681abef074d7b9a65748fca5",
|
||||
"sha256:d0cf2651a8804f6325747c7e55e3be0f90ee2848e25d6b817aa2728d263f9abb",
|
||||
"sha256:e07e92935040c67f49571779d115ecb3e727016d42fb36ee0d8757db4ca12ee0",
|
||||
"sha256:e80d2851109e56420b71f9702ad1646e2f0364528adbf6af85527bc61e49f394",
|
||||
"sha256:ed77b97896312bc2deafe137ca2626e8b63808f5bedb944f73665c68093688a7",
|
||||
"sha256:f32f47fb22c988c0b35756024b61d156e5c4011cb8004aa53d93b03323c45657",
|
||||
"sha256:fdad3122b69cdabdb3da4c2a4107875913ac78dab0117fc73f988ad589c66b66"
|
||||
],
|
||||
"version": "==2021.4.4"
|
||||
"version": "==2021.7.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
"""authentik"""
|
||||
__version__ = "2021.6.2"
|
||||
__version__ = "2021.6.3"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
|
|
@ -5,14 +5,13 @@ from typing import Any, Optional, Type
|
|||
from urllib.parse import urlencode
|
||||
from uuid import uuid4
|
||||
|
||||
import django.db.models.options as options
|
||||
from deepmerge import always_merger
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
||||
from django.core import validators
|
||||
from django.db import models
|
||||
from django.db.models import Q, QuerySet
|
||||
from django.db.models import Q, QuerySet, options
|
||||
from django.http import HttpRequest
|
||||
from django.templatetags.static import static
|
||||
from django.utils.functional import cached_property
|
||||
|
|
|
@ -16,11 +16,6 @@ from authentik.crypto.models import CertificateKeyPair
|
|||
class CertificateBuilder:
|
||||
"""Build self-signed certificates"""
|
||||
|
||||
__public_key = None
|
||||
__private_key = None
|
||||
__builder = None
|
||||
__certificate = None
|
||||
|
||||
common_name: str
|
||||
|
||||
def __init__(self):
|
||||
|
|
|
@ -46,7 +46,7 @@ class NotificationTransportTestSerializer(Serializer):
|
|||
|
||||
messages = ListField(child=CharField())
|
||||
|
||||
def create(self, request: Request) -> Response:
|
||||
def create(self, validated_data: Request) -> Response:
|
||||
raise NotImplementedError
|
||||
|
||||
def update(self, request: Request) -> Response:
|
||||
|
|
|
@ -27,10 +27,9 @@ class GeoIPDict(TypedDict):
|
|||
class GeoIPReader:
|
||||
"""Slim wrapper around GeoIP API"""
|
||||
|
||||
__reader: Optional[Reader] = None
|
||||
__last_mtime: float = 0.0
|
||||
|
||||
def __init__(self):
|
||||
self.__reader: Optional[Reader] = None
|
||||
self.__last_mtime: float = 0.0
|
||||
self.__open()
|
||||
|
||||
def __open(self):
|
||||
|
|
|
@ -40,15 +40,11 @@ def transaction_rollback():
|
|||
class FlowImporter:
|
||||
"""Import Flow from json"""
|
||||
|
||||
__import: FlowBundle
|
||||
|
||||
__pk_map: dict[Any, Model]
|
||||
|
||||
logger: BoundLogger
|
||||
|
||||
def __init__(self, json_input: str):
|
||||
self.__pk_map: dict[Any, Model] = {}
|
||||
self.logger = get_logger()
|
||||
self.__pk_map = {}
|
||||
import_dict = loads(json_input)
|
||||
try:
|
||||
self.__import = from_dict(FlowBundle, import_dict)
|
||||
|
|
|
@ -26,10 +26,9 @@ class ConfigLoader:
|
|||
|
||||
loaded_file = []
|
||||
|
||||
__config = {}
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.__config = {}
|
||||
base_dir = os.path.realpath(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
for path in SEARCH_PATHS:
|
||||
# Check if path is relative, and if so join with base_dir
|
||||
|
|
|
@ -69,7 +69,7 @@ class OutpostConsumer(AuthJsonConsumer):
|
|||
self.last_uid = self.channel_name
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def disconnect(self, close_code):
|
||||
def disconnect(self, code):
|
||||
if self.outpost and self.last_uid:
|
||||
state = OutpostState.for_instance_uid(self.outpost, self.last_uid)
|
||||
if self.channel_name in state.channel_ids:
|
||||
|
|
|
@ -82,13 +82,13 @@ class PolicyBindingSerializer(ModelSerializer):
|
|||
"timeout",
|
||||
]
|
||||
|
||||
def validate(self, data: OrderedDict) -> OrderedDict:
|
||||
def validate(self, attrs: OrderedDict) -> OrderedDict:
|
||||
"""Check that either policy, group or user is set."""
|
||||
count = sum(
|
||||
[
|
||||
bool(data.get("policy", None)),
|
||||
bool(data.get("group", None)),
|
||||
bool(data.get("user", None)),
|
||||
bool(attrs.get("policy", None)),
|
||||
bool(attrs.get("group", None)),
|
||||
bool(attrs.get("user", None)),
|
||||
]
|
||||
)
|
||||
invalid = count > 1
|
||||
|
@ -97,7 +97,7 @@ class PolicyBindingSerializer(ModelSerializer):
|
|||
raise ValidationError("Only one of 'policy', 'group' or 'user' can be set.")
|
||||
if empty:
|
||||
raise ValidationError("One of 'policy', 'group' or 'user' must be set.")
|
||||
return data
|
||||
return attrs
|
||||
|
||||
|
||||
class PolicyBindingViewSet(UsedByMixin, ModelViewSet):
|
||||
|
|
|
@ -62,12 +62,6 @@ class PolicyEngine:
|
|||
# Allow objects with no policies attached to pass
|
||||
empty_result: bool
|
||||
|
||||
__pbm: PolicyBindingModel
|
||||
__cached_policies: list[PolicyResult]
|
||||
__processes: list[PolicyProcessInfo]
|
||||
|
||||
__expected_result_count: int
|
||||
|
||||
def __init__(
|
||||
self, pbm: PolicyBindingModel, user: User, request: HttpRequest = None
|
||||
):
|
||||
|
@ -83,8 +77,8 @@ class PolicyEngine:
|
|||
self.request.obj = pbm
|
||||
if request:
|
||||
self.request.set_http_request(request)
|
||||
self.__cached_policies = []
|
||||
self.__processes = []
|
||||
self.__cached_policies: list[PolicyResult] = []
|
||||
self.__processes: list[PolicyProcessInfo] = []
|
||||
self.use_cache = True
|
||||
self.__expected_result_count = 0
|
||||
|
||||
|
|
|
@ -278,7 +278,7 @@ class OAuth2Provider(Provider):
|
|||
"""Guess launch_url based on first redirect_uri"""
|
||||
if self.redirect_uris == "":
|
||||
return None
|
||||
main_url = self.redirect_uris.split("\n")[0]
|
||||
main_url = self.redirect_uris.split("\n", maxsplit=1)[0]
|
||||
launch_url = urlparse(main_url)
|
||||
return main_url.replace(launch_url.path, "")
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""authentik OAuth2 OpenID Userinfo views"""
|
||||
from typing import Any, Optional
|
||||
|
||||
from deepmerge import always_merger
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from django.views import View
|
||||
|
@ -78,7 +79,7 @@ class UserInfoView(View):
|
|||
)
|
||||
continue
|
||||
LOGGER.debug("updated scope", scope=scope)
|
||||
final_claims.update(value)
|
||||
always_merger.merge(final_claims, value)
|
||||
return final_claims
|
||||
|
||||
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
|
||||
|
|
|
@ -15,7 +15,7 @@ class MessageConsumer(JsonWebsocketConsumer):
|
|||
cache.set(f"user_{self.session_key}_messages_{self.channel_name}", True, None)
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def disconnect(self, close_code):
|
||||
def disconnect(self, code):
|
||||
cache.delete(f"user_{self.session_key}_messages_{self.channel_name}")
|
||||
|
||||
def event_update(self, event: dict):
|
||||
|
|
|
@ -36,7 +36,8 @@ class SourceType:
|
|||
class SourceTypeManager:
|
||||
"""Manager to hold all Source types."""
|
||||
|
||||
__sources: list[SourceType] = []
|
||||
def __init__(self) -> None:
|
||||
self.__sources: list[SourceType] = []
|
||||
|
||||
def type(self):
|
||||
"""Class decorator to register classes inline."""
|
||||
|
|
|
@ -74,12 +74,12 @@ class AuthenticatorValidationChallengeResponse(ChallengeResponse):
|
|||
duo, self.stage.request, self.stage.get_pending_user()
|
||||
)
|
||||
|
||||
def validate(self, data: dict):
|
||||
def validate(self, attrs: dict):
|
||||
# Checking if the given data is from a valid device class is done above
|
||||
# Here we only check if the any data was sent at all
|
||||
if "code" not in data and "webauthn" not in data and "duo" not in data:
|
||||
if "code" not in attrs and "webauthn" not in attrs and "duo" not in attrs:
|
||||
raise ValidationError("Empty response")
|
||||
return data
|
||||
return attrs
|
||||
|
||||
|
||||
class AuthenticatorValidateStageView(ChallengeStageView):
|
||||
|
@ -163,7 +163,7 @@ class AuthenticatorValidateStageView(ChallengeStageView):
|
|||
|
||||
# pylint: disable=unused-argument
|
||||
def challenge_valid(
|
||||
self, challenge: AuthenticatorValidationChallengeResponse
|
||||
self, response: AuthenticatorValidationChallengeResponse
|
||||
) -> HttpResponse:
|
||||
# All validation is done by the serializer
|
||||
return self.executor.stage_ok()
|
||||
|
|
|
@ -38,7 +38,7 @@ class EmailChallengeResponse(ChallengeResponse):
|
|||
|
||||
component = CharField(default="ak-stage-email")
|
||||
|
||||
def validate(self, data):
|
||||
def validate(self, attrs):
|
||||
raise ValidationError("")
|
||||
|
||||
|
||||
|
|
|
@ -73,9 +73,9 @@ class IdentificationChallengeResponse(ChallengeResponse):
|
|||
|
||||
pre_user: Optional[User] = None
|
||||
|
||||
def validate(self, data: dict[str, Any]) -> dict[str, Any]:
|
||||
def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Validate that user exists, and optionally their password"""
|
||||
uid_field = data["uid_field"]
|
||||
uid_field = attrs["uid_field"]
|
||||
current_stage: IdentificationStage = self.stage.executor.current_stage
|
||||
|
||||
pre_user = self.stage.get_user(uid_field)
|
||||
|
@ -101,9 +101,9 @@ class IdentificationChallengeResponse(ChallengeResponse):
|
|||
self.pre_user = pre_user
|
||||
if not current_stage.password_stage:
|
||||
# No password stage select, don't validate the password
|
||||
return data
|
||||
return attrs
|
||||
|
||||
password = data["password"]
|
||||
password = attrs["password"]
|
||||
try:
|
||||
user = authenticate(
|
||||
self.stage.request,
|
||||
|
@ -116,7 +116,7 @@ class IdentificationChallengeResponse(ChallengeResponse):
|
|||
self.pre_user = user
|
||||
except PermissionDenied as exc:
|
||||
raise ValidationError(str(exc)) from exc
|
||||
return data
|
||||
return attrs
|
||||
|
||||
|
||||
class IdentificationStageView(ChallengeStageView):
|
||||
|
|
|
@ -146,8 +146,6 @@ def password_single_validator_factory() -> Callable[[PromptChallenge, str], Any]
|
|||
class ListPolicyEngine(PolicyEngine):
|
||||
"""Slightly modified policy engine, which uses a list instead of a PolicyBindingModel"""
|
||||
|
||||
__list: list[Policy]
|
||||
|
||||
def __init__(
|
||||
self, policies: list[Policy], user: User, request: HttpRequest = None
|
||||
) -> None:
|
||||
|
|
|
@ -21,7 +21,7 @@ services:
|
|||
networks:
|
||||
- internal
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.2}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.3}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
|
@ -44,7 +44,7 @@ services:
|
|||
- "0.0.0.0:9000:9000"
|
||||
- "0.0.0.0:9443:9443"
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.2}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.6.3}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
networks:
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
const VERSION = "2021.6.2"
|
||||
|
||||
func BUILD() string {
|
||||
build := os.Getenv("GIT_BUILD_HASH")
|
||||
if build == "" {
|
||||
|
@ -18,3 +16,5 @@ func BUILD() string {
|
|||
func OutpostUserAgent() string {
|
||||
return fmt.Sprintf("authentik-outpost@%s (%s)", VERSION, BUILD())
|
||||
}
|
||||
|
||||
const VERSION = "2021.6.3"
|
||||
|
|
|
@ -98,19 +98,9 @@ func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry {
|
|||
},
|
||||
}
|
||||
|
||||
if *u.IsActive {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"active"}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"inactive"}})
|
||||
}
|
||||
|
||||
if u.IsSuperuser {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "superuser", Values: []string{"active"}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "superuser", Values: []string{"inactive"}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: pi.GroupsForUser(u)})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "goauthentik.io/ldap/active", Values: []string{BoolToString(*u.IsActive)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "goauthentik.io/ldap/superuser", Values: []string{BoolToString(u.IsSuperuser)}})
|
||||
|
||||
attrs = append(attrs, AKAttrsToLDAP(u.Attributes)...)
|
||||
|
||||
|
|
|
@ -7,6 +7,13 @@ import (
|
|||
"goauthentik.io/api"
|
||||
)
|
||||
|
||||
func BoolToString(in bool) string {
|
||||
if in {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
}
|
||||
|
||||
func AKAttrsToLDAP(attrs interface{}) []*ldap.EntryAttribute {
|
||||
attrList := []*ldap.EntryAttribute{}
|
||||
a := attrs.(*map[string]interface{})
|
||||
|
@ -17,6 +24,8 @@ func AKAttrsToLDAP(attrs interface{}) []*ldap.EntryAttribute {
|
|||
entry.Values = t
|
||||
case string:
|
||||
entry.Values = []string{t}
|
||||
case bool:
|
||||
entry.Values = []string{BoolToString(t)}
|
||||
}
|
||||
attrList = append(attrList, entry)
|
||||
}
|
||||
|
|
|
@ -29,9 +29,10 @@ func (s *Server) bundleProviders(providers []api.ProxyOutpostConfig) []*provider
|
|||
log.WithError(err).Warning("Failed to parse URL, skipping provider")
|
||||
}
|
||||
bundles[idx] = &providerBundle{
|
||||
s: s,
|
||||
Host: externalHost.Host,
|
||||
log: log.WithField("logger", "authentik.outpost.proxy-bundle").WithField("provider", provider.Name),
|
||||
s: s,
|
||||
Host: externalHost.Host,
|
||||
log: log.WithField("logger", "authentik.outpost.proxy-bundle").WithField("provider", provider.Name),
|
||||
endSessionUrl: provider.OidcConfiguration.EndSessionEndpoint,
|
||||
}
|
||||
bundles[idx].Build(provider)
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ type providerBundle struct {
|
|||
proxy *OAuthProxy
|
||||
Host string
|
||||
|
||||
endSessionUrl string
|
||||
|
||||
cert *tls.Certificate
|
||||
|
||||
log *log.Entry
|
||||
|
@ -58,6 +60,8 @@ func (pb *providerBundle) prepareOpts(provider api.ProxyOutpostConfig) *options.
|
|||
providerOpts.RedeemURL = provider.OidcConfiguration.TokenEndpoint
|
||||
providerOpts.OIDCJwksURL = provider.OidcConfiguration.JwksUri
|
||||
providerOpts.ProfileURL = provider.OidcConfiguration.UserinfoEndpoint
|
||||
providerOpts.ValidateURL = provider.OidcConfiguration.UserinfoEndpoint
|
||||
providerOpts.AcrValues = "goauthentik.io/providers/oauth2/default"
|
||||
|
||||
if *provider.SkipPathRegex != "" {
|
||||
skipRegexes := strings.Split(*provider.SkipPathRegex, "\n")
|
||||
|
@ -153,6 +157,7 @@ func (pb *providerBundle) Build(provider api.ProxyOutpostConfig) {
|
|||
oauthproxy.BasicAuthPasswordAttribute = *provider.BasicAuthPasswordAttribute
|
||||
}
|
||||
|
||||
oauthproxy.endSessionEndpoint = pb.endSessionUrl
|
||||
oauthproxy.ExternalHost = pb.Host
|
||||
|
||||
pb.proxy = oauthproxy
|
||||
|
|
|
@ -65,31 +65,33 @@ type OAuthProxy struct {
|
|||
AuthOnlyPath string
|
||||
UserInfoPath string
|
||||
|
||||
endSessionEndpoint string
|
||||
mode api.ProxyMode
|
||||
redirectURL *url.URL // the url to receive requests at
|
||||
whitelistDomains []string
|
||||
provider providers.Provider
|
||||
sessionStore sessionsapi.SessionStore
|
||||
ProxyPrefix string
|
||||
serveMux http.Handler
|
||||
SetXAuthRequest bool
|
||||
SetBasicAuth bool
|
||||
PassUserHeaders bool
|
||||
BasicAuthUserAttribute string
|
||||
BasicAuthPasswordAttribute string
|
||||
ExternalHost string
|
||||
PassAccessToken bool
|
||||
SetAuthorization bool
|
||||
PassAuthorization bool
|
||||
PreferEmailToUser bool
|
||||
skipAuthRegex []string
|
||||
skipAuthPreflight bool
|
||||
skipAuthStripHeaders bool
|
||||
mainJwtBearerVerifier *oidc.IDTokenVerifier
|
||||
extraJwtBearerVerifiers []*oidc.IDTokenVerifier
|
||||
compiledRegex []*regexp.Regexp
|
||||
templates *template.Template
|
||||
realClientIPParser ipapi.RealClientIPParser
|
||||
|
||||
redirectURL *url.URL // the url to receive requests at
|
||||
whitelistDomains []string
|
||||
provider providers.Provider
|
||||
sessionStore sessionsapi.SessionStore
|
||||
ProxyPrefix string
|
||||
serveMux http.Handler
|
||||
SetXAuthRequest bool
|
||||
SetBasicAuth bool
|
||||
PassUserHeaders bool
|
||||
PassAccessToken bool
|
||||
SetAuthorization bool
|
||||
PassAuthorization bool
|
||||
PreferEmailToUser bool
|
||||
skipAuthRegex []string
|
||||
skipAuthPreflight bool
|
||||
skipAuthStripHeaders bool
|
||||
mainJwtBearerVerifier *oidc.IDTokenVerifier
|
||||
extraJwtBearerVerifiers []*oidc.IDTokenVerifier
|
||||
compiledRegex []*regexp.Regexp
|
||||
templates *template.Template
|
||||
realClientIPParser ipapi.RealClientIPParser
|
||||
|
||||
sessionChain alice.Chain
|
||||
|
||||
|
@ -285,19 +287,13 @@ func (p *OAuthProxy) UserInfo(rw http.ResponseWriter, req *http.Request) {
|
|||
|
||||
// SignOut sends a response to clear the authentication cookie
|
||||
func (p *OAuthProxy) SignOut(rw http.ResponseWriter, req *http.Request) {
|
||||
redirect, err := p.GetRedirect(req)
|
||||
if err != nil {
|
||||
p.logger.Errorf("Error obtaining redirect: %v", err)
|
||||
p.ErrorPage(rw, http.StatusInternalServerError, "Internal Server Error", err.Error())
|
||||
return
|
||||
}
|
||||
err = p.ClearSessionCookie(rw, req)
|
||||
err := p.ClearSessionCookie(rw, req)
|
||||
if err != nil {
|
||||
p.logger.Errorf("Error clearing session cookie: %v", err)
|
||||
p.ErrorPage(rw, http.StatusInternalServerError, "Internal Server Error", err.Error())
|
||||
return
|
||||
}
|
||||
http.Redirect(rw, req, redirect, http.StatusFound)
|
||||
http.Redirect(rw, req, p.endSessionEndpoint, http.StatusFound)
|
||||
}
|
||||
|
||||
// AuthenticateOnly checks whether the user is currently logged in
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
openapi: 3.0.3
|
||||
info:
|
||||
title: authentik
|
||||
version: 2021.6.2
|
||||
version: 2021.6.3
|
||||
description: Making authentication simple.
|
||||
contact:
|
||||
email: hello@beryju.org
|
||||
|
|
228
tests/e2e/test_provider_ldap.py
Normal file
228
tests/e2e/test_provider_ldap.py
Normal file
|
@ -0,0 +1,228 @@
|
|||
"""LDAP and Outpost e2e tests"""
|
||||
from sys import platform
|
||||
from time import sleep
|
||||
from unittest.case import skipUnless
|
||||
|
||||
from docker.client import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from guardian.shortcuts import get_anonymous_user
|
||||
from ldap3 import (
|
||||
ALL,
|
||||
ALL_ATTRIBUTES,
|
||||
ALL_OPERATIONAL_ATTRIBUTES,
|
||||
SUBTREE,
|
||||
Connection,
|
||||
Server,
|
||||
)
|
||||
from ldap3.core.exceptions import LDAPInsufficientAccessRightsResult
|
||||
|
||||
from authentik.core.models import Application, Group, User
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.outposts.models import Outpost, OutpostType
|
||||
from authentik.providers.ldap.models import LDAPProvider
|
||||
from tests.e2e.utils import (
|
||||
USER,
|
||||
SeleniumTestCase,
|
||||
apply_migration,
|
||||
object_manager,
|
||||
retry,
|
||||
)
|
||||
|
||||
|
||||
@skipUnless(platform.startswith("linux"), "requires local docker")
|
||||
class TestProviderLDAP(SeleniumTestCase):
|
||||
"""LDAP and Outpost e2e tests"""
|
||||
|
||||
ldap_container: Container
|
||||
|
||||
def tearDown(self) -> None:
|
||||
super().tearDown()
|
||||
self.output_container_logs(self.ldap_container)
|
||||
self.ldap_container.kill()
|
||||
|
||||
def start_ldap(self, outpost: Outpost) -> Container:
|
||||
"""Start ldap container based on outpost created"""
|
||||
client: DockerClient = from_env()
|
||||
container = client.containers.run(
|
||||
image="beryju.org/authentik/outpost-ldap:gh-master",
|
||||
detach=True,
|
||||
network_mode="host",
|
||||
auto_remove=True,
|
||||
environment={
|
||||
"AUTHENTIK_HOST": self.live_server_url,
|
||||
"AUTHENTIK_TOKEN": outpost.token.key,
|
||||
},
|
||||
)
|
||||
return container
|
||||
|
||||
def _prepare(self) -> User:
|
||||
"""prepare user, provider, app and container"""
|
||||
# set additionalHeaders to test later
|
||||
user = USER()
|
||||
user.attributes["extraAttribute"] = "bar"
|
||||
user.save()
|
||||
|
||||
ldap: LDAPProvider = LDAPProvider.objects.create(
|
||||
name="ldap_provider",
|
||||
authorization_flow=Flow.objects.get(slug="default-authentication-flow"),
|
||||
search_group=Group.objects.first(),
|
||||
)
|
||||
# we need to create an application to actually access the ldap
|
||||
Application.objects.create(name="ldap", slug="ldap", provider=ldap)
|
||||
outpost: Outpost = Outpost.objects.create(
|
||||
name="ldap_outpost",
|
||||
type=OutpostType.LDAP,
|
||||
)
|
||||
outpost.providers.add(ldap)
|
||||
outpost.save()
|
||||
user = outpost.user
|
||||
|
||||
self.ldap_container = self.start_ldap(outpost)
|
||||
|
||||
# Wait until outpost healthcheck succeeds
|
||||
healthcheck_retries = 0
|
||||
while healthcheck_retries < 50:
|
||||
if len(outpost.state) > 0:
|
||||
state = outpost.state[0]
|
||||
if state.last_seen:
|
||||
break
|
||||
healthcheck_retries += 1
|
||||
sleep(0.5)
|
||||
return user
|
||||
|
||||
@retry()
|
||||
@apply_migration("authentik_core", "0003_default_user")
|
||||
@apply_migration("authentik_flows", "0008_default_flows")
|
||||
@object_manager
|
||||
def test_ldap_bind_success(self):
|
||||
"""Test simple bind"""
|
||||
self._prepare()
|
||||
server = Server("ldap://localhost:3389", get_info=ALL)
|
||||
_connection = Connection(
|
||||
server,
|
||||
raise_exceptions=True,
|
||||
user=f"cn={USER().username},ou=users,DC=ldap,DC=goauthentik,DC=io",
|
||||
password=USER().username,
|
||||
)
|
||||
_connection.bind()
|
||||
self.assertTrue(
|
||||
Event.objects.filter(
|
||||
action=EventAction.LOGIN,
|
||||
user={
|
||||
"pk": USER().pk,
|
||||
"email": USER().email,
|
||||
"username": USER().username,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@retry()
|
||||
@apply_migration("authentik_core", "0003_default_user")
|
||||
@apply_migration("authentik_flows", "0008_default_flows")
|
||||
@object_manager
|
||||
def test_ldap_bind_fail(self):
|
||||
"""Test simple bind (failed)"""
|
||||
self._prepare()
|
||||
server = Server("ldap://localhost:3389", get_info=ALL)
|
||||
_connection = Connection(
|
||||
server,
|
||||
raise_exceptions=True,
|
||||
user=f"cn={USER().username},ou=users,DC=ldap,DC=goauthentik,DC=io",
|
||||
password=USER().username + "fqwerwqer",
|
||||
)
|
||||
with self.assertRaises(LDAPInsufficientAccessRightsResult):
|
||||
_connection.bind()
|
||||
anon = get_anonymous_user()
|
||||
self.assertTrue(
|
||||
Event.objects.filter(
|
||||
action=EventAction.LOGIN_FAILED,
|
||||
user={"pk": anon.pk, "email": anon.email, "username": anon.username},
|
||||
)
|
||||
)
|
||||
|
||||
@retry()
|
||||
@apply_migration("authentik_core", "0003_default_user")
|
||||
@apply_migration("authentik_core", "0009_group_is_superuser")
|
||||
@apply_migration("authentik_flows", "0008_default_flows")
|
||||
@object_manager
|
||||
def test_ldap_bind_search(self):
|
||||
"""Test simple bind + search"""
|
||||
outpost_user = self._prepare()
|
||||
server = Server("ldap://localhost:3389", get_info=ALL)
|
||||
_connection = Connection(
|
||||
server,
|
||||
raise_exceptions=True,
|
||||
user=f"cn={USER().username},ou=users,dc=ldap,dc=goauthentik,dc=io",
|
||||
password=USER().username,
|
||||
)
|
||||
_connection.bind()
|
||||
self.assertTrue(
|
||||
Event.objects.filter(
|
||||
action=EventAction.LOGIN,
|
||||
user={
|
||||
"pk": USER().pk,
|
||||
"email": USER().email,
|
||||
"username": USER().username,
|
||||
},
|
||||
)
|
||||
)
|
||||
_connection.search(
|
||||
"ou=users,dc=ldap,dc=goauthentik,dc=io",
|
||||
"(objectClass=user)",
|
||||
search_scope=SUBTREE,
|
||||
attributes=[ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES],
|
||||
)
|
||||
response = _connection.response
|
||||
# Remove raw_attributes to make checking easier
|
||||
for obj in response:
|
||||
del obj["raw_attributes"]
|
||||
del obj["raw_dn"]
|
||||
self.assertCountEqual(
|
||||
response,
|
||||
[
|
||||
{
|
||||
"dn": f"cn={outpost_user.username},ou=users,dc=ldap,dc=goauthentik,dc=io",
|
||||
"attributes": {
|
||||
"cn": [outpost_user.username],
|
||||
"uid": [outpost_user.uid],
|
||||
"name": [""],
|
||||
"displayName": [""],
|
||||
"mail": [""],
|
||||
"objectClass": [
|
||||
"user",
|
||||
"organizationalPerson",
|
||||
"goauthentik.io/ldap/user",
|
||||
],
|
||||
"memberOf": [],
|
||||
"goauthentik.io/ldap/active": ["true"],
|
||||
"goauthentik.io/ldap/superuser": ["false"],
|
||||
"goauthentik.io/user/override-ips": ["true"],
|
||||
"goauthentik.io/user/service-account": ["true"],
|
||||
},
|
||||
"type": "searchResEntry",
|
||||
},
|
||||
{
|
||||
"dn": f"cn={USER().username},ou=users,dc=ldap,dc=goauthentik,dc=io",
|
||||
"attributes": {
|
||||
"cn": [USER().username],
|
||||
"uid": [USER().uid],
|
||||
"name": [USER().name],
|
||||
"displayName": [USER().name],
|
||||
"mail": [USER().email],
|
||||
"objectClass": [
|
||||
"user",
|
||||
"organizationalPerson",
|
||||
"goauthentik.io/ldap/user",
|
||||
],
|
||||
"memberOf": [
|
||||
"cn=authentik Admins,ou=groups,dc=ldap,dc=goauthentik,dc=io"
|
||||
],
|
||||
"goauthentik.io/ldap/active": ["true"],
|
||||
"goauthentik.io/ldap/superuser": ["true"],
|
||||
"extraAttribute": ["bar"],
|
||||
},
|
||||
"type": "searchResEntry",
|
||||
},
|
||||
],
|
||||
)
|
|
@ -119,6 +119,13 @@ class TestProviderProxy(SeleniumTestCase):
|
|||
self.assertIn("X-Forwarded-Preferred-Username: akadmin", full_body_text)
|
||||
self.assertIn("X-Foo: bar", full_body_text)
|
||||
|
||||
self.driver.get("http://localhost:4180/akprox/sign_out")
|
||||
sleep(2)
|
||||
full_body_text = self.driver.find_element(
|
||||
By.CSS_SELECTOR, ".pf-c-title.pf-m-3xl"
|
||||
).text
|
||||
self.assertIn("You've logged out of proxy.", full_body_text)
|
||||
|
||||
|
||||
@skipUnless(platform.startswith("linux"), "requires local docker")
|
||||
class TestProviderProxyConnect(ChannelsLiveServerTestCase):
|
||||
|
|
|
@ -62,11 +62,14 @@ class OutpostDockerTests(TestCase):
|
|||
)
|
||||
authentication_kp = CertificateKeyPair.objects.create(
|
||||
name="docker-authentication",
|
||||
# pylint: disable=consider-using-with
|
||||
certificate_data=open(f"{self.ssl_folder}/client/cert.pem").read(),
|
||||
# pylint: disable=consider-using-with
|
||||
key_data=open(f"{self.ssl_folder}/client/key.pem").read(),
|
||||
)
|
||||
verification_kp = CertificateKeyPair.objects.create(
|
||||
name="docker-verification",
|
||||
# pylint: disable=consider-using-with
|
||||
certificate_data=open(f"{self.ssl_folder}/client/ca.pem").read(),
|
||||
)
|
||||
self.service_connection = DockerServiceConnection.objects.create(
|
||||
|
|
|
@ -62,11 +62,14 @@ class TestProxyDocker(TestCase):
|
|||
)
|
||||
authentication_kp = CertificateKeyPair.objects.create(
|
||||
name="docker-authentication",
|
||||
# pylint: disable=consider-using-with
|
||||
certificate_data=open(f"{self.ssl_folder}/client/cert.pem").read(),
|
||||
# pylint: disable=consider-using-with
|
||||
key_data=open(f"{self.ssl_folder}/client/key.pem").read(),
|
||||
)
|
||||
verification_kp = CertificateKeyPair.objects.create(
|
||||
name="docker-verification",
|
||||
# pylint: disable=consider-using-with
|
||||
certificate_data=open(f"{self.ssl_folder}/client/ca.pem").read(),
|
||||
)
|
||||
self.service_connection = DockerServiceConnection.objects.create(
|
||||
|
|
28
web/package-lock.json
generated
28
web/package-lock.json
generated
|
@ -48,7 +48,7 @@
|
|||
"lit-html": "^1.4.1",
|
||||
"moment": "^2.29.1",
|
||||
"rapidoc": "^9.0.0",
|
||||
"rollup": "^2.52.3",
|
||||
"rollup": "^2.52.7",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-cssimport": "^1.0.2",
|
||||
|
@ -58,7 +58,7 @@
|
|||
"rollup-plugin-terser": "^7.0.2",
|
||||
"ts-lit-plugin": "^1.2.1",
|
||||
"tslib": "^2.3.0",
|
||||
"typescript": "^4.3.4",
|
||||
"typescript": "^4.3.5",
|
||||
"webcomponent-qr-code": "^1.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
}
|
||||
|
@ -6770,9 +6770,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.52.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.3.tgz",
|
||||
"integrity": "sha512-QF3Sju8Kl2z0osI4unyOLyUudyhOMK6G0AeqJWgfiyigqLAlnNrfBcDWDx+f1cqn+JU2iIYVkDrgQ6/KtwEfrg==",
|
||||
"version": "2.52.7",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.7.tgz",
|
||||
"integrity": "sha512-55cSH4CCU6MaPr9TAOyrIC+7qFCHscL7tkNsm1MBfIJRRqRbCEY0mmeFn4Wg8FKsHtEH8r389Fz38r/o+kgXLg==",
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
|
@ -7604,9 +7604,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz",
|
||||
"integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==",
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
@ -13200,9 +13200,9 @@
|
|||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.52.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.3.tgz",
|
||||
"integrity": "sha512-QF3Sju8Kl2z0osI4unyOLyUudyhOMK6G0AeqJWgfiyigqLAlnNrfBcDWDx+f1cqn+JU2iIYVkDrgQ6/KtwEfrg==",
|
||||
"version": "2.52.7",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.7.tgz",
|
||||
"integrity": "sha512-55cSH4CCU6MaPr9TAOyrIC+7qFCHscL7tkNsm1MBfIJRRqRbCEY0mmeFn4Wg8FKsHtEH8r389Fz38r/o+kgXLg==",
|
||||
"requires": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
|
@ -13896,9 +13896,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz",
|
||||
"integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew=="
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA=="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.13.0",
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
"lit-html": "^1.4.1",
|
||||
"moment": "^2.29.1",
|
||||
"rapidoc": "^9.0.0",
|
||||
"rollup": "^2.52.3",
|
||||
"rollup": "^2.52.7",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-cssimport": "^1.0.2",
|
||||
|
@ -87,7 +87,7 @@
|
|||
"rollup-plugin-terser": "^7.0.2",
|
||||
"ts-lit-plugin": "^1.2.1",
|
||||
"tslib": "^2.3.0",
|
||||
"typescript": "^4.3.4",
|
||||
"typescript": "^4.3.5",
|
||||
"webcomponent-qr-code": "^1.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
|
|||
export const ERROR_CLASS = "pf-m-danger";
|
||||
export const PROGRESS_CLASS = "pf-m-in-progress";
|
||||
export const CURRENT_CLASS = "pf-m-current";
|
||||
export const VERSION = "2021.6.2";
|
||||
export const VERSION = "2021.6.3";
|
||||
export const PAGE_SIZE = 20;
|
||||
export const EVENT_REFRESH = "ak-refresh";
|
||||
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";
|
||||
|
|
|
@ -12,11 +12,11 @@ This installation method is for test-setups and small-scale productive setups.
|
|||
|
||||
## Preparation
|
||||
|
||||
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.6.2/docker-compose.yml). Place it in a directory of your choice.
|
||||
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.6.3/docker-compose.yml). Place it in a directory of your choice.
|
||||
|
||||
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
|
||||
|
||||
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.6.2 >> .env`
|
||||
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.6.3 >> .env`
|
||||
|
||||
If this is a fresh authentik install run the following commands to generate a password:
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ Local backups can be created by running the following command in your authentik
|
|||
|
||||
```
|
||||
docker-compose run --rm worker backup
|
||||
# Or for kubernetes
|
||||
kubectl exec -it authentik-worker-.... -- ./lifecycle/bootstrap.sh backup
|
||||
```
|
||||
|
||||
This will dump the current database into the `./backups` folder. By defaults, the last 10 Backups are kept.
|
||||
|
@ -26,15 +28,19 @@ Run this command in your authentik installation directory
|
|||
|
||||
```
|
||||
docker-compose run --rm worker restore
|
||||
# Or for kubernetes
|
||||
kubectl exec -it authentik-worker-.... -- ./lifecycle/bootstrap.sh restore
|
||||
```
|
||||
|
||||
This will prompt you to restore from your last backup. If you want to restore from a specific file, use the `-i` flag with the filename:
|
||||
|
||||
```
|
||||
docker-compose run --rm worker restore -i default-2020-10-03-115557.psql
|
||||
# Or for kubernetes
|
||||
kubectl exec -it authentik-worker-.... -- ./lifecycle/bootstrap.sh restore -i default-2020-10-03-115557.psql
|
||||
```
|
||||
|
||||
After you've restored the backup, it is recommended to restart all services with `docker-compose restart`.
|
||||
After you've restored the backup, it is recommended to restart all services with `docker-compose restart` or `kubectl restart deployment --all`.
|
||||
|
||||
### S3 Configuration
|
||||
|
||||
|
@ -92,12 +98,15 @@ Simply enable these options in your values.yaml file
|
|||
|
||||
```yaml
|
||||
# Enable Database Backups to S3
|
||||
backup:
|
||||
accessKey: access-key
|
||||
secretKey: secret-key
|
||||
bucket: s3-bucket
|
||||
region: eu-central-1
|
||||
host: s3-host
|
||||
authentik:
|
||||
postgresql:
|
||||
s3_backup:
|
||||
bucket: "authentik-backup"
|
||||
access_key: foo
|
||||
secret_key: bar
|
||||
region: eu-central-1
|
||||
# Optional S3 host
|
||||
# host: "https://backup-s3.beryju.org"
|
||||
```
|
||||
|
||||
Afterwards, run a `helm upgrade` to update the ConfigMap. Backups are done automatically as above, at 00:00 every day.
|
||||
|
|
|
@ -40,9 +40,9 @@ The following fields are currently sent for users:
|
|||
- "user"
|
||||
- "organizationalPerson"
|
||||
- "goauthentik.io/ldap/user"
|
||||
- `accountStatus`: "active" if the account is active, otherwise "inactive"
|
||||
- `superuser`: "active" if the account is part of a group with superuser permissions, otherwise "inactive"
|
||||
- `memberOf`: A list of all DNs that the user is a member of
|
||||
- `goauthentik.io/ldap/active`: "true" if the account is active, otherwise "false"
|
||||
- `goauthentik.io/ldap/superuser`: "true" if the account is part of a group with superuser permissions, otherwise "false"
|
||||
|
||||
The following fields are current set for groups:
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ version: "3.5"
|
|||
|
||||
services:
|
||||
authentik_proxy:
|
||||
image: ghcr.io/goauthentik/proxy:2021.6.2
|
||||
image: ghcr.io/goauthentik/proxy:2021.6.3
|
||||
ports:
|
||||
- 4180:4180
|
||||
- 4443:4443
|
||||
|
@ -21,7 +21,7 @@ services:
|
|||
AUTHENTIK_TOKEN: token-generated-by-authentik
|
||||
# Or, for the LDAP Outpost
|
||||
authentik_proxy:
|
||||
image: ghcr.io/goauthentik/ldap:2021.6.2
|
||||
image: ghcr.io/goauthentik/ldap:2021.6.3
|
||||
ports:
|
||||
- 389:3389
|
||||
environment:
|
||||
|
|
|
@ -14,7 +14,7 @@ metadata:
|
|||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.6.2
|
||||
app.kubernetes.io/version: 2021.6.3
|
||||
name: authentik-outpost-api
|
||||
stringData:
|
||||
authentik_host: "__AUTHENTIK_URL__"
|
||||
|
@ -29,7 +29,7 @@ metadata:
|
|||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.6.2
|
||||
app.kubernetes.io/version: 2021.6.3
|
||||
name: authentik-outpost
|
||||
spec:
|
||||
ports:
|
||||
|
@ -54,7 +54,7 @@ metadata:
|
|||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.6.2
|
||||
app.kubernetes.io/version: 2021.6.3
|
||||
name: authentik-outpost
|
||||
spec:
|
||||
selector:
|
||||
|
@ -62,14 +62,14 @@ spec:
|
|||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.6.2
|
||||
app.kubernetes.io/version: 2021.6.3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.6.2
|
||||
app.kubernetes.io/version: 2021.6.3
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
|
@ -88,7 +88,7 @@ spec:
|
|||
secretKeyRef:
|
||||
key: authentik_host_insecure
|
||||
name: authentik-outpost-api
|
||||
image: ghcr.io/goauthentik/proxy:2021.6.2
|
||||
image: ghcr.io/goauthentik/proxy:2021.6.3
|
||||
name: proxy
|
||||
ports:
|
||||
- containerPort: 4180
|
||||
|
@ -110,7 +110,7 @@ metadata:
|
|||
app.kubernetes.io/instance: __OUTPOST_NAME__
|
||||
app.kubernetes.io/managed-by: goauthentik.io
|
||||
app.kubernetes.io/name: authentik-proxy
|
||||
app.kubernetes.io/version: 2021.6.2
|
||||
app.kubernetes.io/version: 2021.6.3
|
||||
name: authentik-outpost
|
||||
spec:
|
||||
rules:
|
||||
|
|
|
@ -46,24 +46,46 @@ import TabItem from '@theme/TabItem';
|
|||
<TabItem value="standalone-nginx">
|
||||
|
||||
```
|
||||
location /akprox {
|
||||
proxy_pass http://*ip of your outpost*:4180;
|
||||
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;
|
||||
}
|
||||
server {
|
||||
# SSL and VHost configuration
|
||||
listen 443 ssl http2;
|
||||
server_name _;
|
||||
|
||||
location @akprox_signin {
|
||||
internal;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
return 302 /akprox/start?rd=$request_uri;
|
||||
}
|
||||
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
|
||||
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
|
||||
|
||||
location / {
|
||||
auth_request /akprox/auth?nginx;
|
||||
# All your other options...
|
||||
# Put your proxy_pass to your application here
|
||||
# proxy_pass http://localhost:5000;
|
||||
|
||||
# authentik-specific config
|
||||
auth_request /akprox/auth;
|
||||
error_page 401 = @akprox_signin;
|
||||
# translate headers from the outposts back to the actual upstream
|
||||
auth_request_set $username $upstream_http_x_auth_username;
|
||||
auth_request_set $email $upstream_http_X_Forwarded_Email;
|
||||
proxy_set_header X-Auth-Username $username;
|
||||
proxy_set_header X-Forwarded-Email $email;
|
||||
}
|
||||
|
||||
# all requests to /akprox must be accessible without authentication
|
||||
location /akprox {
|
||||
proxy_pass http://*ip or hostname of the authentik OUTPOST*:4180;
|
||||
# ensure the host of this vserver matches your external URL you've configured
|
||||
# in authentik
|
||||
proxy_set_header Host $host;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||
}
|
||||
|
||||
# Special location for when the /auth endpoint returns a 401,
|
||||
# redirect to the /start URL which initiates SSO
|
||||
location @akprox_signin {
|
||||
internal;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
return 302 /akprox/start?rd=$request_uri;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
|
Reference in a new issue