commit
e177ab33e0
|
@ -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
|
||||
|
|
|
@ -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 = "*"
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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),
|
||||
|
|
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 New Issue