commit
e177ab33e0
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
|
@ -30,7 +30,7 @@ jobs:
|
|||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: prepare ts api client
|
||||
run: |
|
||||
docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/api --additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
|
||||
make gen-web
|
||||
- name: Building Docker Image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
|
@ -51,9 +51,8 @@ jobs:
|
|||
go-version: "^1.15"
|
||||
- name: prepare go api client
|
||||
run: |
|
||||
make gen-outpost
|
||||
cd outpost
|
||||
go get -u github.com/go-swagger/go-swagger/cmd/swagger
|
||||
swagger generate client -f ../swagger.yaml -A authentik -t pkg/
|
||||
go build -v ./cmd/proxy/server.go
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1.1.0
|
||||
|
@ -91,9 +90,8 @@ jobs:
|
|||
go-version: "^1.15"
|
||||
- name: prepare go api client
|
||||
run: |
|
||||
make gen-outpost
|
||||
cd outpost
|
||||
go get -u github.com/go-swagger/go-swagger/cmd/swagger
|
||||
swagger generate client -f ../swagger.yaml -A authentik -t pkg/
|
||||
go build -v ./cmd/ldap/server.go
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1.1.0
|
||||
|
|
2
.github/workflows/tag.yml
vendored
2
.github/workflows/tag.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- name: prepare ts api client
|
||||
run: |
|
||||
docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/api --additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
|
||||
make gen-web
|
||||
- name: Pre-release test
|
||||
run: |
|
||||
sudo apt-get install -y pwgen
|
||||
|
|
27
Makefile
27
Makefile
|
@ -1,5 +1,7 @@
|
|||
.SHELLFLAGS += -x -e
|
||||
PWD = $(shell pwd)
|
||||
UID = $(shell id -u)
|
||||
GID = $(shell id -g)
|
||||
|
||||
all: lint-fix lint test gen
|
||||
|
||||
|
@ -25,16 +27,35 @@ lint:
|
|||
bandit -r authentik tests lifecycle -x node_modules
|
||||
pylint authentik tests lifecycle
|
||||
|
||||
gen:
|
||||
./manage.py generate_swagger -o swagger.yaml -f yaml
|
||||
gen-build:
|
||||
./manage.py spectacular --file schema.yml
|
||||
|
||||
gen-web:
|
||||
docker run \
|
||||
--rm -v ${PWD}:/local \
|
||||
--user ${UID}:${GID} \
|
||||
openapitools/openapi-generator-cli generate \
|
||||
-i /local/swagger.yaml \
|
||||
-i /local/schema.yml \
|
||||
-g typescript-fetch \
|
||||
-o /local/web/api \
|
||||
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
|
||||
cd web/api && npx tsc
|
||||
|
||||
gen-outpost:
|
||||
docker run \
|
||||
--rm -v ${PWD}:/local \
|
||||
--user ${UID}:${GID} \
|
||||
openapitools/openapi-generator-cli generate \
|
||||
--git-host goauthentik.io \
|
||||
--git-repo-id outpost \
|
||||
--git-user-id api \
|
||||
-i /local/schema.yml \
|
||||
-g go \
|
||||
-o /local/outpost/api \
|
||||
--additional-properties=packageName=api,enumClassPrefix=true
|
||||
rm -f outpost/api/go.mod outpost/api/go.sum
|
||||
|
||||
gen: gen-build gen-web gen-outpost
|
||||
|
||||
run:
|
||||
go run -v cmd/server/main.go
|
||||
|
|
2
Pipfile
2
Pipfile
|
@ -22,7 +22,7 @@ django-storages = "*"
|
|||
djangorestframework = "*"
|
||||
djangorestframework-guardian = "*"
|
||||
docker = "*"
|
||||
drf_yasg = "*"
|
||||
drf-spectacular = "*"
|
||||
facebook-sdk = "*"
|
||||
geoip2 = "*"
|
||||
gunicorn = "*"
|
||||
|
|
206
Pipfile.lock
generated
206
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "8a32708c1c04f8da03c817df973de28c37c97ee773f571ce0b3f3f834e1b7094"
|
||||
"sha256": "61354b75aa954ea0a995ee1909b861092a4be5c1af66d3c00c7c7845e056d064"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -56,6 +56,7 @@
|
|||
"sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a",
|
||||
"sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.7.4.post0"
|
||||
},
|
||||
"aioredis": {
|
||||
|
@ -70,6 +71,7 @@
|
|||
"sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2",
|
||||
"sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.0.6"
|
||||
},
|
||||
"asgiref": {
|
||||
|
@ -77,6 +79,7 @@
|
|||
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
|
||||
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.3.4"
|
||||
},
|
||||
"async-timeout": {
|
||||
|
@ -84,6 +87,7 @@
|
|||
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
|
||||
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
|
||||
],
|
||||
"markers": "python_full_version >= '3.5.3'",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"attrs": {
|
||||
|
@ -91,6 +95,7 @@
|
|||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==21.2.0"
|
||||
},
|
||||
"autobahn": {
|
||||
|
@ -98,6 +103,7 @@
|
|||
"sha256:9195df8af03b0ff29ccd4b7f5abbde957ee90273465942205f9a1bad6c3f07ac",
|
||||
"sha256:e126c1f583e872fb59e79d36977cfa1f2d0a8a79f90ae31f406faae7664b8e03"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==21.3.1"
|
||||
},
|
||||
"automat": {
|
||||
|
@ -127,6 +133,7 @@
|
|||
"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"
|
||||
},
|
||||
"cachetools": {
|
||||
|
@ -134,6 +141,7 @@
|
|||
"sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001",
|
||||
"sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"
|
||||
],
|
||||
"markers": "python_version ~= '3.5'",
|
||||
"version": "==4.2.2"
|
||||
},
|
||||
"cbor2": {
|
||||
|
@ -220,6 +228,7 @@
|
|||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"click": {
|
||||
|
@ -227,6 +236,7 @@
|
|||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==7.1.2"
|
||||
},
|
||||
"click-didyoumean": {
|
||||
|
@ -256,20 +266,6 @@
|
|||
],
|
||||
"version": "==15.1.0"
|
||||
},
|
||||
"coreapi": {
|
||||
"hashes": [
|
||||
"sha256:46145fcc1f7017c076a2ef684969b641d18a2991051fddec9458ad3f78ffc1cb",
|
||||
"sha256:bf39d118d6d3e171f10df9ede5666f63ad80bba9a29a8ec17726a66cf52ee6f3"
|
||||
],
|
||||
"version": "==2.3.3"
|
||||
},
|
||||
"coreschema": {
|
||||
"hashes": [
|
||||
"sha256:5e6ef7bf38c1525d5e55a895934ab4273548629f16aed5c0a6caa74ebf45551f",
|
||||
"sha256:9503506007d482ab0867ba14724b93c18a33b22b6d19fb419ef2d239dd4a1607"
|
||||
],
|
||||
"version": "==0.0.4"
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d",
|
||||
|
@ -300,6 +296,7 @@
|
|||
"sha256:76ffae916ba3aa66b46996c14fa713e46004788167a4873d647544e750e0e99f",
|
||||
"sha256:a9af943c79717bc52fe64a3c236ae5d3adccc8b5be19c881b442d2c3db233393"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.2"
|
||||
},
|
||||
"defusedxml": {
|
||||
|
@ -402,13 +399,13 @@
|
|||
"index": "pypi",
|
||||
"version": "==5.0.0"
|
||||
},
|
||||
"drf-yasg": {
|
||||
"drf-spectacular": {
|
||||
"hashes": [
|
||||
"sha256:8b72e5b1875931a8d11af407be3a9a5ba8776541492947a0df5bafda6b7f8267",
|
||||
"sha256:d50f197c7f02545d0b736df88c6d5cf874f8fea2507ad85ad7de6ae5bf2d9e5a"
|
||||
"sha256:4a77c233c99e028b8905cd2cf05388524838ade97b95d5c6e4861e0c3c95af31",
|
||||
"sha256:d7f64b97e8940b143a0e8d1de20523e8d7d5fe8ec557aec574513282c413b0b3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.20.0"
|
||||
"version": "==0.16.0"
|
||||
},
|
||||
"facebook-sdk": {
|
||||
"hashes": [
|
||||
|
@ -422,6 +419,7 @@
|
|||
"hashes": [
|
||||
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.18.2"
|
||||
},
|
||||
"geoip2": {
|
||||
|
@ -437,6 +435,7 @@
|
|||
"sha256:588bdb03a41ecb4978472b847881e5518b5d9ec6153d3d679aa127a55e13b39f",
|
||||
"sha256:9ad25fba07f46a628ad4d0ca09f38dcb262830df2ac95b217f9b0129c9e42206"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.30.0"
|
||||
},
|
||||
"gunicorn": {
|
||||
|
@ -452,6 +451,7 @@
|
|||
"sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6",
|
||||
"sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.12.0"
|
||||
},
|
||||
"hiredis": {
|
||||
|
@ -498,6 +498,7 @@
|
|||
"sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0",
|
||||
"sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"httptools": {
|
||||
|
@ -546,27 +547,15 @@
|
|||
"sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417",
|
||||
"sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"itypes": {
|
||||
"hashes": [
|
||||
"sha256:03da6872ca89d29aef62773672b2d408f490f80db48b23079a4b194c86dd04c6",
|
||||
"sha256:af886f129dea4a2a1e3d36595a2d139589e4dd287f5cab0b40e799ee81570ff1"
|
||||
],
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:2f2de5285cf37f33d33ecd4a9080b75c87cd0c1994d5a9c6df17131ea1f049c6",
|
||||
"sha256:ea8d7dd814ce9df6de6a761ec7f1cac98afe305b8cdc4aaae4e114b8d8ce24c5"
|
||||
],
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"jmespath": {
|
||||
"hashes": [
|
||||
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
|
||||
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.0"
|
||||
},
|
||||
"jsonschema": {
|
||||
|
@ -581,6 +570,7 @@
|
|||
"sha256:6dc509178ac4269b0e66ab4881f70a2035c33d3a622e20585f965986a5182006",
|
||||
"sha256:f4965fba0a4718d47d470beeb5d6446e3357a62402b16c510b6a2f251e05ac3c"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.0.2"
|
||||
},
|
||||
"kubernetes": {
|
||||
|
@ -593,7 +583,10 @@
|
|||
},
|
||||
"ldap3": {
|
||||
"hashes": [
|
||||
"sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c",
|
||||
"sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056",
|
||||
"sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91",
|
||||
"sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59",
|
||||
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57"
|
||||
],
|
||||
"index": "pypi",
|
||||
|
@ -651,49 +644,11 @@
|
|||
"index": "pypi",
|
||||
"version": "==4.6.3"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:007dc055dbce5b1104876acee177dbfd18757e19d562cd440182e1f492e96b95",
|
||||
"sha256:031bf79a27d1c42f69c276d6221172417b47cb4b31cdc73d362a9bf5a1889b9f",
|
||||
"sha256:161d575fa49395860b75da5135162481768b11208490d5a2143ae6785123e77d",
|
||||
"sha256:24bbc3507fb6dfff663af7900a631f2aca90d5a445f272db5fc84999fa5718bc",
|
||||
"sha256:2efaeb1baff547063bad2b2893a8f5e9c459c4624e1a96644bbba08910ae34e0",
|
||||
"sha256:32200f562daaab472921a11cbb63780f1654552ae49518196fc361ed8e12e901",
|
||||
"sha256:3261fae28155e5c8634dd7710635fe540a05b58f160cef7713c7700cb9980e66",
|
||||
"sha256:3b54a9c68995ef4164567e2cd1a5e16db5dac30b2a50c39c82db8d4afaf14f63",
|
||||
"sha256:3c352ff634e289061711608f5e474ec38dbaa21e3e168820d53d5f4015e5b91b",
|
||||
"sha256:3fb47f97f1d338b943126e90b79cad50d4fcfa0b80637b5a9f468941dbbd9ce5",
|
||||
"sha256:441ce2a8c17683d97e06447fcbccbdb057cbf587c78eb75ae43ea7858042fe2c",
|
||||
"sha256:45535241baa0fc0ba2a43961a1ac7562ca3257f46c4c3e9c0de38b722be41bd1",
|
||||
"sha256:4aca81a687975b35e3e80bcf9aa93fe10cd57fac37bf18b2314c186095f57e05",
|
||||
"sha256:4cc563836f13c57f1473bc02d1e01fc37bab70ad4ee6be297d58c1d66bc819bf",
|
||||
"sha256:4fae0677f712ee090721d8b17f412f1cbceefbf0dc180fe91bab3232f38b4527",
|
||||
"sha256:58bc9fce3e1557d463ef5cee05391a05745fd95ed660f23c1742c711712c0abb",
|
||||
"sha256:664832fb88b8162268928df233f4b12a144a0c78b01d38b81bdcf0fc96668ecb",
|
||||
"sha256:70820a1c96311e02449591cbdf5cd1c6a34d5194d5b55094ab725364375c9eb2",
|
||||
"sha256:79b2ae94fa991be023832e6bcc00f41dbc8e5fe9d997a02db965831402551730",
|
||||
"sha256:83cf0228b2f694dcdba1374d5312f2277269d798e65f40344964f642935feac1",
|
||||
"sha256:87de598edfa2230ff274c4de7fcf24c73ffd96208c8e1912d5d0fee459767d75",
|
||||
"sha256:8f806bfd0f218477d7c46a11d3e52dc7f5fdfaa981b18202b7dc84bbc287463b",
|
||||
"sha256:90053234a6479738fd40d155268af631c7fca33365f964f2208867da1349294b",
|
||||
"sha256:a00dce2d96587651ef4fa192c17e039e8cfab63087c67e7d263a5533c7dad715",
|
||||
"sha256:a08cd07d3c3c17cd33d9e66ea9dee8f8fc1c48e2d11bd88fd2dc515a602c709b",
|
||||
"sha256:a19d39b02a24d3082856a5b06490b714a9d4179321225bbf22809ff1e1887cc8",
|
||||
"sha256:d00a669e4a5bec3ee6dbeeeedd82a405ced19f8aeefb109a012ea88a45afff96",
|
||||
"sha256:dab0c685f21f4a6c95bfc2afd1e7eae0033b403dd3d8c1b6d13a652ada75b348",
|
||||
"sha256:df561f65049ed3556e5b52541669310e88713fdae2934845ec3606f283337958",
|
||||
"sha256:e4570d16f88c7f3032ed909dc9e905a17da14a1c4cfd92608e3fda4cb1208bbd",
|
||||
"sha256:e77e4b983e2441aff0c0d07ee711110c106b625f440292dfe02a2f60c8218bd6",
|
||||
"sha256:e79212d09fc0e224d20b43ad44bb0a0a3416d1e04cf6b45fed265114a5d43d20",
|
||||
"sha256:f58b5ba13a5689ca8317b98439fccfbcc673acaaf8241c1869ceea40f5d585bf",
|
||||
"sha256:fef86115fdad7ae774720d7103aa776144cf9b66673b4afa9bcaa7af990ed07b"
|
||||
],
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"maxminddb": {
|
||||
"hashes": [
|
||||
"sha256:47e86a084dd814fac88c99ea34ba3278a74bc9de5a25f4b815b608798747c7dc"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.3"
|
||||
},
|
||||
"msgpack": {
|
||||
|
@ -769,6 +724,7 @@
|
|||
"sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281",
|
||||
"sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.1.0"
|
||||
},
|
||||
"oauthlib": {
|
||||
|
@ -776,6 +732,7 @@
|
|||
"sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
|
||||
"sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"packaging": {
|
||||
|
@ -791,6 +748,7 @@
|
|||
"sha256:030e4f9df5f53db2292eec37c6255957eb76168c6f974e4176c711cf91ed34aa",
|
||||
"sha256:b6c5a9643e3545bcbfd9451766cbaa5d9c67e7303c7bc32c750b6fa70ecb107d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.1"
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
|
@ -798,6 +756,7 @@
|
|||
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
|
||||
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.1'",
|
||||
"version": "==3.0.18"
|
||||
},
|
||||
"psycopg2-binary": {
|
||||
|
@ -843,15 +802,37 @@
|
|||
},
|
||||
"pyasn1": {
|
||||
"hashes": [
|
||||
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
|
||||
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
|
||||
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
|
||||
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
|
||||
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
|
||||
"sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
|
||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
|
||||
"sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
|
||||
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3",
|
||||
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
|
||||
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
|
||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"
|
||||
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
|
||||
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"
|
||||
],
|
||||
"version": "==0.4.8"
|
||||
},
|
||||
"pyasn1-modules": {
|
||||
"hashes": [
|
||||
"sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
|
||||
"sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
|
||||
"sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
|
||||
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
|
||||
"sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
|
||||
"sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
|
||||
"sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
|
||||
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
|
||||
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
|
||||
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
|
||||
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
|
||||
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"
|
||||
"sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
|
||||
"sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
|
||||
],
|
||||
"version": "==0.2.8"
|
||||
},
|
||||
|
@ -860,6 +841,7 @@
|
|||
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
|
||||
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.20"
|
||||
},
|
||||
"pycryptodome": {
|
||||
|
@ -903,6 +885,7 @@
|
|||
"sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316",
|
||||
"sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.0.2"
|
||||
},
|
||||
"pyjwt": {
|
||||
|
@ -925,12 +908,14 @@
|
|||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pyrsistent": {
|
||||
"hashes": [
|
||||
"sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.17.3"
|
||||
},
|
||||
"python-dateutil": {
|
||||
|
@ -938,6 +923,7 @@
|
|||
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
|
||||
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.8.1"
|
||||
},
|
||||
"python-dotenv": {
|
||||
|
@ -994,6 +980,7 @@
|
|||
"sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",
|
||||
"sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==3.5.3"
|
||||
},
|
||||
"requests": {
|
||||
|
@ -1001,10 +988,12 @@
|
|||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"requests-oauthlib": {
|
||||
"hashes": [
|
||||
"sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc",
|
||||
"sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
|
||||
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
|
||||
],
|
||||
|
@ -1019,50 +1008,6 @@
|
|||
"markers": "python_version >= '3.6'",
|
||||
"version": "==4.7.2"
|
||||
},
|
||||
"ruamel.yaml": {
|
||||
"hashes": [
|
||||
"sha256:44bc6b54fddd45e4bc0619059196679f9e8b79c027f4131bb072e6a22f4d5e28",
|
||||
"sha256:ac79fb25f5476e8e9ed1c53b8a2286d2c3f5dde49eb37dbcee5c7eb6a8415a22"
|
||||
],
|
||||
"version": "==0.17.4"
|
||||
},
|
||||
"ruamel.yaml.clib": {
|
||||
"hashes": [
|
||||
"sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b",
|
||||
"sha256:1236df55e0f73cd138c0eca074ee086136c3f16a97c2ac719032c050f7e0622f",
|
||||
"sha256:1f8c0a4577c0e6c99d208de5c4d3fd8aceed9574bb154d7a2b21c16bb924154c",
|
||||
"sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91",
|
||||
"sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc",
|
||||
"sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7",
|
||||
"sha256:2fd336a5c6415c82e2deb40d08c222087febe0aebe520f4d21910629018ab0f3",
|
||||
"sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7",
|
||||
"sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6",
|
||||
"sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6",
|
||||
"sha256:46d6d20815064e8bb023ea8628cfb7402c0f0e83de2c2227a88097e239a7dffd",
|
||||
"sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0",
|
||||
"sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62",
|
||||
"sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99",
|
||||
"sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5",
|
||||
"sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026",
|
||||
"sha256:6c0a5dc52fc74eb87c67374a4e554d4761fd42a4d01390b7e868b30d21f4b8bb",
|
||||
"sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2",
|
||||
"sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1",
|
||||
"sha256:75f0ee6839532e52a3a53f80ce64925ed4aed697dd3fa890c4c918f3304bd4f4",
|
||||
"sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b",
|
||||
"sha256:8be05be57dc5c7b4a0b24edcaa2f7275866d9c907725226cdde46da09367d923",
|
||||
"sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e",
|
||||
"sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c",
|
||||
"sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988",
|
||||
"sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f",
|
||||
"sha256:b4b0d31f2052b3f9f9b5327024dc629a253a83d8649d4734ca7f35b60ec3e9e5",
|
||||
"sha256:c6ac7e45367b1317e56f1461719c853fd6825226f45b835df7436bb04031fd8a",
|
||||
"sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1",
|
||||
"sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2",
|
||||
"sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f"
|
||||
],
|
||||
"markers": "platform_python_implementation == 'CPython' and python_version < '3.10'",
|
||||
"version": "==0.2.2"
|
||||
},
|
||||
"s3transfer": {
|
||||
"hashes": [
|
||||
"sha256:9b3752887a2880690ce628bc263d6d13a3864083aeacff4890c1c9839a5eb0bc",
|
||||
|
@ -1091,6 +1036,7 @@
|
|||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"sqlparse": {
|
||||
|
@ -1098,6 +1044,7 @@
|
|||
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
|
||||
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.4.1"
|
||||
},
|
||||
"structlog": {
|
||||
|
@ -1153,6 +1100,7 @@
|
|||
"sha256:7d6f89745680233f1c4db9ddb748df5e88d2a7a37962be174c0fd04c8dba1dc8",
|
||||
"sha256:c16b55f9a67b2419cfdf8846576e2ec9ba94fe6978a83080c352a80db31c93fb"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==21.2.1"
|
||||
},
|
||||
"typing-extensions": {
|
||||
|
@ -1168,6 +1116,7 @@
|
|||
"sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f",
|
||||
"sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"urllib3": {
|
||||
|
@ -1212,6 +1161,7 @@
|
|||
"sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30",
|
||||
"sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==5.0.0"
|
||||
},
|
||||
"watchgod": {
|
||||
|
@ -1241,6 +1191,7 @@
|
|||
"sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32",
|
||||
"sha256:d376bd60eace9d437ab6d7ee16f4ab4e821c9dae591e1b783c58ebd8aaf80c5c"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.59.0"
|
||||
},
|
||||
"websockets": {
|
||||
|
@ -1327,6 +1278,7 @@
|
|||
"sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a",
|
||||
"sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.6.3"
|
||||
},
|
||||
"zope.interface": {
|
||||
|
@ -1383,6 +1335,7 @@
|
|||
"sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4",
|
||||
"sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==5.4.0"
|
||||
}
|
||||
},
|
||||
|
@ -1399,6 +1352,7 @@
|
|||
"sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e",
|
||||
"sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"
|
||||
],
|
||||
"markers": "python_version ~= '3.6'",
|
||||
"version": "==2.5.6"
|
||||
},
|
||||
"attrs": {
|
||||
|
@ -1406,6 +1360,7 @@
|
|||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==21.2.0"
|
||||
},
|
||||
"bandit": {
|
||||
|
@ -1444,6 +1399,7 @@
|
|||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"click": {
|
||||
|
@ -1451,6 +1407,7 @@
|
|||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==7.1.2"
|
||||
},
|
||||
"colorama": {
|
||||
|
@ -1524,6 +1481,7 @@
|
|||
"sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0",
|
||||
"sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"
|
||||
],
|
||||
"markers": "python_version >= '3.4'",
|
||||
"version": "==4.0.7"
|
||||
},
|
||||
"gitpython": {
|
||||
|
@ -1531,6 +1489,7 @@
|
|||
"sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135",
|
||||
"sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==3.1.17"
|
||||
},
|
||||
"idna": {
|
||||
|
@ -1552,6 +1511,7 @@
|
|||
"sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
|
||||
"sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
|
||||
],
|
||||
"markers": "python_version >= '3.6' and python_version < '4.0'",
|
||||
"version": "==5.8.0"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
|
@ -1579,6 +1539,7 @@
|
|||
"sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
|
||||
"sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.6.0"
|
||||
},
|
||||
"mccabe": {
|
||||
|
@ -1615,6 +1576,7 @@
|
|||
"sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd",
|
||||
"sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"
|
||||
],
|
||||
"markers": "python_version >= '2.6'",
|
||||
"version": "==5.6.0"
|
||||
},
|
||||
"pluggy": {
|
||||
|
@ -1622,6 +1584,7 @@
|
|||
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
|
||||
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.13.1"
|
||||
},
|
||||
"py": {
|
||||
|
@ -1629,6 +1592,7 @@
|
|||
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
|
||||
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.10.0"
|
||||
},
|
||||
"pylint": {
|
||||
|
@ -1659,6 +1623,7 @@
|
|||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pytest": {
|
||||
|
@ -1763,6 +1728,7 @@
|
|||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"requests-mock": {
|
||||
|
@ -1786,6 +1752,7 @@
|
|||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"smmap": {
|
||||
|
@ -1793,6 +1760,7 @@
|
|||
"sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182",
|
||||
"sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"stevedore": {
|
||||
|
@ -1800,6 +1768,7 @@
|
|||
"sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee",
|
||||
"sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.3.0"
|
||||
},
|
||||
"toml": {
|
||||
|
@ -1807,6 +1776,7 @@
|
|||
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
|
||||
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.2"
|
||||
},
|
||||
"urllib3": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""Meta API"""
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.request import Request
|
||||
|
@ -22,7 +22,7 @@ class AppsViewSet(ViewSet):
|
|||
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
@swagger_auto_schema(responses={200: AppSerializer(many=True)})
|
||||
@extend_schema(responses={200: AppSerializer(many=True)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""List current messages and pass into Serializer"""
|
||||
data = []
|
||||
|
|
|
@ -7,12 +7,12 @@ from django.db.models import Count, ExpressionWrapper, F
|
|||
from django.db.models.fields import DurationField
|
||||
from django.db.models.functions import ExtractHour
|
||||
from django.utils.timezone import now
|
||||
from drf_yasg.utils import swagger_auto_schema, swagger_serializer_method
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_field
|
||||
from rest_framework.fields import IntegerField, SerializerMethodField
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import ViewSet
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.events.models import Event, EventAction
|
||||
|
@ -58,24 +58,24 @@ class LoginMetricsSerializer(PassiveSerializer):
|
|||
logins_per_1h = SerializerMethodField()
|
||||
logins_failed_per_1h = SerializerMethodField()
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_logins_per_1h(self, _):
|
||||
"""Get successful logins per hour for the last 24 hours"""
|
||||
return get_events_per_1h(action=EventAction.LOGIN)
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_logins_failed_per_1h(self, _):
|
||||
"""Get failed logins per hour for the last 24 hours"""
|
||||
return get_events_per_1h(action=EventAction.LOGIN_FAILED)
|
||||
|
||||
|
||||
class AdministrationMetricsViewSet(ViewSet):
|
||||
class AdministrationMetricsViewSet(APIView):
|
||||
"""Login Metrics per 1h"""
|
||||
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
@swagger_auto_schema(responses={200: LoginMetricsSerializer(many=False)})
|
||||
def list(self, request: Request) -> Response:
|
||||
@extend_schema(responses={200: LoginMetricsSerializer(many=False)})
|
||||
def get(self, request: Request) -> Response:
|
||||
"""Login Metrics per 1h"""
|
||||
serializer = LoginMetricsSerializer(True)
|
||||
return Response(serializer.data)
|
||||
|
|
|
@ -4,7 +4,8 @@ from importlib import import_module
|
|||
from django.contrib import messages
|
||||
from django.http.response import Http404
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, ChoiceField, DateTimeField, ListField
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
|
@ -34,9 +35,13 @@ class TaskViewSet(ViewSet):
|
|||
"""Read-only view set that returns all background tasks"""
|
||||
|
||||
permission_classes = [IsAdminUser]
|
||||
serializer_class = TaskSerializer
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={200: TaskSerializer(many=False), 404: "Task not found"}
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: TaskSerializer(many=False),
|
||||
404: OpenApiResponse(description="Task not found"),
|
||||
}
|
||||
)
|
||||
# pylint: disable=invalid-name
|
||||
def retrieve(self, request: Request, pk=None) -> Response:
|
||||
|
@ -46,18 +51,19 @@ class TaskViewSet(ViewSet):
|
|||
raise Http404
|
||||
return Response(TaskSerializer(task, many=False).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: TaskSerializer(many=True)})
|
||||
@extend_schema(responses={200: TaskSerializer(many=True)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""List system tasks"""
|
||||
tasks = sorted(TaskInfo.all().values(), key=lambda task: task.task_name)
|
||||
return Response(TaskSerializer(tasks, many=True).data)
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
responses={
|
||||
204: "Task retried successfully",
|
||||
404: "Task not found",
|
||||
500: "Failed to retry task",
|
||||
}
|
||||
204: OpenApiResponse(description="Task retried successfully"),
|
||||
404: OpenApiResponse(description="Task not found"),
|
||||
500: OpenApiResponse(description="Failed to retry task"),
|
||||
},
|
||||
)
|
||||
@action(detail=True, methods=["post"])
|
||||
# pylint: disable=invalid-name
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
from os import environ
|
||||
|
||||
from django.core.cache import cache
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from packaging.version import parse
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from rest_framework.mixins import ListModelMixin
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from authentik import ENV_GIT_HASH_KEY, __version__
|
||||
from authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_version
|
||||
|
@ -47,17 +46,14 @@ class VersionSerializer(PassiveSerializer):
|
|||
)
|
||||
|
||||
|
||||
class VersionViewSet(ListModelMixin, GenericViewSet):
|
||||
class VersionView(APIView):
|
||||
"""Get running and latest version."""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
pagination_class = None
|
||||
filter_backends = []
|
||||
|
||||
def get_queryset(self): # pragma: no cover
|
||||
return None
|
||||
|
||||
@swagger_auto_schema(responses={200: VersionSerializer(many=False)})
|
||||
def list(self, request: Request) -> Response:
|
||||
@extend_schema(responses={200: VersionSerializer(many=False)})
|
||||
def get(self, request: Request) -> Response:
|
||||
"""Get running and latest version."""
|
||||
return Response(VersionSerializer(True).data)
|
||||
|
|
|
@ -1,25 +1,22 @@
|
|||
"""authentik administration overview"""
|
||||
from rest_framework.mixins import ListModelMixin
|
||||
from drf_spectacular.utils import extend_schema, inline_serializer
|
||||
from rest_framework.fields import IntegerField
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import Serializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from authentik.root.celery import CELERY_APP
|
||||
|
||||
|
||||
class WorkerViewSet(ListModelMixin, GenericViewSet):
|
||||
class WorkerView(APIView):
|
||||
"""Get currently connected worker count."""
|
||||
|
||||
serializer_class = Serializer
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
def get_queryset(self): # pragma: no cover
|
||||
return None
|
||||
|
||||
def list(self, request: Request) -> Response:
|
||||
@extend_schema(
|
||||
responses=inline_serializer("Workers", fields={"count": IntegerField()})
|
||||
)
|
||||
def get(self, request: Request) -> Response:
|
||||
"""Get currently connected worker count."""
|
||||
return Response(
|
||||
{"pagination": {"count": len(CELERY_APP.control.ping(timeout=0.5))}}
|
||||
)
|
||||
return Response({"count": len(CELERY_APP.control.ping(timeout=0.5))})
|
||||
|
|
|
@ -74,21 +74,21 @@ class TestAdminAPI(TestCase):
|
|||
|
||||
def test_version(self):
|
||||
"""Test Version API"""
|
||||
response = self.client.get(reverse("authentik_api:admin_version-list"))
|
||||
response = self.client.get(reverse("authentik_api:admin_version"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
body = loads(response.content)
|
||||
self.assertEqual(body["version_current"], __version__)
|
||||
|
||||
def test_workers(self):
|
||||
"""Test Workers API"""
|
||||
response = self.client.get(reverse("authentik_api:admin_workers-list"))
|
||||
response = self.client.get(reverse("authentik_api:admin_workers"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
body = loads(response.content)
|
||||
self.assertEqual(body["pagination"]["count"], 0)
|
||||
self.assertEqual(body["count"], 0)
|
||||
|
||||
def test_metrics(self):
|
||||
"""Test metrics API"""
|
||||
response = self.client.get(reverse("authentik_api:admin_metrics-list"))
|
||||
response = self.client.get(reverse("authentik_api:admin_metrics"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_apps(self):
|
||||
|
|
|
@ -3,6 +3,7 @@ from base64 import b64decode
|
|||
from binascii import Error
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from drf_spectacular.authentication import OpenApiAuthenticationExtension
|
||||
from rest_framework.authentication import BaseAuthentication, get_authorization_header
|
||||
from rest_framework.exceptions import AuthenticationFailed
|
||||
from rest_framework.request import Request
|
||||
|
@ -55,3 +56,18 @@ class AuthentikTokenAuthentication(BaseAuthentication):
|
|||
return None
|
||||
|
||||
return (token.user, None) # pragma: no cover
|
||||
|
||||
|
||||
class TokenSchema(OpenApiAuthenticationExtension):
|
||||
"""Auth schema"""
|
||||
|
||||
target_class = AuthentikTokenAuthentication
|
||||
name = "authentik"
|
||||
|
||||
def get_security_definition(self, auto_schema):
|
||||
"""Auth schema"""
|
||||
return {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": "Authorization",
|
||||
}
|
||||
|
|
|
@ -30,3 +30,47 @@ class Pagination(pagination.PageNumberPagination):
|
|||
"results": data,
|
||||
}
|
||||
)
|
||||
|
||||
def get_paginated_response_schema(self, schema):
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pagination": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"next": {
|
||||
"type": "number",
|
||||
},
|
||||
"previous": {
|
||||
"type": "number",
|
||||
},
|
||||
"count": {
|
||||
"type": "number",
|
||||
},
|
||||
"current": {
|
||||
"type": "number",
|
||||
},
|
||||
"total_pages": {
|
||||
"type": "number",
|
||||
},
|
||||
"start_index": {
|
||||
"type": "number",
|
||||
},
|
||||
"end_index": {
|
||||
"type": "number",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"next",
|
||||
"previous",
|
||||
"count",
|
||||
"current",
|
||||
"total_pages",
|
||||
"start_index",
|
||||
"end_index",
|
||||
],
|
||||
},
|
||||
"results": schema,
|
||||
},
|
||||
"required": ["pagination", "results"],
|
||||
}
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
"""Swagger Pagination Schema class"""
|
||||
from typing import OrderedDict
|
||||
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.inspectors import PaginatorInspector
|
||||
|
||||
|
||||
class PaginationInspector(PaginatorInspector):
|
||||
"""Swagger Pagination Schema class"""
|
||||
|
||||
def get_paginated_response(self, paginator, response_schema):
|
||||
"""
|
||||
:param BasePagination paginator: the paginator
|
||||
:param openapi.Schema response_schema: the response schema that must be paged.
|
||||
:rtype: openapi.Schema
|
||||
"""
|
||||
|
||||
return openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties=OrderedDict(
|
||||
(
|
||||
(
|
||||
"pagination",
|
||||
openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties=OrderedDict(
|
||||
(
|
||||
("next", openapi.Schema(type=openapi.TYPE_NUMBER)),
|
||||
(
|
||||
"previous",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
("count", openapi.Schema(type=openapi.TYPE_NUMBER)),
|
||||
(
|
||||
"current",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
(
|
||||
"total_pages",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
(
|
||||
"start_index",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
(
|
||||
"end_index",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
)
|
||||
),
|
||||
required=[
|
||||
"next",
|
||||
"previous",
|
||||
"count",
|
||||
"current",
|
||||
"total_pages",
|
||||
"start_index",
|
||||
"end_index",
|
||||
],
|
||||
),
|
||||
),
|
||||
("results", response_schema),
|
||||
)
|
||||
),
|
||||
required=["results", "pagination"],
|
||||
)
|
||||
|
||||
def get_paginator_parameters(self, paginator):
|
||||
"""
|
||||
Get the pagination parameters for a single paginator **instance**.
|
||||
|
||||
Should return :data:`.NotHandled` if this inspector
|
||||
does not know how to handle the given `paginator`.
|
||||
|
||||
:param BasePagination paginator: the paginator
|
||||
:rtype: list[openapi.Parameter]
|
||||
"""
|
||||
|
||||
return [
|
||||
openapi.Parameter(
|
||||
"page",
|
||||
openapi.IN_QUERY,
|
||||
"Page Index",
|
||||
False,
|
||||
None,
|
||||
openapi.TYPE_INTEGER,
|
||||
),
|
||||
openapi.Parameter(
|
||||
"page_size",
|
||||
openapi.IN_QUERY,
|
||||
"Page Size",
|
||||
False,
|
||||
None,
|
||||
openapi.TYPE_INTEGER,
|
||||
),
|
||||
]
|
|
@ -1,102 +1,70 @@
|
|||
"""Error Response schema, from https://github.com/axnsan12/drf-yasg/issues/224"""
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.inspectors.view import SwaggerAutoSchema
|
||||
from drf_yasg.utils import force_real_str, is_list_view
|
||||
from rest_framework import exceptions, status
|
||||
from rest_framework.settings import api_settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_spectacular.plumbing import (
|
||||
ResolvedComponent,
|
||||
build_array_type,
|
||||
build_basic_type,
|
||||
build_object_type,
|
||||
)
|
||||
from drf_spectacular.settings import spectacular_settings
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
|
||||
|
||||
class ErrorResponseAutoSchema(SwaggerAutoSchema):
|
||||
"""Inspector which includes an error schema"""
|
||||
def build_standard_type(obj, **kwargs):
|
||||
"""Build a basic type with optional add ons."""
|
||||
schema = build_basic_type(obj)
|
||||
schema.update(kwargs)
|
||||
return schema
|
||||
|
||||
def get_generic_error_schema(self):
|
||||
"""Get a generic error schema"""
|
||||
return openapi.Schema(
|
||||
"Generic API Error",
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
"detail": openapi.Schema(
|
||||
type=openapi.TYPE_STRING, description="Error details"
|
||||
),
|
||||
"code": openapi.Schema(
|
||||
type=openapi.TYPE_STRING, description="Error code"
|
||||
),
|
||||
},
|
||||
required=["detail"],
|
||||
|
||||
GENERIC_ERROR = build_object_type(
|
||||
description=_("Generic API Error"),
|
||||
properties={
|
||||
"detail": build_standard_type(OpenApiTypes.STR),
|
||||
"code": build_standard_type(OpenApiTypes.STR),
|
||||
},
|
||||
required=["detail"],
|
||||
)
|
||||
VALIDATION_ERROR = build_object_type(
|
||||
description=_("Validation Error"),
|
||||
properties={
|
||||
"non_field_errors": build_array_type(build_standard_type(OpenApiTypes.STR)),
|
||||
"code": build_standard_type(OpenApiTypes.STR),
|
||||
},
|
||||
required=["detail"],
|
||||
additionalProperties={},
|
||||
)
|
||||
|
||||
|
||||
def postprocess_schema_responses(result, generator, **kwargs): # noqa: W0613
|
||||
"""Workaround to set a default response for endpoints.
|
||||
Workaround suggested at
|
||||
<https://github.com/tfranzel/drf-spectacular/issues/119#issuecomment-656970357>
|
||||
for the missing drf-spectacular feature discussed in
|
||||
<https://github.com/tfranzel/drf-spectacular/issues/101>.
|
||||
"""
|
||||
|
||||
def create_component(name, schema, type_=ResolvedComponent.SCHEMA):
|
||||
"""Register a component and return a reference to it."""
|
||||
component = ResolvedComponent(
|
||||
name=name,
|
||||
type=type_,
|
||||
schema=schema,
|
||||
object=name,
|
||||
)
|
||||
generator.registry.register_on_missing(component)
|
||||
return component
|
||||
|
||||
def get_validation_error_schema(self):
|
||||
"""Get a generic validation error schema"""
|
||||
return openapi.Schema(
|
||||
"Validation Error",
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
api_settings.NON_FIELD_ERRORS_KEY: openapi.Schema(
|
||||
description="List of validation errors not related to any field",
|
||||
type=openapi.TYPE_ARRAY,
|
||||
items=openapi.Schema(type=openapi.TYPE_STRING),
|
||||
),
|
||||
},
|
||||
additional_properties=openapi.Schema(
|
||||
description=(
|
||||
"A list of error messages for each "
|
||||
"field that triggered a validation error"
|
||||
),
|
||||
type=openapi.TYPE_ARRAY,
|
||||
items=openapi.Schema(type=openapi.TYPE_STRING),
|
||||
),
|
||||
)
|
||||
generic_error = create_component("GenericError", GENERIC_ERROR)
|
||||
validation_error = create_component("ValidationError", VALIDATION_ERROR)
|
||||
|
||||
def get_response_serializers(self):
|
||||
responses = super().get_response_serializers()
|
||||
definitions = self.components.with_scope(
|
||||
openapi.SCHEMA_DEFINITIONS
|
||||
) # type: openapi.ReferenceResolver
|
||||
for path in result["paths"].values():
|
||||
for method in path.values():
|
||||
method["responses"].setdefault("400", validation_error.ref)
|
||||
method["responses"].setdefault("403", generic_error.ref)
|
||||
|
||||
definitions.setdefault("GenericError", self.get_generic_error_schema)
|
||||
definitions.setdefault("ValidationError", self.get_validation_error_schema)
|
||||
definitions.setdefault("APIException", self.get_generic_error_schema)
|
||||
result["components"] = generator.registry.build(
|
||||
spectacular_settings.APPEND_COMPONENTS
|
||||
)
|
||||
|
||||
if self.get_request_serializer() or self.get_query_serializer():
|
||||
responses.setdefault(
|
||||
exceptions.ValidationError.status_code,
|
||||
openapi.Response(
|
||||
description=force_real_str(
|
||||
exceptions.ValidationError.default_detail
|
||||
),
|
||||
schema=openapi.SchemaRef(definitions, "ValidationError"),
|
||||
),
|
||||
)
|
||||
|
||||
security = self.get_security()
|
||||
if security is None or len(security) > 0:
|
||||
# Note: 401 error codes are coerced into 403 see
|
||||
# rest_framework/views.py:433:handle_exception
|
||||
# This is b/c the API uses token auth which doesn't have WWW-Authenticate header
|
||||
responses.setdefault(
|
||||
status.HTTP_403_FORBIDDEN,
|
||||
openapi.Response(
|
||||
description="Authentication credentials were invalid, absent or insufficient.",
|
||||
schema=openapi.SchemaRef(definitions, "GenericError"),
|
||||
),
|
||||
)
|
||||
if not is_list_view(self.path, self.method, self.view):
|
||||
responses.setdefault(
|
||||
exceptions.PermissionDenied.status_code,
|
||||
openapi.Response(
|
||||
description="Permission denied.",
|
||||
schema=openapi.SchemaRef(definitions, "APIException"),
|
||||
),
|
||||
)
|
||||
responses.setdefault(
|
||||
exceptions.NotFound.status_code,
|
||||
openapi.Response(
|
||||
description=(
|
||||
"Object does not exist or caller "
|
||||
"has insufficient permissions to access it."
|
||||
),
|
||||
schema=openapi.SchemaRef(definitions, "APIException"),
|
||||
),
|
||||
)
|
||||
|
||||
return responses
|
||||
return result
|
||||
|
|
|
@ -11,6 +11,6 @@ class TestConfig(APITestCase):
|
|||
def test_config(self):
|
||||
"""Test YAML generation"""
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:configs-list"),
|
||||
reverse("authentik_api:config"),
|
||||
)
|
||||
self.assertTrue(loads(response.content.decode()))
|
||||
|
|
22
authentik/api/tests/test_schema.py
Normal file
22
authentik/api/tests/test_schema.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
"""Schema generation tests"""
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
from yaml import safe_load
|
||||
|
||||
|
||||
class TestSchemaGeneration(APITestCase):
|
||||
"""Generic admin tests"""
|
||||
|
||||
def test_schema(self):
|
||||
"""Test generation"""
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:schema"),
|
||||
)
|
||||
self.assertTrue(safe_load(response.content.decode()))
|
||||
|
||||
def test_browser(self):
|
||||
"""Test API Browser"""
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:schema-browser"),
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
|
@ -1,31 +0,0 @@
|
|||
"""Swagger generation tests"""
|
||||
from json import loads
|
||||
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
from yaml import safe_load
|
||||
|
||||
|
||||
class TestSwaggerGeneration(APITestCase):
|
||||
"""Generic admin tests"""
|
||||
|
||||
def test_yaml(self):
|
||||
"""Test YAML generation"""
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:schema-json", kwargs={"format": ".yaml"}),
|
||||
)
|
||||
self.assertTrue(safe_load(response.content.decode()))
|
||||
|
||||
def test_json(self):
|
||||
"""Test JSON generation"""
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:schema-json", kwargs={"format": ".json"}),
|
||||
)
|
||||
self.assertTrue(loads(response.content.decode()))
|
||||
|
||||
def test_browser(self):
|
||||
"""Test API Browser"""
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:swagger"),
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
|
@ -1,10 +1,10 @@
|
|||
"""core Configs API"""
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.fields import BooleanField, CharField, ListField
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import ViewSet
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.lib.config import CONFIG
|
||||
|
@ -29,13 +29,13 @@ class ConfigSerializer(PassiveSerializer):
|
|||
error_reporting_send_pii = BooleanField(read_only=True)
|
||||
|
||||
|
||||
class ConfigsViewSet(ViewSet):
|
||||
class ConfigView(APIView):
|
||||
"""Read-only view set that returns the current session's Configs"""
|
||||
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
@swagger_auto_schema(responses={200: ConfigSerializer(many=False)})
|
||||
def list(self, request: Request) -> Response:
|
||||
@extend_schema(responses={200: ConfigSerializer(many=False)})
|
||||
def get(self, request: Request) -> Response:
|
||||
"""Retrive public configuration options"""
|
||||
config = ConfigSerializer(
|
||||
{
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
"""api v2 urls"""
|
||||
from django.urls import path, re_path
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.views import get_schema_view
|
||||
from django.urls import path
|
||||
from drf_spectacular.views import SpectacularAPIView
|
||||
from rest_framework import routers
|
||||
from rest_framework.permissions import AllowAny
|
||||
|
||||
from authentik.admin.api.meta import AppsViewSet
|
||||
from authentik.admin.api.metrics import AdministrationMetricsViewSet
|
||||
from authentik.admin.api.tasks import TaskViewSet
|
||||
from authentik.admin.api.version import VersionViewSet
|
||||
from authentik.admin.api.workers import WorkerViewSet
|
||||
from authentik.api.v2.config import ConfigsViewSet
|
||||
from authentik.api.views import SwaggerView
|
||||
from authentik.admin.api.version import VersionView
|
||||
from authentik.admin.api.workers import WorkerView
|
||||
from authentik.api.v2.config import ConfigView
|
||||
from authentik.api.views import APIBrowserView
|
||||
from authentik.core.api.applications import ApplicationViewSet
|
||||
from authentik.core.api.groups import GroupViewSet
|
||||
from authentik.core.api.propertymappings import PropertyMappingViewSet
|
||||
|
@ -100,11 +98,6 @@ from authentik.stages.user_write.api import UserWriteStageViewSet
|
|||
|
||||
router = routers.DefaultRouter()
|
||||
|
||||
router.register("root/config", ConfigsViewSet, basename="configs")
|
||||
|
||||
router.register("admin/version", VersionViewSet, basename="admin_version")
|
||||
router.register("admin/workers", WorkerViewSet, basename="admin_workers")
|
||||
router.register("admin/metrics", AdministrationMetricsViewSet, basename="admin_metrics")
|
||||
router.register("admin/system_tasks", TaskViewSet, basename="admin_system_tasks")
|
||||
router.register("admin/apps", AppsViewSet, basename="apps")
|
||||
|
||||
|
@ -114,7 +107,6 @@ router.register("core/users", UserViewSet)
|
|||
router.register("core/user_consent", UserConsentViewSet)
|
||||
router.register("core/tokens", TokenViewSet)
|
||||
|
||||
router.register("outposts/outposts", OutpostViewSet)
|
||||
router.register("outposts/instances", OutpostViewSet)
|
||||
router.register("outposts/service_connections/all", ServiceConnectionViewSet)
|
||||
router.register("outposts/service_connections/docker", DockerServiceConnectionViewSet)
|
||||
|
@ -196,32 +188,25 @@ router.register("stages/user_write", UserWriteStageViewSet)
|
|||
router.register("stages/dummy", DummyStageViewSet)
|
||||
router.register("policies/dummy", DummyPolicyViewSet)
|
||||
|
||||
info = openapi.Info(
|
||||
title="authentik API",
|
||||
default_version="v2beta",
|
||||
contact=openapi.Contact(email="hello@beryju.org"),
|
||||
license=openapi.License(
|
||||
name="GNU GPLv3",
|
||||
url="https://github.com/goauthentik/authentik/blob/master/LICENSE",
|
||||
),
|
||||
)
|
||||
SchemaView = get_schema_view(info, public=True, permission_classes=(AllowAny,))
|
||||
|
||||
urlpatterns = (
|
||||
[
|
||||
path("", SwaggerView.as_view(), name="swagger"),
|
||||
path("", APIBrowserView.as_view(), name="schema-browser"),
|
||||
]
|
||||
+ router.urls
|
||||
+ [
|
||||
path(
|
||||
"admin/metrics/",
|
||||
AdministrationMetricsViewSet.as_view(),
|
||||
name="admin_metrics",
|
||||
),
|
||||
path("admin/version/", VersionView.as_view(), name="admin_version"),
|
||||
path("admin/workers/", WorkerView.as_view(), name="admin_workers"),
|
||||
path("root/config/", ConfigView.as_view(), name="config"),
|
||||
path(
|
||||
"flows/executor/<slug:flow_slug>/",
|
||||
FlowExecutorView.as_view(),
|
||||
name="flow-executor",
|
||||
),
|
||||
re_path(
|
||||
r"^swagger(?P<format>\.json|\.yaml)$",
|
||||
SchemaView.without_ui(cache_timeout=0),
|
||||
name="schema-json",
|
||||
),
|
||||
path("schema/", SpectacularAPIView.as_view(), name="schema"),
|
||||
]
|
||||
)
|
||||
|
|
|
@ -5,18 +5,15 @@ from django.urls import reverse
|
|||
from django.views.generic import TemplateView
|
||||
|
||||
|
||||
class SwaggerView(TemplateView):
|
||||
"""Show swagger view based on rapi-doc"""
|
||||
class APIBrowserView(TemplateView):
|
||||
"""Show browser view based on rapi-doc"""
|
||||
|
||||
template_name = "api/swagger.html"
|
||||
template_name = "api/browser.html"
|
||||
|
||||
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
||||
path = self.request.build_absolute_uri(
|
||||
reverse(
|
||||
"authentik_api:schema-json",
|
||||
kwargs={
|
||||
"format": ".json",
|
||||
},
|
||||
"authentik_api:schema",
|
||||
)
|
||||
)
|
||||
return super().get_context_data(path=path, **kwargs)
|
||||
|
|
|
@ -5,8 +5,8 @@ from django.core.cache import cache
|
|||
from django.db.models import QuerySet
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
|
@ -58,6 +58,9 @@ class ApplicationSerializer(ModelSerializer):
|
|||
"meta_publisher",
|
||||
"policy_engine_mode",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"meta_icon": {"read_only": True},
|
||||
}
|
||||
|
||||
|
||||
class ApplicationViewSet(ModelViewSet):
|
||||
|
@ -92,10 +95,10 @@ class ApplicationViewSet(ModelViewSet):
|
|||
applications.append(application)
|
||||
return applications
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
204: "Access granted",
|
||||
403: "Access denied",
|
||||
204: OpenApiResponse(description="Access granted"),
|
||||
403: OpenApiResponse(description="Access denied"),
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=["GET"])
|
||||
|
@ -111,12 +114,12 @@ class ApplicationViewSet(ModelViewSet):
|
|||
return Response(status=204)
|
||||
return Response(status=403)
|
||||
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="superuser_full_list",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
@ -151,17 +154,20 @@ class ApplicationViewSet(ModelViewSet):
|
|||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
@permission_required("authentik_core.change_application")
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="file",
|
||||
in_=openapi.IN_FORM,
|
||||
type=openapi.TYPE_FILE,
|
||||
location=OpenApiParameter.QUERY, # TODO: In Form
|
||||
type=OpenApiTypes.BINARY,
|
||||
required=True,
|
||||
)
|
||||
],
|
||||
responses={200: "Success", 400: "Bad request"},
|
||||
responses={
|
||||
200: OpenApiResponse(description="Success"),
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
},
|
||||
)
|
||||
@action(
|
||||
detail=True,
|
||||
|
@ -184,7 +190,7 @@ class ApplicationViewSet(ModelViewSet):
|
|||
@permission_required(
|
||||
"authentik_core.view_application", ["authentik_events.view_event"]
|
||||
)
|
||||
@swagger_auto_schema(responses={200: CoordinateSerializer(many=True)})
|
||||
@extend_schema(responses={200: CoordinateSerializer(many=True)})
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=unused-argument
|
||||
def metrics(self, request: Request, slug: str):
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"""PropertyMapping API Views"""
|
||||
from json import dumps
|
||||
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
|
@ -81,7 +81,7 @@ class PropertyMappingViewSet(
|
|||
def get_queryset(self):
|
||||
return PropertyMapping.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable property-mapping types"""
|
||||
|
@ -100,14 +100,17 @@ class PropertyMappingViewSet(
|
|||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@permission_required("authentik_core.view_propertymapping")
|
||||
@swagger_auto_schema(
|
||||
request_body=PolicyTestSerializer(),
|
||||
responses={200: PropertyMappingTestResultSerializer, 400: "Invalid parameters"},
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
request=PolicyTestSerializer(),
|
||||
responses={
|
||||
200: PropertyMappingTestResultSerializer,
|
||||
400: OpenApiResponse(description="Invalid parameters"),
|
||||
},
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="format_result",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Provider API Views"""
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import ReadOnlyField
|
||||
|
@ -22,7 +22,7 @@ class ProviderSerializer(ModelSerializer, MetaNameSerializer):
|
|||
|
||||
component = SerializerMethodField()
|
||||
|
||||
def get_component(self, obj: Provider): # pragma: no cover
|
||||
def get_component(self, obj: Provider) -> str: # pragma: no cover
|
||||
"""Get object component so that we know how to edit the object"""
|
||||
# pyright: reportGeneralTypeIssues=false
|
||||
if obj.__class__ == Provider:
|
||||
|
@ -66,7 +66,7 @@ class ProviderViewSet(
|
|||
def get_queryset(self):
|
||||
return Provider.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable provider types"""
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Source API Views"""
|
||||
from typing import Iterable
|
||||
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
|
@ -24,7 +24,7 @@ class SourceSerializer(ModelSerializer, MetaNameSerializer):
|
|||
|
||||
component = SerializerMethodField()
|
||||
|
||||
def get_component(self, obj: Source):
|
||||
def get_component(self, obj: Source) -> str:
|
||||
"""Get object component so that we know how to edit the object"""
|
||||
# pyright: reportGeneralTypeIssues=false
|
||||
if obj.__class__ == Source:
|
||||
|
@ -64,7 +64,7 @@ class SourceViewSet(
|
|||
def get_queryset(self):
|
||||
return Source.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable source types"""
|
||||
|
@ -87,7 +87,7 @@ class SourceViewSet(
|
|||
)
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: UserSettingSerializer(many=True)})
|
||||
@extend_schema(responses={200: UserSettingSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def user_settings(self, request: Request) -> Response:
|
||||
"""Get all sources the user can configure"""
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Tokens API Viewset"""
|
||||
from django.http.response import Http404
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.request import Request
|
||||
|
@ -67,10 +67,10 @@ class TokenViewSet(ModelViewSet):
|
|||
serializer.save(user=self.request.user, intent=TokenIntents.INTENT_API)
|
||||
|
||||
@permission_required("authentik_core.view_token_key")
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: TokenViewSerializer(many=False),
|
||||
404: "Token not found or expired",
|
||||
404: OpenApiResponse(description="Token not found or expired"),
|
||||
}
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.urls import reverse_lazy
|
|||
from django.utils.http import urlencode
|
||||
from django_filters.filters import BooleanFilter, CharFilter
|
||||
from django_filters.filterset import FilterSet
|
||||
from drf_yasg.utils import swagger_auto_schema, swagger_serializer_method
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema, extend_schema_field
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, JSONField, SerializerMethodField
|
||||
|
@ -77,13 +77,13 @@ class UserMetricsSerializer(PassiveSerializer):
|
|||
logins_failed_per_1h = SerializerMethodField()
|
||||
authorizations_per_1h = SerializerMethodField()
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_logins_per_1h(self, _):
|
||||
"""Get successful logins per hour for the last 24 hours"""
|
||||
user = self.context["user"]
|
||||
return get_events_per_1h(action=EventAction.LOGIN, user__pk=user.pk)
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_logins_failed_per_1h(self, _):
|
||||
"""Get failed logins per hour for the last 24 hours"""
|
||||
user = self.context["user"]
|
||||
|
@ -91,7 +91,7 @@ class UserMetricsSerializer(PassiveSerializer):
|
|||
action=EventAction.LOGIN_FAILED, context__username=user.username
|
||||
)
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_authorizations_per_1h(self, _):
|
||||
"""Get failed logins per hour for the last 24 hours"""
|
||||
user = self.context["user"]
|
||||
|
@ -142,7 +142,7 @@ class UserViewSet(ModelViewSet):
|
|||
def get_queryset(self):
|
||||
return User.objects.all().exclude(pk=get_anonymous_user().pk)
|
||||
|
||||
@swagger_auto_schema(responses={200: SessionUserSerializer(many=False)})
|
||||
@extend_schema(responses={200: SessionUserSerializer(many=False)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=invalid-name
|
||||
def me(self, request: Request) -> Response:
|
||||
|
@ -158,7 +158,7 @@ class UserViewSet(ModelViewSet):
|
|||
return Response(serializer.data)
|
||||
|
||||
@permission_required("authentik_core.view_user", ["authentik_events.view_event"])
|
||||
@swagger_auto_schema(responses={200: UserMetricsSerializer(many=False)})
|
||||
@extend_schema(responses={200: UserMetricsSerializer(many=False)})
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
def metrics(self, request: Request, pk: int) -> Response:
|
||||
|
@ -169,8 +169,11 @@ class UserViewSet(ModelViewSet):
|
|||
return Response(serializer.data)
|
||||
|
||||
@permission_required("authentik_core.reset_user_password")
|
||||
@swagger_auto_schema(
|
||||
responses={"200": LinkSerializer(many=False), "404": "No recovery flow found."},
|
||||
@extend_schema(
|
||||
responses={
|
||||
"200": LinkSerializer(many=False),
|
||||
"404": OpenApiResponse(description="No recovery flow found."),
|
||||
},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
|
|
|
@ -28,6 +28,9 @@ class PassiveSerializer(Serializer):
|
|||
) -> Model: # pragma: no cover
|
||||
return Model()
|
||||
|
||||
class Meta:
|
||||
model = Model
|
||||
|
||||
|
||||
class MetaNameSerializer(PassiveSerializer):
|
||||
"""Add verbose names to response"""
|
||||
|
|
|
@ -5,8 +5,8 @@ from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
|||
from cryptography.x509 import load_pem_x509_certificate
|
||||
from django.http.response import HttpResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import (
|
||||
CharField,
|
||||
|
@ -125,9 +125,12 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
|||
filterset_class = CertificateKeyPairFilter
|
||||
|
||||
@permission_required(None, ["authentik_crypto.add_certificatekeypair"])
|
||||
@swagger_auto_schema(
|
||||
request_body=CertificateGenerationSerializer(),
|
||||
responses={200: CertificateKeyPairSerializer, 400: "Bad request"},
|
||||
@extend_schema(
|
||||
request=CertificateGenerationSerializer(),
|
||||
responses={
|
||||
200: CertificateKeyPairSerializer,
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
},
|
||||
)
|
||||
@action(detail=False, methods=["POST"])
|
||||
def generate(self, request: Request) -> Response:
|
||||
|
@ -147,12 +150,12 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
|||
serializer = self.get_serializer(instance)
|
||||
return Response(serializer.data)
|
||||
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
],
|
||||
responses={200: CertificateDataSerializer(many=False)},
|
||||
|
@ -180,12 +183,12 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
|||
CertificateDataSerializer({"data": certificate.certificate_data}).data
|
||||
)
|
||||
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
],
|
||||
responses={200: CertificateDataSerializer(many=False)},
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
import django_filters
|
||||
from django.db.models.aggregates import Count
|
||||
from django.db.models.fields.json import KeyTextTransform
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, DictField, IntegerField
|
||||
|
@ -38,12 +39,6 @@ class EventSerializer(ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class EventTopPerUserParams(PassiveSerializer):
|
||||
"""Query params for top_per_user"""
|
||||
|
||||
top_n = IntegerField(default=15)
|
||||
|
||||
|
||||
class EventTopPerUserSerializer(PassiveSerializer):
|
||||
"""Response object of Event's top_per_user"""
|
||||
|
||||
|
@ -111,12 +106,19 @@ class EventViewSet(ReadOnlyModelViewSet):
|
|||
]
|
||||
filterset_class = EventsFilter
|
||||
|
||||
@swagger_auto_schema(
|
||||
method="GET",
|
||||
@extend_schema(
|
||||
methods=["GET"],
|
||||
responses={200: EventTopPerUserSerializer(many=True)},
|
||||
query_serializer=EventTopPerUserParams,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
"top_n",
|
||||
type=OpenApiTypes.INT,
|
||||
location=OpenApiParameter.QUERY,
|
||||
required=False,
|
||||
)
|
||||
],
|
||||
)
|
||||
@action(detail=False, methods=["GET"])
|
||||
@action(detail=False, methods=["GET"], pagination_class=None)
|
||||
def top_per_user(self, request: Request):
|
||||
"""Get the top_n events grouped by user count"""
|
||||
filtered_action = request.query_params.get("action", EventAction.LOGIN)
|
||||
|
@ -134,7 +136,7 @@ class EventViewSet(ReadOnlyModelViewSet):
|
|||
.order_by("-counted_events")[:top_n]
|
||||
)
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def actions(self, request: Request) -> Response:
|
||||
"""Get all actions"""
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"""NotificationTransport API Views"""
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
||||
from rest_framework.request import Request
|
||||
|
@ -22,7 +23,7 @@ class NotificationTransportSerializer(ModelSerializer):
|
|||
|
||||
mode_verbose = SerializerMethodField()
|
||||
|
||||
def get_mode_verbose(self, instance: NotificationTransport):
|
||||
def get_mode_verbose(self, instance: NotificationTransport) -> str:
|
||||
"""Return selected mode with a UI Label"""
|
||||
return TransportMode(instance.mode).label
|
||||
|
||||
|
@ -58,12 +59,12 @@ class NotificationTransportViewSet(ModelViewSet):
|
|||
serializer_class = NotificationTransportSerializer
|
||||
|
||||
@permission_required("authentik_events.change_notificationtransport")
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: NotificationTransportTestSerializer(many=False),
|
||||
503: "Failed to test transport",
|
||||
500: OpenApiResponse(description="Failed to test transport"),
|
||||
},
|
||||
request_body=no_body,
|
||||
request=OpenApiTypes.NONE,
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[], methods=["post"])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
|
@ -83,4 +84,4 @@ class NotificationTransportViewSet(ModelViewSet):
|
|||
response.is_valid()
|
||||
return Response(response.data)
|
||||
except NotificationTransportError as exc:
|
||||
return Response(str(exc.__cause__ or None), status=503)
|
||||
return Response(str(exc.__cause__ or None), status=500)
|
||||
|
|
|
@ -6,8 +6,8 @@ from django.db.models import Model
|
|||
from django.http.response import HttpResponseBadRequest, JsonResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
|
@ -41,7 +41,7 @@ class FlowSerializer(ModelSerializer):
|
|||
|
||||
cache_count = SerializerMethodField()
|
||||
|
||||
def get_cache_count(self, flow: Flow):
|
||||
def get_cache_count(self, flow: Flow) -> int:
|
||||
"""Get count of cached flows"""
|
||||
return len(cache.keys(f"{cache_key(flow)}*"))
|
||||
|
||||
|
@ -61,6 +61,9 @@ class FlowSerializer(ModelSerializer):
|
|||
"cache_count",
|
||||
"policy_engine_mode",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"background": {"read_only": True},
|
||||
}
|
||||
|
||||
|
||||
class FlowDiagramSerializer(Serializer):
|
||||
|
@ -97,16 +100,19 @@ class FlowViewSet(ModelViewSet):
|
|||
filterset_fields = ["flow_uuid", "name", "slug", "designation"]
|
||||
|
||||
@permission_required(None, ["authentik_flows.view_flow_cache"])
|
||||
@swagger_auto_schema(responses={200: CacheSerializer(many=False)})
|
||||
@extend_schema(responses={200: CacheSerializer(many=False)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def cache_info(self, request: Request) -> Response:
|
||||
"""Info about cached flows"""
|
||||
return Response(data={"count": len(cache.keys("flow_*"))})
|
||||
|
||||
@permission_required(None, ["authentik_flows.clear_flow_cache"])
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
responses={204: "Successfully cleared cache", 400: "Bad request"},
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
responses={
|
||||
204: OpenApiResponse(description="Successfully cleared cache"),
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
},
|
||||
)
|
||||
@action(detail=False, methods=["POST"])
|
||||
def cache_clear(self, request: Request) -> Response:
|
||||
|
@ -133,17 +139,20 @@ class FlowViewSet(ModelViewSet):
|
|||
"authentik_stages_prompt.change_prompt",
|
||||
],
|
||||
)
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="file",
|
||||
in_=openapi.IN_FORM,
|
||||
type=openapi.TYPE_FILE,
|
||||
location=OpenApiParameter.QUERY, # TODO: Form
|
||||
type=OpenApiTypes.BINARY,
|
||||
required=True,
|
||||
)
|
||||
],
|
||||
responses={204: "Successfully imported flow", 400: "Bad request"},
|
||||
responses={
|
||||
204: OpenApiResponse(description="Successfully imported flow"),
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
},
|
||||
)
|
||||
@action(detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
|
||||
def import_flow(self, request: Request) -> Response:
|
||||
|
@ -171,11 +180,9 @@ class FlowViewSet(ModelViewSet):
|
|||
"authentik_stages_prompt.view_prompt",
|
||||
],
|
||||
)
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
"200": openapi.Response(
|
||||
"File Attachment", schema=openapi.Schema(type=openapi.TYPE_FILE)
|
||||
),
|
||||
"200": OpenApiResponse(response=OpenApiTypes.BINARY),
|
||||
},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
|
@ -188,7 +195,7 @@ class FlowViewSet(ModelViewSet):
|
|||
response["Content-Disposition"] = f'attachment; filename="{flow.slug}.akflow"'
|
||||
return response
|
||||
|
||||
@swagger_auto_schema(responses={200: FlowDiagramSerializer()})
|
||||
@extend_schema(responses={200: FlowDiagramSerializer()})
|
||||
@action(detail=True, pagination_class=None, filter_backends=[], methods=["get"])
|
||||
# pylint: disable=unused-argument
|
||||
def diagram(self, request: Request, slug: str) -> Response:
|
||||
|
@ -259,17 +266,20 @@ class FlowViewSet(ModelViewSet):
|
|||
return Response({"diagram": diagram})
|
||||
|
||||
@permission_required("authentik_flows.change_flow")
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="file",
|
||||
in_=openapi.IN_FORM,
|
||||
type=openapi.TYPE_FILE,
|
||||
location=OpenApiParameter.QUERY, # TODO: Form
|
||||
type=OpenApiTypes.BINARY,
|
||||
required=True,
|
||||
)
|
||||
],
|
||||
responses={200: "Success", 400: "Bad request"},
|
||||
responses={
|
||||
200: OpenApiResponse(description="Success"),
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
},
|
||||
)
|
||||
@action(
|
||||
detail=True,
|
||||
|
@ -289,8 +299,11 @@ class FlowViewSet(ModelViewSet):
|
|||
app.save()
|
||||
return Response({})
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={200: LinkSerializer(many=False), 400: "Flow not applicable"},
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: LinkSerializer(many=False),
|
||||
400: OpenApiResponse(description="Flow not applicable"),
|
||||
},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=unused-argument
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Flow Stage API Views"""
|
||||
from typing import Iterable
|
||||
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField
|
||||
|
@ -68,7 +68,7 @@ class StageViewSet(
|
|||
def get_queryset(self):
|
||||
return Stage.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable stage types"""
|
||||
|
@ -86,7 +86,7 @@ class StageViewSet(
|
|||
data = sorted(data, key=lambda x: x["name"])
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: StageUserSettingSerializer(many=True)})
|
||||
@extend_schema(responses={200: StageUserSettingSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def user_settings(self, request: Request) -> Response:
|
||||
"""Get all stages the user can configure"""
|
||||
|
|
|
@ -10,8 +10,8 @@ from django.template.response import TemplateResponse
|
|||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
||||
from django.views.generic import View
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.views import APIView
|
||||
from sentry_sdk import capture_exception
|
||||
|
@ -22,7 +22,6 @@ from authentik.events.models import cleanse_dict
|
|||
from authentik.flows.challenge import (
|
||||
AccessDeniedChallenge,
|
||||
Challenge,
|
||||
ChallengeResponse,
|
||||
ChallengeTypes,
|
||||
HttpChallengeResponse,
|
||||
RedirectChallenge,
|
||||
|
@ -125,19 +124,21 @@ class FlowExecutorView(APIView):
|
|||
self.current_stage_view.request = request
|
||||
return super().dispatch(request)
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: Challenge(),
|
||||
404: "No Token found", # This error can be raised by the email stage
|
||||
404: OpenApiResponse(
|
||||
description="No Token found"
|
||||
), # This error can be raised by the email stage
|
||||
},
|
||||
request_body=no_body,
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
"query",
|
||||
openapi.IN_QUERY,
|
||||
request=OpenApiTypes.NONE,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="query",
|
||||
location=OpenApiParameter.QUERY,
|
||||
required=True,
|
||||
description="Querystring as received",
|
||||
type=openapi.TYPE_STRING,
|
||||
type=OpenApiTypes.STR,
|
||||
)
|
||||
],
|
||||
operation_id="flows_executor_get",
|
||||
|
@ -157,16 +158,16 @@ class FlowExecutorView(APIView):
|
|||
self._logger.warning(exc)
|
||||
return to_stage_response(request, FlowErrorResponse(request, exc))
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={200: Challenge()},
|
||||
request_body=ChallengeResponse(),
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
"query",
|
||||
openapi.IN_QUERY,
|
||||
request=OpenApiTypes.OBJECT,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="query",
|
||||
location=OpenApiParameter.QUERY,
|
||||
required=True,
|
||||
description="Querystring as received",
|
||||
type=openapi.TYPE_STRING,
|
||||
type=OpenApiTypes.STR,
|
||||
)
|
||||
],
|
||||
operation_id="flows_executor_solve",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from dataclasses import asdict
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from kubernetes.client.configuration import Configuration
|
||||
from kubernetes.config.config_exception import ConfigException
|
||||
from kubernetes.config.kube_config import load_kube_config_from_dict
|
||||
|
@ -69,7 +69,7 @@ class ServiceConnectionViewSet(
|
|||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable service connection types"""
|
||||
|
@ -87,7 +87,7 @@ class ServiceConnectionViewSet(
|
|||
)
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: ServiceConnectionStateSerializer(many=False)})
|
||||
@extend_schema(responses={200: ServiceConnectionStateSerializer(many=False)})
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=unused-argument, invalid-name
|
||||
def state(self, request: Request, pk: str) -> Response:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Outpost API Views"""
|
||||
from dacite.core import from_dict
|
||||
from dacite.exceptions import DaciteError
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField, CharField, DateTimeField
|
||||
from rest_framework.request import Request
|
||||
|
@ -72,8 +72,8 @@ class OutpostViewSet(ModelViewSet):
|
|||
]
|
||||
ordering = ["name"]
|
||||
|
||||
@swagger_auto_schema(responses={200: OutpostHealthSerializer(many=True)})
|
||||
@action(methods=["GET"], detail=True)
|
||||
@extend_schema(responses={200: OutpostHealthSerializer(many=True)})
|
||||
@action(methods=["GET"], detail=True, pagination_class=None)
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
def health(self, request: Request, pk: int) -> Response:
|
||||
"""Get outposts current health"""
|
||||
|
@ -90,7 +90,7 @@ class OutpostViewSet(ModelViewSet):
|
|||
)
|
||||
return Response(OutpostHealthSerializer(states, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: OutpostDefaultConfigSerializer(many=False)})
|
||||
@extend_schema(responses={200: OutpostDefaultConfigSerializer(many=False)})
|
||||
@action(detail=False, methods=["GET"])
|
||||
def default_settings(self, request: Request) -> Response:
|
||||
"""Global default outpost config"""
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""policy API Views"""
|
||||
from django.core.cache import cache
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
|
@ -96,7 +97,7 @@ class PolicyViewSet(
|
|||
"bindings", "promptstage_set"
|
||||
)
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable policy types"""
|
||||
|
@ -114,16 +115,19 @@ class PolicyViewSet(
|
|||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@permission_required(None, ["authentik_policies.view_policy_cache"])
|
||||
@swagger_auto_schema(responses={200: CacheSerializer(many=False)})
|
||||
@extend_schema(responses={200: CacheSerializer(many=False)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def cache_info(self, request: Request) -> Response:
|
||||
"""Info about cached policies"""
|
||||
return Response(data={"count": len(cache.keys("policy_*"))})
|
||||
|
||||
@permission_required(None, ["authentik_policies.clear_policy_cache"])
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
responses={204: "Successfully cleared cache", 400: "Bad request"},
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
responses={
|
||||
204: OpenApiResponse(description="Successfully cleared cache"),
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
},
|
||||
)
|
||||
@action(detail=False, methods=["POST"])
|
||||
def cache_clear(self, request: Request) -> Response:
|
||||
|
@ -137,9 +141,12 @@ class PolicyViewSet(
|
|||
return Response(status=204)
|
||||
|
||||
@permission_required("authentik_policies.view_policy")
|
||||
@swagger_auto_schema(
|
||||
request_body=PolicyTestSerializer(),
|
||||
responses={200: PolicyTestResultSerializer(), 400: "Invalid parameters"},
|
||||
@extend_schema(
|
||||
request=PolicyTestSerializer(),
|
||||
responses={
|
||||
200: PolicyTestResultSerializer(),
|
||||
400: OpenApiResponse(description="Invalid parameters"),
|
||||
},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[], methods=["POST"])
|
||||
# pylint: disable=unused-argument, invalid-name
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""OAuth2Provider API Views"""
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import ReadOnlyField
|
||||
from rest_framework.generics import get_object_or_404
|
||||
|
@ -67,10 +67,10 @@ class OAuth2ProviderViewSet(ModelViewSet):
|
|||
queryset = OAuth2Provider.objects.all()
|
||||
serializer_class = OAuth2ProviderSerializer
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: OAuth2ProviderSetupURLs(many=False),
|
||||
404: "Provider has no application assigned",
|
||||
200: OAuth2ProviderSetupURLs,
|
||||
404: OpenApiResponse(description="Provider has no application assigned"),
|
||||
}
|
||||
)
|
||||
@action(methods=["GET"], detail=True)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""ProxyProvider API Views"""
|
||||
from typing import Any
|
||||
|
||||
from drf_yasg.utils import swagger_serializer_method
|
||||
from drf_spectacular.utils import extend_schema_field
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
|
@ -107,7 +107,7 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
|
|||
"forward_auth_mode",
|
||||
]
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=OpenIDConnectConfigurationSerializer)
|
||||
@extend_schema_field(OpenIDConnectConfigurationSerializer)
|
||||
def get_oidc_configuration(self, obj: ProxyProvider):
|
||||
"""Embed OpenID Connect provider information"""
|
||||
return ProviderInfoView(request=self.context["request"]._request).get_info(obj)
|
||||
|
|
|
@ -5,8 +5,8 @@ from defusedxml.ElementTree import fromstring
|
|||
from django.http.response import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, FileField, ReadOnlyField
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
|
@ -80,16 +80,16 @@ class SAMLProviderViewSet(ModelViewSet):
|
|||
queryset = SAMLProvider.objects.all()
|
||||
serializer_class = SAMLProviderSerializer
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: SAMLMetadataSerializer(many=False),
|
||||
404: "Provider has no application assigned",
|
||||
404: OpenApiResponse(description="Provider has no application assigned"),
|
||||
},
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
@ -118,9 +118,12 @@ class SAMLProviderViewSet(ModelViewSet):
|
|||
"authentik_crypto.add_certificatekeypair",
|
||||
],
|
||||
)
|
||||
@swagger_auto_schema(
|
||||
request_body=SAMLProviderImportSerializer(),
|
||||
responses={204: "Successfully imported provider", 400: "Bad request"},
|
||||
@extend_schema(
|
||||
request=SAMLProviderImportSerializer(),
|
||||
responses={
|
||||
204: OpenApiResponse(description="Successfully imported provider"),
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
},
|
||||
)
|
||||
@action(detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
|
||||
def import_metadata(self, request: Request) -> Response:
|
||||
|
|
|
@ -128,7 +128,7 @@ INSTALLED_APPS = [
|
|||
"authentik.stages.user_write",
|
||||
"rest_framework",
|
||||
"django_filters",
|
||||
"drf_yasg",
|
||||
"drf_spectacular",
|
||||
"guardian",
|
||||
"django_prometheus",
|
||||
"channels",
|
||||
|
@ -137,15 +137,28 @@ INSTALLED_APPS = [
|
|||
|
||||
GUARDIAN_MONKEY_PATCH = False
|
||||
|
||||
SWAGGER_SETTINGS = {
|
||||
"DEFAULT_AUTO_SCHEMA_CLASS": "authentik.api.schema.ErrorResponseAutoSchema",
|
||||
"DEFAULT_INFO": "authentik.api.v2.urls.info",
|
||||
"DEFAULT_PAGINATOR_INSPECTORS": [
|
||||
"authentik.api.pagination_schema.PaginationInspector",
|
||||
],
|
||||
"SECURITY_DEFINITIONS": {
|
||||
"Bearer": {"type": "apiKey", "name": "Authorization", "in": "header"}
|
||||
SPECTACULAR_SETTINGS = {
|
||||
"TITLE": "authentik",
|
||||
"DESCRIPTION": "Making authentication simple.",
|
||||
"VERSION": __version__,
|
||||
"COMPONENT_SPLIT_REQUEST": True,
|
||||
"CONTACT": {
|
||||
"email": "hello@beryju.org",
|
||||
},
|
||||
"LICENSE": {
|
||||
"name": "GNU GPLv3",
|
||||
"url": "https://github.com/goauthentik/authentik/blob/master/LICENSE",
|
||||
},
|
||||
"ENUM_NAME_OVERRIDES": {
|
||||
"ChallengeChoices": "authentik.flows.challenge.ChallengeTypes",
|
||||
"FlowDesignationEnum": "authentik.flows.models.FlowDesignation",
|
||||
"PolicyEngineMode": "authentik.policies.models.PolicyEngineMode",
|
||||
},
|
||||
"ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
|
||||
"POSTPROCESSING_HOOKS": [
|
||||
"authentik.api.schema.postprocess_schema_responses",
|
||||
"drf_spectacular.hooks.postprocess_schema_enums",
|
||||
],
|
||||
}
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
|
@ -167,6 +180,7 @@ REST_FRAMEWORK = {
|
|||
"DEFAULT_RENDERER_CLASSES": [
|
||||
"rest_framework.renderers.JSONRenderer",
|
||||
],
|
||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||
}
|
||||
|
||||
CACHES = {
|
||||
|
@ -446,7 +460,6 @@ _LOGGING_HANDLER_MAP = {
|
|||
"kubernetes": "INFO",
|
||||
"asyncio": "WARNING",
|
||||
"aioredis": "WARNING",
|
||||
"drf_yasg.utils": "WARNING",
|
||||
}
|
||||
for handler_name, level in _LOGGING_HANDLER_MAP.items():
|
||||
# pyright: reportGeneralTypeIssues=false
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Source API Views"""
|
||||
from django.http.response import Http404
|
||||
from django.utils.text import slugify
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
@ -48,8 +48,11 @@ class LDAPSourceViewSet(ModelViewSet):
|
|||
serializer_class = LDAPSourceSerializer
|
||||
lookup_field = "slug"
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={200: TaskSerializer(many=False), 404: "Task not found"}
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: TaskSerializer(many=False),
|
||||
404: OpenApiResponse(description="Task not found"),
|
||||
}
|
||||
)
|
||||
@action(methods=["GET"], detail=True)
|
||||
# pylint: disable=unused-argument
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""OAuth Source Serializer"""
|
||||
from django.urls.base import reverse_lazy
|
||||
from drf_yasg.utils import swagger_auto_schema, swagger_serializer_method
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_field
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField, CharField, SerializerMethodField
|
||||
from rest_framework.request import Request
|
||||
|
@ -43,7 +43,7 @@ class OAuthSourceSerializer(SourceSerializer):
|
|||
|
||||
type = SerializerMethodField()
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=SourceTypeSerializer)
|
||||
@extend_schema_field(SourceTypeSerializer)
|
||||
def get_type(self, instace: OAuthSource) -> SourceTypeSerializer:
|
||||
"""Get source's type configuration"""
|
||||
return SourceTypeSerializer(instace.type).data
|
||||
|
@ -85,7 +85,7 @@ class OAuthSourceViewSet(ModelViewSet):
|
|||
serializer_class = OAuthSourceSerializer
|
||||
lookup_field = "slug"
|
||||
|
||||
@swagger_auto_schema(responses={200: SourceTypeSerializer(many=True)})
|
||||
@extend_schema(responses={200: SourceTypeSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def source_types(self, request: Request) -> Response:
|
||||
"""Get all creatable source types"""
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Plex Source Serializer"""
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.fields import CharField
|
||||
|
@ -50,18 +50,18 @@ class PlexSourceViewSet(ModelViewSet):
|
|||
lookup_field = "slug"
|
||||
|
||||
@permission_required(None)
|
||||
@swagger_auto_schema(
|
||||
request_body=PlexTokenRedeemSerializer(),
|
||||
@extend_schema(
|
||||
request=PlexTokenRedeemSerializer(),
|
||||
responses={
|
||||
200: RedirectChallenge(),
|
||||
400: "Token not found",
|
||||
403: "Access denied",
|
||||
400: OpenApiResponse(description="Token not found"),
|
||||
403: OpenApiResponse(description="Access denied"),
|
||||
},
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="slug",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_STRING,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.STR,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""SAMLSource API Views"""
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
@ -39,7 +39,7 @@ class SAMLSourceViewSet(ModelViewSet):
|
|||
serializer_class = SAMLSourceSerializer
|
||||
lookup_field = "slug"
|
||||
|
||||
@swagger_auto_schema(responses={200: SAMLMetadataSerializer(many=False)})
|
||||
@extend_schema(responses={200: SAMLMetadataSerializer(many=False)})
|
||||
@action(methods=["GET"], detail=True)
|
||||
# pylint: disable=unused-argument
|
||||
def metadata(self, request: Request, slug: str) -> Response:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""AuthenticatorStaticStage API Views"""
|
||||
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, StaticToken
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
|
@ -27,14 +27,24 @@ class AuthenticatorStaticStageViewSet(ModelViewSet):
|
|||
serializer_class = AuthenticatorStaticStageSerializer
|
||||
|
||||
|
||||
class StaticDeviceTokenSerializer(ModelSerializer):
|
||||
"""Serializer for static device's tokens"""
|
||||
|
||||
class Meta:
|
||||
|
||||
model = StaticToken
|
||||
fields = ["token"]
|
||||
|
||||
|
||||
class StaticDeviceSerializer(ModelSerializer):
|
||||
"""Serializer for static authenticator devices"""
|
||||
|
||||
token_set = StaticDeviceTokenSerializer(many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
|
||||
model = StaticDevice
|
||||
fields = ["name", "token_set", "pk"]
|
||||
depth = 2
|
||||
|
||||
|
||||
class StaticDeviceViewSet(ModelViewSet):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""EmailStage API Views"""
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
@ -52,7 +52,7 @@ class EmailStageViewSet(ModelViewSet):
|
|||
queryset = EmailStage.objects.all()
|
||||
serializer_class = EmailStageSerializer
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def templates(self, request: Request) -> Response:
|
||||
"""Get all available templates, including custom templates"""
|
||||
|
|
|
@ -305,8 +305,7 @@ stages:
|
|||
displayName: Build static files for e2e
|
||||
inputs:
|
||||
script: |
|
||||
docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/api --additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
|
||||
sudo chmod 777 -R web/api/
|
||||
make gen-web
|
||||
cd web
|
||||
cd api && npm i && cd ..
|
||||
npm i
|
||||
|
@ -394,36 +393,19 @@ stages:
|
|||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: bash <(curl -s https://codecov.io/bash)
|
||||
- stage: generate
|
||||
jobs:
|
||||
- job: swagger_generate
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/api --additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: 'web/api/'
|
||||
artifact: 'ts_swagger_client'
|
||||
publishLocation: 'pipeline'
|
||||
- stage: Build
|
||||
jobs:
|
||||
- job: build_server
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@2
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'ts_swagger_client'
|
||||
path: "web/api/"
|
||||
versionSpec: '16.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: make gen-web
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
|
|
3
outpost/.gitignore
vendored
3
outpost/.gitignore
vendored
|
@ -1,2 +1 @@
|
|||
pkg/client/
|
||||
pkg/models/
|
||||
api/
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
all: clean generate
|
||||
|
||||
generate:
|
||||
go get -u github.com/go-swagger/go-swagger/cmd/swagger
|
||||
swagger generate client -f ../swagger.yaml -A authentik -t pkg/
|
||||
all: clean
|
||||
|
||||
run:
|
||||
go run -v .
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
# authentik outpost
|
||||
|
||||
[![CI Build status](https://img.shields.io/azure-devops/build/beryjuorg/authentik/3?style=flat-square)](https://dev.azure.com/beryjuorg/authentik/_build?definitionId=8)
|
||||
[![CI Build status](https://img.shields.io/azure-devops/build/beryjuorg/authentik/8?style=flat-square)](https://dev.azure.com/beryjuorg/authentik/_build?definitionId=8)
|
||||
![Docker pulls (proxy)](https://img.shields.io/docker/pulls/beryju/authentik-proxy.svg?style=flat-square)
|
||||
![Docker pulls (ldap)](https://img.shields.io/docker/pulls/beryju/authentik-ldap.svg?style=flat-square)
|
||||
|
||||
Reverse Proxy based on [oauth2_proxy](https://github.com/oauth2-proxy/oauth2-proxy), completely managed and monitored by authentik.
|
||||
|
||||
LDAP Server using [ldap](https://github.com/nmcclain/ldap), completely managed and monitored by authentik.
|
||||
|
||||
## Usage
|
||||
|
||||
authentik Proxy is built to be configured by authentik itself, hence the only options you can directly give it are connection params.
|
||||
authentik Outpost is built to be configured by authentik itself, hence the only options you can directly give it are connection params.
|
||||
|
||||
The following environment variable are implemented:
|
||||
|
||||
|
@ -19,6 +22,6 @@ The following environment variable are implemented:
|
|||
|
||||
## Development
|
||||
|
||||
authentik Proxy uses an auto-generated API Client to communicate with authentik. This client is not kept in git. To generate the client locally, run `make generate`.
|
||||
authentik outpost uses an auto-generated API Client to communicate with authentik. This client is not kept in git. To generate the client locally, run `make gen-outpost` in the root directory of the repo.
|
||||
|
||||
Afterwards you can build the proxy like any other Go project, using `go build`.
|
||||
Afterwards you can build the outpost like any other Go project, using `go build ./cmd/proxy/server.go` or `go build ./cmd/ldap/server.go`.
|
||||
|
|
|
@ -15,7 +15,7 @@ variables:
|
|||
stages:
|
||||
- stage: generate
|
||||
jobs:
|
||||
- job: swagger_generate
|
||||
- job: generate_api
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
|
@ -24,16 +24,11 @@ stages:
|
|||
version: '1.16.3'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo wget -O /usr/local/bin/swagger https://github.com/go-swagger/go-swagger/releases/latest/download/swagger_linux_amd64
|
||||
sudo chmod +x /usr/local/bin/swagger
|
||||
mkdir -p $(go env GOPATH)
|
||||
swagger generate client -f ../swagger.yaml -A authentik -t pkg/
|
||||
workingDirectory: 'outpost/'
|
||||
script: make gen-outpost
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: 'outpost/pkg/'
|
||||
artifact: 'go_swagger_client'
|
||||
targetPath: 'outpost/api/'
|
||||
artifact: 'go_api_client'
|
||||
publishLocation: 'pipeline'
|
||||
- stage: lint
|
||||
jobs:
|
||||
|
@ -47,12 +42,17 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'go_swagger_client'
|
||||
path: "outpost/pkg/"
|
||||
artifactName: 'go_api_client'
|
||||
path: "outpost/api/"
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.39.0 golangci-lint run -v --timeout 200s
|
||||
docker run \
|
||||
--rm \
|
||||
-v $(pwd):/app \
|
||||
-w /app \
|
||||
golangci/golangci-lint:v1.39.0 \
|
||||
golangci-lint run -v --timeout 200s
|
||||
workingDirectory: 'outpost/'
|
||||
- stage: build_go
|
||||
jobs:
|
||||
|
@ -66,8 +66,8 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'go_swagger_client'
|
||||
path: "outpost/pkg/"
|
||||
artifactName: 'go_api_client'
|
||||
path: "outpost/api/"
|
||||
- task: Go@0
|
||||
inputs:
|
||||
command: 'build'
|
||||
|
@ -83,8 +83,8 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'go_swagger_client'
|
||||
path: "outpost/pkg/"
|
||||
artifactName: 'go_api_client'
|
||||
path: "outpost/api/"
|
||||
- task: Go@0
|
||||
inputs:
|
||||
command: 'build'
|
||||
|
@ -102,8 +102,8 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'go_swagger_client'
|
||||
path: "outpost/pkg/"
|
||||
artifactName: 'go_api_client'
|
||||
path: "outpost/api/"
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
|
@ -138,8 +138,8 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'go_swagger_client'
|
||||
path: "outpost/pkg/"
|
||||
artifactName: 'go_api_client'
|
||||
path: "outpost/api/"
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
module goauthentik.io/outpost
|
||||
|
||||
go 1.14
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/felixge/httpsnoop v1.0.2 // indirect
|
||||
github.com/getsentry/sentry-go v0.10.0
|
||||
github.com/go-ldap/ldap/v3 v3.3.0
|
||||
github.com/go-openapi/analysis v0.20.1 // indirect
|
||||
github.com/go-openapi/errors v0.20.0
|
||||
github.com/go-openapi/errors v0.20.0 // indirect
|
||||
github.com/go-openapi/runtime v0.19.28
|
||||
github.com/go-openapi/strfmt v0.20.1
|
||||
github.com/go-openapi/swag v0.19.15
|
||||
github.com/go-openapi/validate v0.20.2
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-openapi/validate v0.20.2 // indirect
|
||||
github.com/go-redis/redis/v7 v7.4.0 // indirect
|
||||
github.com/go-swagger/go-swagger v0.27.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||
github.com/justinas/alice v1.2.0
|
||||
|
@ -25,9 +23,9 @@ require (
|
|||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 // indirect
|
||||
github.com/nmcclain/ldap v0.0.0-20191021200707-3b3b69a7e9e3 // indirect
|
||||
github.com/nmcclain/ldap v0.0.0-20191021200707-3b3b69a7e9e3
|
||||
github.com/oauth2-proxy/oauth2-proxy v0.0.0-20200831161845-e4e5580852dc
|
||||
github.com/pelletier/go-toml v1.9.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.1 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac // indirect
|
||||
github.com/recws-org/recws v1.3.1
|
||||
|
@ -37,10 +35,11 @@ require (
|
|||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.7.1 // indirect
|
||||
go.mongodb.org/mongo-driver v1.5.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
||||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 // indirect
|
||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 // indirect
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
||||
|
|
|
@ -43,7 +43,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
|||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
|
||||
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
|
||||
github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYIc=
|
||||
github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI=
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
|
@ -104,7 +103,6 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
|||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
@ -126,9 +124,6 @@ github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHj
|
|||
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
|
||||
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/frankban/quicktest v1.10.0 h1:Gfh+GAJZOAoKZsIZeZbdn2JF10kN1XHNvjsvQK8gVkE=
|
||||
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
|
@ -177,8 +172,6 @@ github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX
|
|||
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.20.0 h1:Sxpo9PjEHDzhs3FbnGNonvDgWcMW2U7wGTcDDSFSceM=
|
||||
github.com/go-openapi/errors v0.20.0/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
|
@ -208,7 +201,6 @@ github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29g
|
|||
github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo=
|
||||
github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98=
|
||||
github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk=
|
||||
github.com/go-openapi/runtime v0.19.27/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M=
|
||||
github.com/go-openapi/runtime v0.19.28 h1:9lYu6axek8LJrVkMVViVirRcpoaCxXX7+sSvmizGVnA=
|
||||
github.com/go-openapi/runtime v0.19.28/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M=
|
||||
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
|
@ -259,9 +251,6 @@ github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRf
|
|||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-swagger/go-swagger v0.27.0 h1:K7+nkBuf4oS1jTBrdvWqYFpqD69V5CN8HamZzCDDhAI=
|
||||
github.com/go-swagger/go-swagger v0.27.0/go.mod h1:WodZVysInJilkW7e6IRw+dZGp5yW6rlMFZ4cb+THl9A=
|
||||
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0=
|
||||
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
||||
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
|
||||
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
|
||||
|
@ -323,7 +312,6 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
|
|||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/gomodule/redigo v1.8.1 h1:Abmo0bI7Xf0IhdIPc7HZQzZcShdnmxeoVuDDtIQp8N8=
|
||||
github.com/gomodule/redigo v1.8.1/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
@ -350,7 +338,6 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
|
|||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
@ -359,8 +346,6 @@ github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+
|
|||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
|
@ -399,8 +384,6 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/
|
|||
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
|
||||
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
|
||||
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
|
||||
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
|
@ -464,7 +447,6 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
|
|||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
|
@ -532,9 +514,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP
|
|||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
|
||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||
github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0=
|
||||
github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml v1.9.1 h1:a6qW1EVNZWH9WGI6CsYdD8WAylkoXBS5yv0XHlh17Tc=
|
||||
github.com/pelletier/go-toml v1.9.1/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI=
|
||||
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||
|
@ -567,7 +548,6 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
|||
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
||||
|
@ -594,7 +574,6 @@ github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
|||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
|
@ -603,7 +582,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
@ -621,8 +599,6 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
|||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ=
|
||||
github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
|
@ -657,7 +633,6 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ
|
|||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191213034115-f46add6fdb5c/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
|
||||
|
@ -670,8 +645,9 @@ go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS
|
|||
go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI=
|
||||
go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw=
|
||||
go.mongodb.org/mongo-driver v1.5.2 h1:AsxOLoJTgP6YNM0fXWw4OjdluYmWzQYp+lFJL7xu9fU=
|
||||
go.mongodb.org/mongo-driver v1.5.2/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
|
@ -731,8 +707,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -773,15 +747,13 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/
|
|||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210331060903-cb1fcc7394e5/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk=
|
||||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -798,7 +770,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -849,12 +820,9 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM=
|
||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -921,8 +889,6 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
|
|||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
package ak
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/recws-org/recws"
|
||||
"goauthentik.io/outpost/api"
|
||||
"goauthentik.io/outpost/pkg"
|
||||
"goauthentik.io/outpost/pkg/client"
|
||||
"goauthentik.io/outpost/pkg/client/outposts"
|
||||
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -25,8 +25,7 @@ const ConfigErrorReportingEnvironment = "error_reporting_environment"
|
|||
|
||||
// APIController main controller which connects to the authentik api via http and ws
|
||||
type APIController struct {
|
||||
Client *client.Authentik
|
||||
Auth runtime.ClientAuthInfoWriter
|
||||
Client *api.APIClient
|
||||
token string
|
||||
|
||||
Server Outpost
|
||||
|
@ -41,31 +40,32 @@ type APIController struct {
|
|||
|
||||
// NewAPIController initialise new API Controller instance from URL and API token
|
||||
func NewAPIController(akURL url.URL, token string) *APIController {
|
||||
transport := httptransport.New(akURL.Host, client.DefaultBasePath, []string{akURL.Scheme})
|
||||
transport.Transport = SetUserAgent(GetTLSTransport(), pkg.UserAgent())
|
||||
|
||||
// create the transport
|
||||
auth := httptransport.BearerToken(token)
|
||||
config := api.NewConfiguration()
|
||||
config.Host = akURL.Host
|
||||
config.Scheme = akURL.Scheme
|
||||
config.HTTPClient = &http.Client{
|
||||
Transport: SetUserAgent(GetTLSTransport(), pkg.UserAgent()),
|
||||
}
|
||||
config.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||
|
||||
// create the API client, with the transport
|
||||
apiClient := client.New(transport, strfmt.Default)
|
||||
apiClient := api.NewAPIClient(config)
|
||||
|
||||
log := log.WithField("logger", "authentik.outpost.ak-api-controller")
|
||||
|
||||
// Because we don't know the outpost UUID, we simply do a list and pick the first
|
||||
// The service account this token belongs to should only have access to a single outpost
|
||||
outposts, err := apiClient.Outposts.OutpostsInstancesList(outposts.NewOutpostsInstancesListParams(), auth)
|
||||
outposts, _, err := apiClient.OutpostsApi.OutpostsInstancesList(context.Background()).Execute()
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to fetch configuration")
|
||||
os.Exit(1)
|
||||
}
|
||||
outpost := outposts.Payload.Results[0]
|
||||
doGlobalSetup(outpost.Config.(map[string]interface{}))
|
||||
outpost := outposts.Results[0]
|
||||
doGlobalSetup(outpost.Config)
|
||||
|
||||
ac := &APIController{
|
||||
Client: apiClient,
|
||||
Auth: auth,
|
||||
token: token,
|
||||
|
||||
logger: log,
|
||||
|
@ -74,7 +74,7 @@ func NewAPIController(akURL url.URL, token string) *APIController {
|
|||
instanceUUID: uuid.New(),
|
||||
}
|
||||
ac.logger.Debugf("HA Reload offset: %s", ac.reloadOffset)
|
||||
ac.initWS(akURL, outpost.Pk)
|
||||
ac.initWS(akURL, strfmt.UUID(outpost.Pk))
|
||||
return ac
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package ak
|
||||
|
||||
import (
|
||||
"goauthentik.io/outpost/pkg/client/outposts"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
"context"
|
||||
|
||||
"goauthentik.io/outpost/api"
|
||||
)
|
||||
|
||||
func (a *APIController) Update() ([]*models.ProxyOutpostConfig, error) {
|
||||
providers, err := a.Client.Outposts.OutpostsProxyList(outposts.NewOutpostsProxyListParams(), a.Auth)
|
||||
func (a *APIController) Update() ([]api.ProxyOutpostConfig, error) {
|
||||
providers, _, err := a.Client.OutpostsApi.OutpostsProxyList(context.Background()).Execute()
|
||||
if err != nil {
|
||||
a.logger.WithError(err).Error("Failed to fetch providers")
|
||||
return nil, err
|
||||
}
|
||||
return providers.Payload.Results, nil
|
||||
return providers.Results, nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ldap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
@ -9,28 +10,27 @@ import (
|
|||
|
||||
"github.com/go-openapi/strfmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/outpost/pkg/client/outposts"
|
||||
)
|
||||
|
||||
func (ls *LDAPServer) Refresh() error {
|
||||
outposts, err := ls.ac.Client.Outposts.OutpostsLdapList(outposts.NewOutpostsLdapListParams(), ls.ac.Auth)
|
||||
outposts, _, err := ls.ac.Client.OutpostsApi.OutpostsLdapList(context.Background()).Execute()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(outposts.Payload.Results) < 1 {
|
||||
if len(outposts.Results) < 1 {
|
||||
return errors.New("no ldap provider defined")
|
||||
}
|
||||
providers := make([]*ProviderInstance, len(outposts.Payload.Results))
|
||||
for idx, provider := range outposts.Payload.Results {
|
||||
userDN := strings.ToLower(fmt.Sprintf("ou=users,%s", provider.BaseDn))
|
||||
groupDN := strings.ToLower(fmt.Sprintf("ou=groups,%s", provider.BaseDn))
|
||||
providers := make([]*ProviderInstance, len(outposts.Results))
|
||||
for idx, provider := range outposts.Results {
|
||||
userDN := strings.ToLower(fmt.Sprintf("ou=users,%s", *provider.BaseDn))
|
||||
groupDN := strings.ToLower(fmt.Sprintf("ou=groups,%s", *provider.BaseDn))
|
||||
providers[idx] = &ProviderInstance{
|
||||
BaseDN: provider.BaseDn,
|
||||
BaseDN: *provider.BaseDn,
|
||||
GroupDN: groupDN,
|
||||
UserDN: userDN,
|
||||
appSlug: *provider.ApplicationSlug,
|
||||
flowSlug: *provider.BindFlowSlug,
|
||||
searchAllowedGroups: []*strfmt.UUID{provider.SearchGroup},
|
||||
appSlug: provider.ApplicationSlug,
|
||||
flowSlug: provider.BindFlowSlug,
|
||||
searchAllowedGroups: []*strfmt.UUID{(*strfmt.UUID)(provider.SearchGroup.Get())},
|
||||
boundUsersMutex: sync.RWMutex{},
|
||||
boundUsers: make(map[string]UserFlags),
|
||||
s: ls,
|
||||
|
|
|
@ -12,25 +12,14 @@ import (
|
|||
"time"
|
||||
|
||||
goldap "github.com/go-ldap/ldap/v3"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/nmcclain/ldap"
|
||||
"goauthentik.io/outpost/api"
|
||||
"goauthentik.io/outpost/pkg"
|
||||
"goauthentik.io/outpost/pkg/ak"
|
||||
"goauthentik.io/outpost/pkg/client/core"
|
||||
"goauthentik.io/outpost/pkg/client/flows"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
)
|
||||
|
||||
const ContextUserKey = "ak_user"
|
||||
|
||||
type UIDResponse struct {
|
||||
UIDFIeld string `json:"uid_field"`
|
||||
}
|
||||
|
||||
type PasswordResponse struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func (pi *ProviderInstance) getUsername(dn string) (string, error) {
|
||||
if !strings.HasSuffix(strings.ToLower(dn), strings.ToLower(pi.BaseDN)) {
|
||||
return "", errors.New("invalid base DN")
|
||||
|
@ -60,16 +49,25 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne
|
|||
pi.log.WithError(err).Warning("Failed to get remote IP")
|
||||
return ldap.LDAPResultOperationsError, nil
|
||||
}
|
||||
|
||||
// Create new http client that also sets the correct ip
|
||||
client := &http.Client{
|
||||
config := api.NewConfiguration()
|
||||
// Carry over the bearer authentication, so that failed login attempts are attributed to the outpost
|
||||
config.DefaultHeader = pi.s.ac.Client.GetConfig().DefaultHeader
|
||||
config.Host = pi.s.ac.Client.GetConfig().Host
|
||||
config.Scheme = pi.s.ac.Client.GetConfig().Scheme
|
||||
config.HTTPClient = &http.Client{
|
||||
Jar: jar,
|
||||
Transport: newTransport(ak.SetUserAgent(ak.GetTLSTransport(), pkg.UserAgent()), map[string]string{
|
||||
"X-authentik-remote-ip": host,
|
||||
}),
|
||||
}
|
||||
// create the API client, with the transport
|
||||
apiClient := api.NewAPIClient(config)
|
||||
|
||||
params := url.Values{}
|
||||
params.Add("goauthentik.io/outpost/ldap", "true")
|
||||
passed, err := pi.solveFlowChallenge(username, bindPW, client, params.Encode(), 1)
|
||||
passed, err := pi.solveFlowChallenge(username, bindPW, apiClient, params.Encode(), 1)
|
||||
if err != nil {
|
||||
pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to solve challenge")
|
||||
return ldap.LDAPResultOperationsError, nil
|
||||
|
@ -77,33 +75,26 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne
|
|||
if !passed {
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
_, err = pi.s.ac.Client.Core.CoreApplicationsCheckAccess(&core.CoreApplicationsCheckAccessParams{
|
||||
Slug: pi.appSlug,
|
||||
Context: context.Background(),
|
||||
HTTPClient: client,
|
||||
}, httptransport.PassThroughAuth)
|
||||
r, err := pi.s.ac.Client.CoreApi.CoreApplicationsCheckAccessRetrieve(context.Background(), pi.appSlug).Execute()
|
||||
if r.StatusCode == 403 {
|
||||
pi.log.WithField("bindDN", bindDN).Info("Access denied for user")
|
||||
return ldap.LDAPResultInsufficientAccessRights, nil
|
||||
}
|
||||
if err != nil {
|
||||
if _, denied := err.(*core.CoreApplicationsCheckAccessForbidden); denied {
|
||||
pi.log.WithField("bindDN", bindDN).Info("Access denied for user")
|
||||
return ldap.LDAPResultInsufficientAccessRights, nil
|
||||
}
|
||||
pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to check access")
|
||||
return ldap.LDAPResultOperationsError, nil
|
||||
}
|
||||
pi.log.WithField("bindDN", bindDN).Info("User has access")
|
||||
// Get user info to store in context
|
||||
userInfo, err := pi.s.ac.Client.Core.CoreUsersMe(&core.CoreUsersMeParams{
|
||||
Context: context.Background(),
|
||||
HTTPClient: client,
|
||||
}, httptransport.PassThroughAuth)
|
||||
userInfo, _, err := pi.s.ac.Client.CoreApi.CoreUsersMeRetrieve(context.Background()).Execute()
|
||||
if err != nil {
|
||||
pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to get user info")
|
||||
return ldap.LDAPResultOperationsError, nil
|
||||
}
|
||||
pi.boundUsersMutex.Lock()
|
||||
pi.boundUsers[bindDN] = UserFlags{
|
||||
UserInfo: *userInfo.Payload.User,
|
||||
CanSearch: pi.SearchAccessCheck(userInfo.Payload.User),
|
||||
UserInfo: userInfo.User,
|
||||
CanSearch: pi.SearchAccessCheck(userInfo.User),
|
||||
}
|
||||
defer pi.boundUsersMutex.Unlock()
|
||||
pi.delayDeleteUserInfo(username)
|
||||
|
@ -111,11 +102,11 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne
|
|||
}
|
||||
|
||||
// SearchAccessCheck Check if the current user is allowed to search
|
||||
func (pi *ProviderInstance) SearchAccessCheck(user *models.User) bool {
|
||||
func (pi *ProviderInstance) SearchAccessCheck(user api.User) bool {
|
||||
for _, group := range user.Groups {
|
||||
for _, allowedGroup := range pi.searchAllowedGroups {
|
||||
pi.log.WithField("userGroup", group.Pk).WithField("allowedGroup", allowedGroup).Trace("Checking search access")
|
||||
if group.Pk.String() == allowedGroup.String() {
|
||||
if group.Pk == allowedGroup.String() {
|
||||
pi.log.WithField("group", group.Name).Info("Allowed access to search")
|
||||
return true
|
||||
}
|
||||
|
@ -142,51 +133,48 @@ func (pi *ProviderInstance) delayDeleteUserInfo(dn string) {
|
|||
}()
|
||||
}
|
||||
|
||||
func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, client *http.Client, urlParams string, depth int) (bool, error) {
|
||||
challenge, err := pi.s.ac.Client.Flows.FlowsExecutorGet(&flows.FlowsExecutorGetParams{
|
||||
FlowSlug: pi.flowSlug,
|
||||
Query: urlParams,
|
||||
Context: context.Background(),
|
||||
HTTPClient: client,
|
||||
}, pi.s.ac.Auth)
|
||||
func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, client *api.APIClient, urlParams string, depth int) (bool, error) {
|
||||
req := client.FlowsApi.FlowsExecutorGet(context.Background(), pi.flowSlug)
|
||||
req.Query(urlParams)
|
||||
challenge, _, err := req.Execute()
|
||||
if err != nil {
|
||||
pi.log.WithError(err).Warning("Failed to get challenge")
|
||||
return false, err
|
||||
}
|
||||
pi.log.WithField("component", challenge.Payload.Component).WithField("type", *challenge.Payload.Type).Debug("Got challenge")
|
||||
responseParams := &flows.FlowsExecutorSolveParams{
|
||||
FlowSlug: pi.flowSlug,
|
||||
Query: urlParams,
|
||||
Context: context.Background(),
|
||||
HTTPClient: client,
|
||||
}
|
||||
switch challenge.Payload.Component {
|
||||
pi.log.WithField("component", challenge.Component).WithField("type", challenge.Type).Debug("Got challenge")
|
||||
responseReq := client.FlowsApi.FlowsExecutorSolve(context.Background(), pi.flowSlug)
|
||||
responseReq.Query(urlParams)
|
||||
switch *challenge.Component {
|
||||
case "ak-stage-identification":
|
||||
responseParams.Data = &UIDResponse{UIDFIeld: bindDN}
|
||||
responseReq.RequestBody(map[string]interface{}{
|
||||
"uid_field": bindDN,
|
||||
})
|
||||
case "ak-stage-password":
|
||||
responseParams.Data = &PasswordResponse{Password: password}
|
||||
responseReq.RequestBody(map[string]interface{}{
|
||||
"password": password,
|
||||
})
|
||||
case "ak-stage-access-denied":
|
||||
return false, errors.New("got ak-stage-access-denied")
|
||||
default:
|
||||
return false, fmt.Errorf("unsupported challenge type: %s", challenge.Payload.Component)
|
||||
return false, fmt.Errorf("unsupported challenge type: %s", *challenge.Component)
|
||||
}
|
||||
response, err := pi.s.ac.Client.Flows.FlowsExecutorSolve(responseParams, pi.s.ac.Auth)
|
||||
pi.log.WithField("component", response.Payload.Component).WithField("type", *response.Payload.Type).Debug("Got response")
|
||||
switch response.Payload.Component {
|
||||
response, _, err := responseReq.Execute()
|
||||
pi.log.WithField("component", response.Component).WithField("type", response.Type).Debug("Got response")
|
||||
switch *response.Component {
|
||||
case "ak-stage-access-denied":
|
||||
return false, errors.New("got ak-stage-access-denied")
|
||||
}
|
||||
if *response.Payload.Type == "redirect" {
|
||||
if response.Type == "redirect" {
|
||||
return true, nil
|
||||
}
|
||||
if err != nil {
|
||||
pi.log.WithError(err).Warning("Failed to submit challenge")
|
||||
return false, err
|
||||
}
|
||||
if len(response.Payload.ResponseErrors) > 0 {
|
||||
for key, errs := range response.Payload.ResponseErrors {
|
||||
if len(*response.ResponseErrors) > 0 {
|
||||
for key, errs := range *response.ResponseErrors {
|
||||
for _, err := range errs {
|
||||
pi.log.WithField("key", key).WithField("code", *err.Code).Debug(*err.String)
|
||||
pi.log.WithField("key", key).WithField("code", err.Code).Debug(err.String)
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package ldap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
"goauthentik.io/outpost/pkg/client/core"
|
||||
)
|
||||
|
||||
func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) {
|
||||
|
@ -43,16 +43,16 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest,
|
|||
default:
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, searchReq.Filter)
|
||||
case GroupObjectClass:
|
||||
groups, err := pi.s.ac.Client.Core.CoreGroupsList(core.NewCoreGroupsListParams(), pi.s.ac.Auth)
|
||||
groups, _, err := pi.s.ac.Client.CoreApi.CoreGroupsList(context.Background()).Execute()
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("API Error: %s", err)
|
||||
}
|
||||
pi.log.WithField("count", len(groups.Payload.Results)).Trace("Got results from API")
|
||||
for _, g := range groups.Payload.Results {
|
||||
pi.log.WithField("count", len(groups.Results)).Trace("Got results from API")
|
||||
for _, g := range groups.Results {
|
||||
attrs := []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "cn",
|
||||
Values: []string{*g.Name},
|
||||
Values: []string{g.Name},
|
||||
},
|
||||
{
|
||||
Name: "uid",
|
||||
|
@ -69,31 +69,31 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest,
|
|||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
case UserObjectClass, "":
|
||||
users, err := pi.s.ac.Client.Core.CoreUsersList(core.NewCoreUsersListParams(), pi.s.ac.Auth)
|
||||
users, _, err := pi.s.ac.Client.CoreApi.CoreUsersList(context.Background()).Execute()
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("API Error: %s", err)
|
||||
}
|
||||
for _, u := range users.Payload.Results {
|
||||
for _, u := range users.Results {
|
||||
attrs := []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "cn",
|
||||
Values: []string{*u.Username},
|
||||
Values: []string{u.Username},
|
||||
},
|
||||
{
|
||||
Name: "uid",
|
||||
Values: []string{u.UID},
|
||||
Values: []string{u.Uid},
|
||||
},
|
||||
{
|
||||
Name: "name",
|
||||
Values: []string{*u.Name},
|
||||
Values: []string{u.Name},
|
||||
},
|
||||
{
|
||||
Name: "displayName",
|
||||
Values: []string{*u.Name},
|
||||
Values: []string{u.Name},
|
||||
},
|
||||
{
|
||||
Name: "mail",
|
||||
Values: []string{u.Email.String()},
|
||||
Values: []string{*u.Email},
|
||||
},
|
||||
{
|
||||
Name: "objectClass",
|
||||
|
@ -101,13 +101,13 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest,
|
|||
},
|
||||
}
|
||||
|
||||
if u.IsActive {
|
||||
if *u.IsActive {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"inactive"}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"active"}})
|
||||
}
|
||||
|
||||
if *u.IsSuperuser {
|
||||
if u.IsSuperuser {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "superuser", Values: []string{"inactive"}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "superuser", Values: []string{"active"}})
|
||||
|
@ -117,7 +117,7 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest,
|
|||
|
||||
attrs = append(attrs, AKAttrsToLDAP(u.Attributes)...)
|
||||
|
||||
dn := fmt.Sprintf("cn=%s,%s", *u.Username, pi.UserDN)
|
||||
dn := fmt.Sprintf("cn=%s,%s", u.Username, pi.UserDN)
|
||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ import (
|
|||
|
||||
"github.com/go-openapi/strfmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/outpost/api"
|
||||
"goauthentik.io/outpost/pkg/ak"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
)
|
||||
|
@ -31,7 +31,7 @@ type ProviderInstance struct {
|
|||
}
|
||||
|
||||
type UserFlags struct {
|
||||
UserInfo models.User
|
||||
UserInfo api.User
|
||||
CanSearch bool
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
"goauthentik.io/outpost/api"
|
||||
)
|
||||
|
||||
func AKAttrsToLDAP(attrs interface{}) []*ldap.EntryAttribute {
|
||||
|
@ -22,7 +22,7 @@ func AKAttrsToLDAP(attrs interface{}) []*ldap.EntryAttribute {
|
|||
return attrList
|
||||
}
|
||||
|
||||
func (pi *ProviderInstance) GroupsForUser(user *models.User) []string {
|
||||
func (pi *ProviderInstance) GroupsForUser(user api.User) []string {
|
||||
groups := make([]string, len(user.Groups))
|
||||
for i, group := range user.Groups {
|
||||
groups[i] = pi.GetGroupDN(group)
|
||||
|
@ -30,6 +30,6 @@ func (pi *ProviderInstance) GroupsForUser(user *models.User) []string {
|
|||
return groups
|
||||
}
|
||||
|
||||
func (pi *ProviderInstance) GetGroupDN(group *models.Group) string {
|
||||
return fmt.Sprintf("cn=%s,%s", *group.Name, pi.GroupDN)
|
||||
func (pi *ProviderInstance) GetGroupDN(group api.Group) string {
|
||||
return fmt.Sprintf("cn=%s,%s", group.Name, pi.GroupDN)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net/url"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
"goauthentik.io/outpost/api"
|
||||
)
|
||||
|
||||
func (s *Server) Refresh() error {
|
||||
|
@ -21,10 +21,10 @@ func (s *Server) Refresh() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) bundleProviders(providers []*models.ProxyOutpostConfig) []*providerBundle {
|
||||
func (s *Server) bundleProviders(providers []api.ProxyOutpostConfig) []*providerBundle {
|
||||
bundles := make([]*providerBundle, len(providers))
|
||||
for idx, provider := range providers {
|
||||
externalHost, err := url.Parse(*provider.ExternalHost)
|
||||
externalHost, err := url.Parse(provider.ExternalHost)
|
||||
if err != nil {
|
||||
log.WithError(err).Warning("Failed to parse URL, skipping provider")
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@ import (
|
|||
"github.com/oauth2-proxy/oauth2-proxy/pkg/middleware"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/outpost/pkg/client/crypto"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
"goauthentik.io/outpost/api"
|
||||
)
|
||||
|
||||
type providerBundle struct {
|
||||
|
@ -35,8 +34,8 @@ func intToPointer(i int) *int {
|
|||
return &i
|
||||
}
|
||||
|
||||
func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *options.Options {
|
||||
externalHost, err := url.Parse(*provider.ExternalHost)
|
||||
func (pb *providerBundle) prepareOpts(provider api.ProxyOutpostConfig) *options.Options {
|
||||
externalHost, err := url.Parse(provider.ExternalHost)
|
||||
if err != nil {
|
||||
log.WithError(err).Warning("Failed to parse URL, skipping provider")
|
||||
return nil
|
||||
|
@ -47,25 +46,25 @@ func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *opti
|
|||
log.WithError(err).Warning("Failed to copy options, skipping provider")
|
||||
return nil
|
||||
}
|
||||
providerOpts.ClientID = provider.ClientID
|
||||
providerOpts.ClientSecret = provider.ClientSecret
|
||||
providerOpts.ClientID = *provider.ClientId
|
||||
providerOpts.ClientSecret = *provider.ClientSecret
|
||||
|
||||
providerOpts.Cookie.Secret = provider.CookieSecret
|
||||
providerOpts.Cookie.Secret = *provider.CookieSecret
|
||||
providerOpts.Cookie.Secure = externalHost.Scheme == "https"
|
||||
|
||||
providerOpts.SkipOIDCDiscovery = true
|
||||
providerOpts.OIDCIssuerURL = *provider.OidcConfiguration.Issuer
|
||||
providerOpts.LoginURL = *provider.OidcConfiguration.AuthorizationEndpoint
|
||||
providerOpts.RedeemURL = *provider.OidcConfiguration.TokenEndpoint
|
||||
providerOpts.OIDCJwksURL = *provider.OidcConfiguration.JwksURI
|
||||
providerOpts.ProfileURL = *provider.OidcConfiguration.UserinfoEndpoint
|
||||
providerOpts.OIDCIssuerURL = provider.OidcConfiguration.Issuer
|
||||
providerOpts.LoginURL = provider.OidcConfiguration.AuthorizationEndpoint
|
||||
providerOpts.RedeemURL = provider.OidcConfiguration.TokenEndpoint
|
||||
providerOpts.OIDCJwksURL = provider.OidcConfiguration.JwksUri
|
||||
providerOpts.ProfileURL = provider.OidcConfiguration.UserinfoEndpoint
|
||||
|
||||
if provider.SkipPathRegex != "" {
|
||||
skipRegexes := strings.Split(provider.SkipPathRegex, "\n")
|
||||
if *provider.SkipPathRegex != "" {
|
||||
skipRegexes := strings.Split(*provider.SkipPathRegex, "\n")
|
||||
providerOpts.SkipAuthRegex = skipRegexes
|
||||
}
|
||||
|
||||
if provider.ForwardAuthMode {
|
||||
if *provider.ForwardAuthMode {
|
||||
providerOpts.UpstreamServers = []options.Upstream{
|
||||
{
|
||||
ID: "static",
|
||||
|
@ -78,33 +77,27 @@ func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *opti
|
|||
providerOpts.UpstreamServers = []options.Upstream{
|
||||
{
|
||||
ID: "default",
|
||||
URI: provider.InternalHost,
|
||||
URI: *provider.InternalHost,
|
||||
Path: "/",
|
||||
InsecureSkipTLSVerify: !provider.InternalHostSslValidation,
|
||||
InsecureSkipTLSVerify: !(*provider.InternalHostSslValidation),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if provider.Certificate != nil {
|
||||
if provider.Certificate.Get() != nil {
|
||||
pb.log.WithField("provider", provider.Name).Debug("Enabling TLS")
|
||||
cert, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewCertificate(&crypto.CryptoCertificatekeypairsViewCertificateParams{
|
||||
Context: context.Background(),
|
||||
KpUUID: *provider.Certificate,
|
||||
}, pb.s.ak.Auth)
|
||||
cert, _, err := pb.s.ak.Client.CryptoApi.CryptoCertificatekeypairsViewCertificateRetrieve(context.Background(), *provider.Certificate.Get()).Execute()
|
||||
if err != nil {
|
||||
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch certificate")
|
||||
return providerOpts
|
||||
}
|
||||
key, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewPrivateKey(&crypto.CryptoCertificatekeypairsViewPrivateKeyParams{
|
||||
Context: context.Background(),
|
||||
KpUUID: *provider.Certificate,
|
||||
}, pb.s.ak.Auth)
|
||||
key, _, err := pb.s.ak.Client.CryptoApi.CryptoCertificatekeypairsViewPrivateKeyRetrieve(context.Background(), *provider.Certificate.Get()).Execute()
|
||||
if err != nil {
|
||||
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch private key")
|
||||
return providerOpts
|
||||
}
|
||||
|
||||
x509cert, err := tls.X509KeyPair([]byte(cert.Payload.Data), []byte(key.Payload.Data))
|
||||
x509cert, err := tls.X509KeyPair([]byte(cert.Data), []byte(key.Data))
|
||||
if err != nil {
|
||||
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to parse certificate")
|
||||
return providerOpts
|
||||
|
@ -115,7 +108,7 @@ func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *opti
|
|||
return providerOpts
|
||||
}
|
||||
|
||||
func (pb *providerBundle) Build(provider *models.ProxyOutpostConfig) {
|
||||
func (pb *providerBundle) Build(provider api.ProxyOutpostConfig) {
|
||||
opts := pb.prepareOpts(provider)
|
||||
|
||||
chain := alice.New()
|
||||
|
@ -154,10 +147,10 @@ func (pb *providerBundle) Build(provider *models.ProxyOutpostConfig) {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
if provider.BasicAuthEnabled {
|
||||
if *provider.BasicAuthEnabled {
|
||||
oauthproxy.SetBasicAuth = true
|
||||
oauthproxy.BasicAuthUserAttribute = provider.BasicAuthUserAttribute
|
||||
oauthproxy.BasicAuthPasswordAttribute = provider.BasicAuthPasswordAttribute
|
||||
oauthproxy.BasicAuthUserAttribute = *provider.BasicAuthUserAttribute
|
||||
oauthproxy.BasicAuthPasswordAttribute = *provider.BasicAuthPasswordAttribute
|
||||
}
|
||||
|
||||
pb.proxy = oauthproxy
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/upstream"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
||||
"goauthentik.io/outpost/pkg/models"
|
||||
"goauthentik.io/outpost/api"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -94,7 +94,7 @@ type OAuthProxy struct {
|
|||
}
|
||||
|
||||
// NewOAuthProxy creates a new instance of OAuthProxy from the options provided
|
||||
func NewOAuthProxy(opts *options.Options, provider *models.ProxyOutpostConfig) (*OAuthProxy, error) {
|
||||
func NewOAuthProxy(opts *options.Options, provider api.ProxyOutpostConfig) (*OAuthProxy, error) {
|
||||
logger := log.WithField("logger", "authentik.outpost.proxy").WithField("provider", provider.Name)
|
||||
sessionStore, err := sessions.NewSessionStore(&opts.Session, &opts.Cookie)
|
||||
if err != nil {
|
||||
|
@ -133,7 +133,7 @@ func NewOAuthProxy(opts *options.Options, provider *models.ProxyOutpostConfig) (
|
|||
CookieRefresh: opts.Cookie.Refresh,
|
||||
CookieSameSite: opts.Cookie.SameSite,
|
||||
|
||||
forwardAuthMode: provider.ForwardAuthMode,
|
||||
forwardAuthMode: *provider.ForwardAuthMode,
|
||||
RobotsPath: "/robots.txt",
|
||||
SignInPath: fmt.Sprintf("%s/sign_in", opts.ProxyPrefix),
|
||||
SignOutPath: fmt.Sprintf("%s/sign_out", opts.ProxyPrefix),
|
||||
|
|
23973
schema.yml
Normal file
23973
schema.yml
Normal file
File diff suppressed because it is too large
Load diff
19149
swagger.yaml
19149
swagger.yaml
File diff suppressed because it is too large
Load diff
|
@ -9,7 +9,7 @@ trigger:
|
|||
stages:
|
||||
- stage: generate
|
||||
jobs:
|
||||
- job: swagger_generate
|
||||
- job: generate_api
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
|
@ -19,12 +19,11 @@ stages:
|
|||
displayName: 'Install Node.js'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/api --additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
|
||||
script: make gen-web
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: 'web/api/'
|
||||
artifact: 'ts_swagger_client'
|
||||
artifact: 'ts_api_client'
|
||||
publishLocation: 'pipeline'
|
||||
- stage: lint
|
||||
jobs:
|
||||
|
@ -39,7 +38,7 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'ts_swagger_client'
|
||||
artifactName: 'ts_api_client'
|
||||
path: "web/api/"
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
|
@ -61,7 +60,7 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'ts_swagger_client'
|
||||
artifactName: 'ts_api_client'
|
||||
path: "web/api/"
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
|
@ -85,7 +84,7 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'ts_swagger_client'
|
||||
artifactName: 'ts_api_client'
|
||||
path: "web/api/"
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
|
|
|
@ -15,13 +15,13 @@ export class LoggingMiddleware implements Middleware {
|
|||
let globalConfigPromise: Promise<Config>;
|
||||
export function config(): Promise<Config> {
|
||||
if (!globalConfigPromise) {
|
||||
globalConfigPromise = new RootApi(DEFAULT_CONFIG).rootConfigList();
|
||||
globalConfigPromise = new RootApi(DEFAULT_CONFIG).rootConfigRetrieve();
|
||||
}
|
||||
return globalConfigPromise;
|
||||
}
|
||||
|
||||
export const DEFAULT_CONFIG = new Configuration({
|
||||
basePath: "/api/v2beta",
|
||||
basePath: "",
|
||||
headers: {
|
||||
"X-CSRFToken": getCookie("authentik_csrf"),
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ChallengeTypeEnum } from "authentik-api";
|
||||
import { ChallengeChoices } from "authentik-api";
|
||||
|
||||
export interface Error {
|
||||
code: string;
|
||||
|
@ -10,7 +10,7 @@ export interface ErrorDict {
|
|||
}
|
||||
|
||||
export interface Challenge {
|
||||
type: ChallengeTypeEnum;
|
||||
type: ChallengeChoices;
|
||||
component?: string;
|
||||
title?: string;
|
||||
response_errors?: ErrorDict;
|
||||
|
|
|
@ -4,9 +4,14 @@ import { DEFAULT_CONFIG } from "./Config";
|
|||
let globalMePromise: Promise<SessionUser>;
|
||||
export function me(): Promise<SessionUser> {
|
||||
if (!globalMePromise) {
|
||||
globalMePromise = new CoreApi(DEFAULT_CONFIG).coreUsersMe().catch((ex) => {
|
||||
globalMePromise = new CoreApi(DEFAULT_CONFIG).coreUsersMeRetrieve().catch((ex) => {
|
||||
const defaultUser: SessionUser = {
|
||||
user: {
|
||||
pk: -1,
|
||||
isSuperuser: false,
|
||||
groups: [],
|
||||
avatar: "",
|
||||
uid: "",
|
||||
username: "",
|
||||
name: ""
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ export class TokenCopyButton extends ActionButton {
|
|||
if (!this.identifier) {
|
||||
return Promise.reject();
|
||||
}
|
||||
return new CoreApi(DEFAULT_CONFIG).coreTokensViewKey({
|
||||
return new CoreApi(DEFAULT_CONFIG).coreTokensViewKeyRetrieve({
|
||||
identifier: this.identifier
|
||||
}).then((token) => {
|
||||
if (!token.key) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
|||
export class AdminLoginsChart extends AKChart<LoginMetrics> {
|
||||
|
||||
apiRequest(): Promise<LoginMetrics> {
|
||||
return new AdminApi(DEFAULT_CONFIG).adminMetricsList();
|
||||
return new AdminApi(DEFAULT_CONFIG).adminMetricsRetrieve();
|
||||
}
|
||||
|
||||
getChartData(data: LoginMetrics): ChartData {
|
||||
|
|
|
@ -11,7 +11,7 @@ export class ApplicationAuthorizeChart extends AKChart<Coordinate[]> {
|
|||
applicationSlug!: string;
|
||||
|
||||
apiRequest(): Promise<Coordinate[]> {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsMetrics({ slug: this.applicationSlug });
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsMetricsList({ slug: this.applicationSlug });
|
||||
}
|
||||
|
||||
getChartData(data: Coordinate[]): ChartData {
|
||||
|
|
|
@ -11,7 +11,7 @@ export class UserChart extends AKChart<UserMetrics> {
|
|||
userId?: number;
|
||||
|
||||
apiRequest(): Promise<UserMetrics> {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreUsersMetrics({
|
||||
return new CoreApi(DEFAULT_CONFIG).coreUsersMetricsRetrieve({
|
||||
id: this.userId || 0,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-gro
|
|||
import { MessageLevel } from "../messages/Message";
|
||||
import { IronFormElement } from "@polymer/iron-form/iron-form";
|
||||
import { camelToSnake, convertToSlug } from "../../utils";
|
||||
import { ValidationError } from "authentik-api/src";
|
||||
import { ValidationError } from "authentik-api";
|
||||
import { EVENT_REFRESH } from "../../constants";
|
||||
|
||||
export class APIError extends Error {
|
||||
|
|
|
@ -32,7 +32,7 @@ export class NotificationDrawer extends LitElement {
|
|||
|
||||
firstUpdated(): void {
|
||||
new EventsApi(DEFAULT_CONFIG).eventsNotificationsList({
|
||||
seen: "false",
|
||||
seen: false,
|
||||
ordering: "-created",
|
||||
}).then(r => {
|
||||
this.notifications = r;
|
||||
|
@ -73,7 +73,7 @@ export class NotificationDrawer extends LitElement {
|
|||
<button class="pf-c-dropdown__toggle pf-m-plain" type="button" @click=${() => {
|
||||
new EventsApi(DEFAULT_CONFIG).eventsNotificationsPartialUpdate({
|
||||
uuid: item.pk || "",
|
||||
data: {
|
||||
patchedNotificationRequest: {
|
||||
seen: true,
|
||||
}
|
||||
}).then(() => {
|
||||
|
|
|
@ -10,8 +10,8 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
|||
|
||||
@customElement("ak-user-oauth-code-list")
|
||||
export class UserOAuthCodeList extends Table<ExpiringBaseGrantModel> {
|
||||
@property()
|
||||
userId?: string;
|
||||
@property({ type: Number })
|
||||
userId?: number;
|
||||
|
||||
apiEndpoint(page: number): Promise<AKResponse<ExpiringBaseGrantModel>> {
|
||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2AuthorizationCodesList({
|
||||
|
@ -45,7 +45,7 @@ export class UserOAuthCodeList extends Table<ExpiringBaseGrantModel> {
|
|||
.obj=${item}
|
||||
objectLabel=${t`Authorization Code`}
|
||||
.delete=${() => {
|
||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2AuthorizationCodesDelete({
|
||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2AuthorizationCodesDestroy({
|
||||
id: item.pk || 0,
|
||||
});
|
||||
}}>
|
||||
|
|
|
@ -10,8 +10,8 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
|||
|
||||
@customElement("ak-user-oauth-refresh-list")
|
||||
export class UserOAuthRefreshList extends Table<ExpiringBaseGrantModel> {
|
||||
@property()
|
||||
userId?: string;
|
||||
@property({ type: Number })
|
||||
userId?: number;
|
||||
|
||||
apiEndpoint(page: number): Promise<AKResponse<ExpiringBaseGrantModel>> {
|
||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensList({
|
||||
|
@ -45,7 +45,7 @@ export class UserOAuthRefreshList extends Table<ExpiringBaseGrantModel> {
|
|||
.obj=${item}
|
||||
objectLabel=${t`Refresh Code`}
|
||||
.delete=${() => {
|
||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensDelete({
|
||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensDestroy({
|
||||
id: item.pk || 0,
|
||||
});
|
||||
}}>
|
||||
|
|
|
@ -21,6 +21,7 @@ export const DefaultConfig: Config = {
|
|||
errorReportingEnabled: false,
|
||||
errorReportingEnvironment: "",
|
||||
errorReportingSendPii: false,
|
||||
uiFooterLinks: [],
|
||||
};
|
||||
|
||||
@customElement("ak-sidebar-brand")
|
||||
|
|
|
@ -10,8 +10,8 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
|||
|
||||
@customElement("ak-user-consent-list")
|
||||
export class UserConsentList extends Table<UserConsent> {
|
||||
@property()
|
||||
userId?: string;
|
||||
@property({ type: Number })
|
||||
userId?: number;
|
||||
|
||||
apiEndpoint(page: number): Promise<AKResponse<UserConsent>> {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreUserConsentList({
|
||||
|
@ -41,7 +41,7 @@ export class UserConsentList extends Table<UserConsent> {
|
|||
.obj=${item}
|
||||
objectLabel=${t`Consent`}
|
||||
.delete=${() => {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreUserConsentDelete({
|
||||
return new CoreApi(DEFAULT_CONFIG).coreUserConsentDestroy({
|
||||
id: item.pk || 0,
|
||||
});
|
||||
}}>
|
||||
|
|
|
@ -37,7 +37,7 @@ import { AuthenticatorValidateStageChallenge } from "./stages/authenticator_vali
|
|||
import { WebAuthnAuthenticatorRegisterChallenge } from "./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
|
||||
import { CaptchaChallenge } from "./stages/captcha/CaptchaStage";
|
||||
import { StageHost } from "./stages/base";
|
||||
import { Challenge, ChallengeTypeEnum, Config, FlowsApi } from "authentik-api";
|
||||
import { Challenge, ChallengeChoices, Config, FlowsApi } from "authentik-api";
|
||||
import { config, DEFAULT_CONFIG } from "../api/Config";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
import { until } from "lit-html/directives/until";
|
||||
|
@ -114,7 +114,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
|||
this.loading = true;
|
||||
return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolveRaw({
|
||||
flowSlug: this.flowSlug,
|
||||
data: formData || {},
|
||||
requestBody: formData || {},
|
||||
query: window.location.search.substring(1),
|
||||
}).then((challengeRaw) => {
|
||||
return challengeRaw.raw.json();
|
||||
|
@ -155,7 +155,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
|||
|
||||
errorMessage(error: string): void {
|
||||
this.challenge = <ShellChallenge>{
|
||||
type: ChallengeTypeEnum.Shell,
|
||||
type: ChallengeChoices.Shell,
|
||||
body: `<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">
|
||||
${t`Whoops!`}
|
||||
|
@ -188,16 +188,16 @@ export class FlowExecutor extends LitElement implements StageHost {
|
|||
return html``;
|
||||
}
|
||||
switch (this.challenge.type) {
|
||||
case ChallengeTypeEnum.Redirect:
|
||||
case ChallengeChoices.Redirect:
|
||||
console.debug("authentik/flows: redirecting to url from server", (this.challenge as RedirectChallenge).to);
|
||||
window.location.assign((this.challenge as RedirectChallenge).to);
|
||||
return html`<ak-empty-state
|
||||
?loading=${true}
|
||||
header=${t`Loading`}>
|
||||
</ak-empty-state>`;
|
||||
case ChallengeTypeEnum.Shell:
|
||||
case ChallengeChoices.Shell:
|
||||
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
|
||||
case ChallengeTypeEnum.Native:
|
||||
case ChallengeChoices.Native:
|
||||
switch (this.challenge.component) {
|
||||
case "ak-stage-access-denied":
|
||||
return html`<ak-stage-access-denied .host=${this} .challenge=${this.challenge as AccessDeniedChallenge}></ak-stage-access-denied>`;
|
||||
|
|
|
@ -38,8 +38,8 @@ export class PlexLoginInit extends BaseStage {
|
|||
const authWindow = popupCenterScreen(authInfo.authUrl, "plex auth", 550, 700);
|
||||
PlexAPIClient.pinPoll(this.challenge?.client_id || "", authInfo.pin.id).then(token => {
|
||||
authWindow?.close();
|
||||
new SourcesApi(DEFAULT_CONFIG).sourcesPlexRedeemToken({
|
||||
data: {
|
||||
new SourcesApi(DEFAULT_CONFIG).sourcesPlexRedeemTokenCreate({
|
||||
plexTokenRedeemRequest: {
|
||||
plexToken: token,
|
||||
},
|
||||
slug: this.challenge?.slug || "",
|
||||
|
|
|
@ -51,11 +51,11 @@ export abstract class Interface extends LitElement {
|
|||
|
||||
render(): TemplateResult {
|
||||
return html`
|
||||
${until(new AdminApi(DEFAULT_CONFIG).adminVersionList().then(version => {
|
||||
${until(new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve().then(version => {
|
||||
if (version.versionCurrent !== VERSION) {
|
||||
return html`<ak-banner>
|
||||
${t`A newer version of the frontend is available.`}
|
||||
<button @click=${() => { window.location.reload(); }}>
|
||||
<button @click=${() => { window.location.reload(true); }}>
|
||||
${t`Reload`}
|
||||
</button>
|
||||
</ak-banner>`;
|
||||
|
|
|
@ -56,7 +56,7 @@ export class LibraryApplication extends LitElement {
|
|||
if (!this.application) {
|
||||
return html`<ak-spinner></ak-spinner>`;
|
||||
}
|
||||
return html` <a href="${ifDefined(this.application.launchUrl)}" class="pf-c-card pf-m-hoverable pf-m-compact">
|
||||
return html` <a href="${ifDefined(this.application.launchUrl ?? "")}" class="pf-c-card pf-m-hoverable pf-m-compact">
|
||||
<div class="pf-c-card__header">
|
||||
${this.application.metaIcon
|
||||
? html`<img class="app-icon pf-c-avatar" src="${ifDefined(this.application.metaIcon)}" alt="Application Icon"/>`
|
||||
|
|
|
@ -18,7 +18,7 @@ export class TopApplicationsTable extends LitElement {
|
|||
}
|
||||
|
||||
firstUpdated(): void {
|
||||
new EventsApi(DEFAULT_CONFIG).eventsEventsTopPerUser({
|
||||
new EventsApi(DEFAULT_CONFIG).eventsEventsTopPerUserList({
|
||||
action: "authorize_application",
|
||||
topN: 11,
|
||||
}).then((events) => {
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import { t } from "@lingui/macro";
|
||||
import { customElement, html, TemplateResult } from "lit-element";
|
||||
import { AdminStatus, AdminStatusCard } from "./AdminStatusCard";
|
||||
import { AdminApi, TaskStatusEnum } from "authentik-api";
|
||||
import { AdminApi, StatusEnum } from "authentik-api";
|
||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||
import { convertToTitle } from "../../../utils";
|
||||
|
||||
@customElement("ak-admin-status-card-backup")
|
||||
export class BackupStatusCard extends AdminStatusCard<TaskStatusEnum> {
|
||||
export class BackupStatusCard extends AdminStatusCard<StatusEnum> {
|
||||
|
||||
getPrimaryValue(): Promise<TaskStatusEnum> {
|
||||
return new AdminApi(DEFAULT_CONFIG).adminSystemTasksRead({
|
||||
getPrimaryValue(): Promise<StatusEnum> {
|
||||
return new AdminApi(DEFAULT_CONFIG).adminSystemTasksRetrieve({
|
||||
id: "backup_database"
|
||||
}).then((value) => {
|
||||
return value.status;
|
||||
}).catch(() => {
|
||||
return TaskStatusEnum.Error;
|
||||
return StatusEnum.Error;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -22,14 +22,14 @@ export class BackupStatusCard extends AdminStatusCard<TaskStatusEnum> {
|
|||
return html`${convertToTitle(this.value?.toString() || "")}`;
|
||||
}
|
||||
|
||||
getStatus(value: TaskStatusEnum): Promise<AdminStatus> {
|
||||
getStatus(value: StatusEnum): Promise<AdminStatus> {
|
||||
switch (value) {
|
||||
case TaskStatusEnum.Warning:
|
||||
case StatusEnum.Warning:
|
||||
return Promise.resolve<AdminStatus>({
|
||||
icon: "fa fa-exclamation-triangle pf-m-warning",
|
||||
message: t`Backup finished with warnings.`,
|
||||
});
|
||||
case TaskStatusEnum.Error:
|
||||
case StatusEnum.Error:
|
||||
return Promise.resolve<AdminStatus>({
|
||||
icon: "fa fa-times-circle pf-m-danger",
|
||||
message: t`Backup finished with errors.`,
|
||||
|
|
|
@ -8,7 +8,7 @@ import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
|
|||
export class VersionStatusCard extends AdminStatusCard<Version> {
|
||||
|
||||
getPrimaryValue(): Promise<Version> {
|
||||
return new AdminApi(DEFAULT_CONFIG).adminVersionList();
|
||||
return new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve();
|
||||
}
|
||||
|
||||
getStatus(value: Version): Promise<AdminStatus> {
|
||||
|
|
|
@ -8,8 +8,8 @@ import { AdminStatus, AdminStatusCard } from "./AdminStatusCard";
|
|||
export class WorkersStatusCard extends AdminStatusCard<number> {
|
||||
|
||||
getPrimaryValue(): Promise<number> {
|
||||
return new AdminApi(DEFAULT_CONFIG).adminWorkersList({}).then((workers) => {
|
||||
return workers.pagination.count;
|
||||
return new AdminApi(DEFAULT_CONFIG).adminWorkersRetrieve().then((workers) => {
|
||||
return workers.count;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ export class PolicyStatusChart extends AKChart<FlowMetrics> {
|
|||
|
||||
async apiRequest(): Promise<FlowMetrics> {
|
||||
const api = new FlowsApi(DEFAULT_CONFIG);
|
||||
const cached = (await api.flowsInstancesCacheInfo()).count || 0;
|
||||
const cached = (await api.flowsInstancesCacheInfoRetrieve()).count || 0;
|
||||
const count = (await api.flowsInstancesList({
|
||||
pageSize: 1
|
||||
})).pagination.count;
|
||||
|
|
|
@ -34,7 +34,7 @@ export class GroupCountStatusChart extends AKChart<GroupMetrics> {
|
|||
pageSize: 1
|
||||
})).pagination.count;
|
||||
const superusers = (await api.coreGroupsList({
|
||||
isSuperuser: "true"
|
||||
isSuperuser: true
|
||||
})).pagination.count;
|
||||
this.centerText = count.toString();
|
||||
return {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { t } from "@lingui/macro";
|
||||
import { customElement } from "lit-element";
|
||||
import { SourcesApi, TaskStatusEnum } from "authentik-api";
|
||||
import { SourcesApi, StatusEnum } from "authentik-api";
|
||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||
import "../../../elements/forms/ConfirmationForm";
|
||||
import { AKChart } from "../../../elements/charts/Chart";
|
||||
|
@ -38,10 +38,10 @@ export class LDAPSyncStatusChart extends AKChart<LDAPSyncStats> {
|
|||
let unsynced = 0;
|
||||
await Promise.all(sources.results.map(async (element) => {
|
||||
try {
|
||||
const health = await api.sourcesLdapSyncStatus({
|
||||
const health = await api.sourcesLdapSyncStatusRetrieve({
|
||||
slug: element.slug,
|
||||
});
|
||||
if (health.status !== TaskStatusEnum.Successful) {
|
||||
if (health.status !== StatusEnum.Successful) {
|
||||
failed += 1;
|
||||
}
|
||||
const now = new Date().getTime();
|
||||
|
|
|
@ -37,7 +37,7 @@ export class OutpostStatusChart extends AKChart<OutpostStats> {
|
|||
let outdated = 0;
|
||||
let unhealthy = 0;
|
||||
await Promise.all(outposts.results.map(async (element) => {
|
||||
const health = await api.outpostsOutpostsHealth({
|
||||
const health = await api.outpostsInstancesHealthList({
|
||||
uuid: element.pk || "",
|
||||
});
|
||||
if (health.length === 0) {
|
||||
|
|
|
@ -32,13 +32,13 @@ export class PolicyStatusChart extends AKChart<PolicyMetrics> {
|
|||
|
||||
async apiRequest(): Promise<PolicyMetrics> {
|
||||
const api = new PoliciesApi(DEFAULT_CONFIG);
|
||||
const cached = (await api.policiesAllCacheInfo()).count || 0;
|
||||
const cached = (await api.policiesAllCacheInfoRetrieve()).count || 0;
|
||||
const count = (await api.policiesAllList({
|
||||
pageSize: 1
|
||||
})).pagination.count;
|
||||
const unbound = (await api.policiesAllList({
|
||||
bindingsIsnull: "true",
|
||||
promptstageIsnull: "true",
|
||||
bindingsIsnull: true,
|
||||
promptstageIsnull: true,
|
||||
})).pagination.count;
|
||||
this.centerText = count.toString();
|
||||
return {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { CoreApi, Application, ProvidersApi, Provider, ApplicationPolicyEngineModeEnum } from "authentik-api";
|
||||
import { CoreApi, Application, ProvidersApi, Provider, PolicyEngineMode } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { CSSResult, customElement, property } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
|
@ -18,7 +18,7 @@ import { ModelForm } from "../../elements/forms/ModelForm";
|
|||
export class ApplicationForm extends ModelForm<Application, string> {
|
||||
|
||||
loadInstance(pk: string): Promise<Application> {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsRead({
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsRetrieve({
|
||||
slug: pk
|
||||
});
|
||||
}
|
||||
|
@ -43,17 +43,17 @@ export class ApplicationForm extends ModelForm<Application, string> {
|
|||
if (this.instance) {
|
||||
writeOp = new CoreApi(DEFAULT_CONFIG).coreApplicationsUpdate({
|
||||
slug: this.instance.slug,
|
||||
data: data
|
||||
applicationRequest: data
|
||||
});
|
||||
} else {
|
||||
writeOp = new CoreApi(DEFAULT_CONFIG).coreApplicationsCreate({
|
||||
data: data
|
||||
applicationRequest: data
|
||||
});
|
||||
}
|
||||
const icon = this.getFormFile();
|
||||
if (icon) {
|
||||
return writeOp.then(app => {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIcon({
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIconCreate({
|
||||
slug: app.slug,
|
||||
file: icon
|
||||
});
|
||||
|
@ -115,7 +115,7 @@ export class ApplicationForm extends ModelForm<Application, string> {
|
|||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
</button>
|
||||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
${until(new ProvidersApi(DEFAULT_CONFIG).providersAllTypes().then((types) => {
|
||||
${until(new ProvidersApi(DEFAULT_CONFIG).providersAllTypesList().then((types) => {
|
||||
return types.map((type) => {
|
||||
return html`<li>
|
||||
<ak-forms-modal>
|
||||
|
@ -145,10 +145,10 @@ export class ApplicationForm extends ModelForm<Application, string> {
|
|||
?required=${true}
|
||||
name="policyEngineMode">
|
||||
<select class="pf-c-form-control">
|
||||
<option value=${ApplicationPolicyEngineModeEnum.Any} ?selected=${this.instance?.policyEngineMode === ApplicationPolicyEngineModeEnum.Any}>
|
||||
<option value=${PolicyEngineMode.Any} ?selected=${this.instance?.policyEngineMode === PolicyEngineMode.Any}>
|
||||
${t`ANY, any policy must match to grant access.`}
|
||||
</option>
|
||||
<option value=${ApplicationPolicyEngineModeEnum.All} ?selected=${this.instance?.policyEngineMode === ApplicationPolicyEngineModeEnum.All}>
|
||||
<option value=${PolicyEngineMode.All} ?selected=${this.instance?.policyEngineMode === PolicyEngineMode.All}>
|
||||
${t`ALL, all policies must match to grant access.`}
|
||||
</option>
|
||||
</select>
|
||||
|
|
|
@ -104,7 +104,7 @@ export class ApplicationListPage extends TablePage<Application> {
|
|||
.obj=${item}
|
||||
objectLabel=${t`Application`}
|
||||
.delete=${() => {
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsDelete({
|
||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsDestroy({
|
||||
slug: item.slug || ""
|
||||
});
|
||||
}}>
|
||||
|
|
|
@ -26,7 +26,7 @@ export class ApplicationViewPage extends LitElement {
|
|||
|
||||
@property()
|
||||
set applicationSlug(value: string) {
|
||||
new CoreApi(DEFAULT_CONFIG).coreApplicationsRead({
|
||||
new CoreApi(DEFAULT_CONFIG).coreApplicationsRetrieve({
|
||||
slug: value
|
||||
}).then((app) => {
|
||||
this.application = app;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { CertificateGeneration, CryptoApi } from "authentik-api";
|
||||
import { CertificateGenerationRequest, CryptoApi } from "authentik-api";
|
||||
import { CertificateKeyPair } from "authentik-api/src";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement } from "lit-element";
|
||||
|
@ -8,15 +8,15 @@ import { Form } from "../../elements/forms/Form";
|
|||
import "../../elements/forms/HorizontalFormElement";
|
||||
|
||||
@customElement("ak-crypto-certificate-generate-form")
|
||||
export class CertificateKeyPairForm extends Form<CertificateGeneration> {
|
||||
export class CertificateKeyPairForm extends Form<CertificateGenerationRequest> {
|
||||
|
||||
getSuccessMessage(): string {
|
||||
return t`Successfully generated certificate-key pair.`;
|
||||
}
|
||||
|
||||
send = (data: CertificateGeneration): Promise<CertificateKeyPair> => {
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsGenerate({
|
||||
data: data
|
||||
send = (data: CertificateGenerationRequest): Promise<CertificateKeyPair> => {
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsGenerateCreate({
|
||||
certificateGenerationRequest: data
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { CertificateKeyPair, CryptoApi } from "authentik-api";
|
||||
import { CertificateKeyPair, CertificateKeyPairRequest, CryptoApi } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
|
@ -12,7 +12,7 @@ import { ModelForm } from "../../elements/forms/ModelForm";
|
|||
export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string> {
|
||||
|
||||
loadInstance(pk: string): Promise<CertificateKeyPair> {
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsRead({
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsRetrieve({
|
||||
kpUuid: pk,
|
||||
});
|
||||
}
|
||||
|
@ -29,11 +29,11 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
|||
if (this.instance) {
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsPartialUpdate({
|
||||
kpUuid: this.instance.pk || "",
|
||||
data: data
|
||||
patchedCertificateKeyPairRequest: data
|
||||
});
|
||||
} else {
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsCreate({
|
||||
data: data
|
||||
certificateKeyPairRequest: data as unknown as CertificateKeyPairRequest
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -51,14 +51,14 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
|||
name="certificateData"
|
||||
?writeOnly=${this.instance !== undefined}
|
||||
?required=${true}>
|
||||
<textarea class="pf-c-form-control" required>${ifDefined(this.instance?.certificateData)}</textarea>
|
||||
<textarea class="pf-c-form-control" required></textarea>
|
||||
<p class="pf-c-form__helper-text">${t`PEM-encoded Certificate data.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
name="keyData"
|
||||
?writeOnly=${this.instance !== undefined}
|
||||
label=${t`Private Key`}>
|
||||
<textarea class="pf-c-form-control" >${ifDefined(this.instance?.keyData)}</textarea>
|
||||
<textarea class="pf-c-form-control" ></textarea>
|
||||
<p class="pf-c-form__helper-text">${t`Optional Private Key. If this is set, you can use this keypair for encryption.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
</form>`;
|
||||
|
|
|
@ -80,7 +80,7 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
|
|||
.obj=${item}
|
||||
objectLabel=${t`Certificate-Key Pair`}
|
||||
.delete=${() => {
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsDelete({
|
||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsDestroy({
|
||||
kpUuid: item.pk || ""
|
||||
});
|
||||
}}>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue