commit
e177ab33e0
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
|
@ -30,7 +30,7 @@ jobs:
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: prepare ts api client
|
- name: prepare ts api client
|
||||||
run: |
|
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
|
- name: Building Docker Image
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
|
@ -51,9 +51,8 @@ jobs:
|
||||||
go-version: "^1.15"
|
go-version: "^1.15"
|
||||||
- name: prepare go api client
|
- name: prepare go api client
|
||||||
run: |
|
run: |
|
||||||
|
make gen-outpost
|
||||||
cd 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
|
go build -v ./cmd/proxy/server.go
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1.1.0
|
uses: docker/setup-qemu-action@v1.1.0
|
||||||
|
@ -91,9 +90,8 @@ jobs:
|
||||||
go-version: "^1.15"
|
go-version: "^1.15"
|
||||||
- name: prepare go api client
|
- name: prepare go api client
|
||||||
run: |
|
run: |
|
||||||
|
make gen-outpost
|
||||||
cd 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
|
go build -v ./cmd/ldap/server.go
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1.1.0
|
uses: docker/setup-qemu-action@v1.1.0
|
||||||
|
|
2
.github/workflows/tag.yml
vendored
2
.github/workflows/tag.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: prepare ts api client
|
- name: prepare ts api client
|
||||||
run: |
|
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
|
- name: Pre-release test
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install -y pwgen
|
sudo apt-get install -y pwgen
|
||||||
|
|
27
Makefile
27
Makefile
|
@ -1,5 +1,7 @@
|
||||||
.SHELLFLAGS += -x -e
|
.SHELLFLAGS += -x -e
|
||||||
PWD = $(shell pwd)
|
PWD = $(shell pwd)
|
||||||
|
UID = $(shell id -u)
|
||||||
|
GID = $(shell id -g)
|
||||||
|
|
||||||
all: lint-fix lint test gen
|
all: lint-fix lint test gen
|
||||||
|
|
||||||
|
@ -25,16 +27,35 @@ lint:
|
||||||
bandit -r authentik tests lifecycle -x node_modules
|
bandit -r authentik tests lifecycle -x node_modules
|
||||||
pylint authentik tests lifecycle
|
pylint authentik tests lifecycle
|
||||||
|
|
||||||
gen:
|
gen-build:
|
||||||
./manage.py generate_swagger -o swagger.yaml -f yaml
|
./manage.py spectacular --file schema.yml
|
||||||
|
|
||||||
|
gen-web:
|
||||||
docker run \
|
docker run \
|
||||||
--rm -v ${PWD}:/local \
|
--rm -v ${PWD}:/local \
|
||||||
|
--user ${UID}:${GID} \
|
||||||
openapitools/openapi-generator-cli generate \
|
openapitools/openapi-generator-cli generate \
|
||||||
-i /local/swagger.yaml \
|
-i /local/schema.yml \
|
||||||
-g typescript-fetch \
|
-g typescript-fetch \
|
||||||
-o /local/web/api \
|
-o /local/web/api \
|
||||||
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
|
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
|
||||||
cd web/api && npx tsc
|
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:
|
run:
|
||||||
go run -v cmd/server/main.go
|
go run -v cmd/server/main.go
|
||||||
|
|
2
Pipfile
2
Pipfile
|
@ -22,7 +22,7 @@ django-storages = "*"
|
||||||
djangorestframework = "*"
|
djangorestframework = "*"
|
||||||
djangorestframework-guardian = "*"
|
djangorestframework-guardian = "*"
|
||||||
docker = "*"
|
docker = "*"
|
||||||
drf_yasg = "*"
|
drf-spectacular = "*"
|
||||||
facebook-sdk = "*"
|
facebook-sdk = "*"
|
||||||
geoip2 = "*"
|
geoip2 = "*"
|
||||||
gunicorn = "*"
|
gunicorn = "*"
|
||||||
|
|
206
Pipfile.lock
generated
206
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "8a32708c1c04f8da03c817df973de28c37c97ee773f571ce0b3f3f834e1b7094"
|
"sha256": "61354b75aa954ea0a995ee1909b861092a4be5c1af66d3c00c7c7845e056d064"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -56,6 +56,7 @@
|
||||||
"sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a",
|
"sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a",
|
||||||
"sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"
|
"sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==3.7.4.post0"
|
"version": "==3.7.4.post0"
|
||||||
},
|
},
|
||||||
"aioredis": {
|
"aioredis": {
|
||||||
|
@ -70,6 +71,7 @@
|
||||||
"sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2",
|
"sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2",
|
||||||
"sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb"
|
"sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==5.0.6"
|
"version": "==5.0.6"
|
||||||
},
|
},
|
||||||
"asgiref": {
|
"asgiref": {
|
||||||
|
@ -77,6 +79,7 @@
|
||||||
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
|
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
|
||||||
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
|
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==3.3.4"
|
"version": "==3.3.4"
|
||||||
},
|
},
|
||||||
"async-timeout": {
|
"async-timeout": {
|
||||||
|
@ -84,6 +87,7 @@
|
||||||
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
|
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
|
||||||
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
|
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
|
||||||
],
|
],
|
||||||
|
"markers": "python_full_version >= '3.5.3'",
|
||||||
"version": "==3.0.1"
|
"version": "==3.0.1"
|
||||||
},
|
},
|
||||||
"attrs": {
|
"attrs": {
|
||||||
|
@ -91,6 +95,7 @@
|
||||||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==21.2.0"
|
"version": "==21.2.0"
|
||||||
},
|
},
|
||||||
"autobahn": {
|
"autobahn": {
|
||||||
|
@ -98,6 +103,7 @@
|
||||||
"sha256:9195df8af03b0ff29ccd4b7f5abbde957ee90273465942205f9a1bad6c3f07ac",
|
"sha256:9195df8af03b0ff29ccd4b7f5abbde957ee90273465942205f9a1bad6c3f07ac",
|
||||||
"sha256:e126c1f583e872fb59e79d36977cfa1f2d0a8a79f90ae31f406faae7664b8e03"
|
"sha256:e126c1f583e872fb59e79d36977cfa1f2d0a8a79f90ae31f406faae7664b8e03"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==21.3.1"
|
"version": "==21.3.1"
|
||||||
},
|
},
|
||||||
"automat": {
|
"automat": {
|
||||||
|
@ -127,6 +133,7 @@
|
||||||
"sha256:4b4aa58c61d4b125bc6ec1597924b2749e19de8f2c9a374ac087aa2561e71828",
|
"sha256:4b4aa58c61d4b125bc6ec1597924b2749e19de8f2c9a374ac087aa2561e71828",
|
||||||
"sha256:69dc0b6fdc0855f5a4f8b1d29c96b9cec44e71054fea0f968e5904d6ccfd4fd9"
|
"sha256:69dc0b6fdc0855f5a4f8b1d29c96b9cec44e71054fea0f968e5904d6ccfd4fd9"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||||
"version": "==1.20.73"
|
"version": "==1.20.73"
|
||||||
},
|
},
|
||||||
"cachetools": {
|
"cachetools": {
|
||||||
|
@ -134,6 +141,7 @@
|
||||||
"sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001",
|
"sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001",
|
||||||
"sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"
|
"sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version ~= '3.5'",
|
||||||
"version": "==4.2.2"
|
"version": "==4.2.2"
|
||||||
},
|
},
|
||||||
"cbor2": {
|
"cbor2": {
|
||||||
|
@ -220,6 +228,7 @@
|
||||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==4.0.0"
|
"version": "==4.0.0"
|
||||||
},
|
},
|
||||||
"click": {
|
"click": {
|
||||||
|
@ -227,6 +236,7 @@
|
||||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==7.1.2"
|
"version": "==7.1.2"
|
||||||
},
|
},
|
||||||
"click-didyoumean": {
|
"click-didyoumean": {
|
||||||
|
@ -256,20 +266,6 @@
|
||||||
],
|
],
|
||||||
"version": "==15.1.0"
|
"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": {
|
"cryptography": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d",
|
"sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d",
|
||||||
|
@ -300,6 +296,7 @@
|
||||||
"sha256:76ffae916ba3aa66b46996c14fa713e46004788167a4873d647544e750e0e99f",
|
"sha256:76ffae916ba3aa66b46996c14fa713e46004788167a4873d647544e750e0e99f",
|
||||||
"sha256:a9af943c79717bc52fe64a3c236ae5d3adccc8b5be19c881b442d2c3db233393"
|
"sha256:a9af943c79717bc52fe64a3c236ae5d3adccc8b5be19c881b442d2c3db233393"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==3.0.2"
|
"version": "==3.0.2"
|
||||||
},
|
},
|
||||||
"defusedxml": {
|
"defusedxml": {
|
||||||
|
@ -402,13 +399,13 @@
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==5.0.0"
|
"version": "==5.0.0"
|
||||||
},
|
},
|
||||||
"drf-yasg": {
|
"drf-spectacular": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:8b72e5b1875931a8d11af407be3a9a5ba8776541492947a0df5bafda6b7f8267",
|
"sha256:4a77c233c99e028b8905cd2cf05388524838ade97b95d5c6e4861e0c3c95af31",
|
||||||
"sha256:d50f197c7f02545d0b736df88c6d5cf874f8fea2507ad85ad7de6ae5bf2d9e5a"
|
"sha256:d7f64b97e8940b143a0e8d1de20523e8d7d5fe8ec557aec574513282c413b0b3"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.20.0"
|
"version": "==0.16.0"
|
||||||
},
|
},
|
||||||
"facebook-sdk": {
|
"facebook-sdk": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -422,6 +419,7 @@
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
|
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==0.18.2"
|
"version": "==0.18.2"
|
||||||
},
|
},
|
||||||
"geoip2": {
|
"geoip2": {
|
||||||
|
@ -437,6 +435,7 @@
|
||||||
"sha256:588bdb03a41ecb4978472b847881e5518b5d9ec6153d3d679aa127a55e13b39f",
|
"sha256:588bdb03a41ecb4978472b847881e5518b5d9ec6153d3d679aa127a55e13b39f",
|
||||||
"sha256:9ad25fba07f46a628ad4d0ca09f38dcb262830df2ac95b217f9b0129c9e42206"
|
"sha256:9ad25fba07f46a628ad4d0ca09f38dcb262830df2ac95b217f9b0129c9e42206"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||||
"version": "==1.30.0"
|
"version": "==1.30.0"
|
||||||
},
|
},
|
||||||
"gunicorn": {
|
"gunicorn": {
|
||||||
|
@ -452,6 +451,7 @@
|
||||||
"sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6",
|
"sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6",
|
||||||
"sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"
|
"sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==0.12.0"
|
"version": "==0.12.0"
|
||||||
},
|
},
|
||||||
"hiredis": {
|
"hiredis": {
|
||||||
|
@ -498,6 +498,7 @@
|
||||||
"sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0",
|
"sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0",
|
||||||
"sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a"
|
"sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==2.0.0"
|
"version": "==2.0.0"
|
||||||
},
|
},
|
||||||
"httptools": {
|
"httptools": {
|
||||||
|
@ -546,27 +547,15 @@
|
||||||
"sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417",
|
"sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417",
|
||||||
"sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"
|
"sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
"version": "==0.5.1"
|
"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": {
|
"jmespath": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
|
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
|
||||||
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
|
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==0.10.0"
|
"version": "==0.10.0"
|
||||||
},
|
},
|
||||||
"jsonschema": {
|
"jsonschema": {
|
||||||
|
@ -581,6 +570,7 @@
|
||||||
"sha256:6dc509178ac4269b0e66ab4881f70a2035c33d3a622e20585f965986a5182006",
|
"sha256:6dc509178ac4269b0e66ab4881f70a2035c33d3a622e20585f965986a5182006",
|
||||||
"sha256:f4965fba0a4718d47d470beeb5d6446e3357a62402b16c510b6a2f251e05ac3c"
|
"sha256:f4965fba0a4718d47d470beeb5d6446e3357a62402b16c510b6a2f251e05ac3c"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==5.0.2"
|
"version": "==5.0.2"
|
||||||
},
|
},
|
||||||
"kubernetes": {
|
"kubernetes": {
|
||||||
|
@ -593,7 +583,10 @@
|
||||||
},
|
},
|
||||||
"ldap3": {
|
"ldap3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
"sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c",
|
||||||
|
"sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056",
|
||||||
"sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91",
|
"sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91",
|
||||||
|
"sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59",
|
||||||
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57"
|
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
|
@ -651,49 +644,11 @@
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==4.6.3"
|
"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": {
|
"maxminddb": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:47e86a084dd814fac88c99ea34ba3278a74bc9de5a25f4b815b608798747c7dc"
|
"sha256:47e86a084dd814fac88c99ea34ba3278a74bc9de5a25f4b815b608798747c7dc"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==2.0.3"
|
"version": "==2.0.3"
|
||||||
},
|
},
|
||||||
"msgpack": {
|
"msgpack": {
|
||||||
|
@ -769,6 +724,7 @@
|
||||||
"sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281",
|
"sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281",
|
||||||
"sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"
|
"sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==5.1.0"
|
"version": "==5.1.0"
|
||||||
},
|
},
|
||||||
"oauthlib": {
|
"oauthlib": {
|
||||||
|
@ -776,6 +732,7 @@
|
||||||
"sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
|
"sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
|
||||||
"sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
|
"sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==3.1.0"
|
"version": "==3.1.0"
|
||||||
},
|
},
|
||||||
"packaging": {
|
"packaging": {
|
||||||
|
@ -791,6 +748,7 @@
|
||||||
"sha256:030e4f9df5f53db2292eec37c6255957eb76168c6f974e4176c711cf91ed34aa",
|
"sha256:030e4f9df5f53db2292eec37c6255957eb76168c6f974e4176c711cf91ed34aa",
|
||||||
"sha256:b6c5a9643e3545bcbfd9451766cbaa5d9c67e7303c7bc32c750b6fa70ecb107d"
|
"sha256:b6c5a9643e3545bcbfd9451766cbaa5d9c67e7303c7bc32c750b6fa70ecb107d"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==0.10.1"
|
"version": "==0.10.1"
|
||||||
},
|
},
|
||||||
"prompt-toolkit": {
|
"prompt-toolkit": {
|
||||||
|
@ -798,6 +756,7 @@
|
||||||
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
|
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
|
||||||
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
|
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
|
||||||
],
|
],
|
||||||
|
"markers": "python_full_version >= '3.6.1'",
|
||||||
"version": "==3.0.18"
|
"version": "==3.0.18"
|
||||||
},
|
},
|
||||||
"psycopg2-binary": {
|
"psycopg2-binary": {
|
||||||
|
@ -843,15 +802,37 @@
|
||||||
},
|
},
|
||||||
"pyasn1": {
|
"pyasn1": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
|
||||||
|
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
|
||||||
|
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
|
||||||
|
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
|
||||||
|
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
|
||||||
|
"sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
|
||||||
|
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
|
||||||
|
"sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
|
||||||
|
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3",
|
||||||
|
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
|
||||||
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
|
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
|
||||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"
|
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
|
||||||
|
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"
|
||||||
],
|
],
|
||||||
"version": "==0.4.8"
|
"version": "==0.4.8"
|
||||||
},
|
},
|
||||||
"pyasn1-modules": {
|
"pyasn1-modules": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
"sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
|
||||||
|
"sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
|
||||||
|
"sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
|
||||||
|
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
|
||||||
|
"sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
|
||||||
|
"sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
|
||||||
|
"sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
|
||||||
|
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
|
||||||
|
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
|
||||||
|
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
|
||||||
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
|
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
|
||||||
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"
|
"sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
|
||||||
|
"sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
|
||||||
],
|
],
|
||||||
"version": "==0.2.8"
|
"version": "==0.2.8"
|
||||||
},
|
},
|
||||||
|
@ -860,6 +841,7 @@
|
||||||
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
|
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
|
||||||
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
|
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==2.20"
|
"version": "==2.20"
|
||||||
},
|
},
|
||||||
"pycryptodome": {
|
"pycryptodome": {
|
||||||
|
@ -903,6 +885,7 @@
|
||||||
"sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316",
|
"sha256:412e00137858f04bde0729913874a48485665f2d36fe9ee449f26be864af9316",
|
||||||
"sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29"
|
"sha256:7ead136e03655af85069b6f47b23eb7c3e5c221aa9f022a4fbb499f5b7308f29"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
"version": "==2.0.2"
|
"version": "==2.0.2"
|
||||||
},
|
},
|
||||||
"pyjwt": {
|
"pyjwt": {
|
||||||
|
@ -925,12 +908,14 @@
|
||||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==2.4.7"
|
"version": "==2.4.7"
|
||||||
},
|
},
|
||||||
"pyrsistent": {
|
"pyrsistent": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"
|
"sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
"version": "==0.17.3"
|
"version": "==0.17.3"
|
||||||
},
|
},
|
||||||
"python-dateutil": {
|
"python-dateutil": {
|
||||||
|
@ -938,6 +923,7 @@
|
||||||
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
|
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
|
||||||
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
|
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==2.8.1"
|
"version": "==2.8.1"
|
||||||
},
|
},
|
||||||
"python-dotenv": {
|
"python-dotenv": {
|
||||||
|
@ -994,6 +980,7 @@
|
||||||
"sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",
|
"sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",
|
||||||
"sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"
|
"sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==3.5.3"
|
"version": "==3.5.3"
|
||||||
},
|
},
|
||||||
"requests": {
|
"requests": {
|
||||||
|
@ -1001,10 +988,12 @@
|
||||||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==2.25.1"
|
"version": "==2.25.1"
|
||||||
},
|
},
|
||||||
"requests-oauthlib": {
|
"requests-oauthlib": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
"sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc",
|
||||||
"sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
|
"sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
|
||||||
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
|
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"
|
||||||
],
|
],
|
||||||
|
@ -1019,50 +1008,6 @@
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==4.7.2"
|
"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": {
|
"s3transfer": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:9b3752887a2880690ce628bc263d6d13a3864083aeacff4890c1c9839a5eb0bc",
|
"sha256:9b3752887a2880690ce628bc263d6d13a3864083aeacff4890c1c9839a5eb0bc",
|
||||||
|
@ -1091,6 +1036,7 @@
|
||||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==1.16.0"
|
"version": "==1.16.0"
|
||||||
},
|
},
|
||||||
"sqlparse": {
|
"sqlparse": {
|
||||||
|
@ -1098,6 +1044,7 @@
|
||||||
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
|
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
|
||||||
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
|
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
"version": "==0.4.1"
|
"version": "==0.4.1"
|
||||||
},
|
},
|
||||||
"structlog": {
|
"structlog": {
|
||||||
|
@ -1153,6 +1100,7 @@
|
||||||
"sha256:7d6f89745680233f1c4db9ddb748df5e88d2a7a37962be174c0fd04c8dba1dc8",
|
"sha256:7d6f89745680233f1c4db9ddb748df5e88d2a7a37962be174c0fd04c8dba1dc8",
|
||||||
"sha256:c16b55f9a67b2419cfdf8846576e2ec9ba94fe6978a83080c352a80db31c93fb"
|
"sha256:c16b55f9a67b2419cfdf8846576e2ec9ba94fe6978a83080c352a80db31c93fb"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==21.2.1"
|
"version": "==21.2.1"
|
||||||
},
|
},
|
||||||
"typing-extensions": {
|
"typing-extensions": {
|
||||||
|
@ -1168,6 +1116,7 @@
|
||||||
"sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f",
|
"sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f",
|
||||||
"sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"
|
"sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==3.0.1"
|
"version": "==3.0.1"
|
||||||
},
|
},
|
||||||
"urllib3": {
|
"urllib3": {
|
||||||
|
@ -1212,6 +1161,7 @@
|
||||||
"sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30",
|
"sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30",
|
||||||
"sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"
|
"sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==5.0.0"
|
"version": "==5.0.0"
|
||||||
},
|
},
|
||||||
"watchgod": {
|
"watchgod": {
|
||||||
|
@ -1241,6 +1191,7 @@
|
||||||
"sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32",
|
"sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32",
|
||||||
"sha256:d376bd60eace9d437ab6d7ee16f4ab4e821c9dae591e1b783c58ebd8aaf80c5c"
|
"sha256:d376bd60eace9d437ab6d7ee16f4ab4e821c9dae591e1b783c58ebd8aaf80c5c"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==0.59.0"
|
"version": "==0.59.0"
|
||||||
},
|
},
|
||||||
"websockets": {
|
"websockets": {
|
||||||
|
@ -1327,6 +1278,7 @@
|
||||||
"sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a",
|
"sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a",
|
||||||
"sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"
|
"sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==1.6.3"
|
"version": "==1.6.3"
|
||||||
},
|
},
|
||||||
"zope.interface": {
|
"zope.interface": {
|
||||||
|
@ -1383,6 +1335,7 @@
|
||||||
"sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4",
|
"sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4",
|
||||||
"sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"
|
"sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==5.4.0"
|
"version": "==5.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1399,6 +1352,7 @@
|
||||||
"sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e",
|
"sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e",
|
||||||
"sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"
|
"sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version ~= '3.6'",
|
||||||
"version": "==2.5.6"
|
"version": "==2.5.6"
|
||||||
},
|
},
|
||||||
"attrs": {
|
"attrs": {
|
||||||
|
@ -1406,6 +1360,7 @@
|
||||||
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
"sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
|
||||||
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
"sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==21.2.0"
|
"version": "==21.2.0"
|
||||||
},
|
},
|
||||||
"bandit": {
|
"bandit": {
|
||||||
|
@ -1444,6 +1399,7 @@
|
||||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==4.0.0"
|
"version": "==4.0.0"
|
||||||
},
|
},
|
||||||
"click": {
|
"click": {
|
||||||
|
@ -1451,6 +1407,7 @@
|
||||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==7.1.2"
|
"version": "==7.1.2"
|
||||||
},
|
},
|
||||||
"colorama": {
|
"colorama": {
|
||||||
|
@ -1524,6 +1481,7 @@
|
||||||
"sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0",
|
"sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0",
|
||||||
"sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"
|
"sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.4'",
|
||||||
"version": "==4.0.7"
|
"version": "==4.0.7"
|
||||||
},
|
},
|
||||||
"gitpython": {
|
"gitpython": {
|
||||||
|
@ -1531,6 +1489,7 @@
|
||||||
"sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135",
|
"sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135",
|
||||||
"sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e"
|
"sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
"version": "==3.1.17"
|
"version": "==3.1.17"
|
||||||
},
|
},
|
||||||
"idna": {
|
"idna": {
|
||||||
|
@ -1552,6 +1511,7 @@
|
||||||
"sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
|
"sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
|
||||||
"sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
|
"sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6' and python_version < '4.0'",
|
||||||
"version": "==5.8.0"
|
"version": "==5.8.0"
|
||||||
},
|
},
|
||||||
"lazy-object-proxy": {
|
"lazy-object-proxy": {
|
||||||
|
@ -1579,6 +1539,7 @@
|
||||||
"sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
|
"sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
|
||||||
"sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
|
"sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||||
"version": "==1.6.0"
|
"version": "==1.6.0"
|
||||||
},
|
},
|
||||||
"mccabe": {
|
"mccabe": {
|
||||||
|
@ -1615,6 +1576,7 @@
|
||||||
"sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd",
|
"sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd",
|
||||||
"sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"
|
"sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.6'",
|
||||||
"version": "==5.6.0"
|
"version": "==5.6.0"
|
||||||
},
|
},
|
||||||
"pluggy": {
|
"pluggy": {
|
||||||
|
@ -1622,6 +1584,7 @@
|
||||||
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
|
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
|
||||||
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
|
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==0.13.1"
|
"version": "==0.13.1"
|
||||||
},
|
},
|
||||||
"py": {
|
"py": {
|
||||||
|
@ -1629,6 +1592,7 @@
|
||||||
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
|
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
|
||||||
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
|
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==1.10.0"
|
"version": "==1.10.0"
|
||||||
},
|
},
|
||||||
"pylint": {
|
"pylint": {
|
||||||
|
@ -1659,6 +1623,7 @@
|
||||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==2.4.7"
|
"version": "==2.4.7"
|
||||||
},
|
},
|
||||||
"pytest": {
|
"pytest": {
|
||||||
|
@ -1763,6 +1728,7 @@
|
||||||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
"version": "==2.25.1"
|
"version": "==2.25.1"
|
||||||
},
|
},
|
||||||
"requests-mock": {
|
"requests-mock": {
|
||||||
|
@ -1786,6 +1752,7 @@
|
||||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==1.16.0"
|
"version": "==1.16.0"
|
||||||
},
|
},
|
||||||
"smmap": {
|
"smmap": {
|
||||||
|
@ -1793,6 +1760,7 @@
|
||||||
"sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182",
|
"sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182",
|
||||||
"sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"
|
"sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
"version": "==4.0.0"
|
"version": "==4.0.0"
|
||||||
},
|
},
|
||||||
"stevedore": {
|
"stevedore": {
|
||||||
|
@ -1800,6 +1768,7 @@
|
||||||
"sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee",
|
"sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee",
|
||||||
"sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"
|
"sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==3.3.0"
|
"version": "==3.3.0"
|
||||||
},
|
},
|
||||||
"toml": {
|
"toml": {
|
||||||
|
@ -1807,6 +1776,7 @@
|
||||||
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
|
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
|
||||||
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
|
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
|
||||||
],
|
],
|
||||||
|
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==0.10.2"
|
"version": "==0.10.2"
|
||||||
},
|
},
|
||||||
"urllib3": {
|
"urllib3": {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""Meta API"""
|
"""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.fields import CharField
|
||||||
from rest_framework.permissions import IsAdminUser
|
from rest_framework.permissions import IsAdminUser
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
@ -22,7 +22,7 @@ class AppsViewSet(ViewSet):
|
||||||
|
|
||||||
permission_classes = [IsAdminUser]
|
permission_classes = [IsAdminUser]
|
||||||
|
|
||||||
@swagger_auto_schema(responses={200: AppSerializer(many=True)})
|
@extend_schema(responses={200: AppSerializer(many=True)})
|
||||||
def list(self, request: Request) -> Response:
|
def list(self, request: Request) -> Response:
|
||||||
"""List current messages and pass into Serializer"""
|
"""List current messages and pass into Serializer"""
|
||||||
data = []
|
data = []
|
||||||
|
|
|
@ -7,12 +7,12 @@ from django.db.models import Count, ExpressionWrapper, F
|
||||||
from django.db.models.fields import DurationField
|
from django.db.models.fields import DurationField
|
||||||
from django.db.models.functions import ExtractHour
|
from django.db.models.functions import ExtractHour
|
||||||
from django.utils.timezone import now
|
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.fields import IntegerField, SerializerMethodField
|
||||||
from rest_framework.permissions import IsAdminUser
|
from rest_framework.permissions import IsAdminUser
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
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.core.api.utils import PassiveSerializer
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
|
@ -58,24 +58,24 @@ class LoginMetricsSerializer(PassiveSerializer):
|
||||||
logins_per_1h = SerializerMethodField()
|
logins_per_1h = SerializerMethodField()
|
||||||
logins_failed_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, _):
|
def get_logins_per_1h(self, _):
|
||||||
"""Get successful logins per hour for the last 24 hours"""
|
"""Get successful logins per hour for the last 24 hours"""
|
||||||
return get_events_per_1h(action=EventAction.LOGIN)
|
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, _):
|
def get_logins_failed_per_1h(self, _):
|
||||||
"""Get failed logins per hour for the last 24 hours"""
|
"""Get failed logins per hour for the last 24 hours"""
|
||||||
return get_events_per_1h(action=EventAction.LOGIN_FAILED)
|
return get_events_per_1h(action=EventAction.LOGIN_FAILED)
|
||||||
|
|
||||||
|
|
||||||
class AdministrationMetricsViewSet(ViewSet):
|
class AdministrationMetricsViewSet(APIView):
|
||||||
"""Login Metrics per 1h"""
|
"""Login Metrics per 1h"""
|
||||||
|
|
||||||
permission_classes = [IsAdminUser]
|
permission_classes = [IsAdminUser]
|
||||||
|
|
||||||
@swagger_auto_schema(responses={200: LoginMetricsSerializer(many=False)})
|
@extend_schema(responses={200: LoginMetricsSerializer(many=False)})
|
||||||
def list(self, request: Request) -> Response:
|
def get(self, request: Request) -> Response:
|
||||||
"""Login Metrics per 1h"""
|
"""Login Metrics per 1h"""
|
||||||
serializer = LoginMetricsSerializer(True)
|
serializer = LoginMetricsSerializer(True)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
|
@ -4,7 +4,8 @@ from importlib import import_module
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.http.response import Http404
|
from django.http.response import Http404
|
||||||
from django.utils.translation import gettext_lazy as _
|
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.decorators import action
|
||||||
from rest_framework.fields import CharField, ChoiceField, DateTimeField, ListField
|
from rest_framework.fields import CharField, ChoiceField, DateTimeField, ListField
|
||||||
from rest_framework.permissions import IsAdminUser
|
from rest_framework.permissions import IsAdminUser
|
||||||
|
@ -34,9 +35,13 @@ class TaskViewSet(ViewSet):
|
||||||
"""Read-only view set that returns all background tasks"""
|
"""Read-only view set that returns all background tasks"""
|
||||||
|
|
||||||
permission_classes = [IsAdminUser]
|
permission_classes = [IsAdminUser]
|
||||||
|
serializer_class = TaskSerializer
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={200: TaskSerializer(many=False), 404: "Task not found"}
|
responses={
|
||||||
|
200: TaskSerializer(many=False),
|
||||||
|
404: OpenApiResponse(description="Task not found"),
|
||||||
|
}
|
||||||
)
|
)
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
def retrieve(self, request: Request, pk=None) -> Response:
|
def retrieve(self, request: Request, pk=None) -> Response:
|
||||||
|
@ -46,18 +51,19 @@ class TaskViewSet(ViewSet):
|
||||||
raise Http404
|
raise Http404
|
||||||
return Response(TaskSerializer(task, many=False).data)
|
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:
|
def list(self, request: Request) -> Response:
|
||||||
"""List system tasks"""
|
"""List system tasks"""
|
||||||
tasks = sorted(TaskInfo.all().values(), key=lambda task: task.task_name)
|
tasks = sorted(TaskInfo.all().values(), key=lambda task: task.task_name)
|
||||||
return Response(TaskSerializer(tasks, many=True).data)
|
return Response(TaskSerializer(tasks, many=True).data)
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
|
request=OpenApiTypes.NONE,
|
||||||
responses={
|
responses={
|
||||||
204: "Task retried successfully",
|
204: OpenApiResponse(description="Task retried successfully"),
|
||||||
404: "Task not found",
|
404: OpenApiResponse(description="Task not found"),
|
||||||
500: "Failed to retry task",
|
500: OpenApiResponse(description="Failed to retry task"),
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=["post"])
|
@action(detail=True, methods=["post"])
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
||||||
from django.core.cache import cache
|
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 packaging.version import parse
|
||||||
from rest_framework.fields import SerializerMethodField
|
from rest_framework.fields import SerializerMethodField
|
||||||
from rest_framework.mixins import ListModelMixin
|
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
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 import ENV_GIT_HASH_KEY, __version__
|
||||||
from authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_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."""
|
"""Get running and latest version."""
|
||||||
|
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
pagination_class = None
|
pagination_class = None
|
||||||
filter_backends = []
|
filter_backends = []
|
||||||
|
|
||||||
def get_queryset(self): # pragma: no cover
|
@extend_schema(responses={200: VersionSerializer(many=False)})
|
||||||
return None
|
def get(self, request: Request) -> Response:
|
||||||
|
|
||||||
@swagger_auto_schema(responses={200: VersionSerializer(many=False)})
|
|
||||||
def list(self, request: Request) -> Response:
|
|
||||||
"""Get running and latest version."""
|
"""Get running and latest version."""
|
||||||
return Response(VersionSerializer(True).data)
|
return Response(VersionSerializer(True).data)
|
||||||
|
|
|
@ -1,25 +1,22 @@
|
||||||
"""authentik administration overview"""
|
"""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.permissions import IsAdminUser
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import Serializer
|
from rest_framework.views import APIView
|
||||||
from rest_framework.viewsets import GenericViewSet
|
|
||||||
|
|
||||||
from authentik.root.celery import CELERY_APP
|
from authentik.root.celery import CELERY_APP
|
||||||
|
|
||||||
|
|
||||||
class WorkerViewSet(ListModelMixin, GenericViewSet):
|
class WorkerView(APIView):
|
||||||
"""Get currently connected worker count."""
|
"""Get currently connected worker count."""
|
||||||
|
|
||||||
serializer_class = Serializer
|
|
||||||
permission_classes = [IsAdminUser]
|
permission_classes = [IsAdminUser]
|
||||||
|
|
||||||
def get_queryset(self): # pragma: no cover
|
@extend_schema(
|
||||||
return None
|
responses=inline_serializer("Workers", fields={"count": IntegerField()})
|
||||||
|
)
|
||||||
def list(self, request: Request) -> Response:
|
def get(self, request: Request) -> Response:
|
||||||
"""Get currently connected worker count."""
|
"""Get currently connected worker count."""
|
||||||
return Response(
|
return Response({"count": len(CELERY_APP.control.ping(timeout=0.5))})
|
||||||
{"pagination": {"count": len(CELERY_APP.control.ping(timeout=0.5))}}
|
|
||||||
)
|
|
||||||
|
|
|
@ -74,21 +74,21 @@ class TestAdminAPI(TestCase):
|
||||||
|
|
||||||
def test_version(self):
|
def test_version(self):
|
||||||
"""Test Version API"""
|
"""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)
|
self.assertEqual(response.status_code, 200)
|
||||||
body = loads(response.content)
|
body = loads(response.content)
|
||||||
self.assertEqual(body["version_current"], __version__)
|
self.assertEqual(body["version_current"], __version__)
|
||||||
|
|
||||||
def test_workers(self):
|
def test_workers(self):
|
||||||
"""Test Workers API"""
|
"""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)
|
self.assertEqual(response.status_code, 200)
|
||||||
body = loads(response.content)
|
body = loads(response.content)
|
||||||
self.assertEqual(body["pagination"]["count"], 0)
|
self.assertEqual(body["count"], 0)
|
||||||
|
|
||||||
def test_metrics(self):
|
def test_metrics(self):
|
||||||
"""Test metrics API"""
|
"""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)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_apps(self):
|
def test_apps(self):
|
||||||
|
|
|
@ -3,6 +3,7 @@ from base64 import b64decode
|
||||||
from binascii import Error
|
from binascii import Error
|
||||||
from typing import Any, Optional, Union
|
from typing import Any, Optional, Union
|
||||||
|
|
||||||
|
from drf_spectacular.authentication import OpenApiAuthenticationExtension
|
||||||
from rest_framework.authentication import BaseAuthentication, get_authorization_header
|
from rest_framework.authentication import BaseAuthentication, get_authorization_header
|
||||||
from rest_framework.exceptions import AuthenticationFailed
|
from rest_framework.exceptions import AuthenticationFailed
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
@ -55,3 +56,18 @@ class AuthentikTokenAuthentication(BaseAuthentication):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return (token.user, None) # pragma: no cover
|
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,
|
"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"""
|
"""Error Response schema, from https://github.com/axnsan12/drf-yasg/issues/224"""
|
||||||
from drf_yasg import openapi
|
from django.utils.translation import gettext_lazy as _
|
||||||
from drf_yasg.inspectors.view import SwaggerAutoSchema
|
from drf_spectacular.plumbing import (
|
||||||
from drf_yasg.utils import force_real_str, is_list_view
|
ResolvedComponent,
|
||||||
from rest_framework import exceptions, status
|
build_array_type,
|
||||||
from rest_framework.settings import api_settings
|
build_basic_type,
|
||||||
|
build_object_type,
|
||||||
|
)
|
||||||
|
from drf_spectacular.settings import spectacular_settings
|
||||||
|
from drf_spectacular.types import OpenApiTypes
|
||||||
|
|
||||||
|
|
||||||
class ErrorResponseAutoSchema(SwaggerAutoSchema):
|
def build_standard_type(obj, **kwargs):
|
||||||
"""Inspector which includes an error schema"""
|
"""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"""
|
GENERIC_ERROR = build_object_type(
|
||||||
return openapi.Schema(
|
description=_("Generic API Error"),
|
||||||
"Generic API Error",
|
properties={
|
||||||
type=openapi.TYPE_OBJECT,
|
"detail": build_standard_type(OpenApiTypes.STR),
|
||||||
properties={
|
"code": build_standard_type(OpenApiTypes.STR),
|
||||||
"detail": openapi.Schema(
|
},
|
||||||
type=openapi.TYPE_STRING, description="Error details"
|
required=["detail"],
|
||||||
),
|
)
|
||||||
"code": openapi.Schema(
|
VALIDATION_ERROR = build_object_type(
|
||||||
type=openapi.TYPE_STRING, description="Error code"
|
description=_("Validation Error"),
|
||||||
),
|
properties={
|
||||||
},
|
"non_field_errors": build_array_type(build_standard_type(OpenApiTypes.STR)),
|
||||||
required=["detail"],
|
"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):
|
generic_error = create_component("GenericError", GENERIC_ERROR)
|
||||||
"""Get a generic validation error schema"""
|
validation_error = create_component("ValidationError", VALIDATION_ERROR)
|
||||||
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),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_response_serializers(self):
|
for path in result["paths"].values():
|
||||||
responses = super().get_response_serializers()
|
for method in path.values():
|
||||||
definitions = self.components.with_scope(
|
method["responses"].setdefault("400", validation_error.ref)
|
||||||
openapi.SCHEMA_DEFINITIONS
|
method["responses"].setdefault("403", generic_error.ref)
|
||||||
) # type: openapi.ReferenceResolver
|
|
||||||
|
|
||||||
definitions.setdefault("GenericError", self.get_generic_error_schema)
|
result["components"] = generator.registry.build(
|
||||||
definitions.setdefault("ValidationError", self.get_validation_error_schema)
|
spectacular_settings.APPEND_COMPONENTS
|
||||||
definitions.setdefault("APIException", self.get_generic_error_schema)
|
)
|
||||||
|
|
||||||
if self.get_request_serializer() or self.get_query_serializer():
|
return result
|
||||||
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
|
|
||||||
|
|
|
@ -11,6 +11,6 @@ class TestConfig(APITestCase):
|
||||||
def test_config(self):
|
def test_config(self):
|
||||||
"""Test YAML generation"""
|
"""Test YAML generation"""
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse("authentik_api:configs-list"),
|
reverse("authentik_api:config"),
|
||||||
)
|
)
|
||||||
self.assertTrue(loads(response.content.decode()))
|
self.assertTrue(loads(response.content.decode()))
|
||||||
|
|
22
authentik/api/tests/test_schema.py
Normal file
22
authentik/api/tests/test_schema.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
"""Schema generation tests"""
|
||||||
|
from django.urls import reverse
|
||||||
|
from rest_framework.test import APITestCase
|
||||||
|
from yaml import safe_load
|
||||||
|
|
||||||
|
|
||||||
|
class TestSchemaGeneration(APITestCase):
|
||||||
|
"""Generic admin tests"""
|
||||||
|
|
||||||
|
def test_schema(self):
|
||||||
|
"""Test generation"""
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("authentik_api:schema"),
|
||||||
|
)
|
||||||
|
self.assertTrue(safe_load(response.content.decode()))
|
||||||
|
|
||||||
|
def test_browser(self):
|
||||||
|
"""Test API Browser"""
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("authentik_api:schema-browser"),
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
|
@ -1,31 +0,0 @@
|
||||||
"""Swagger generation tests"""
|
|
||||||
from json import loads
|
|
||||||
|
|
||||||
from django.urls import reverse
|
|
||||||
from rest_framework.test import APITestCase
|
|
||||||
from yaml import safe_load
|
|
||||||
|
|
||||||
|
|
||||||
class TestSwaggerGeneration(APITestCase):
|
|
||||||
"""Generic admin tests"""
|
|
||||||
|
|
||||||
def test_yaml(self):
|
|
||||||
"""Test YAML generation"""
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("authentik_api:schema-json", kwargs={"format": ".yaml"}),
|
|
||||||
)
|
|
||||||
self.assertTrue(safe_load(response.content.decode()))
|
|
||||||
|
|
||||||
def test_json(self):
|
|
||||||
"""Test JSON generation"""
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("authentik_api:schema-json", kwargs={"format": ".json"}),
|
|
||||||
)
|
|
||||||
self.assertTrue(loads(response.content.decode()))
|
|
||||||
|
|
||||||
def test_browser(self):
|
|
||||||
"""Test API Browser"""
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("authentik_api:swagger"),
|
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
|
@ -1,10 +1,10 @@
|
||||||
"""core Configs API"""
|
"""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.fields import BooleanField, CharField, ListField
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
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.core.api.utils import PassiveSerializer
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
|
@ -29,13 +29,13 @@ class ConfigSerializer(PassiveSerializer):
|
||||||
error_reporting_send_pii = BooleanField(read_only=True)
|
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"""
|
"""Read-only view set that returns the current session's Configs"""
|
||||||
|
|
||||||
permission_classes = [AllowAny]
|
permission_classes = [AllowAny]
|
||||||
|
|
||||||
@swagger_auto_schema(responses={200: ConfigSerializer(many=False)})
|
@extend_schema(responses={200: ConfigSerializer(many=False)})
|
||||||
def list(self, request: Request) -> Response:
|
def get(self, request: Request) -> Response:
|
||||||
"""Retrive public configuration options"""
|
"""Retrive public configuration options"""
|
||||||
config = ConfigSerializer(
|
config = ConfigSerializer(
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
"""api v2 urls"""
|
"""api v2 urls"""
|
||||||
from django.urls import path, re_path
|
from django.urls import path
|
||||||
from drf_yasg import openapi
|
from drf_spectacular.views import SpectacularAPIView
|
||||||
from drf_yasg.views import get_schema_view
|
|
||||||
from rest_framework import routers
|
from rest_framework import routers
|
||||||
from rest_framework.permissions import AllowAny
|
|
||||||
|
|
||||||
from authentik.admin.api.meta import AppsViewSet
|
from authentik.admin.api.meta import AppsViewSet
|
||||||
from authentik.admin.api.metrics import AdministrationMetricsViewSet
|
from authentik.admin.api.metrics import AdministrationMetricsViewSet
|
||||||
from authentik.admin.api.tasks import TaskViewSet
|
from authentik.admin.api.tasks import TaskViewSet
|
||||||
from authentik.admin.api.version import VersionViewSet
|
from authentik.admin.api.version import VersionView
|
||||||
from authentik.admin.api.workers import WorkerViewSet
|
from authentik.admin.api.workers import WorkerView
|
||||||
from authentik.api.v2.config import ConfigsViewSet
|
from authentik.api.v2.config import ConfigView
|
||||||
from authentik.api.views import SwaggerView
|
from authentik.api.views import APIBrowserView
|
||||||
from authentik.core.api.applications import ApplicationViewSet
|
from authentik.core.api.applications import ApplicationViewSet
|
||||||
from authentik.core.api.groups import GroupViewSet
|
from authentik.core.api.groups import GroupViewSet
|
||||||
from authentik.core.api.propertymappings import PropertyMappingViewSet
|
from authentik.core.api.propertymappings import PropertyMappingViewSet
|
||||||
|
@ -100,11 +98,6 @@ from authentik.stages.user_write.api import UserWriteStageViewSet
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
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/system_tasks", TaskViewSet, basename="admin_system_tasks")
|
||||||
router.register("admin/apps", AppsViewSet, basename="apps")
|
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/user_consent", UserConsentViewSet)
|
||||||
router.register("core/tokens", TokenViewSet)
|
router.register("core/tokens", TokenViewSet)
|
||||||
|
|
||||||
router.register("outposts/outposts", OutpostViewSet)
|
|
||||||
router.register("outposts/instances", OutpostViewSet)
|
router.register("outposts/instances", OutpostViewSet)
|
||||||
router.register("outposts/service_connections/all", ServiceConnectionViewSet)
|
router.register("outposts/service_connections/all", ServiceConnectionViewSet)
|
||||||
router.register("outposts/service_connections/docker", DockerServiceConnectionViewSet)
|
router.register("outposts/service_connections/docker", DockerServiceConnectionViewSet)
|
||||||
|
@ -196,32 +188,25 @@ router.register("stages/user_write", UserWriteStageViewSet)
|
||||||
router.register("stages/dummy", DummyStageViewSet)
|
router.register("stages/dummy", DummyStageViewSet)
|
||||||
router.register("policies/dummy", DummyPolicyViewSet)
|
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 = (
|
urlpatterns = (
|
||||||
[
|
[
|
||||||
path("", SwaggerView.as_view(), name="swagger"),
|
path("", APIBrowserView.as_view(), name="schema-browser"),
|
||||||
]
|
]
|
||||||
+ router.urls
|
+ 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(
|
path(
|
||||||
"flows/executor/<slug:flow_slug>/",
|
"flows/executor/<slug:flow_slug>/",
|
||||||
FlowExecutorView.as_view(),
|
FlowExecutorView.as_view(),
|
||||||
name="flow-executor",
|
name="flow-executor",
|
||||||
),
|
),
|
||||||
re_path(
|
path("schema/", SpectacularAPIView.as_view(), name="schema"),
|
||||||
r"^swagger(?P<format>\.json|\.yaml)$",
|
|
||||||
SchemaView.without_ui(cache_timeout=0),
|
|
||||||
name="schema-json",
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,18 +5,15 @@ from django.urls import reverse
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
|
||||||
class SwaggerView(TemplateView):
|
class APIBrowserView(TemplateView):
|
||||||
"""Show swagger view based on rapi-doc"""
|
"""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]:
|
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
||||||
path = self.request.build_absolute_uri(
|
path = self.request.build_absolute_uri(
|
||||||
reverse(
|
reverse(
|
||||||
"authentik_api:schema-json",
|
"authentik_api:schema",
|
||||||
kwargs={
|
|
||||||
"format": ".json",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return super().get_context_data(path=path, **kwargs)
|
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.db.models import QuerySet
|
||||||
from django.http.response import HttpResponseBadRequest
|
from django.http.response import HttpResponseBadRequest
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from drf_yasg import openapi
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import SerializerMethodField
|
from rest_framework.fields import SerializerMethodField
|
||||||
from rest_framework.parsers import MultiPartParser
|
from rest_framework.parsers import MultiPartParser
|
||||||
|
@ -58,6 +58,9 @@ class ApplicationSerializer(ModelSerializer):
|
||||||
"meta_publisher",
|
"meta_publisher",
|
||||||
"policy_engine_mode",
|
"policy_engine_mode",
|
||||||
]
|
]
|
||||||
|
extra_kwargs = {
|
||||||
|
"meta_icon": {"read_only": True},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ApplicationViewSet(ModelViewSet):
|
class ApplicationViewSet(ModelViewSet):
|
||||||
|
@ -92,10 +95,10 @@ class ApplicationViewSet(ModelViewSet):
|
||||||
applications.append(application)
|
applications.append(application)
|
||||||
return applications
|
return applications
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={
|
responses={
|
||||||
204: "Access granted",
|
204: OpenApiResponse(description="Access granted"),
|
||||||
403: "Access denied",
|
403: OpenApiResponse(description="Access denied"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=["GET"])
|
@action(detail=True, methods=["GET"])
|
||||||
|
@ -111,12 +114,12 @@ class ApplicationViewSet(ModelViewSet):
|
||||||
return Response(status=204)
|
return Response(status=204)
|
||||||
return Response(status=403)
|
return Response(status=403)
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
name="superuser_full_list",
|
name="superuser_full_list",
|
||||||
in_=openapi.IN_QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
type=openapi.TYPE_BOOLEAN,
|
type=OpenApiTypes.BOOL,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -151,17 +154,20 @@ class ApplicationViewSet(ModelViewSet):
|
||||||
return self.get_paginated_response(serializer.data)
|
return self.get_paginated_response(serializer.data)
|
||||||
|
|
||||||
@permission_required("authentik_core.change_application")
|
@permission_required("authentik_core.change_application")
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=no_body,
|
request=OpenApiTypes.NONE,
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
name="file",
|
name="file",
|
||||||
in_=openapi.IN_FORM,
|
location=OpenApiParameter.QUERY, # TODO: In Form
|
||||||
type=openapi.TYPE_FILE,
|
type=OpenApiTypes.BINARY,
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
responses={200: "Success", 400: "Bad request"},
|
responses={
|
||||||
|
200: OpenApiResponse(description="Success"),
|
||||||
|
400: OpenApiResponse(description="Bad request"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
@action(
|
@action(
|
||||||
detail=True,
|
detail=True,
|
||||||
|
@ -184,7 +190,7 @@ class ApplicationViewSet(ModelViewSet):
|
||||||
@permission_required(
|
@permission_required(
|
||||||
"authentik_core.view_application", ["authentik_events.view_event"]
|
"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=[])
|
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def metrics(self, request: Request, slug: str):
|
def metrics(self, request: Request, slug: str):
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
"""PropertyMapping API Views"""
|
"""PropertyMapping API Views"""
|
||||||
from json import dumps
|
from json import dumps
|
||||||
|
|
||||||
from drf_yasg import openapi
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_yasg.utils import swagger_auto_schema
|
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||||
from guardian.shortcuts import get_objects_for_user
|
from guardian.shortcuts import get_objects_for_user
|
||||||
from rest_framework import mixins
|
from rest_framework import mixins
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
@ -81,7 +81,7 @@ class PropertyMappingViewSet(
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return PropertyMapping.objects.select_subclasses()
|
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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def types(self, request: Request) -> Response:
|
def types(self, request: Request) -> Response:
|
||||||
"""Get all creatable property-mapping types"""
|
"""Get all creatable property-mapping types"""
|
||||||
|
@ -100,14 +100,17 @@ class PropertyMappingViewSet(
|
||||||
return Response(TypeCreateSerializer(data, many=True).data)
|
return Response(TypeCreateSerializer(data, many=True).data)
|
||||||
|
|
||||||
@permission_required("authentik_core.view_propertymapping")
|
@permission_required("authentik_core.view_propertymapping")
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=PolicyTestSerializer(),
|
request=PolicyTestSerializer(),
|
||||||
responses={200: PropertyMappingTestResultSerializer, 400: "Invalid parameters"},
|
responses={
|
||||||
manual_parameters=[
|
200: PropertyMappingTestResultSerializer,
|
||||||
openapi.Parameter(
|
400: OpenApiResponse(description="Invalid parameters"),
|
||||||
|
},
|
||||||
|
parameters=[
|
||||||
|
OpenApiParameter(
|
||||||
name="format_result",
|
name="format_result",
|
||||||
in_=openapi.IN_QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
type=openapi.TYPE_BOOLEAN,
|
type=OpenApiTypes.BOOL,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Provider API Views"""
|
"""Provider API Views"""
|
||||||
from django.utils.translation import gettext_lazy as _
|
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 import mixins
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import ReadOnlyField
|
from rest_framework.fields import ReadOnlyField
|
||||||
|
@ -22,7 +22,7 @@ class ProviderSerializer(ModelSerializer, MetaNameSerializer):
|
||||||
|
|
||||||
component = SerializerMethodField()
|
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"""
|
"""Get object component so that we know how to edit the object"""
|
||||||
# pyright: reportGeneralTypeIssues=false
|
# pyright: reportGeneralTypeIssues=false
|
||||||
if obj.__class__ == Provider:
|
if obj.__class__ == Provider:
|
||||||
|
@ -66,7 +66,7 @@ class ProviderViewSet(
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Provider.objects.select_subclasses()
|
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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def types(self, request: Request) -> Response:
|
def types(self, request: Request) -> Response:
|
||||||
"""Get all creatable provider types"""
|
"""Get all creatable provider types"""
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Source API Views"""
|
"""Source API Views"""
|
||||||
from typing import Iterable
|
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 import mixins
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
@ -24,7 +24,7 @@ class SourceSerializer(ModelSerializer, MetaNameSerializer):
|
||||||
|
|
||||||
component = SerializerMethodField()
|
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"""
|
"""Get object component so that we know how to edit the object"""
|
||||||
# pyright: reportGeneralTypeIssues=false
|
# pyright: reportGeneralTypeIssues=false
|
||||||
if obj.__class__ == Source:
|
if obj.__class__ == Source:
|
||||||
|
@ -64,7 +64,7 @@ class SourceViewSet(
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Source.objects.select_subclasses()
|
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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def types(self, request: Request) -> Response:
|
def types(self, request: Request) -> Response:
|
||||||
"""Get all creatable source types"""
|
"""Get all creatable source types"""
|
||||||
|
@ -87,7 +87,7 @@ class SourceViewSet(
|
||||||
)
|
)
|
||||||
return Response(TypeCreateSerializer(data, many=True).data)
|
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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def user_settings(self, request: Request) -> Response:
|
def user_settings(self, request: Request) -> Response:
|
||||||
"""Get all sources the user can configure"""
|
"""Get all sources the user can configure"""
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Tokens API Viewset"""
|
"""Tokens API Viewset"""
|
||||||
from django.http.response import Http404
|
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.decorators import action
|
||||||
from rest_framework.fields import CharField
|
from rest_framework.fields import CharField
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
@ -67,10 +67,10 @@ class TokenViewSet(ModelViewSet):
|
||||||
serializer.save(user=self.request.user, intent=TokenIntents.INTENT_API)
|
serializer.save(user=self.request.user, intent=TokenIntents.INTENT_API)
|
||||||
|
|
||||||
@permission_required("authentik_core.view_token_key")
|
@permission_required("authentik_core.view_token_key")
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={
|
responses={
|
||||||
200: TokenViewSerializer(many=False),
|
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=[])
|
@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.utils.http import urlencode
|
||||||
from django_filters.filters import BooleanFilter, CharFilter
|
from django_filters.filters import BooleanFilter, CharFilter
|
||||||
from django_filters.filterset import FilterSet
|
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 guardian.utils import get_anonymous_user
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import CharField, JSONField, SerializerMethodField
|
from rest_framework.fields import CharField, JSONField, SerializerMethodField
|
||||||
|
@ -77,13 +77,13 @@ class UserMetricsSerializer(PassiveSerializer):
|
||||||
logins_failed_per_1h = SerializerMethodField()
|
logins_failed_per_1h = SerializerMethodField()
|
||||||
authorizations_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, _):
|
def get_logins_per_1h(self, _):
|
||||||
"""Get successful logins per hour for the last 24 hours"""
|
"""Get successful logins per hour for the last 24 hours"""
|
||||||
user = self.context["user"]
|
user = self.context["user"]
|
||||||
return get_events_per_1h(action=EventAction.LOGIN, user__pk=user.pk)
|
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, _):
|
def get_logins_failed_per_1h(self, _):
|
||||||
"""Get failed logins per hour for the last 24 hours"""
|
"""Get failed logins per hour for the last 24 hours"""
|
||||||
user = self.context["user"]
|
user = self.context["user"]
|
||||||
|
@ -91,7 +91,7 @@ class UserMetricsSerializer(PassiveSerializer):
|
||||||
action=EventAction.LOGIN_FAILED, context__username=user.username
|
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, _):
|
def get_authorizations_per_1h(self, _):
|
||||||
"""Get failed logins per hour for the last 24 hours"""
|
"""Get failed logins per hour for the last 24 hours"""
|
||||||
user = self.context["user"]
|
user = self.context["user"]
|
||||||
|
@ -142,7 +142,7 @@ class UserViewSet(ModelViewSet):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return User.objects.all().exclude(pk=get_anonymous_user().pk)
|
return User.objects.all().exclude(pk=get_anonymous_user().pk)
|
||||||
|
|
||||||
@swagger_auto_schema(responses={200: SessionUserSerializer(many=False)})
|
@extend_schema(responses={200: SessionUserSerializer(many=False)})
|
||||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
def me(self, request: Request) -> Response:
|
def me(self, request: Request) -> Response:
|
||||||
|
@ -158,7 +158,7 @@ class UserViewSet(ModelViewSet):
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
@permission_required("authentik_core.view_user", ["authentik_events.view_event"])
|
@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=[])
|
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||||
# pylint: disable=invalid-name, unused-argument
|
# pylint: disable=invalid-name, unused-argument
|
||||||
def metrics(self, request: Request, pk: int) -> Response:
|
def metrics(self, request: Request, pk: int) -> Response:
|
||||||
|
@ -169,8 +169,11 @@ class UserViewSet(ModelViewSet):
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
@permission_required("authentik_core.reset_user_password")
|
@permission_required("authentik_core.reset_user_password")
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={"200": LinkSerializer(many=False), "404": "No recovery flow found."},
|
responses={
|
||||||
|
"200": LinkSerializer(many=False),
|
||||||
|
"404": OpenApiResponse(description="No recovery flow found."),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||||
# pylint: disable=invalid-name, unused-argument
|
# pylint: disable=invalid-name, unused-argument
|
||||||
|
|
|
@ -28,6 +28,9 @@ class PassiveSerializer(Serializer):
|
||||||
) -> Model: # pragma: no cover
|
) -> Model: # pragma: no cover
|
||||||
return Model()
|
return Model()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Model
|
||||||
|
|
||||||
|
|
||||||
class MetaNameSerializer(PassiveSerializer):
|
class MetaNameSerializer(PassiveSerializer):
|
||||||
"""Add verbose names to response"""
|
"""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 cryptography.x509 import load_pem_x509_certificate
|
||||||
from django.http.response import HttpResponse
|
from django.http.response import HttpResponse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from drf_yasg import openapi
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_yasg.utils import swagger_auto_schema
|
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import (
|
from rest_framework.fields import (
|
||||||
CharField,
|
CharField,
|
||||||
|
@ -125,9 +125,12 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
||||||
filterset_class = CertificateKeyPairFilter
|
filterset_class = CertificateKeyPairFilter
|
||||||
|
|
||||||
@permission_required(None, ["authentik_crypto.add_certificatekeypair"])
|
@permission_required(None, ["authentik_crypto.add_certificatekeypair"])
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=CertificateGenerationSerializer(),
|
request=CertificateGenerationSerializer(),
|
||||||
responses={200: CertificateKeyPairSerializer, 400: "Bad request"},
|
responses={
|
||||||
|
200: CertificateKeyPairSerializer,
|
||||||
|
400: OpenApiResponse(description="Bad request"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
@action(detail=False, methods=["POST"])
|
@action(detail=False, methods=["POST"])
|
||||||
def generate(self, request: Request) -> Response:
|
def generate(self, request: Request) -> Response:
|
||||||
|
@ -147,12 +150,12 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
||||||
serializer = self.get_serializer(instance)
|
serializer = self.get_serializer(instance)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
name="download",
|
name="download",
|
||||||
in_=openapi.IN_QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
type=openapi.TYPE_BOOLEAN,
|
type=OpenApiTypes.BOOL,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
responses={200: CertificateDataSerializer(many=False)},
|
responses={200: CertificateDataSerializer(many=False)},
|
||||||
|
@ -180,12 +183,12 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
||||||
CertificateDataSerializer({"data": certificate.certificate_data}).data
|
CertificateDataSerializer({"data": certificate.certificate_data}).data
|
||||||
)
|
)
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
name="download",
|
name="download",
|
||||||
in_=openapi.IN_QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
type=openapi.TYPE_BOOLEAN,
|
type=OpenApiTypes.BOOL,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
responses={200: CertificateDataSerializer(many=False)},
|
responses={200: CertificateDataSerializer(many=False)},
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
import django_filters
|
import django_filters
|
||||||
from django.db.models.aggregates import Count
|
from django.db.models.aggregates import Count
|
||||||
from django.db.models.fields.json import KeyTextTransform
|
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 guardian.shortcuts import get_objects_for_user
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import CharField, DictField, IntegerField
|
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):
|
class EventTopPerUserSerializer(PassiveSerializer):
|
||||||
"""Response object of Event's top_per_user"""
|
"""Response object of Event's top_per_user"""
|
||||||
|
|
||||||
|
@ -111,12 +106,19 @@ class EventViewSet(ReadOnlyModelViewSet):
|
||||||
]
|
]
|
||||||
filterset_class = EventsFilter
|
filterset_class = EventsFilter
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
method="GET",
|
methods=["GET"],
|
||||||
responses={200: EventTopPerUserSerializer(many=True)},
|
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):
|
def top_per_user(self, request: Request):
|
||||||
"""Get the top_n events grouped by user count"""
|
"""Get the top_n events grouped by user count"""
|
||||||
filtered_action = request.query_params.get("action", EventAction.LOGIN)
|
filtered_action = request.query_params.get("action", EventAction.LOGIN)
|
||||||
|
@ -134,7 +136,7 @@ class EventViewSet(ReadOnlyModelViewSet):
|
||||||
.order_by("-counted_events")[:top_n]
|
.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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def actions(self, request: Request) -> Response:
|
def actions(self, request: Request) -> Response:
|
||||||
"""Get all actions"""
|
"""Get all actions"""
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""NotificationTransport API Views"""
|
"""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.decorators import action
|
||||||
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
@ -22,7 +23,7 @@ class NotificationTransportSerializer(ModelSerializer):
|
||||||
|
|
||||||
mode_verbose = SerializerMethodField()
|
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 selected mode with a UI Label"""
|
||||||
return TransportMode(instance.mode).label
|
return TransportMode(instance.mode).label
|
||||||
|
|
||||||
|
@ -58,12 +59,12 @@ class NotificationTransportViewSet(ModelViewSet):
|
||||||
serializer_class = NotificationTransportSerializer
|
serializer_class = NotificationTransportSerializer
|
||||||
|
|
||||||
@permission_required("authentik_events.change_notificationtransport")
|
@permission_required("authentik_events.change_notificationtransport")
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={
|
responses={
|
||||||
200: NotificationTransportTestSerializer(many=False),
|
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"])
|
@action(detail=True, pagination_class=None, filter_backends=[], methods=["post"])
|
||||||
# pylint: disable=invalid-name, unused-argument
|
# pylint: disable=invalid-name, unused-argument
|
||||||
|
@ -83,4 +84,4 @@ class NotificationTransportViewSet(ModelViewSet):
|
||||||
response.is_valid()
|
response.is_valid()
|
||||||
return Response(response.data)
|
return Response(response.data)
|
||||||
except NotificationTransportError as exc:
|
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.http.response import HttpResponseBadRequest, JsonResponse
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from drf_yasg import openapi
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||||
from guardian.shortcuts import get_objects_for_user
|
from guardian.shortcuts import get_objects_for_user
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.parsers import MultiPartParser
|
from rest_framework.parsers import MultiPartParser
|
||||||
|
@ -41,7 +41,7 @@ class FlowSerializer(ModelSerializer):
|
||||||
|
|
||||||
cache_count = SerializerMethodField()
|
cache_count = SerializerMethodField()
|
||||||
|
|
||||||
def get_cache_count(self, flow: Flow):
|
def get_cache_count(self, flow: Flow) -> int:
|
||||||
"""Get count of cached flows"""
|
"""Get count of cached flows"""
|
||||||
return len(cache.keys(f"{cache_key(flow)}*"))
|
return len(cache.keys(f"{cache_key(flow)}*"))
|
||||||
|
|
||||||
|
@ -61,6 +61,9 @@ class FlowSerializer(ModelSerializer):
|
||||||
"cache_count",
|
"cache_count",
|
||||||
"policy_engine_mode",
|
"policy_engine_mode",
|
||||||
]
|
]
|
||||||
|
extra_kwargs = {
|
||||||
|
"background": {"read_only": True},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class FlowDiagramSerializer(Serializer):
|
class FlowDiagramSerializer(Serializer):
|
||||||
|
@ -97,16 +100,19 @@ class FlowViewSet(ModelViewSet):
|
||||||
filterset_fields = ["flow_uuid", "name", "slug", "designation"]
|
filterset_fields = ["flow_uuid", "name", "slug", "designation"]
|
||||||
|
|
||||||
@permission_required(None, ["authentik_flows.view_flow_cache"])
|
@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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def cache_info(self, request: Request) -> Response:
|
def cache_info(self, request: Request) -> Response:
|
||||||
"""Info about cached flows"""
|
"""Info about cached flows"""
|
||||||
return Response(data={"count": len(cache.keys("flow_*"))})
|
return Response(data={"count": len(cache.keys("flow_*"))})
|
||||||
|
|
||||||
@permission_required(None, ["authentik_flows.clear_flow_cache"])
|
@permission_required(None, ["authentik_flows.clear_flow_cache"])
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=no_body,
|
request=OpenApiTypes.NONE,
|
||||||
responses={204: "Successfully cleared cache", 400: "Bad request"},
|
responses={
|
||||||
|
204: OpenApiResponse(description="Successfully cleared cache"),
|
||||||
|
400: OpenApiResponse(description="Bad request"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
@action(detail=False, methods=["POST"])
|
@action(detail=False, methods=["POST"])
|
||||||
def cache_clear(self, request: Request) -> Response:
|
def cache_clear(self, request: Request) -> Response:
|
||||||
|
@ -133,17 +139,20 @@ class FlowViewSet(ModelViewSet):
|
||||||
"authentik_stages_prompt.change_prompt",
|
"authentik_stages_prompt.change_prompt",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=no_body,
|
request=OpenApiTypes.NONE,
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
name="file",
|
name="file",
|
||||||
in_=openapi.IN_FORM,
|
location=OpenApiParameter.QUERY, # TODO: Form
|
||||||
type=openapi.TYPE_FILE,
|
type=OpenApiTypes.BINARY,
|
||||||
required=True,
|
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,))
|
@action(detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
|
||||||
def import_flow(self, request: Request) -> Response:
|
def import_flow(self, request: Request) -> Response:
|
||||||
|
@ -171,11 +180,9 @@ class FlowViewSet(ModelViewSet):
|
||||||
"authentik_stages_prompt.view_prompt",
|
"authentik_stages_prompt.view_prompt",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={
|
responses={
|
||||||
"200": openapi.Response(
|
"200": OpenApiResponse(response=OpenApiTypes.BINARY),
|
||||||
"File Attachment", schema=openapi.Schema(type=openapi.TYPE_FILE)
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||||
|
@ -188,7 +195,7 @@ class FlowViewSet(ModelViewSet):
|
||||||
response["Content-Disposition"] = f'attachment; filename="{flow.slug}.akflow"'
|
response["Content-Disposition"] = f'attachment; filename="{flow.slug}.akflow"'
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@swagger_auto_schema(responses={200: FlowDiagramSerializer()})
|
@extend_schema(responses={200: FlowDiagramSerializer()})
|
||||||
@action(detail=True, pagination_class=None, filter_backends=[], methods=["get"])
|
@action(detail=True, pagination_class=None, filter_backends=[], methods=["get"])
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def diagram(self, request: Request, slug: str) -> Response:
|
def diagram(self, request: Request, slug: str) -> Response:
|
||||||
|
@ -259,17 +266,20 @@ class FlowViewSet(ModelViewSet):
|
||||||
return Response({"diagram": diagram})
|
return Response({"diagram": diagram})
|
||||||
|
|
||||||
@permission_required("authentik_flows.change_flow")
|
@permission_required("authentik_flows.change_flow")
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=no_body,
|
request=OpenApiTypes.NONE,
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
name="file",
|
name="file",
|
||||||
in_=openapi.IN_FORM,
|
location=OpenApiParameter.QUERY, # TODO: Form
|
||||||
type=openapi.TYPE_FILE,
|
type=OpenApiTypes.BINARY,
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
responses={200: "Success", 400: "Bad request"},
|
responses={
|
||||||
|
200: OpenApiResponse(description="Success"),
|
||||||
|
400: OpenApiResponse(description="Bad request"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
@action(
|
@action(
|
||||||
detail=True,
|
detail=True,
|
||||||
|
@ -289,8 +299,11 @@ class FlowViewSet(ModelViewSet):
|
||||||
app.save()
|
app.save()
|
||||||
return Response({})
|
return Response({})
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={200: LinkSerializer(many=False), 400: "Flow not applicable"},
|
responses={
|
||||||
|
200: LinkSerializer(many=False),
|
||||||
|
400: OpenApiResponse(description="Flow not applicable"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Flow Stage API Views"""
|
"""Flow Stage API Views"""
|
||||||
from typing import Iterable
|
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 import mixins
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import BooleanField
|
from rest_framework.fields import BooleanField
|
||||||
|
@ -68,7 +68,7 @@ class StageViewSet(
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Stage.objects.select_subclasses()
|
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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def types(self, request: Request) -> Response:
|
def types(self, request: Request) -> Response:
|
||||||
"""Get all creatable stage types"""
|
"""Get all creatable stage types"""
|
||||||
|
@ -86,7 +86,7 @@ class StageViewSet(
|
||||||
data = sorted(data, key=lambda x: x["name"])
|
data = sorted(data, key=lambda x: x["name"])
|
||||||
return Response(TypeCreateSerializer(data, many=True).data)
|
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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def user_settings(self, request: Request) -> Response:
|
def user_settings(self, request: Request) -> Response:
|
||||||
"""Get all stages the user can configure"""
|
"""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.utils.decorators import method_decorator
|
||||||
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
from drf_yasg import openapi
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from sentry_sdk import capture_exception
|
from sentry_sdk import capture_exception
|
||||||
|
@ -22,7 +22,6 @@ from authentik.events.models import cleanse_dict
|
||||||
from authentik.flows.challenge import (
|
from authentik.flows.challenge import (
|
||||||
AccessDeniedChallenge,
|
AccessDeniedChallenge,
|
||||||
Challenge,
|
Challenge,
|
||||||
ChallengeResponse,
|
|
||||||
ChallengeTypes,
|
ChallengeTypes,
|
||||||
HttpChallengeResponse,
|
HttpChallengeResponse,
|
||||||
RedirectChallenge,
|
RedirectChallenge,
|
||||||
|
@ -125,19 +124,21 @@ class FlowExecutorView(APIView):
|
||||||
self.current_stage_view.request = request
|
self.current_stage_view.request = request
|
||||||
return super().dispatch(request)
|
return super().dispatch(request)
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={
|
responses={
|
||||||
200: Challenge(),
|
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,
|
request=OpenApiTypes.NONE,
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
"query",
|
name="query",
|
||||||
openapi.IN_QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
required=True,
|
required=True,
|
||||||
description="Querystring as received",
|
description="Querystring as received",
|
||||||
type=openapi.TYPE_STRING,
|
type=OpenApiTypes.STR,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
operation_id="flows_executor_get",
|
operation_id="flows_executor_get",
|
||||||
|
@ -157,16 +158,16 @@ class FlowExecutorView(APIView):
|
||||||
self._logger.warning(exc)
|
self._logger.warning(exc)
|
||||||
return to_stage_response(request, FlowErrorResponse(request, exc))
|
return to_stage_response(request, FlowErrorResponse(request, exc))
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={200: Challenge()},
|
responses={200: Challenge()},
|
||||||
request_body=ChallengeResponse(),
|
request=OpenApiTypes.OBJECT,
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
"query",
|
name="query",
|
||||||
openapi.IN_QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
required=True,
|
required=True,
|
||||||
description="Querystring as received",
|
description="Querystring as received",
|
||||||
type=openapi.TYPE_STRING,
|
type=OpenApiTypes.STR,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
operation_id="flows_executor_solve",
|
operation_id="flows_executor_solve",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
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.client.configuration import Configuration
|
||||||
from kubernetes.config.config_exception import ConfigException
|
from kubernetes.config.config_exception import ConfigException
|
||||||
from kubernetes.config.kube_config import load_kube_config_from_dict
|
from kubernetes.config.kube_config import load_kube_config_from_dict
|
||||||
|
@ -69,7 +69,7 @@ class ServiceConnectionViewSet(
|
||||||
search_fields = ["name"]
|
search_fields = ["name"]
|
||||||
filterset_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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def types(self, request: Request) -> Response:
|
def types(self, request: Request) -> Response:
|
||||||
"""Get all creatable service connection types"""
|
"""Get all creatable service connection types"""
|
||||||
|
@ -87,7 +87,7 @@ class ServiceConnectionViewSet(
|
||||||
)
|
)
|
||||||
return Response(TypeCreateSerializer(data, many=True).data)
|
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=[])
|
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||||
# pylint: disable=unused-argument, invalid-name
|
# pylint: disable=unused-argument, invalid-name
|
||||||
def state(self, request: Request, pk: str) -> Response:
|
def state(self, request: Request, pk: str) -> Response:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Outpost API Views"""
|
"""Outpost API Views"""
|
||||||
from dacite.core import from_dict
|
from dacite.core import from_dict
|
||||||
from dacite.exceptions import DaciteError
|
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.decorators import action
|
||||||
from rest_framework.fields import BooleanField, CharField, DateTimeField
|
from rest_framework.fields import BooleanField, CharField, DateTimeField
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
@ -72,8 +72,8 @@ class OutpostViewSet(ModelViewSet):
|
||||||
]
|
]
|
||||||
ordering = ["name"]
|
ordering = ["name"]
|
||||||
|
|
||||||
@swagger_auto_schema(responses={200: OutpostHealthSerializer(many=True)})
|
@extend_schema(responses={200: OutpostHealthSerializer(many=True)})
|
||||||
@action(methods=["GET"], detail=True)
|
@action(methods=["GET"], detail=True, pagination_class=None)
|
||||||
# pylint: disable=invalid-name, unused-argument
|
# pylint: disable=invalid-name, unused-argument
|
||||||
def health(self, request: Request, pk: int) -> Response:
|
def health(self, request: Request, pk: int) -> Response:
|
||||||
"""Get outposts current health"""
|
"""Get outposts current health"""
|
||||||
|
@ -90,7 +90,7 @@ class OutpostViewSet(ModelViewSet):
|
||||||
)
|
)
|
||||||
return Response(OutpostHealthSerializer(states, many=True).data)
|
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"])
|
@action(detail=False, methods=["GET"])
|
||||||
def default_settings(self, request: Request) -> Response:
|
def default_settings(self, request: Request) -> Response:
|
||||||
"""Global default outpost config"""
|
"""Global default outpost config"""
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""policy API Views"""
|
"""policy API Views"""
|
||||||
from django.core.cache import cache
|
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 guardian.shortcuts import get_objects_for_user
|
||||||
from rest_framework import mixins
|
from rest_framework import mixins
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
@ -96,7 +97,7 @@ class PolicyViewSet(
|
||||||
"bindings", "promptstage_set"
|
"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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def types(self, request: Request) -> Response:
|
def types(self, request: Request) -> Response:
|
||||||
"""Get all creatable policy types"""
|
"""Get all creatable policy types"""
|
||||||
|
@ -114,16 +115,19 @@ class PolicyViewSet(
|
||||||
return Response(TypeCreateSerializer(data, many=True).data)
|
return Response(TypeCreateSerializer(data, many=True).data)
|
||||||
|
|
||||||
@permission_required(None, ["authentik_policies.view_policy_cache"])
|
@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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def cache_info(self, request: Request) -> Response:
|
def cache_info(self, request: Request) -> Response:
|
||||||
"""Info about cached policies"""
|
"""Info about cached policies"""
|
||||||
return Response(data={"count": len(cache.keys("policy_*"))})
|
return Response(data={"count": len(cache.keys("policy_*"))})
|
||||||
|
|
||||||
@permission_required(None, ["authentik_policies.clear_policy_cache"])
|
@permission_required(None, ["authentik_policies.clear_policy_cache"])
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=no_body,
|
request=OpenApiTypes.NONE,
|
||||||
responses={204: "Successfully cleared cache", 400: "Bad request"},
|
responses={
|
||||||
|
204: OpenApiResponse(description="Successfully cleared cache"),
|
||||||
|
400: OpenApiResponse(description="Bad request"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
@action(detail=False, methods=["POST"])
|
@action(detail=False, methods=["POST"])
|
||||||
def cache_clear(self, request: Request) -> Response:
|
def cache_clear(self, request: Request) -> Response:
|
||||||
|
@ -137,9 +141,12 @@ class PolicyViewSet(
|
||||||
return Response(status=204)
|
return Response(status=204)
|
||||||
|
|
||||||
@permission_required("authentik_policies.view_policy")
|
@permission_required("authentik_policies.view_policy")
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=PolicyTestSerializer(),
|
request=PolicyTestSerializer(),
|
||||||
responses={200: PolicyTestResultSerializer(), 400: "Invalid parameters"},
|
responses={
|
||||||
|
200: PolicyTestResultSerializer(),
|
||||||
|
400: OpenApiResponse(description="Invalid parameters"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
@action(detail=True, pagination_class=None, filter_backends=[], methods=["POST"])
|
@action(detail=True, pagination_class=None, filter_backends=[], methods=["POST"])
|
||||||
# pylint: disable=unused-argument, invalid-name
|
# pylint: disable=unused-argument, invalid-name
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""OAuth2Provider API Views"""
|
"""OAuth2Provider API Views"""
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
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.decorators import action
|
||||||
from rest_framework.fields import ReadOnlyField
|
from rest_framework.fields import ReadOnlyField
|
||||||
from rest_framework.generics import get_object_or_404
|
from rest_framework.generics import get_object_or_404
|
||||||
|
@ -67,10 +67,10 @@ class OAuth2ProviderViewSet(ModelViewSet):
|
||||||
queryset = OAuth2Provider.objects.all()
|
queryset = OAuth2Provider.objects.all()
|
||||||
serializer_class = OAuth2ProviderSerializer
|
serializer_class = OAuth2ProviderSerializer
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={
|
responses={
|
||||||
200: OAuth2ProviderSetupURLs(many=False),
|
200: OAuth2ProviderSetupURLs,
|
||||||
404: "Provider has no application assigned",
|
404: OpenApiResponse(description="Provider has no application assigned"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@action(methods=["GET"], detail=True)
|
@action(methods=["GET"], detail=True)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""ProxyProvider API Views"""
|
"""ProxyProvider API Views"""
|
||||||
from typing import Any
|
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.exceptions import ValidationError
|
||||||
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
@ -107,7 +107,7 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
|
||||||
"forward_auth_mode",
|
"forward_auth_mode",
|
||||||
]
|
]
|
||||||
|
|
||||||
@swagger_serializer_method(serializer_or_field=OpenIDConnectConfigurationSerializer)
|
@extend_schema_field(OpenIDConnectConfigurationSerializer)
|
||||||
def get_oidc_configuration(self, obj: ProxyProvider):
|
def get_oidc_configuration(self, obj: ProxyProvider):
|
||||||
"""Embed OpenID Connect provider information"""
|
"""Embed OpenID Connect provider information"""
|
||||||
return ProviderInfoView(request=self.context["request"]._request).get_info(obj)
|
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.http.response import HttpResponse
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from drf_yasg import openapi
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_yasg.utils import swagger_auto_schema
|
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import CharField, FileField, ReadOnlyField
|
from rest_framework.fields import CharField, FileField, ReadOnlyField
|
||||||
from rest_framework.parsers import MultiPartParser
|
from rest_framework.parsers import MultiPartParser
|
||||||
|
@ -80,16 +80,16 @@ class SAMLProviderViewSet(ModelViewSet):
|
||||||
queryset = SAMLProvider.objects.all()
|
queryset = SAMLProvider.objects.all()
|
||||||
serializer_class = SAMLProviderSerializer
|
serializer_class = SAMLProviderSerializer
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={
|
responses={
|
||||||
200: SAMLMetadataSerializer(many=False),
|
200: SAMLMetadataSerializer(many=False),
|
||||||
404: "Provider has no application assigned",
|
404: OpenApiResponse(description="Provider has no application assigned"),
|
||||||
},
|
},
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
name="download",
|
name="download",
|
||||||
in_=openapi.IN_QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
type=openapi.TYPE_BOOLEAN,
|
type=OpenApiTypes.BOOL,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -118,9 +118,12 @@ class SAMLProviderViewSet(ModelViewSet):
|
||||||
"authentik_crypto.add_certificatekeypair",
|
"authentik_crypto.add_certificatekeypair",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=SAMLProviderImportSerializer(),
|
request=SAMLProviderImportSerializer(),
|
||||||
responses={204: "Successfully imported provider", 400: "Bad request"},
|
responses={
|
||||||
|
204: OpenApiResponse(description="Successfully imported provider"),
|
||||||
|
400: OpenApiResponse(description="Bad request"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
@action(detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
|
@action(detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
|
||||||
def import_metadata(self, request: Request) -> Response:
|
def import_metadata(self, request: Request) -> Response:
|
||||||
|
|
|
@ -128,7 +128,7 @@ INSTALLED_APPS = [
|
||||||
"authentik.stages.user_write",
|
"authentik.stages.user_write",
|
||||||
"rest_framework",
|
"rest_framework",
|
||||||
"django_filters",
|
"django_filters",
|
||||||
"drf_yasg",
|
"drf_spectacular",
|
||||||
"guardian",
|
"guardian",
|
||||||
"django_prometheus",
|
"django_prometheus",
|
||||||
"channels",
|
"channels",
|
||||||
|
@ -137,15 +137,28 @@ INSTALLED_APPS = [
|
||||||
|
|
||||||
GUARDIAN_MONKEY_PATCH = False
|
GUARDIAN_MONKEY_PATCH = False
|
||||||
|
|
||||||
SWAGGER_SETTINGS = {
|
SPECTACULAR_SETTINGS = {
|
||||||
"DEFAULT_AUTO_SCHEMA_CLASS": "authentik.api.schema.ErrorResponseAutoSchema",
|
"TITLE": "authentik",
|
||||||
"DEFAULT_INFO": "authentik.api.v2.urls.info",
|
"DESCRIPTION": "Making authentication simple.",
|
||||||
"DEFAULT_PAGINATOR_INSPECTORS": [
|
"VERSION": __version__,
|
||||||
"authentik.api.pagination_schema.PaginationInspector",
|
"COMPONENT_SPLIT_REQUEST": True,
|
||||||
],
|
"CONTACT": {
|
||||||
"SECURITY_DEFINITIONS": {
|
"email": "hello@beryju.org",
|
||||||
"Bearer": {"type": "apiKey", "name": "Authorization", "in": "header"}
|
|
||||||
},
|
},
|
||||||
|
"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 = {
|
REST_FRAMEWORK = {
|
||||||
|
@ -167,6 +180,7 @@ REST_FRAMEWORK = {
|
||||||
"DEFAULT_RENDERER_CLASSES": [
|
"DEFAULT_RENDERER_CLASSES": [
|
||||||
"rest_framework.renderers.JSONRenderer",
|
"rest_framework.renderers.JSONRenderer",
|
||||||
],
|
],
|
||||||
|
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||||
}
|
}
|
||||||
|
|
||||||
CACHES = {
|
CACHES = {
|
||||||
|
@ -446,7 +460,6 @@ _LOGGING_HANDLER_MAP = {
|
||||||
"kubernetes": "INFO",
|
"kubernetes": "INFO",
|
||||||
"asyncio": "WARNING",
|
"asyncio": "WARNING",
|
||||||
"aioredis": "WARNING",
|
"aioredis": "WARNING",
|
||||||
"drf_yasg.utils": "WARNING",
|
|
||||||
}
|
}
|
||||||
for handler_name, level in _LOGGING_HANDLER_MAP.items():
|
for handler_name, level in _LOGGING_HANDLER_MAP.items():
|
||||||
# pyright: reportGeneralTypeIssues=false
|
# pyright: reportGeneralTypeIssues=false
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Source API Views"""
|
"""Source API Views"""
|
||||||
from django.http.response import Http404
|
from django.http.response import Http404
|
||||||
from django.utils.text import slugify
|
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.decorators import action
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
@ -48,8 +48,11 @@ class LDAPSourceViewSet(ModelViewSet):
|
||||||
serializer_class = LDAPSourceSerializer
|
serializer_class = LDAPSourceSerializer
|
||||||
lookup_field = "slug"
|
lookup_field = "slug"
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
responses={200: TaskSerializer(many=False), 404: "Task not found"}
|
responses={
|
||||||
|
200: TaskSerializer(many=False),
|
||||||
|
404: OpenApiResponse(description="Task not found"),
|
||||||
|
}
|
||||||
)
|
)
|
||||||
@action(methods=["GET"], detail=True)
|
@action(methods=["GET"], detail=True)
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""OAuth Source Serializer"""
|
"""OAuth Source Serializer"""
|
||||||
from django.urls.base import reverse_lazy
|
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.decorators import action
|
||||||
from rest_framework.fields import BooleanField, CharField, SerializerMethodField
|
from rest_framework.fields import BooleanField, CharField, SerializerMethodField
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
@ -43,7 +43,7 @@ class OAuthSourceSerializer(SourceSerializer):
|
||||||
|
|
||||||
type = SerializerMethodField()
|
type = SerializerMethodField()
|
||||||
|
|
||||||
@swagger_serializer_method(serializer_or_field=SourceTypeSerializer)
|
@extend_schema_field(SourceTypeSerializer)
|
||||||
def get_type(self, instace: OAuthSource) -> SourceTypeSerializer:
|
def get_type(self, instace: OAuthSource) -> SourceTypeSerializer:
|
||||||
"""Get source's type configuration"""
|
"""Get source's type configuration"""
|
||||||
return SourceTypeSerializer(instace.type).data
|
return SourceTypeSerializer(instace.type).data
|
||||||
|
@ -85,7 +85,7 @@ class OAuthSourceViewSet(ModelViewSet):
|
||||||
serializer_class = OAuthSourceSerializer
|
serializer_class = OAuthSourceSerializer
|
||||||
lookup_field = "slug"
|
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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def source_types(self, request: Request) -> Response:
|
def source_types(self, request: Request) -> Response:
|
||||||
"""Get all creatable source types"""
|
"""Get all creatable source types"""
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Plex Source Serializer"""
|
"""Plex Source Serializer"""
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from drf_yasg import openapi
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_yasg.utils import swagger_auto_schema
|
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.fields import CharField
|
from rest_framework.fields import CharField
|
||||||
|
@ -50,18 +50,18 @@ class PlexSourceViewSet(ModelViewSet):
|
||||||
lookup_field = "slug"
|
lookup_field = "slug"
|
||||||
|
|
||||||
@permission_required(None)
|
@permission_required(None)
|
||||||
@swagger_auto_schema(
|
@extend_schema(
|
||||||
request_body=PlexTokenRedeemSerializer(),
|
request=PlexTokenRedeemSerializer(),
|
||||||
responses={
|
responses={
|
||||||
200: RedirectChallenge(),
|
200: RedirectChallenge(),
|
||||||
400: "Token not found",
|
400: OpenApiResponse(description="Token not found"),
|
||||||
403: "Access denied",
|
403: OpenApiResponse(description="Access denied"),
|
||||||
},
|
},
|
||||||
manual_parameters=[
|
parameters=[
|
||||||
openapi.Parameter(
|
OpenApiParameter(
|
||||||
name="slug",
|
name="slug",
|
||||||
in_=openapi.IN_QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
type=openapi.TYPE_STRING,
|
type=OpenApiTypes.STR,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""SAMLSource API Views"""
|
"""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.decorators import action
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
@ -39,7 +39,7 @@ class SAMLSourceViewSet(ModelViewSet):
|
||||||
serializer_class = SAMLSourceSerializer
|
serializer_class = SAMLSourceSerializer
|
||||||
lookup_field = "slug"
|
lookup_field = "slug"
|
||||||
|
|
||||||
@swagger_auto_schema(responses={200: SAMLMetadataSerializer(many=False)})
|
@extend_schema(responses={200: SAMLMetadataSerializer(many=False)})
|
||||||
@action(methods=["GET"], detail=True)
|
@action(methods=["GET"], detail=True)
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def metadata(self, request: Request, slug: str) -> Response:
|
def metadata(self, request: Request, slug: str) -> Response:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""AuthenticatorStaticStage API Views"""
|
"""AuthenticatorStaticStage API Views"""
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from django_otp.plugins.otp_static.models import StaticDevice
|
from django_otp.plugins.otp_static.models import StaticDevice, StaticToken
|
||||||
from guardian.utils import get_anonymous_user
|
from guardian.utils import get_anonymous_user
|
||||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||||
from rest_framework.permissions import IsAdminUser
|
from rest_framework.permissions import IsAdminUser
|
||||||
|
@ -27,14 +27,24 @@ class AuthenticatorStaticStageViewSet(ModelViewSet):
|
||||||
serializer_class = AuthenticatorStaticStageSerializer
|
serializer_class = AuthenticatorStaticStageSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class StaticDeviceTokenSerializer(ModelSerializer):
|
||||||
|
"""Serializer for static device's tokens"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = StaticToken
|
||||||
|
fields = ["token"]
|
||||||
|
|
||||||
|
|
||||||
class StaticDeviceSerializer(ModelSerializer):
|
class StaticDeviceSerializer(ModelSerializer):
|
||||||
"""Serializer for static authenticator devices"""
|
"""Serializer for static authenticator devices"""
|
||||||
|
|
||||||
|
token_set = StaticDeviceTokenSerializer(many=True, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = StaticDevice
|
model = StaticDevice
|
||||||
fields = ["name", "token_set", "pk"]
|
fields = ["name", "token_set", "pk"]
|
||||||
depth = 2
|
|
||||||
|
|
||||||
|
|
||||||
class StaticDeviceViewSet(ModelViewSet):
|
class StaticDeviceViewSet(ModelViewSet):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""EmailStage API Views"""
|
"""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.decorators import action
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
@ -52,7 +52,7 @@ class EmailStageViewSet(ModelViewSet):
|
||||||
queryset = EmailStage.objects.all()
|
queryset = EmailStage.objects.all()
|
||||||
serializer_class = EmailStageSerializer
|
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=[])
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
def templates(self, request: Request) -> Response:
|
def templates(self, request: Request) -> Response:
|
||||||
"""Get all available templates, including custom templates"""
|
"""Get all available templates, including custom templates"""
|
||||||
|
|
|
@ -305,8 +305,7 @@ stages:
|
||||||
displayName: Build static files for e2e
|
displayName: Build static files for e2e
|
||||||
inputs:
|
inputs:
|
||||||
script: |
|
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
|
make gen-web
|
||||||
sudo chmod 777 -R web/api/
|
|
||||||
cd web
|
cd web
|
||||||
cd api && npm i && cd ..
|
cd api && npm i && cd ..
|
||||||
npm i
|
npm i
|
||||||
|
@ -394,36 +393,19 @@ stages:
|
||||||
- task: CmdLine@2
|
- task: CmdLine@2
|
||||||
inputs:
|
inputs:
|
||||||
script: bash <(curl -s https://codecov.io/bash)
|
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
|
- stage: Build
|
||||||
jobs:
|
jobs:
|
||||||
- job: build_server
|
- job: build_server
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-latest'
|
vmImage: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: NodeTool@0
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
versionSpec: '16.x'
|
||||||
artifactName: 'ts_swagger_client'
|
displayName: 'Install Node.js'
|
||||||
path: "web/api/"
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: make gen-web
|
||||||
- task: Bash@3
|
- task: Bash@3
|
||||||
inputs:
|
inputs:
|
||||||
targetType: 'inline'
|
targetType: 'inline'
|
||||||
|
|
3
outpost/.gitignore
vendored
3
outpost/.gitignore
vendored
|
@ -1,2 +1 @@
|
||||||
pkg/client/
|
api/
|
||||||
pkg/models/
|
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
all: clean generate
|
all: clean
|
||||||
|
|
||||||
generate:
|
|
||||||
go get -u github.com/go-swagger/go-swagger/cmd/swagger
|
|
||||||
swagger generate client -f ../swagger.yaml -A authentik -t pkg/
|
|
||||||
|
|
||||||
run:
|
run:
|
||||||
go run -v .
|
go run -v .
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
# authentik outpost
|
# authentik outpost
|
||||||
|
|
||||||
[](https://dev.azure.com/beryjuorg/authentik/_build?definitionId=8)
|
[](https://dev.azure.com/beryjuorg/authentik/_build?definitionId=8)
|
||||||

|

|
||||||
|

|
||||||
|
|
||||||
Reverse Proxy based on [oauth2_proxy](https://github.com/oauth2-proxy/oauth2-proxy), completely managed and monitored by authentik.
|
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
|
## 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:
|
The following environment variable are implemented:
|
||||||
|
|
||||||
|
@ -19,6 +22,6 @@ The following environment variable are implemented:
|
||||||
|
|
||||||
## Development
|
## 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:
|
stages:
|
||||||
- stage: generate
|
- stage: generate
|
||||||
jobs:
|
jobs:
|
||||||
- job: swagger_generate
|
- job: generate_api
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-latest'
|
vmImage: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
|
@ -24,16 +24,11 @@ stages:
|
||||||
version: '1.16.3'
|
version: '1.16.3'
|
||||||
- task: CmdLine@2
|
- task: CmdLine@2
|
||||||
inputs:
|
inputs:
|
||||||
script: |
|
script: make gen-outpost
|
||||||
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/'
|
|
||||||
- task: PublishPipelineArtifact@1
|
- task: PublishPipelineArtifact@1
|
||||||
inputs:
|
inputs:
|
||||||
targetPath: 'outpost/pkg/'
|
targetPath: 'outpost/api/'
|
||||||
artifact: 'go_swagger_client'
|
artifact: 'go_api_client'
|
||||||
publishLocation: 'pipeline'
|
publishLocation: 'pipeline'
|
||||||
- stage: lint
|
- stage: lint
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -47,12 +42,17 @@ stages:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: 'go_swagger_client'
|
artifactName: 'go_api_client'
|
||||||
path: "outpost/pkg/"
|
path: "outpost/api/"
|
||||||
- task: CmdLine@2
|
- task: CmdLine@2
|
||||||
inputs:
|
inputs:
|
||||||
script: |
|
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/'
|
workingDirectory: 'outpost/'
|
||||||
- stage: build_go
|
- stage: build_go
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -66,8 +66,8 @@ stages:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: 'go_swagger_client'
|
artifactName: 'go_api_client'
|
||||||
path: "outpost/pkg/"
|
path: "outpost/api/"
|
||||||
- task: Go@0
|
- task: Go@0
|
||||||
inputs:
|
inputs:
|
||||||
command: 'build'
|
command: 'build'
|
||||||
|
@ -83,8 +83,8 @@ stages:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: 'go_swagger_client'
|
artifactName: 'go_api_client'
|
||||||
path: "outpost/pkg/"
|
path: "outpost/api/"
|
||||||
- task: Go@0
|
- task: Go@0
|
||||||
inputs:
|
inputs:
|
||||||
command: 'build'
|
command: 'build'
|
||||||
|
@ -102,8 +102,8 @@ stages:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: 'go_swagger_client'
|
artifactName: 'go_api_client'
|
||||||
path: "outpost/pkg/"
|
path: "outpost/api/"
|
||||||
- task: Bash@3
|
- task: Bash@3
|
||||||
inputs:
|
inputs:
|
||||||
targetType: 'inline'
|
targetType: 'inline'
|
||||||
|
@ -138,8 +138,8 @@ stages:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: 'go_swagger_client'
|
artifactName: 'go_api_client'
|
||||||
path: "outpost/pkg/"
|
path: "outpost/api/"
|
||||||
- task: Bash@3
|
- task: Bash@3
|
||||||
inputs:
|
inputs:
|
||||||
targetType: 'inline'
|
targetType: 'inline'
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
module goauthentik.io/outpost
|
module goauthentik.io/outpost
|
||||||
|
|
||||||
go 1.14
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
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/getsentry/sentry-go v0.10.0
|
||||||
github.com/go-ldap/ldap/v3 v3.3.0
|
github.com/go-ldap/ldap/v3 v3.3.0
|
||||||
github.com/go-openapi/analysis v0.20.1 // indirect
|
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/runtime v0.19.28
|
||||||
github.com/go-openapi/strfmt v0.20.1
|
github.com/go-openapi/strfmt v0.20.1
|
||||||
github.com/go-openapi/swag v0.19.15
|
github.com/go-openapi/swag v0.19.15 // indirect
|
||||||
github.com/go-openapi/validate v0.20.2
|
github.com/go-openapi/validate v0.20.2 // indirect
|
||||||
github.com/go-redis/redis/v7 v7.4.0 // 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/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/gorilla/websocket v1.4.2
|
||||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||||
github.com/justinas/alice v1.2.0
|
github.com/justinas/alice v1.2.0
|
||||||
|
@ -25,9 +23,9 @@ require (
|
||||||
github.com/magiconair/properties v1.8.5 // indirect
|
github.com/magiconair/properties v1.8.5 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 // 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/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/pkg/errors v0.9.1
|
||||||
github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac // indirect
|
github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac // indirect
|
||||||
github.com/recws-org/recws v1.3.1
|
github.com/recws-org/recws v1.3.1
|
||||||
|
@ -37,10 +35,11 @@ require (
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/spf13/viper v1.7.1 // 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/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
||||||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 // indirect
|
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 // indirect
|
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558
|
||||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 // indirect
|
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.5.1 // 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/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/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/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/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/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
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/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/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 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/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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/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/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
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 h1:Gfh+GAJZOAoKZsIZeZbdn2JF10kN1XHNvjsvQK8gVkE=
|
||||||
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
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.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 h1:Sxpo9PjEHDzhs3FbnGNonvDgWcMW2U7wGTcDDSFSceM=
|
||||||
github.com/go-openapi/errors v0.20.0/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
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.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.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
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.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.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.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 h1:9lYu6axek8LJrVkMVViVirRcpoaCxXX7+sSvmizGVnA=
|
||||||
github.com/go-openapi/runtime v0.19.28/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M=
|
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=
|
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-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 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
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/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.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
|
||||||
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
|
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/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.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.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/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 v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/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/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/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.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.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 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
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/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 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
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.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
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/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/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/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 h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
|
||||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
|
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=
|
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/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/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/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/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.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
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.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.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
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.1 h1:a6qW1EVNZWH9WGI6CsYdD8WAylkoXBS5yv0XHlh17Tc=
|
||||||
github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0=
|
github.com/pelletier/go-toml v1.9.1/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/pelletier/go-toml v1.9.0/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 h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI=
|
||||||
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
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=
|
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.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/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 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 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/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=
|
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/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.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
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.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
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/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.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.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 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
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=
|
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 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
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/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.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
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=
|
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.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/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.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-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-20191213034115-f46add6fdb5c/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
|
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.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.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.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.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.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
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.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.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.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-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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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-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-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-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-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-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-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-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-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-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
|
||||||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk=
|
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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-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-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-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-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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-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-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-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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM=
|
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
|
||||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
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/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.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/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-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-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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
|
package ak
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-openapi/runtime"
|
"github.com/go-openapi/strfmt"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/recws-org/recws"
|
"github.com/recws-org/recws"
|
||||||
|
"goauthentik.io/outpost/api"
|
||||||
"goauthentik.io/outpost/pkg"
|
"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"
|
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
|
// APIController main controller which connects to the authentik api via http and ws
|
||||||
type APIController struct {
|
type APIController struct {
|
||||||
Client *client.Authentik
|
Client *api.APIClient
|
||||||
Auth runtime.ClientAuthInfoWriter
|
|
||||||
token string
|
token string
|
||||||
|
|
||||||
Server Outpost
|
Server Outpost
|
||||||
|
@ -41,31 +40,32 @@ type APIController struct {
|
||||||
|
|
||||||
// NewAPIController initialise new API Controller instance from URL and API token
|
// NewAPIController initialise new API Controller instance from URL and API token
|
||||||
func NewAPIController(akURL url.URL, token string) *APIController {
|
func NewAPIController(akURL url.URL, token string) *APIController {
|
||||||
transport := httptransport.New(akURL.Host, client.DefaultBasePath, []string{akURL.Scheme})
|
config := api.NewConfiguration()
|
||||||
transport.Transport = SetUserAgent(GetTLSTransport(), pkg.UserAgent())
|
config.Host = akURL.Host
|
||||||
|
config.Scheme = akURL.Scheme
|
||||||
// create the transport
|
config.HTTPClient = &http.Client{
|
||||||
auth := httptransport.BearerToken(token)
|
Transport: SetUserAgent(GetTLSTransport(), pkg.UserAgent()),
|
||||||
|
}
|
||||||
|
config.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||||
|
|
||||||
// create the API client, with the transport
|
// 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")
|
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
|
// 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
|
// 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 {
|
if err != nil {
|
||||||
log.WithError(err).Error("Failed to fetch configuration")
|
log.WithError(err).Error("Failed to fetch configuration")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
outpost := outposts.Payload.Results[0]
|
outpost := outposts.Results[0]
|
||||||
doGlobalSetup(outpost.Config.(map[string]interface{}))
|
doGlobalSetup(outpost.Config)
|
||||||
|
|
||||||
ac := &APIController{
|
ac := &APIController{
|
||||||
Client: apiClient,
|
Client: apiClient,
|
||||||
Auth: auth,
|
|
||||||
token: token,
|
token: token,
|
||||||
|
|
||||||
logger: log,
|
logger: log,
|
||||||
|
@ -74,7 +74,7 @@ func NewAPIController(akURL url.URL, token string) *APIController {
|
||||||
instanceUUID: uuid.New(),
|
instanceUUID: uuid.New(),
|
||||||
}
|
}
|
||||||
ac.logger.Debugf("HA Reload offset: %s", ac.reloadOffset)
|
ac.logger.Debugf("HA Reload offset: %s", ac.reloadOffset)
|
||||||
ac.initWS(akURL, outpost.Pk)
|
ac.initWS(akURL, strfmt.UUID(outpost.Pk))
|
||||||
return ac
|
return ac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
package ak
|
package ak
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"goauthentik.io/outpost/pkg/client/outposts"
|
"context"
|
||||||
"goauthentik.io/outpost/pkg/models"
|
|
||||||
|
"goauthentik.io/outpost/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *APIController) Update() ([]*models.ProxyOutpostConfig, error) {
|
func (a *APIController) Update() ([]api.ProxyOutpostConfig, error) {
|
||||||
providers, err := a.Client.Outposts.OutpostsProxyList(outposts.NewOutpostsProxyListParams(), a.Auth)
|
providers, _, err := a.Client.OutpostsApi.OutpostsProxyList(context.Background()).Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.logger.WithError(err).Error("Failed to fetch providers")
|
a.logger.WithError(err).Error("Failed to fetch providers")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return providers.Payload.Results, nil
|
return providers.Results, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ldap
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -9,28 +10,27 @@ import (
|
||||||
|
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"goauthentik.io/outpost/pkg/client/outposts"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ls *LDAPServer) Refresh() error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(outposts.Payload.Results) < 1 {
|
if len(outposts.Results) < 1 {
|
||||||
return errors.New("no ldap provider defined")
|
return errors.New("no ldap provider defined")
|
||||||
}
|
}
|
||||||
providers := make([]*ProviderInstance, len(outposts.Payload.Results))
|
providers := make([]*ProviderInstance, len(outposts.Results))
|
||||||
for idx, provider := range outposts.Payload.Results {
|
for idx, provider := range outposts.Results {
|
||||||
userDN := strings.ToLower(fmt.Sprintf("ou=users,%s", provider.BaseDn))
|
userDN := strings.ToLower(fmt.Sprintf("ou=users,%s", *provider.BaseDn))
|
||||||
groupDN := strings.ToLower(fmt.Sprintf("ou=groups,%s", provider.BaseDn))
|
groupDN := strings.ToLower(fmt.Sprintf("ou=groups,%s", *provider.BaseDn))
|
||||||
providers[idx] = &ProviderInstance{
|
providers[idx] = &ProviderInstance{
|
||||||
BaseDN: provider.BaseDn,
|
BaseDN: *provider.BaseDn,
|
||||||
GroupDN: groupDN,
|
GroupDN: groupDN,
|
||||||
UserDN: userDN,
|
UserDN: userDN,
|
||||||
appSlug: *provider.ApplicationSlug,
|
appSlug: provider.ApplicationSlug,
|
||||||
flowSlug: *provider.BindFlowSlug,
|
flowSlug: provider.BindFlowSlug,
|
||||||
searchAllowedGroups: []*strfmt.UUID{provider.SearchGroup},
|
searchAllowedGroups: []*strfmt.UUID{(*strfmt.UUID)(provider.SearchGroup.Get())},
|
||||||
boundUsersMutex: sync.RWMutex{},
|
boundUsersMutex: sync.RWMutex{},
|
||||||
boundUsers: make(map[string]UserFlags),
|
boundUsers: make(map[string]UserFlags),
|
||||||
s: ls,
|
s: ls,
|
||||||
|
|
|
@ -12,25 +12,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
goldap "github.com/go-ldap/ldap/v3"
|
goldap "github.com/go-ldap/ldap/v3"
|
||||||
httptransport "github.com/go-openapi/runtime/client"
|
|
||||||
"github.com/nmcclain/ldap"
|
"github.com/nmcclain/ldap"
|
||||||
|
"goauthentik.io/outpost/api"
|
||||||
"goauthentik.io/outpost/pkg"
|
"goauthentik.io/outpost/pkg"
|
||||||
"goauthentik.io/outpost/pkg/ak"
|
"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"
|
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) {
|
func (pi *ProviderInstance) getUsername(dn string) (string, error) {
|
||||||
if !strings.HasSuffix(strings.ToLower(dn), strings.ToLower(pi.BaseDN)) {
|
if !strings.HasSuffix(strings.ToLower(dn), strings.ToLower(pi.BaseDN)) {
|
||||||
return "", errors.New("invalid base DN")
|
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")
|
pi.log.WithError(err).Warning("Failed to get remote IP")
|
||||||
return ldap.LDAPResultOperationsError, nil
|
return ldap.LDAPResultOperationsError, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new http client that also sets the correct ip
|
// 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,
|
Jar: jar,
|
||||||
Transport: newTransport(ak.SetUserAgent(ak.GetTLSTransport(), pkg.UserAgent()), map[string]string{
|
Transport: newTransport(ak.SetUserAgent(ak.GetTLSTransport(), pkg.UserAgent()), map[string]string{
|
||||||
"X-authentik-remote-ip": host,
|
"X-authentik-remote-ip": host,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
// create the API client, with the transport
|
||||||
|
apiClient := api.NewAPIClient(config)
|
||||||
|
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
params.Add("goauthentik.io/outpost/ldap", "true")
|
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 {
|
if err != nil {
|
||||||
pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to solve challenge")
|
pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to solve challenge")
|
||||||
return ldap.LDAPResultOperationsError, nil
|
return ldap.LDAPResultOperationsError, nil
|
||||||
|
@ -77,33 +75,26 @@ func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn ne
|
||||||
if !passed {
|
if !passed {
|
||||||
return ldap.LDAPResultInvalidCredentials, nil
|
return ldap.LDAPResultInvalidCredentials, nil
|
||||||
}
|
}
|
||||||
_, err = pi.s.ac.Client.Core.CoreApplicationsCheckAccess(&core.CoreApplicationsCheckAccessParams{
|
r, err := pi.s.ac.Client.CoreApi.CoreApplicationsCheckAccessRetrieve(context.Background(), pi.appSlug).Execute()
|
||||||
Slug: pi.appSlug,
|
if r.StatusCode == 403 {
|
||||||
Context: context.Background(),
|
pi.log.WithField("bindDN", bindDN).Info("Access denied for user")
|
||||||
HTTPClient: client,
|
return ldap.LDAPResultInsufficientAccessRights, nil
|
||||||
}, httptransport.PassThroughAuth)
|
}
|
||||||
if err != 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")
|
pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to check access")
|
||||||
return ldap.LDAPResultOperationsError, nil
|
return ldap.LDAPResultOperationsError, nil
|
||||||
}
|
}
|
||||||
pi.log.WithField("bindDN", bindDN).Info("User has access")
|
pi.log.WithField("bindDN", bindDN).Info("User has access")
|
||||||
// Get user info to store in context
|
// Get user info to store in context
|
||||||
userInfo, err := pi.s.ac.Client.Core.CoreUsersMe(&core.CoreUsersMeParams{
|
userInfo, _, err := pi.s.ac.Client.CoreApi.CoreUsersMeRetrieve(context.Background()).Execute()
|
||||||
Context: context.Background(),
|
|
||||||
HTTPClient: client,
|
|
||||||
}, httptransport.PassThroughAuth)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to get user info")
|
pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to get user info")
|
||||||
return ldap.LDAPResultOperationsError, nil
|
return ldap.LDAPResultOperationsError, nil
|
||||||
}
|
}
|
||||||
pi.boundUsersMutex.Lock()
|
pi.boundUsersMutex.Lock()
|
||||||
pi.boundUsers[bindDN] = UserFlags{
|
pi.boundUsers[bindDN] = UserFlags{
|
||||||
UserInfo: *userInfo.Payload.User,
|
UserInfo: userInfo.User,
|
||||||
CanSearch: pi.SearchAccessCheck(userInfo.Payload.User),
|
CanSearch: pi.SearchAccessCheck(userInfo.User),
|
||||||
}
|
}
|
||||||
defer pi.boundUsersMutex.Unlock()
|
defer pi.boundUsersMutex.Unlock()
|
||||||
pi.delayDeleteUserInfo(username)
|
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
|
// 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 _, group := range user.Groups {
|
||||||
for _, allowedGroup := range pi.searchAllowedGroups {
|
for _, allowedGroup := range pi.searchAllowedGroups {
|
||||||
pi.log.WithField("userGroup", group.Pk).WithField("allowedGroup", allowedGroup).Trace("Checking search access")
|
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")
|
pi.log.WithField("group", group.Name).Info("Allowed access to search")
|
||||||
return true
|
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) {
|
func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, client *api.APIClient, urlParams string, depth int) (bool, error) {
|
||||||
challenge, err := pi.s.ac.Client.Flows.FlowsExecutorGet(&flows.FlowsExecutorGetParams{
|
req := client.FlowsApi.FlowsExecutorGet(context.Background(), pi.flowSlug)
|
||||||
FlowSlug: pi.flowSlug,
|
req.Query(urlParams)
|
||||||
Query: urlParams,
|
challenge, _, err := req.Execute()
|
||||||
Context: context.Background(),
|
|
||||||
HTTPClient: client,
|
|
||||||
}, pi.s.ac.Auth)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pi.log.WithError(err).Warning("Failed to get challenge")
|
pi.log.WithError(err).Warning("Failed to get challenge")
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
pi.log.WithField("component", challenge.Payload.Component).WithField("type", *challenge.Payload.Type).Debug("Got challenge")
|
pi.log.WithField("component", challenge.Component).WithField("type", challenge.Type).Debug("Got challenge")
|
||||||
responseParams := &flows.FlowsExecutorSolveParams{
|
responseReq := client.FlowsApi.FlowsExecutorSolve(context.Background(), pi.flowSlug)
|
||||||
FlowSlug: pi.flowSlug,
|
responseReq.Query(urlParams)
|
||||||
Query: urlParams,
|
switch *challenge.Component {
|
||||||
Context: context.Background(),
|
|
||||||
HTTPClient: client,
|
|
||||||
}
|
|
||||||
switch challenge.Payload.Component {
|
|
||||||
case "ak-stage-identification":
|
case "ak-stage-identification":
|
||||||
responseParams.Data = &UIDResponse{UIDFIeld: bindDN}
|
responseReq.RequestBody(map[string]interface{}{
|
||||||
|
"uid_field": bindDN,
|
||||||
|
})
|
||||||
case "ak-stage-password":
|
case "ak-stage-password":
|
||||||
responseParams.Data = &PasswordResponse{Password: password}
|
responseReq.RequestBody(map[string]interface{}{
|
||||||
|
"password": password,
|
||||||
|
})
|
||||||
case "ak-stage-access-denied":
|
case "ak-stage-access-denied":
|
||||||
return false, errors.New("got ak-stage-access-denied")
|
return false, errors.New("got ak-stage-access-denied")
|
||||||
default:
|
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)
|
response, _, err := responseReq.Execute()
|
||||||
pi.log.WithField("component", response.Payload.Component).WithField("type", *response.Payload.Type).Debug("Got response")
|
pi.log.WithField("component", response.Component).WithField("type", response.Type).Debug("Got response")
|
||||||
switch response.Payload.Component {
|
switch *response.Component {
|
||||||
case "ak-stage-access-denied":
|
case "ak-stage-access-denied":
|
||||||
return false, errors.New("got 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
|
return true, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pi.log.WithError(err).Warning("Failed to submit challenge")
|
pi.log.WithError(err).Warning("Failed to submit challenge")
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if len(response.Payload.ResponseErrors) > 0 {
|
if len(*response.ResponseErrors) > 0 {
|
||||||
for key, errs := range response.Payload.ResponseErrors {
|
for key, errs := range *response.ResponseErrors {
|
||||||
for _, err := range errs {
|
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
|
return false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package ldap
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/nmcclain/ldap"
|
"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) {
|
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:
|
default:
|
||||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, searchReq.Filter)
|
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, searchReq.Filter)
|
||||||
case GroupObjectClass:
|
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 {
|
if err != nil {
|
||||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("API Error: %s", err)
|
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")
|
pi.log.WithField("count", len(groups.Results)).Trace("Got results from API")
|
||||||
for _, g := range groups.Payload.Results {
|
for _, g := range groups.Results {
|
||||||
attrs := []*ldap.EntryAttribute{
|
attrs := []*ldap.EntryAttribute{
|
||||||
{
|
{
|
||||||
Name: "cn",
|
Name: "cn",
|
||||||
Values: []string{*g.Name},
|
Values: []string{g.Name},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "uid",
|
Name: "uid",
|
||||||
|
@ -69,31 +69,31 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest,
|
||||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||||
}
|
}
|
||||||
case UserObjectClass, "":
|
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 {
|
if err != nil {
|
||||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("API Error: %s", err)
|
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{
|
attrs := []*ldap.EntryAttribute{
|
||||||
{
|
{
|
||||||
Name: "cn",
|
Name: "cn",
|
||||||
Values: []string{*u.Username},
|
Values: []string{u.Username},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "uid",
|
Name: "uid",
|
||||||
Values: []string{u.UID},
|
Values: []string{u.Uid},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Values: []string{*u.Name},
|
Values: []string{u.Name},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "displayName",
|
Name: "displayName",
|
||||||
Values: []string{*u.Name},
|
Values: []string{u.Name},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "mail",
|
Name: "mail",
|
||||||
Values: []string{u.Email.String()},
|
Values: []string{*u.Email},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "objectClass",
|
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"}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"inactive"}})
|
||||||
} else {
|
} else {
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"active"}})
|
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"}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "superuser", Values: []string{"inactive"}})
|
||||||
} else {
|
} else {
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "superuser", Values: []string{"active"}})
|
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)...)
|
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})
|
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"goauthentik.io/outpost/api"
|
||||||
"goauthentik.io/outpost/pkg/ak"
|
"goauthentik.io/outpost/pkg/ak"
|
||||||
"goauthentik.io/outpost/pkg/models"
|
|
||||||
|
|
||||||
"github.com/nmcclain/ldap"
|
"github.com/nmcclain/ldap"
|
||||||
)
|
)
|
||||||
|
@ -31,7 +31,7 @@ type ProviderInstance struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserFlags struct {
|
type UserFlags struct {
|
||||||
UserInfo models.User
|
UserInfo api.User
|
||||||
CanSearch bool
|
CanSearch bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nmcclain/ldap"
|
"github.com/nmcclain/ldap"
|
||||||
"goauthentik.io/outpost/pkg/models"
|
"goauthentik.io/outpost/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AKAttrsToLDAP(attrs interface{}) []*ldap.EntryAttribute {
|
func AKAttrsToLDAP(attrs interface{}) []*ldap.EntryAttribute {
|
||||||
|
@ -22,7 +22,7 @@ func AKAttrsToLDAP(attrs interface{}) []*ldap.EntryAttribute {
|
||||||
return attrList
|
return attrList
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pi *ProviderInstance) GroupsForUser(user *models.User) []string {
|
func (pi *ProviderInstance) GroupsForUser(user api.User) []string {
|
||||||
groups := make([]string, len(user.Groups))
|
groups := make([]string, len(user.Groups))
|
||||||
for i, group := range user.Groups {
|
for i, group := range user.Groups {
|
||||||
groups[i] = pi.GetGroupDN(group)
|
groups[i] = pi.GetGroupDN(group)
|
||||||
|
@ -30,6 +30,6 @@ func (pi *ProviderInstance) GroupsForUser(user *models.User) []string {
|
||||||
return groups
|
return groups
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pi *ProviderInstance) GetGroupDN(group *models.Group) string {
|
func (pi *ProviderInstance) GetGroupDN(group api.Group) string {
|
||||||
return fmt.Sprintf("cn=%s,%s", *group.Name, pi.GroupDN)
|
return fmt.Sprintf("cn=%s,%s", group.Name, pi.GroupDN)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"goauthentik.io/outpost/pkg/models"
|
"goauthentik.io/outpost/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) Refresh() error {
|
func (s *Server) Refresh() error {
|
||||||
|
@ -21,10 +21,10 @@ func (s *Server) Refresh() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) bundleProviders(providers []*models.ProxyOutpostConfig) []*providerBundle {
|
func (s *Server) bundleProviders(providers []api.ProxyOutpostConfig) []*providerBundle {
|
||||||
bundles := make([]*providerBundle, len(providers))
|
bundles := make([]*providerBundle, len(providers))
|
||||||
for idx, provider := range providers {
|
for idx, provider := range providers {
|
||||||
externalHost, err := url.Parse(*provider.ExternalHost)
|
externalHost, err := url.Parse(provider.ExternalHost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Warning("Failed to parse URL, skipping provider")
|
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/middleware"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"goauthentik.io/outpost/pkg/client/crypto"
|
"goauthentik.io/outpost/api"
|
||||||
"goauthentik.io/outpost/pkg/models"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type providerBundle struct {
|
type providerBundle struct {
|
||||||
|
@ -35,8 +34,8 @@ func intToPointer(i int) *int {
|
||||||
return &i
|
return &i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *options.Options {
|
func (pb *providerBundle) prepareOpts(provider api.ProxyOutpostConfig) *options.Options {
|
||||||
externalHost, err := url.Parse(*provider.ExternalHost)
|
externalHost, err := url.Parse(provider.ExternalHost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Warning("Failed to parse URL, skipping provider")
|
log.WithError(err).Warning("Failed to parse URL, skipping provider")
|
||||||
return nil
|
return nil
|
||||||
|
@ -47,25 +46,25 @@ func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *opti
|
||||||
log.WithError(err).Warning("Failed to copy options, skipping provider")
|
log.WithError(err).Warning("Failed to copy options, skipping provider")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
providerOpts.ClientID = provider.ClientID
|
providerOpts.ClientID = *provider.ClientId
|
||||||
providerOpts.ClientSecret = provider.ClientSecret
|
providerOpts.ClientSecret = *provider.ClientSecret
|
||||||
|
|
||||||
providerOpts.Cookie.Secret = provider.CookieSecret
|
providerOpts.Cookie.Secret = *provider.CookieSecret
|
||||||
providerOpts.Cookie.Secure = externalHost.Scheme == "https"
|
providerOpts.Cookie.Secure = externalHost.Scheme == "https"
|
||||||
|
|
||||||
providerOpts.SkipOIDCDiscovery = true
|
providerOpts.SkipOIDCDiscovery = true
|
||||||
providerOpts.OIDCIssuerURL = *provider.OidcConfiguration.Issuer
|
providerOpts.OIDCIssuerURL = provider.OidcConfiguration.Issuer
|
||||||
providerOpts.LoginURL = *provider.OidcConfiguration.AuthorizationEndpoint
|
providerOpts.LoginURL = provider.OidcConfiguration.AuthorizationEndpoint
|
||||||
providerOpts.RedeemURL = *provider.OidcConfiguration.TokenEndpoint
|
providerOpts.RedeemURL = provider.OidcConfiguration.TokenEndpoint
|
||||||
providerOpts.OIDCJwksURL = *provider.OidcConfiguration.JwksURI
|
providerOpts.OIDCJwksURL = provider.OidcConfiguration.JwksUri
|
||||||
providerOpts.ProfileURL = *provider.OidcConfiguration.UserinfoEndpoint
|
providerOpts.ProfileURL = provider.OidcConfiguration.UserinfoEndpoint
|
||||||
|
|
||||||
if provider.SkipPathRegex != "" {
|
if *provider.SkipPathRegex != "" {
|
||||||
skipRegexes := strings.Split(provider.SkipPathRegex, "\n")
|
skipRegexes := strings.Split(*provider.SkipPathRegex, "\n")
|
||||||
providerOpts.SkipAuthRegex = skipRegexes
|
providerOpts.SkipAuthRegex = skipRegexes
|
||||||
}
|
}
|
||||||
|
|
||||||
if provider.ForwardAuthMode {
|
if *provider.ForwardAuthMode {
|
||||||
providerOpts.UpstreamServers = []options.Upstream{
|
providerOpts.UpstreamServers = []options.Upstream{
|
||||||
{
|
{
|
||||||
ID: "static",
|
ID: "static",
|
||||||
|
@ -78,33 +77,27 @@ func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *opti
|
||||||
providerOpts.UpstreamServers = []options.Upstream{
|
providerOpts.UpstreamServers = []options.Upstream{
|
||||||
{
|
{
|
||||||
ID: "default",
|
ID: "default",
|
||||||
URI: provider.InternalHost,
|
URI: *provider.InternalHost,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
InsecureSkipTLSVerify: !provider.InternalHostSslValidation,
|
InsecureSkipTLSVerify: !(*provider.InternalHostSslValidation),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if provider.Certificate != nil {
|
if provider.Certificate.Get() != nil {
|
||||||
pb.log.WithField("provider", provider.Name).Debug("Enabling TLS")
|
pb.log.WithField("provider", provider.Name).Debug("Enabling TLS")
|
||||||
cert, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewCertificate(&crypto.CryptoCertificatekeypairsViewCertificateParams{
|
cert, _, err := pb.s.ak.Client.CryptoApi.CryptoCertificatekeypairsViewCertificateRetrieve(context.Background(), *provider.Certificate.Get()).Execute()
|
||||||
Context: context.Background(),
|
|
||||||
KpUUID: *provider.Certificate,
|
|
||||||
}, pb.s.ak.Auth)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch certificate")
|
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch certificate")
|
||||||
return providerOpts
|
return providerOpts
|
||||||
}
|
}
|
||||||
key, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewPrivateKey(&crypto.CryptoCertificatekeypairsViewPrivateKeyParams{
|
key, _, err := pb.s.ak.Client.CryptoApi.CryptoCertificatekeypairsViewPrivateKeyRetrieve(context.Background(), *provider.Certificate.Get()).Execute()
|
||||||
Context: context.Background(),
|
|
||||||
KpUUID: *provider.Certificate,
|
|
||||||
}, pb.s.ak.Auth)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch private key")
|
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch private key")
|
||||||
return providerOpts
|
return providerOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
x509cert, err := tls.X509KeyPair([]byte(cert.Payload.Data), []byte(key.Payload.Data))
|
x509cert, err := tls.X509KeyPair([]byte(cert.Data), []byte(key.Data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to parse certificate")
|
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to parse certificate")
|
||||||
return providerOpts
|
return providerOpts
|
||||||
|
@ -115,7 +108,7 @@ func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *opti
|
||||||
return providerOpts
|
return providerOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pb *providerBundle) Build(provider *models.ProxyOutpostConfig) {
|
func (pb *providerBundle) Build(provider api.ProxyOutpostConfig) {
|
||||||
opts := pb.prepareOpts(provider)
|
opts := pb.prepareOpts(provider)
|
||||||
|
|
||||||
chain := alice.New()
|
chain := alice.New()
|
||||||
|
@ -154,10 +147,10 @@ func (pb *providerBundle) Build(provider *models.ProxyOutpostConfig) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if provider.BasicAuthEnabled {
|
if *provider.BasicAuthEnabled {
|
||||||
oauthproxy.SetBasicAuth = true
|
oauthproxy.SetBasicAuth = true
|
||||||
oauthproxy.BasicAuthUserAttribute = provider.BasicAuthUserAttribute
|
oauthproxy.BasicAuthUserAttribute = *provider.BasicAuthUserAttribute
|
||||||
oauthproxy.BasicAuthPasswordAttribute = provider.BasicAuthPasswordAttribute
|
oauthproxy.BasicAuthPasswordAttribute = *provider.BasicAuthPasswordAttribute
|
||||||
}
|
}
|
||||||
|
|
||||||
pb.proxy = oauthproxy
|
pb.proxy = oauthproxy
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/upstream"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/upstream"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
||||||
"goauthentik.io/outpost/pkg/models"
|
"goauthentik.io/outpost/api"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -94,7 +94,7 @@ type OAuthProxy struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOAuthProxy creates a new instance of OAuthProxy from the options provided
|
// 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)
|
logger := log.WithField("logger", "authentik.outpost.proxy").WithField("provider", provider.Name)
|
||||||
sessionStore, err := sessions.NewSessionStore(&opts.Session, &opts.Cookie)
|
sessionStore, err := sessions.NewSessionStore(&opts.Session, &opts.Cookie)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -133,7 +133,7 @@ func NewOAuthProxy(opts *options.Options, provider *models.ProxyOutpostConfig) (
|
||||||
CookieRefresh: opts.Cookie.Refresh,
|
CookieRefresh: opts.Cookie.Refresh,
|
||||||
CookieSameSite: opts.Cookie.SameSite,
|
CookieSameSite: opts.Cookie.SameSite,
|
||||||
|
|
||||||
forwardAuthMode: provider.ForwardAuthMode,
|
forwardAuthMode: *provider.ForwardAuthMode,
|
||||||
RobotsPath: "/robots.txt",
|
RobotsPath: "/robots.txt",
|
||||||
SignInPath: fmt.Sprintf("%s/sign_in", opts.ProxyPrefix),
|
SignInPath: fmt.Sprintf("%s/sign_in", opts.ProxyPrefix),
|
||||||
SignOutPath: fmt.Sprintf("%s/sign_out", opts.ProxyPrefix),
|
SignOutPath: fmt.Sprintf("%s/sign_out", opts.ProxyPrefix),
|
||||||
|
|
23973
schema.yml
Normal file
23973
schema.yml
Normal file
File diff suppressed because it is too large
Load diff
19149
swagger.yaml
19149
swagger.yaml
File diff suppressed because it is too large
Load diff
|
@ -9,7 +9,7 @@ trigger:
|
||||||
stages:
|
stages:
|
||||||
- stage: generate
|
- stage: generate
|
||||||
jobs:
|
jobs:
|
||||||
- job: swagger_generate
|
- job: generate_api
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-latest'
|
vmImage: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
|
@ -19,12 +19,11 @@ stages:
|
||||||
displayName: 'Install Node.js'
|
displayName: 'Install Node.js'
|
||||||
- task: CmdLine@2
|
- task: CmdLine@2
|
||||||
inputs:
|
inputs:
|
||||||
script: |
|
script: make gen-web
|
||||||
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
|
- task: PublishPipelineArtifact@1
|
||||||
inputs:
|
inputs:
|
||||||
targetPath: 'web/api/'
|
targetPath: 'web/api/'
|
||||||
artifact: 'ts_swagger_client'
|
artifact: 'ts_api_client'
|
||||||
publishLocation: 'pipeline'
|
publishLocation: 'pipeline'
|
||||||
- stage: lint
|
- stage: lint
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -39,7 +38,7 @@ stages:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: 'ts_swagger_client'
|
artifactName: 'ts_api_client'
|
||||||
path: "web/api/"
|
path: "web/api/"
|
||||||
- task: Npm@1
|
- task: Npm@1
|
||||||
inputs:
|
inputs:
|
||||||
|
@ -61,7 +60,7 @@ stages:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: 'ts_swagger_client'
|
artifactName: 'ts_api_client'
|
||||||
path: "web/api/"
|
path: "web/api/"
|
||||||
- task: Npm@1
|
- task: Npm@1
|
||||||
inputs:
|
inputs:
|
||||||
|
@ -85,7 +84,7 @@ stages:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: 'ts_swagger_client'
|
artifactName: 'ts_api_client'
|
||||||
path: "web/api/"
|
path: "web/api/"
|
||||||
- task: Npm@1
|
- task: Npm@1
|
||||||
inputs:
|
inputs:
|
||||||
|
|
|
@ -15,13 +15,13 @@ export class LoggingMiddleware implements Middleware {
|
||||||
let globalConfigPromise: Promise<Config>;
|
let globalConfigPromise: Promise<Config>;
|
||||||
export function config(): Promise<Config> {
|
export function config(): Promise<Config> {
|
||||||
if (!globalConfigPromise) {
|
if (!globalConfigPromise) {
|
||||||
globalConfigPromise = new RootApi(DEFAULT_CONFIG).rootConfigList();
|
globalConfigPromise = new RootApi(DEFAULT_CONFIG).rootConfigRetrieve();
|
||||||
}
|
}
|
||||||
return globalConfigPromise;
|
return globalConfigPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_CONFIG = new Configuration({
|
export const DEFAULT_CONFIG = new Configuration({
|
||||||
basePath: "/api/v2beta",
|
basePath: "",
|
||||||
headers: {
|
headers: {
|
||||||
"X-CSRFToken": getCookie("authentik_csrf"),
|
"X-CSRFToken": getCookie("authentik_csrf"),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ChallengeTypeEnum } from "authentik-api";
|
import { ChallengeChoices } from "authentik-api";
|
||||||
|
|
||||||
export interface Error {
|
export interface Error {
|
||||||
code: string;
|
code: string;
|
||||||
|
@ -10,7 +10,7 @@ export interface ErrorDict {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Challenge {
|
export interface Challenge {
|
||||||
type: ChallengeTypeEnum;
|
type: ChallengeChoices;
|
||||||
component?: string;
|
component?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
response_errors?: ErrorDict;
|
response_errors?: ErrorDict;
|
||||||
|
|
|
@ -4,9 +4,14 @@ import { DEFAULT_CONFIG } from "./Config";
|
||||||
let globalMePromise: Promise<SessionUser>;
|
let globalMePromise: Promise<SessionUser>;
|
||||||
export function me(): Promise<SessionUser> {
|
export function me(): Promise<SessionUser> {
|
||||||
if (!globalMePromise) {
|
if (!globalMePromise) {
|
||||||
globalMePromise = new CoreApi(DEFAULT_CONFIG).coreUsersMe().catch((ex) => {
|
globalMePromise = new CoreApi(DEFAULT_CONFIG).coreUsersMeRetrieve().catch((ex) => {
|
||||||
const defaultUser: SessionUser = {
|
const defaultUser: SessionUser = {
|
||||||
user: {
|
user: {
|
||||||
|
pk: -1,
|
||||||
|
isSuperuser: false,
|
||||||
|
groups: [],
|
||||||
|
avatar: "",
|
||||||
|
uid: "",
|
||||||
username: "",
|
username: "",
|
||||||
name: ""
|
name: ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ export class TokenCopyButton extends ActionButton {
|
||||||
if (!this.identifier) {
|
if (!this.identifier) {
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreTokensViewKey({
|
return new CoreApi(DEFAULT_CONFIG).coreTokensViewKeyRetrieve({
|
||||||
identifier: this.identifier
|
identifier: this.identifier
|
||||||
}).then((token) => {
|
}).then((token) => {
|
||||||
if (!token.key) {
|
if (!token.key) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
export class AdminLoginsChart extends AKChart<LoginMetrics> {
|
export class AdminLoginsChart extends AKChart<LoginMetrics> {
|
||||||
|
|
||||||
apiRequest(): Promise<LoginMetrics> {
|
apiRequest(): Promise<LoginMetrics> {
|
||||||
return new AdminApi(DEFAULT_CONFIG).adminMetricsList();
|
return new AdminApi(DEFAULT_CONFIG).adminMetricsRetrieve();
|
||||||
}
|
}
|
||||||
|
|
||||||
getChartData(data: LoginMetrics): ChartData {
|
getChartData(data: LoginMetrics): ChartData {
|
||||||
|
|
|
@ -11,7 +11,7 @@ export class ApplicationAuthorizeChart extends AKChart<Coordinate[]> {
|
||||||
applicationSlug!: string;
|
applicationSlug!: string;
|
||||||
|
|
||||||
apiRequest(): Promise<Coordinate[]> {
|
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 {
|
getChartData(data: Coordinate[]): ChartData {
|
||||||
|
|
|
@ -11,7 +11,7 @@ export class UserChart extends AKChart<UserMetrics> {
|
||||||
userId?: number;
|
userId?: number;
|
||||||
|
|
||||||
apiRequest(): Promise<UserMetrics> {
|
apiRequest(): Promise<UserMetrics> {
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreUsersMetrics({
|
return new CoreApi(DEFAULT_CONFIG).coreUsersMetricsRetrieve({
|
||||||
id: this.userId || 0,
|
id: this.userId || 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-gro
|
||||||
import { MessageLevel } from "../messages/Message";
|
import { MessageLevel } from "../messages/Message";
|
||||||
import { IronFormElement } from "@polymer/iron-form/iron-form";
|
import { IronFormElement } from "@polymer/iron-form/iron-form";
|
||||||
import { camelToSnake, convertToSlug } from "../../utils";
|
import { camelToSnake, convertToSlug } from "../../utils";
|
||||||
import { ValidationError } from "authentik-api/src";
|
import { ValidationError } from "authentik-api";
|
||||||
import { EVENT_REFRESH } from "../../constants";
|
import { EVENT_REFRESH } from "../../constants";
|
||||||
|
|
||||||
export class APIError extends Error {
|
export class APIError extends Error {
|
||||||
|
|
|
@ -32,7 +32,7 @@ export class NotificationDrawer extends LitElement {
|
||||||
|
|
||||||
firstUpdated(): void {
|
firstUpdated(): void {
|
||||||
new EventsApi(DEFAULT_CONFIG).eventsNotificationsList({
|
new EventsApi(DEFAULT_CONFIG).eventsNotificationsList({
|
||||||
seen: "false",
|
seen: false,
|
||||||
ordering: "-created",
|
ordering: "-created",
|
||||||
}).then(r => {
|
}).then(r => {
|
||||||
this.notifications = 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=${() => {
|
<button class="pf-c-dropdown__toggle pf-m-plain" type="button" @click=${() => {
|
||||||
new EventsApi(DEFAULT_CONFIG).eventsNotificationsPartialUpdate({
|
new EventsApi(DEFAULT_CONFIG).eventsNotificationsPartialUpdate({
|
||||||
uuid: item.pk || "",
|
uuid: item.pk || "",
|
||||||
data: {
|
patchedNotificationRequest: {
|
||||||
seen: true,
|
seen: true,
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
|
@ -10,8 +10,8 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
|
|
||||||
@customElement("ak-user-oauth-code-list")
|
@customElement("ak-user-oauth-code-list")
|
||||||
export class UserOAuthCodeList extends Table<ExpiringBaseGrantModel> {
|
export class UserOAuthCodeList extends Table<ExpiringBaseGrantModel> {
|
||||||
@property()
|
@property({ type: Number })
|
||||||
userId?: string;
|
userId?: number;
|
||||||
|
|
||||||
apiEndpoint(page: number): Promise<AKResponse<ExpiringBaseGrantModel>> {
|
apiEndpoint(page: number): Promise<AKResponse<ExpiringBaseGrantModel>> {
|
||||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2AuthorizationCodesList({
|
return new Oauth2Api(DEFAULT_CONFIG).oauth2AuthorizationCodesList({
|
||||||
|
@ -45,7 +45,7 @@ export class UserOAuthCodeList extends Table<ExpiringBaseGrantModel> {
|
||||||
.obj=${item}
|
.obj=${item}
|
||||||
objectLabel=${t`Authorization Code`}
|
objectLabel=${t`Authorization Code`}
|
||||||
.delete=${() => {
|
.delete=${() => {
|
||||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2AuthorizationCodesDelete({
|
return new Oauth2Api(DEFAULT_CONFIG).oauth2AuthorizationCodesDestroy({
|
||||||
id: item.pk || 0,
|
id: item.pk || 0,
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
|
|
|
@ -10,8 +10,8 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
|
|
||||||
@customElement("ak-user-oauth-refresh-list")
|
@customElement("ak-user-oauth-refresh-list")
|
||||||
export class UserOAuthRefreshList extends Table<ExpiringBaseGrantModel> {
|
export class UserOAuthRefreshList extends Table<ExpiringBaseGrantModel> {
|
||||||
@property()
|
@property({ type: Number })
|
||||||
userId?: string;
|
userId?: number;
|
||||||
|
|
||||||
apiEndpoint(page: number): Promise<AKResponse<ExpiringBaseGrantModel>> {
|
apiEndpoint(page: number): Promise<AKResponse<ExpiringBaseGrantModel>> {
|
||||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensList({
|
return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensList({
|
||||||
|
@ -45,7 +45,7 @@ export class UserOAuthRefreshList extends Table<ExpiringBaseGrantModel> {
|
||||||
.obj=${item}
|
.obj=${item}
|
||||||
objectLabel=${t`Refresh Code`}
|
objectLabel=${t`Refresh Code`}
|
||||||
.delete=${() => {
|
.delete=${() => {
|
||||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensDelete({
|
return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensDestroy({
|
||||||
id: item.pk || 0,
|
id: item.pk || 0,
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
|
|
|
@ -21,6 +21,7 @@ export const DefaultConfig: Config = {
|
||||||
errorReportingEnabled: false,
|
errorReportingEnabled: false,
|
||||||
errorReportingEnvironment: "",
|
errorReportingEnvironment: "",
|
||||||
errorReportingSendPii: false,
|
errorReportingSendPii: false,
|
||||||
|
uiFooterLinks: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
@customElement("ak-sidebar-brand")
|
@customElement("ak-sidebar-brand")
|
||||||
|
|
|
@ -10,8 +10,8 @@ import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
|
|
||||||
@customElement("ak-user-consent-list")
|
@customElement("ak-user-consent-list")
|
||||||
export class UserConsentList extends Table<UserConsent> {
|
export class UserConsentList extends Table<UserConsent> {
|
||||||
@property()
|
@property({ type: Number })
|
||||||
userId?: string;
|
userId?: number;
|
||||||
|
|
||||||
apiEndpoint(page: number): Promise<AKResponse<UserConsent>> {
|
apiEndpoint(page: number): Promise<AKResponse<UserConsent>> {
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreUserConsentList({
|
return new CoreApi(DEFAULT_CONFIG).coreUserConsentList({
|
||||||
|
@ -41,7 +41,7 @@ export class UserConsentList extends Table<UserConsent> {
|
||||||
.obj=${item}
|
.obj=${item}
|
||||||
objectLabel=${t`Consent`}
|
objectLabel=${t`Consent`}
|
||||||
.delete=${() => {
|
.delete=${() => {
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreUserConsentDelete({
|
return new CoreApi(DEFAULT_CONFIG).coreUserConsentDestroy({
|
||||||
id: item.pk || 0,
|
id: item.pk || 0,
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
|
|
|
@ -37,7 +37,7 @@ import { AuthenticatorValidateStageChallenge } from "./stages/authenticator_vali
|
||||||
import { WebAuthnAuthenticatorRegisterChallenge } from "./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
|
import { WebAuthnAuthenticatorRegisterChallenge } from "./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
|
||||||
import { CaptchaChallenge } from "./stages/captcha/CaptchaStage";
|
import { CaptchaChallenge } from "./stages/captcha/CaptchaStage";
|
||||||
import { StageHost } from "./stages/base";
|
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 { config, DEFAULT_CONFIG } from "../api/Config";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import { until } from "lit-html/directives/until";
|
import { until } from "lit-html/directives/until";
|
||||||
|
@ -114,7 +114,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolveRaw({
|
return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolveRaw({
|
||||||
flowSlug: this.flowSlug,
|
flowSlug: this.flowSlug,
|
||||||
data: formData || {},
|
requestBody: formData || {},
|
||||||
query: window.location.search.substring(1),
|
query: window.location.search.substring(1),
|
||||||
}).then((challengeRaw) => {
|
}).then((challengeRaw) => {
|
||||||
return challengeRaw.raw.json();
|
return challengeRaw.raw.json();
|
||||||
|
@ -155,7 +155,7 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
|
|
||||||
errorMessage(error: string): void {
|
errorMessage(error: string): void {
|
||||||
this.challenge = <ShellChallenge>{
|
this.challenge = <ShellChallenge>{
|
||||||
type: ChallengeTypeEnum.Shell,
|
type: ChallengeChoices.Shell,
|
||||||
body: `<header class="pf-c-login__main-header">
|
body: `<header class="pf-c-login__main-header">
|
||||||
<h1 class="pf-c-title pf-m-3xl">
|
<h1 class="pf-c-title pf-m-3xl">
|
||||||
${t`Whoops!`}
|
${t`Whoops!`}
|
||||||
|
@ -188,16 +188,16 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
switch (this.challenge.type) {
|
switch (this.challenge.type) {
|
||||||
case ChallengeTypeEnum.Redirect:
|
case ChallengeChoices.Redirect:
|
||||||
console.debug("authentik/flows: redirecting to url from server", (this.challenge as RedirectChallenge).to);
|
console.debug("authentik/flows: redirecting to url from server", (this.challenge as RedirectChallenge).to);
|
||||||
window.location.assign((this.challenge as RedirectChallenge).to);
|
window.location.assign((this.challenge as RedirectChallenge).to);
|
||||||
return html`<ak-empty-state
|
return html`<ak-empty-state
|
||||||
?loading=${true}
|
?loading=${true}
|
||||||
header=${t`Loading`}>
|
header=${t`Loading`}>
|
||||||
</ak-empty-state>`;
|
</ak-empty-state>`;
|
||||||
case ChallengeTypeEnum.Shell:
|
case ChallengeChoices.Shell:
|
||||||
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
|
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
|
||||||
case ChallengeTypeEnum.Native:
|
case ChallengeChoices.Native:
|
||||||
switch (this.challenge.component) {
|
switch (this.challenge.component) {
|
||||||
case "ak-stage-access-denied":
|
case "ak-stage-access-denied":
|
||||||
return html`<ak-stage-access-denied .host=${this} .challenge=${this.challenge as AccessDeniedChallenge}></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);
|
const authWindow = popupCenterScreen(authInfo.authUrl, "plex auth", 550, 700);
|
||||||
PlexAPIClient.pinPoll(this.challenge?.client_id || "", authInfo.pin.id).then(token => {
|
PlexAPIClient.pinPoll(this.challenge?.client_id || "", authInfo.pin.id).then(token => {
|
||||||
authWindow?.close();
|
authWindow?.close();
|
||||||
new SourcesApi(DEFAULT_CONFIG).sourcesPlexRedeemToken({
|
new SourcesApi(DEFAULT_CONFIG).sourcesPlexRedeemTokenCreate({
|
||||||
data: {
|
plexTokenRedeemRequest: {
|
||||||
plexToken: token,
|
plexToken: token,
|
||||||
},
|
},
|
||||||
slug: this.challenge?.slug || "",
|
slug: this.challenge?.slug || "",
|
||||||
|
|
|
@ -51,11 +51,11 @@ export abstract class Interface extends LitElement {
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
${until(new AdminApi(DEFAULT_CONFIG).adminVersionList().then(version => {
|
${until(new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve().then(version => {
|
||||||
if (version.versionCurrent !== VERSION) {
|
if (version.versionCurrent !== VERSION) {
|
||||||
return html`<ak-banner>
|
return html`<ak-banner>
|
||||||
${t`A newer version of the frontend is available.`}
|
${t`A newer version of the frontend is available.`}
|
||||||
<button @click=${() => { window.location.reload(); }}>
|
<button @click=${() => { window.location.reload(true); }}>
|
||||||
${t`Reload`}
|
${t`Reload`}
|
||||||
</button>
|
</button>
|
||||||
</ak-banner>`;
|
</ak-banner>`;
|
||||||
|
|
|
@ -56,7 +56,7 @@ export class LibraryApplication extends LitElement {
|
||||||
if (!this.application) {
|
if (!this.application) {
|
||||||
return html`<ak-spinner></ak-spinner>`;
|
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">
|
<div class="pf-c-card__header">
|
||||||
${this.application.metaIcon
|
${this.application.metaIcon
|
||||||
? html`<img class="app-icon pf-c-avatar" src="${ifDefined(this.application.metaIcon)}" alt="Application Icon"/>`
|
? 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 {
|
firstUpdated(): void {
|
||||||
new EventsApi(DEFAULT_CONFIG).eventsEventsTopPerUser({
|
new EventsApi(DEFAULT_CONFIG).eventsEventsTopPerUserList({
|
||||||
action: "authorize_application",
|
action: "authorize_application",
|
||||||
topN: 11,
|
topN: 11,
|
||||||
}).then((events) => {
|
}).then((events) => {
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { customElement, html, TemplateResult } from "lit-element";
|
import { customElement, html, TemplateResult } from "lit-element";
|
||||||
import { AdminStatus, AdminStatusCard } from "./AdminStatusCard";
|
import { AdminStatus, AdminStatusCard } from "./AdminStatusCard";
|
||||||
import { AdminApi, TaskStatusEnum } from "authentik-api";
|
import { AdminApi, StatusEnum } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
import { convertToTitle } from "../../../utils";
|
import { convertToTitle } from "../../../utils";
|
||||||
|
|
||||||
@customElement("ak-admin-status-card-backup")
|
@customElement("ak-admin-status-card-backup")
|
||||||
export class BackupStatusCard extends AdminStatusCard<TaskStatusEnum> {
|
export class BackupStatusCard extends AdminStatusCard<StatusEnum> {
|
||||||
|
|
||||||
getPrimaryValue(): Promise<TaskStatusEnum> {
|
getPrimaryValue(): Promise<StatusEnum> {
|
||||||
return new AdminApi(DEFAULT_CONFIG).adminSystemTasksRead({
|
return new AdminApi(DEFAULT_CONFIG).adminSystemTasksRetrieve({
|
||||||
id: "backup_database"
|
id: "backup_database"
|
||||||
}).then((value) => {
|
}).then((value) => {
|
||||||
return value.status;
|
return value.status;
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
return TaskStatusEnum.Error;
|
return StatusEnum.Error;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,14 +22,14 @@ export class BackupStatusCard extends AdminStatusCard<TaskStatusEnum> {
|
||||||
return html`${convertToTitle(this.value?.toString() || "")}`;
|
return html`${convertToTitle(this.value?.toString() || "")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatus(value: TaskStatusEnum): Promise<AdminStatus> {
|
getStatus(value: StatusEnum): Promise<AdminStatus> {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case TaskStatusEnum.Warning:
|
case StatusEnum.Warning:
|
||||||
return Promise.resolve<AdminStatus>({
|
return Promise.resolve<AdminStatus>({
|
||||||
icon: "fa fa-exclamation-triangle pf-m-warning",
|
icon: "fa fa-exclamation-triangle pf-m-warning",
|
||||||
message: t`Backup finished with warnings.`,
|
message: t`Backup finished with warnings.`,
|
||||||
});
|
});
|
||||||
case TaskStatusEnum.Error:
|
case StatusEnum.Error:
|
||||||
return Promise.resolve<AdminStatus>({
|
return Promise.resolve<AdminStatus>({
|
||||||
icon: "fa fa-times-circle pf-m-danger",
|
icon: "fa fa-times-circle pf-m-danger",
|
||||||
message: t`Backup finished with errors.`,
|
message: t`Backup finished with errors.`,
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { AdminStatusCard, AdminStatus } from "./AdminStatusCard";
|
||||||
export class VersionStatusCard extends AdminStatusCard<Version> {
|
export class VersionStatusCard extends AdminStatusCard<Version> {
|
||||||
|
|
||||||
getPrimaryValue(): Promise<Version> {
|
getPrimaryValue(): Promise<Version> {
|
||||||
return new AdminApi(DEFAULT_CONFIG).adminVersionList();
|
return new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve();
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatus(value: Version): Promise<AdminStatus> {
|
getStatus(value: Version): Promise<AdminStatus> {
|
||||||
|
|
|
@ -8,8 +8,8 @@ import { AdminStatus, AdminStatusCard } from "./AdminStatusCard";
|
||||||
export class WorkersStatusCard extends AdminStatusCard<number> {
|
export class WorkersStatusCard extends AdminStatusCard<number> {
|
||||||
|
|
||||||
getPrimaryValue(): Promise<number> {
|
getPrimaryValue(): Promise<number> {
|
||||||
return new AdminApi(DEFAULT_CONFIG).adminWorkersList({}).then((workers) => {
|
return new AdminApi(DEFAULT_CONFIG).adminWorkersRetrieve().then((workers) => {
|
||||||
return workers.pagination.count;
|
return workers.count;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ export class PolicyStatusChart extends AKChart<FlowMetrics> {
|
||||||
|
|
||||||
async apiRequest(): Promise<FlowMetrics> {
|
async apiRequest(): Promise<FlowMetrics> {
|
||||||
const api = new FlowsApi(DEFAULT_CONFIG);
|
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({
|
const count = (await api.flowsInstancesList({
|
||||||
pageSize: 1
|
pageSize: 1
|
||||||
})).pagination.count;
|
})).pagination.count;
|
||||||
|
|
|
@ -34,7 +34,7 @@ export class GroupCountStatusChart extends AKChart<GroupMetrics> {
|
||||||
pageSize: 1
|
pageSize: 1
|
||||||
})).pagination.count;
|
})).pagination.count;
|
||||||
const superusers = (await api.coreGroupsList({
|
const superusers = (await api.coreGroupsList({
|
||||||
isSuperuser: "true"
|
isSuperuser: true
|
||||||
})).pagination.count;
|
})).pagination.count;
|
||||||
this.centerText = count.toString();
|
this.centerText = count.toString();
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { customElement } from "lit-element";
|
import { customElement } from "lit-element";
|
||||||
import { SourcesApi, TaskStatusEnum } from "authentik-api";
|
import { SourcesApi, StatusEnum } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
import "../../../elements/forms/ConfirmationForm";
|
import "../../../elements/forms/ConfirmationForm";
|
||||||
import { AKChart } from "../../../elements/charts/Chart";
|
import { AKChart } from "../../../elements/charts/Chart";
|
||||||
|
@ -38,10 +38,10 @@ export class LDAPSyncStatusChart extends AKChart<LDAPSyncStats> {
|
||||||
let unsynced = 0;
|
let unsynced = 0;
|
||||||
await Promise.all(sources.results.map(async (element) => {
|
await Promise.all(sources.results.map(async (element) => {
|
||||||
try {
|
try {
|
||||||
const health = await api.sourcesLdapSyncStatus({
|
const health = await api.sourcesLdapSyncStatusRetrieve({
|
||||||
slug: element.slug,
|
slug: element.slug,
|
||||||
});
|
});
|
||||||
if (health.status !== TaskStatusEnum.Successful) {
|
if (health.status !== StatusEnum.Successful) {
|
||||||
failed += 1;
|
failed += 1;
|
||||||
}
|
}
|
||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
|
|
|
@ -37,7 +37,7 @@ export class OutpostStatusChart extends AKChart<OutpostStats> {
|
||||||
let outdated = 0;
|
let outdated = 0;
|
||||||
let unhealthy = 0;
|
let unhealthy = 0;
|
||||||
await Promise.all(outposts.results.map(async (element) => {
|
await Promise.all(outposts.results.map(async (element) => {
|
||||||
const health = await api.outpostsOutpostsHealth({
|
const health = await api.outpostsInstancesHealthList({
|
||||||
uuid: element.pk || "",
|
uuid: element.pk || "",
|
||||||
});
|
});
|
||||||
if (health.length === 0) {
|
if (health.length === 0) {
|
||||||
|
|
|
@ -32,13 +32,13 @@ export class PolicyStatusChart extends AKChart<PolicyMetrics> {
|
||||||
|
|
||||||
async apiRequest(): Promise<PolicyMetrics> {
|
async apiRequest(): Promise<PolicyMetrics> {
|
||||||
const api = new PoliciesApi(DEFAULT_CONFIG);
|
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({
|
const count = (await api.policiesAllList({
|
||||||
pageSize: 1
|
pageSize: 1
|
||||||
})).pagination.count;
|
})).pagination.count;
|
||||||
const unbound = (await api.policiesAllList({
|
const unbound = (await api.policiesAllList({
|
||||||
bindingsIsnull: "true",
|
bindingsIsnull: true,
|
||||||
promptstageIsnull: "true",
|
promptstageIsnull: true,
|
||||||
})).pagination.count;
|
})).pagination.count;
|
||||||
this.centerText = count.toString();
|
this.centerText = count.toString();
|
||||||
return {
|
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 { t } from "@lingui/macro";
|
||||||
import { CSSResult, customElement, property } from "lit-element";
|
import { CSSResult, customElement, property } from "lit-element";
|
||||||
import { html, TemplateResult } from "lit-html";
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
@ -18,7 +18,7 @@ import { ModelForm } from "../../elements/forms/ModelForm";
|
||||||
export class ApplicationForm extends ModelForm<Application, string> {
|
export class ApplicationForm extends ModelForm<Application, string> {
|
||||||
|
|
||||||
loadInstance(pk: string): Promise<Application> {
|
loadInstance(pk: string): Promise<Application> {
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsRead({
|
return new CoreApi(DEFAULT_CONFIG).coreApplicationsRetrieve({
|
||||||
slug: pk
|
slug: pk
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -43,17 +43,17 @@ export class ApplicationForm extends ModelForm<Application, string> {
|
||||||
if (this.instance) {
|
if (this.instance) {
|
||||||
writeOp = new CoreApi(DEFAULT_CONFIG).coreApplicationsUpdate({
|
writeOp = new CoreApi(DEFAULT_CONFIG).coreApplicationsUpdate({
|
||||||
slug: this.instance.slug,
|
slug: this.instance.slug,
|
||||||
data: data
|
applicationRequest: data
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
writeOp = new CoreApi(DEFAULT_CONFIG).coreApplicationsCreate({
|
writeOp = new CoreApi(DEFAULT_CONFIG).coreApplicationsCreate({
|
||||||
data: data
|
applicationRequest: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const icon = this.getFormFile();
|
const icon = this.getFormFile();
|
||||||
if (icon) {
|
if (icon) {
|
||||||
return writeOp.then(app => {
|
return writeOp.then(app => {
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIcon({
|
return new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIconCreate({
|
||||||
slug: app.slug,
|
slug: app.slug,
|
||||||
file: icon
|
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>
|
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<ul class="pf-c-dropdown__menu" hidden>
|
<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 types.map((type) => {
|
||||||
return html`<li>
|
return html`<li>
|
||||||
<ak-forms-modal>
|
<ak-forms-modal>
|
||||||
|
@ -145,10 +145,10 @@ export class ApplicationForm extends ModelForm<Application, string> {
|
||||||
?required=${true}
|
?required=${true}
|
||||||
name="policyEngineMode">
|
name="policyEngineMode">
|
||||||
<select class="pf-c-form-control">
|
<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.`}
|
${t`ANY, any policy must match to grant access.`}
|
||||||
</option>
|
</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.`}
|
${t`ALL, all policies must match to grant access.`}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
|
@ -104,7 +104,7 @@ export class ApplicationListPage extends TablePage<Application> {
|
||||||
.obj=${item}
|
.obj=${item}
|
||||||
objectLabel=${t`Application`}
|
objectLabel=${t`Application`}
|
||||||
.delete=${() => {
|
.delete=${() => {
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationsDelete({
|
return new CoreApi(DEFAULT_CONFIG).coreApplicationsDestroy({
|
||||||
slug: item.slug || ""
|
slug: item.slug || ""
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
|
|
|
@ -26,7 +26,7 @@ export class ApplicationViewPage extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
set applicationSlug(value: string) {
|
set applicationSlug(value: string) {
|
||||||
new CoreApi(DEFAULT_CONFIG).coreApplicationsRead({
|
new CoreApi(DEFAULT_CONFIG).coreApplicationsRetrieve({
|
||||||
slug: value
|
slug: value
|
||||||
}).then((app) => {
|
}).then((app) => {
|
||||||
this.application = 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 { CertificateKeyPair } from "authentik-api/src";
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { customElement } from "lit-element";
|
import { customElement } from "lit-element";
|
||||||
|
@ -8,15 +8,15 @@ import { Form } from "../../elements/forms/Form";
|
||||||
import "../../elements/forms/HorizontalFormElement";
|
import "../../elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
@customElement("ak-crypto-certificate-generate-form")
|
@customElement("ak-crypto-certificate-generate-form")
|
||||||
export class CertificateKeyPairForm extends Form<CertificateGeneration> {
|
export class CertificateKeyPairForm extends Form<CertificateGenerationRequest> {
|
||||||
|
|
||||||
getSuccessMessage(): string {
|
getSuccessMessage(): string {
|
||||||
return t`Successfully generated certificate-key pair.`;
|
return t`Successfully generated certificate-key pair.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
send = (data: CertificateGeneration): Promise<CertificateKeyPair> => {
|
send = (data: CertificateGenerationRequest): Promise<CertificateKeyPair> => {
|
||||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsGenerate({
|
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsGenerateCreate({
|
||||||
data: data
|
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 { t } from "@lingui/macro";
|
||||||
import { customElement } from "lit-element";
|
import { customElement } from "lit-element";
|
||||||
import { html, TemplateResult } from "lit-html";
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
@ -12,7 +12,7 @@ import { ModelForm } from "../../elements/forms/ModelForm";
|
||||||
export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string> {
|
export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string> {
|
||||||
|
|
||||||
loadInstance(pk: string): Promise<CertificateKeyPair> {
|
loadInstance(pk: string): Promise<CertificateKeyPair> {
|
||||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsRead({
|
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsRetrieve({
|
||||||
kpUuid: pk,
|
kpUuid: pk,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,11 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
||||||
if (this.instance) {
|
if (this.instance) {
|
||||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsPartialUpdate({
|
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsPartialUpdate({
|
||||||
kpUuid: this.instance.pk || "",
|
kpUuid: this.instance.pk || "",
|
||||||
data: data
|
patchedCertificateKeyPairRequest: data
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsCreate({
|
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"
|
name="certificateData"
|
||||||
?writeOnly=${this.instance !== undefined}
|
?writeOnly=${this.instance !== undefined}
|
||||||
?required=${true}>
|
?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>
|
<p class="pf-c-form__helper-text">${t`PEM-encoded Certificate data.`}</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
name="keyData"
|
name="keyData"
|
||||||
?writeOnly=${this.instance !== undefined}
|
?writeOnly=${this.instance !== undefined}
|
||||||
label=${t`Private Key`}>
|
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>
|
<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>
|
</ak-form-element-horizontal>
|
||||||
</form>`;
|
</form>`;
|
||||||
|
|
|
@ -80,7 +80,7 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
|
||||||
.obj=${item}
|
.obj=${item}
|
||||||
objectLabel=${t`Certificate-Key Pair`}
|
objectLabel=${t`Certificate-Key Pair`}
|
||||||
.delete=${() => {
|
.delete=${() => {
|
||||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsDelete({
|
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsDestroy({
|
||||||
kpUuid: item.pk || ""
|
kpUuid: item.pk || ""
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue