Merge branch 'master' into version-2021.3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> # Conflicts: # docker-compose.yml # helm/README.md # web/src/authentik.css # web/src/flows/FlowExecutor.ts # web/src/flows/stages/identification/IdentificationStage.ts # website/docs/installation/kubernetes.md
This commit is contained in:
commit
2713b05e8c
|
@ -36,3 +36,7 @@ values =
|
|||
[bumpversion:file:outpost/pkg/version.go]
|
||||
|
||||
[bumpversion:file:web/src/constants.ts]
|
||||
|
||||
[bumpversion:file:website/docs/outpusts/manual-deploy-docker-compose.md]
|
||||
|
||||
[bumpversion:file:website/docs/outpusts/manual-deploy-kubernetes.md]
|
||||
|
|
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
|
@ -59,6 +59,9 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: prepare ts api client
|
||||
run: |
|
||||
docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/src/api --additional-properties=typescriptThreePlus=true
|
||||
- name: Docker Login Registry
|
||||
env:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
|
|
@ -45,4 +45,5 @@ COPY ./lifecycle/ /lifecycle
|
|||
USER authentik
|
||||
STOPSIGNAL SIGINT
|
||||
ENV TMPDIR /dev/shm/
|
||||
ENV PYTHONUBUFFERED 1
|
||||
ENTRYPOINT [ "/lifecycle/bootstrap.sh" ]
|
||||
|
|
174
Pipfile.lock
generated
174
Pipfile.lock
generated
|
@ -18,45 +18,45 @@
|
|||
"default": {
|
||||
"aiohttp": {
|
||||
"hashes": [
|
||||
"sha256:119feb2bd551e58d83d1b38bfa4cb921af8ddedec9fad7183132db334c3133e0",
|
||||
"sha256:16d0683ef8a6d803207f02b899c928223eb219111bd52420ef3d7a8aa76227b6",
|
||||
"sha256:2eb3efe243e0f4ecbb654b08444ae6ffab37ac0ef8f69d3a2ffb958905379daf",
|
||||
"sha256:2ffea7904e70350da429568113ae422c88d2234ae776519549513c8f217f58a9",
|
||||
"sha256:40bd1b101b71a18a528ffce812cc14ff77d4a2a1272dfb8b11b200967489ef3e",
|
||||
"sha256:418597633b5cd9639e514b1d748f358832c08cd5d9ef0870026535bd5eaefdd0",
|
||||
"sha256:481d4b96969fbfdcc3ff35eea5305d8565a8300410d3d269ccac69e7256b1329",
|
||||
"sha256:4c1bdbfdd231a20eee3e56bd0ac1cd88c4ff41b64ab679ed65b75c9c74b6c5c2",
|
||||
"sha256:5563ad7fde451b1986d42b9bb9140e2599ecf4f8e42241f6da0d3d624b776f40",
|
||||
"sha256:58c62152c4c8731a3152e7e650b29ace18304d086cb5552d317a54ff2749d32a",
|
||||
"sha256:5b50e0b9460100fe05d7472264d1975f21ac007b35dcd6fd50279b72925a27f4",
|
||||
"sha256:5d84ecc73141d0a0d61ece0742bb7ff5751b0657dab8405f899d3ceb104cc7de",
|
||||
"sha256:5dde6d24bacac480be03f4f864e9a67faac5032e28841b00533cd168ab39cad9",
|
||||
"sha256:5e91e927003d1ed9283dee9abcb989334fc8e72cf89ebe94dc3e07e3ff0b11e9",
|
||||
"sha256:62bc216eafac3204877241569209d9ba6226185aa6d561c19159f2e1cbb6abfb",
|
||||
"sha256:6c8200abc9dc5f27203986100579fc19ccad7a832c07d2bc151ce4ff17190076",
|
||||
"sha256:6ca56bdfaf825f4439e9e3673775e1032d8b6ea63b8953d3812c71bd6a8b81de",
|
||||
"sha256:71680321a8a7176a58dfbc230789790639db78dad61a6e120b39f314f43f1907",
|
||||
"sha256:7c7820099e8b3171e54e7eedc33e9450afe7cd08172632d32128bd527f8cb77d",
|
||||
"sha256:7dbd087ff2f4046b9b37ba28ed73f15fd0bc9f4fdc8ef6781913da7f808d9536",
|
||||
"sha256:822bd4fd21abaa7b28d65fc9871ecabaddc42767884a626317ef5b75c20e8a2d",
|
||||
"sha256:8ec1a38074f68d66ccb467ed9a673a726bb397142c273f90d4ba954666e87d54",
|
||||
"sha256:950b7ef08b2afdab2488ee2edaff92a03ca500a48f1e1aaa5900e73d6cf992bc",
|
||||
"sha256:99c5a5bf7135607959441b7d720d96c8e5c46a1f96e9d6d4c9498be8d5f24212",
|
||||
"sha256:b84ad94868e1e6a5e30d30ec419956042815dfaea1b1df1cef623e4564c374d9",
|
||||
"sha256:bc3d14bf71a3fb94e5acf5bbf67331ab335467129af6416a437bd6024e4f743d",
|
||||
"sha256:c2a80fd9a8d7e41b4e38ea9fe149deed0d6aaede255c497e66b8213274d6d61b",
|
||||
"sha256:c44d3c82a933c6cbc21039326767e778eface44fca55c65719921c4b9661a3f7",
|
||||
"sha256:cc31e906be1cc121ee201adbdf844522ea3349600dd0a40366611ca18cd40e81",
|
||||
"sha256:d5d102e945ecca93bcd9801a7bb2fa703e37ad188a2f81b1e65e4abe4b51b00c",
|
||||
"sha256:dd7936f2a6daa861143e376b3a1fb56e9b802f4980923594edd9ca5670974895",
|
||||
"sha256:dee68ec462ff10c1d836c0ea2642116aba6151c6880b688e56b4c0246770f297",
|
||||
"sha256:e76e78863a4eaec3aee5722d85d04dcbd9844bc6cd3bfa6aa880ff46ad16bfcb",
|
||||
"sha256:eab51036cac2da8a50d7ff0ea30be47750547c9aa1aa2cf1a1b710a1827e7dbe",
|
||||
"sha256:f4496d8d04da2e98cc9133e238ccebf6a13ef39a93da2e87146c8c8ac9768242",
|
||||
"sha256:fbd3b5e18d34683decc00d9a360179ac1e7a320a5fee10ab8053ffd6deab76e0",
|
||||
"sha256:feb24ff1226beeb056e247cf2e24bba5232519efb5645121c4aea5b6ad74c1f2"
|
||||
"sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe",
|
||||
"sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe",
|
||||
"sha256:114b281e4d68302a324dd33abb04778e8557d88947875cbf4e842c2c01a030c5",
|
||||
"sha256:14762875b22d0055f05d12abc7f7d61d5fd4fe4642ce1a249abdf8c700bf1fd8",
|
||||
"sha256:15492a6368d985b76a2a5fdd2166cddfea5d24e69eefed4630cbaae5c81d89bd",
|
||||
"sha256:17c073de315745a1510393a96e680d20af8e67e324f70b42accbd4cb3315c9fb",
|
||||
"sha256:209b4a8ee987eccc91e2bd3ac36adee0e53a5970b8ac52c273f7f8fd4872c94c",
|
||||
"sha256:230a8f7e24298dea47659251abc0fd8b3c4e38a664c59d4b89cca7f6c09c9e87",
|
||||
"sha256:2e19413bf84934d651344783c9f5e22dee452e251cfd220ebadbed2d9931dbf0",
|
||||
"sha256:393f389841e8f2dfc86f774ad22f00923fdee66d238af89b70ea314c4aefd290",
|
||||
"sha256:3cf75f7cdc2397ed4442594b935a11ed5569961333d49b7539ea741be2cc79d5",
|
||||
"sha256:3d78619672183be860b96ed96f533046ec97ca067fd46ac1f6a09cd9b7484287",
|
||||
"sha256:40eced07f07a9e60e825554a31f923e8d3997cfc7fb31dbc1328c70826e04cde",
|
||||
"sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf",
|
||||
"sha256:4b302b45040890cea949ad092479e01ba25911a15e648429c7c5aae9650c67a8",
|
||||
"sha256:515dfef7f869a0feb2afee66b957cc7bbe9ad0cdee45aec7fdc623f4ecd4fb16",
|
||||
"sha256:547da6cacac20666422d4882cfcd51298d45f7ccb60a04ec27424d2f36ba3eaf",
|
||||
"sha256:5df68496d19f849921f05f14f31bd6ef53ad4b00245da3195048c69934521809",
|
||||
"sha256:64322071e046020e8797117b3658b9c2f80e3267daec409b350b6a7a05041213",
|
||||
"sha256:7615dab56bb07bff74bc865307aeb89a8bfd9941d2ef9d817b9436da3a0ea54f",
|
||||
"sha256:79ebfc238612123a713a457d92afb4096e2148be17df6c50fb9bf7a81c2f8013",
|
||||
"sha256:7b18b97cf8ee5452fa5f4e3af95d01d84d86d32c5e2bfa260cf041749d66360b",
|
||||
"sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9",
|
||||
"sha256:a00bb73540af068ca7390e636c01cbc4f644961896fa9363154ff43fd37af2f5",
|
||||
"sha256:a5ca29ee66f8343ed336816c553e82d6cade48a3ad702b9ffa6125d187e2dedb",
|
||||
"sha256:af9aa9ef5ba1fd5b8c948bb11f44891968ab30356d65fd0cc6707d989cd521df",
|
||||
"sha256:bb437315738aa441251214dad17428cafda9cdc9729499f1d6001748e1d432f4",
|
||||
"sha256:bdb230b4943891321e06fc7def63c7aace16095be7d9cf3b1e01be2f10fba439",
|
||||
"sha256:c6e9dcb4cb338d91a73f178d866d051efe7c62a7166653a91e7d9fb18274058f",
|
||||
"sha256:cffe3ab27871bc3ea47df5d8f7013945712c46a3cc5a95b6bee15887f1675c22",
|
||||
"sha256:d012ad7911653a906425d8473a1465caa9f8dea7fcf07b6d870397b774ea7c0f",
|
||||
"sha256:d9e13b33afd39ddeb377eff2c1c4f00544e191e1d1dee5b6c51ddee8ea6f0cf5",
|
||||
"sha256:e4b2b334e68b18ac9817d828ba44d8fcb391f6acb398bcc5062b14b2cbeac970",
|
||||
"sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009",
|
||||
"sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc",
|
||||
"sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a",
|
||||
"sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"
|
||||
],
|
||||
"version": "==3.7.4"
|
||||
"version": "==3.7.4.post0"
|
||||
},
|
||||
"aioredis": {
|
||||
"hashes": [
|
||||
|
@ -116,18 +116,17 @@
|
|||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:2219f1ebe88d266afa5516f993983eba8742b957fa4fd6854f3c73aa3030e931",
|
||||
"sha256:c0d51f344b71656c2d395d2168600d91bea252a64fb5d503a955ea96426cde8b"
|
||||
"sha256:64a8900b3a110e2d6ff4d87f4d8cd56f0c8527361d9fc9385fcb50efe7a4975a",
|
||||
"sha256:8e9ff8006c41889ed8a11831dee62adf922e071f14d54c52946d1f7855ae7a8e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.17.20"
|
||||
"version": "==1.17.26"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:80c32a81fb1ee8bdfa074a79bfb885bb2006e8a9782f2353c0c9f6392704e13a",
|
||||
"sha256:e9e724b59278ebf5caf032be1e32bde0990d79e8052e3bbbb97b6c1d32feba28"
|
||||
"sha256:4a785847a351e59f2329627fc9a19cf50f07644ea68996a1595d5a20487a423f"
|
||||
],
|
||||
"version": "==1.20.20"
|
||||
"version": "==1.20.26"
|
||||
},
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
|
@ -217,10 +216,10 @@
|
|||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
|
@ -304,11 +303,11 @@
|
|||
},
|
||||
"defusedxml": {
|
||||
"hashes": [
|
||||
"sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93",
|
||||
"sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"
|
||||
"sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69",
|
||||
"sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.6.0"
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
|
@ -445,10 +444,10 @@
|
|||
},
|
||||
"google-auth": {
|
||||
"hashes": [
|
||||
"sha256:d3640ea61ee025d5af00e3ffd82ba0a06dd99724adaf50bdd52f49daf29f3f65",
|
||||
"sha256:da5218cbf33b8461d7661d6b4ad91c12c0107e2767904d5e3ae6408031d5463e"
|
||||
"sha256:63a5636d7eacfe6ef5b7e36e112b3149fa1c5b5ad77dd6df54910459bcd6b89f",
|
||||
"sha256:d8958af6968e4ecd599f82357ebcfeb126f826ed0656126ad68416f810f7531e"
|
||||
],
|
||||
"version": "==1.27.0"
|
||||
"version": "==1.27.1"
|
||||
},
|
||||
"gunicorn": {
|
||||
"hashes": [
|
||||
|
@ -817,10 +816,10 @@
|
|||
},
|
||||
"prompt-toolkit": {
|
||||
"hashes": [
|
||||
"sha256:0fa02fa80363844a4ab4b8d6891f62dd0645ba672723130423ca4037b80c1974",
|
||||
"sha256:62c811e46bd09130fb11ab759012a4ae385ce4fb2073442d1898867a824183bd"
|
||||
"sha256:4cea7d09e46723885cb8bc54678175453e5071e9449821dce6f017b1d1fbfc1a",
|
||||
"sha256:9397a7162cf45449147ad6042fa37983a081b8a73363a5253dd4072666333137"
|
||||
],
|
||||
"version": "==3.0.16"
|
||||
"version": "==3.0.17"
|
||||
},
|
||||
"psycopg2-binary": {
|
||||
"hashes": [
|
||||
|
@ -1024,15 +1023,23 @@
|
|||
"sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018",
|
||||
"sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e",
|
||||
"sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253",
|
||||
"sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347",
|
||||
"sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183",
|
||||
"sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541",
|
||||
"sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb",
|
||||
"sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185",
|
||||
"sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc",
|
||||
"sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db",
|
||||
"sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa",
|
||||
"sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46",
|
||||
"sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122",
|
||||
"sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b",
|
||||
"sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63",
|
||||
"sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df",
|
||||
"sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"
|
||||
"sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc",
|
||||
"sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247",
|
||||
"sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6",
|
||||
"sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.4.1"
|
||||
|
@ -1069,10 +1076,47 @@
|
|||
},
|
||||
"ruamel.yaml": {
|
||||
"hashes": [
|
||||
"sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5",
|
||||
"sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e"
|
||||
"sha256:64b06e7873eb8e1125525ecef7345447d786368cadca92a7cd9b59eae62e95a3",
|
||||
"sha256:bb48c514222702878759a05af96f4b7ecdba9b33cd4efcf25c86b882cef3a942"
|
||||
],
|
||||
"version": "==0.16.12"
|
||||
"version": "==0.16.13"
|
||||
},
|
||||
"ruamel.yaml.clib": {
|
||||
"hashes": [
|
||||
"sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b",
|
||||
"sha256:1236df55e0f73cd138c0eca074ee086136c3f16a97c2ac719032c050f7e0622f",
|
||||
"sha256:1f8c0a4577c0e6c99d208de5c4d3fd8aceed9574bb154d7a2b21c16bb924154c",
|
||||
"sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91",
|
||||
"sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc",
|
||||
"sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7",
|
||||
"sha256:2fd336a5c6415c82e2deb40d08c222087febe0aebe520f4d21910629018ab0f3",
|
||||
"sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7",
|
||||
"sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6",
|
||||
"sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6",
|
||||
"sha256:46d6d20815064e8bb023ea8628cfb7402c0f0e83de2c2227a88097e239a7dffd",
|
||||
"sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0",
|
||||
"sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62",
|
||||
"sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99",
|
||||
"sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5",
|
||||
"sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026",
|
||||
"sha256:6c0a5dc52fc74eb87c67374a4e554d4761fd42a4d01390b7e868b30d21f4b8bb",
|
||||
"sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2",
|
||||
"sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1",
|
||||
"sha256:75f0ee6839532e52a3a53f80ce64925ed4aed697dd3fa890c4c918f3304bd4f4",
|
||||
"sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b",
|
||||
"sha256:8be05be57dc5c7b4a0b24edcaa2f7275866d9c907725226cdde46da09367d923",
|
||||
"sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e",
|
||||
"sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c",
|
||||
"sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988",
|
||||
"sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f",
|
||||
"sha256:b4b0d31f2052b3f9f9b5327024dc629a253a83d8649d4734ca7f35b60ec3e9e5",
|
||||
"sha256:c6ac7e45367b1317e56f1461719c853fd6825226f45b835df7436bb04031fd8a",
|
||||
"sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1",
|
||||
"sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2",
|
||||
"sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f"
|
||||
],
|
||||
"markers": "platform_python_implementation == 'CPython' and python_version < '3.10'",
|
||||
"version": "==0.2.2"
|
||||
},
|
||||
"s3transfer": {
|
||||
"hashes": [
|
||||
|
@ -1765,15 +1809,23 @@
|
|||
"sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018",
|
||||
"sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e",
|
||||
"sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253",
|
||||
"sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347",
|
||||
"sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183",
|
||||
"sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541",
|
||||
"sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb",
|
||||
"sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185",
|
||||
"sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc",
|
||||
"sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db",
|
||||
"sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa",
|
||||
"sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46",
|
||||
"sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122",
|
||||
"sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b",
|
||||
"sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63",
|
||||
"sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df",
|
||||
"sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"
|
||||
"sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc",
|
||||
"sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247",
|
||||
"sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6",
|
||||
"sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.4.1"
|
||||
|
|
|
@ -7,8 +7,8 @@ from django.db.models import Count, ExpressionWrapper, F, Model
|
|||
from django.db.models.fields import DurationField
|
||||
from django.db.models.functions import ExtractHour
|
||||
from django.utils.timezone import now
|
||||
from drf_yasg2.utils import swagger_auto_schema
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from drf_yasg2.utils import swagger_auto_schema, swagger_serializer_method
|
||||
from rest_framework.fields import IntegerField, SerializerMethodField
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
@ -37,23 +37,39 @@ def get_events_per_1h(**filter_kwargs) -> list[dict[str, int]]:
|
|||
for hour in range(0, -24, -1):
|
||||
results.append(
|
||||
{
|
||||
"x": time.mktime((_now + timedelta(hours=hour)).timetuple()) * 1000,
|
||||
"y": data[hour * -1],
|
||||
"x_cord": time.mktime((_now + timedelta(hours=hour)).timetuple())
|
||||
* 1000,
|
||||
"y_cord": data[hour * -1],
|
||||
}
|
||||
)
|
||||
return results
|
||||
|
||||
|
||||
class AdministrationMetricsSerializer(Serializer):
|
||||
class CoordinateSerializer(Serializer):
|
||||
"""Coordinates for diagrams"""
|
||||
|
||||
x_cord = IntegerField(read_only=True)
|
||||
y_cord = IntegerField(read_only=True)
|
||||
|
||||
def create(self, validated_data: dict) -> Model:
|
||||
raise NotImplementedError
|
||||
|
||||
def update(self, instance: Model, validated_data: dict) -> Model:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class LoginMetricsSerializer(Serializer):
|
||||
"""Login Metrics per 1h"""
|
||||
|
||||
logins_per_1h = SerializerMethodField()
|
||||
logins_failed_per_1h = SerializerMethodField()
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
def get_logins_per_1h(self, _):
|
||||
"""Get successful logins per hour for the last 24 hours"""
|
||||
return get_events_per_1h(action=EventAction.LOGIN)
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
def get_logins_failed_per_1h(self, _):
|
||||
"""Get failed logins per hour for the last 24 hours"""
|
||||
return get_events_per_1h(action=EventAction.LOGIN_FAILED)
|
||||
|
@ -70,8 +86,8 @@ class AdministrationMetricsViewSet(ViewSet):
|
|||
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
@swagger_auto_schema(responses={200: AdministrationMetricsSerializer(many=True)})
|
||||
@swagger_auto_schema(responses={200: LoginMetricsSerializer(many=False)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""Login Metrics per 1h"""
|
||||
serializer = AdministrationMetricsSerializer(True)
|
||||
serializer = LoginMetricsSerializer(True)
|
||||
return Response(serializer.data)
|
||||
|
|
|
@ -25,8 +25,8 @@ class TaskSerializer(Serializer):
|
|||
task_finish_timestamp = DateTimeField(source="finish_timestamp")
|
||||
|
||||
status = ChoiceField(
|
||||
source="result.status.value",
|
||||
choices=[(x.value, x.name) for x in TaskResultStatus],
|
||||
source="result.status.name",
|
||||
choices=[(x.name, x.name) for x in TaskResultStatus],
|
||||
)
|
||||
messages = ListField(source="result.messages")
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""api v2 urls"""
|
||||
from django.conf import settings
|
||||
from django.urls import path, re_path
|
||||
from drf_yasg2 import openapi
|
||||
from drf_yasg2.views import get_schema_view
|
||||
|
@ -54,12 +55,24 @@ from authentik.providers.saml.api import SAMLPropertyMappingViewSet, SAMLProvide
|
|||
from authentik.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet
|
||||
from authentik.sources.oauth.api import OAuthSourceViewSet
|
||||
from authentik.sources.saml.api import SAMLSourceViewSet
|
||||
from authentik.stages.authenticator_static.api import AuthenticatorStaticStageViewSet
|
||||
from authentik.stages.authenticator_totp.api import AuthenticatorTOTPStageViewSet
|
||||
from authentik.stages.authenticator_static.api import (
|
||||
AuthenticatorStaticStageViewSet,
|
||||
StaticAdminDeviceViewSet,
|
||||
StaticDeviceViewSet,
|
||||
)
|
||||
from authentik.stages.authenticator_totp.api import (
|
||||
AuthenticatorTOTPStageViewSet,
|
||||
TOTPAdminDeviceViewSet,
|
||||
TOTPDeviceViewSet,
|
||||
)
|
||||
from authentik.stages.authenticator_validate.api import (
|
||||
AuthenticatorValidateStageViewSet,
|
||||
)
|
||||
from authentik.stages.authenticator_webauthn.api import AuthenticateWebAuthnStageViewSet
|
||||
from authentik.stages.authenticator_webauthn.api import (
|
||||
AuthenticateWebAuthnStageViewSet,
|
||||
WebAuthnAdminDeviceViewSet,
|
||||
WebAuthnDeviceViewSet,
|
||||
)
|
||||
from authentik.stages.captcha.api import CaptchaStageViewSet
|
||||
from authentik.stages.consent.api import ConsentStageViewSet
|
||||
from authentik.stages.deny.api import DenyStageViewSet
|
||||
|
@ -133,6 +146,13 @@ router.register("propertymappings/ldap", LDAPPropertyMappingViewSet)
|
|||
router.register("propertymappings/saml", SAMLPropertyMappingViewSet)
|
||||
router.register("propertymappings/scope", ScopeMappingViewSet)
|
||||
|
||||
router.register("authenticators/static", StaticDeviceViewSet)
|
||||
router.register("authenticators/totp", TOTPDeviceViewSet)
|
||||
router.register("authenticators/webauthn", WebAuthnDeviceViewSet)
|
||||
router.register("authenticators/admin/static", StaticAdminDeviceViewSet)
|
||||
router.register("authenticators/admin/totp", TOTPAdminDeviceViewSet)
|
||||
router.register("authenticators/admin/webauthn", WebAuthnAdminDeviceViewSet)
|
||||
|
||||
router.register("stages/all", StageViewSet)
|
||||
router.register("stages/authenticator/static", AuthenticatorStaticStageViewSet)
|
||||
router.register("stages/authenticator/totp", AuthenticatorTOTPStageViewSet)
|
||||
|
@ -164,27 +184,26 @@ info = openapi.Info(
|
|||
name="GNU GPLv3", url="https://github.com/BeryJu/authentik/blob/master/LICENSE"
|
||||
),
|
||||
)
|
||||
SchemaView = get_schema_view(
|
||||
info,
|
||||
public=True,
|
||||
permission_classes=(AllowAny,),
|
||||
)
|
||||
SchemaView = get_schema_view(info, public=True, permission_classes=(AllowAny,))
|
||||
|
||||
urlpatterns = [
|
||||
re_path(
|
||||
r"^swagger(?P<format>\.json|\.yaml)$",
|
||||
SchemaView.without_ui(cache_timeout=0),
|
||||
name="schema-json",
|
||||
),
|
||||
path(
|
||||
"swagger/",
|
||||
SchemaView.with_ui("swagger", cache_timeout=0),
|
||||
name="schema-swagger-ui",
|
||||
),
|
||||
path("redoc/", SchemaView.with_ui("redoc", cache_timeout=0), name="schema-redoc"),
|
||||
urlpatterns = router.urls + [
|
||||
path(
|
||||
"flows/executor/<slug:flow_slug>/",
|
||||
FlowExecutorView.as_view(),
|
||||
name="flow-executor",
|
||||
),
|
||||
] + router.urls
|
||||
re_path(
|
||||
r"^swagger(?P<format>\.json|\.yaml)$",
|
||||
SchemaView.without_ui(cache_timeout=0),
|
||||
name="schema-json",
|
||||
),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns = urlpatterns + [
|
||||
path(
|
||||
"swagger/",
|
||||
SchemaView.with_ui("swagger", cache_timeout=0),
|
||||
name="schema-swagger-ui",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from django.core.cache import cache
|
||||
from django.db.models import QuerySet
|
||||
from django.http.response import Http404
|
||||
from drf_yasg2.utils import swagger_auto_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
|
@ -13,7 +14,7 @@ from rest_framework.viewsets import ModelViewSet
|
|||
from rest_framework_guardian.filters import ObjectPermissionsFilter
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.admin.api.metrics import get_events_per_1h
|
||||
from authentik.admin.api.metrics import CoordinateSerializer, get_events_per_1h
|
||||
from authentik.core.api.providers import ProviderSerializer
|
||||
from authentik.core.models import Application
|
||||
from authentik.events.models import EventAction
|
||||
|
@ -109,6 +110,7 @@ class ApplicationViewSet(ModelViewSet):
|
|||
serializer = self.get_serializer(allowed_applications, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
@swagger_auto_schema(responses={200: CoordinateSerializer(many=True)})
|
||||
@action(detail=True)
|
||||
def metrics(self, request: Request, slug: str):
|
||||
"""Metrics for application logins"""
|
||||
|
|
|
@ -21,3 +21,4 @@ class GroupViewSet(ModelViewSet):
|
|||
serializer_class = GroupSerializer
|
||||
search_fields = ["name", "is_superuser"]
|
||||
filterset_fields = ["name", "is_superuser"]
|
||||
ordering = ["name"]
|
||||
|
|
|
@ -28,9 +28,9 @@ class MetaNameSerializer(Serializer):
|
|||
class TypeCreateSerializer(Serializer):
|
||||
"""Types of an object that can be created"""
|
||||
|
||||
name = CharField(read_only=True)
|
||||
description = CharField(read_only=True)
|
||||
link = CharField(read_only=True)
|
||||
name = CharField(required=True)
|
||||
description = CharField(required=True)
|
||||
link = CharField(required=True)
|
||||
|
||||
def create(self, validated_data: dict) -> Model:
|
||||
raise NotImplementedError
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
{% extends container_template|default:"administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load authentik_utils %}
|
||||
|
||||
{% block content %}
|
||||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
{% block above_form %}
|
||||
|
@ -38,4 +35,3 @@
|
|||
<input class="pf-c-button pf-m-danger" type="submit" form="delete-form" value="{% trans 'Delete' %}" />
|
||||
<a class="pf-c-button pf-m-secondary" href="{% back %}">{% trans "Back" %}</a>
|
||||
</footer>
|
||||
{% endblock %}
|
||||
|
|
|
@ -7,6 +7,7 @@ from django.contrib.auth.mixins import (
|
|||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.http.response import HttpResponse
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import UpdateView
|
||||
from django.views.generic.base import TemplateView
|
||||
|
@ -34,7 +35,7 @@ class UserDetailsView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
|
|||
form_class = UserDetailForm
|
||||
|
||||
success_message = _("Successfully updated user.")
|
||||
success_url = "/"
|
||||
success_url = reverse_lazy("authentik_core:user-details")
|
||||
|
||||
def get_object(self):
|
||||
return self.request.user
|
||||
|
|
|
@ -13,7 +13,7 @@ class NotificationSerializer(ModelSerializer):
|
|||
|
||||
body = ReadOnlyField()
|
||||
severity = ReadOnlyField()
|
||||
event = EventSerializer()
|
||||
event = EventSerializer(required=False)
|
||||
|
||||
class Meta:
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
"""NotificationTransport API Views"""
|
||||
from django.http.response import Http404
|
||||
from drf_yasg2.utils import no_body, swagger_auto_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.serializers import ModelSerializer, Serializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.events.models import (
|
||||
|
@ -38,12 +39,28 @@ class NotificationTransportSerializer(ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class NotificationTransportTestSerializer(Serializer):
|
||||
"""Notification test serializer"""
|
||||
|
||||
messages = ListField(child=CharField())
|
||||
|
||||
def create(self, request: Request) -> Response:
|
||||
raise NotImplementedError
|
||||
|
||||
def update(self, request: Request) -> Response:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class NotificationTransportViewSet(ModelViewSet):
|
||||
"""NotificationTransport Viewset"""
|
||||
|
||||
queryset = NotificationTransport.objects.all()
|
||||
serializer_class = NotificationTransportSerializer
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={200: NotificationTransportTestSerializer(many=False)},
|
||||
request_body=no_body,
|
||||
)
|
||||
@action(detail=True, methods=["post"])
|
||||
# pylint: disable=invalid-name
|
||||
def test(self, request: Request, pk=None) -> Response:
|
||||
|
@ -61,6 +78,10 @@ class NotificationTransportViewSet(ModelViewSet):
|
|||
user=request.user,
|
||||
)
|
||||
try:
|
||||
return Response(transport.send(notification))
|
||||
response = NotificationTransportTestSerializer(
|
||||
data={"messages": transport.send(notification)}
|
||||
)
|
||||
response.is_valid()
|
||||
return Response(response.data)
|
||||
except NotificationTransportError as exc:
|
||||
return Response(str(exc.__cause__ or None), status=503)
|
||||
|
|
|
@ -12,7 +12,10 @@ def get_geoip_reader() -> Optional[Reader]:
|
|||
path = CONFIG.y("authentik.geoip")
|
||||
if path == "" or not path:
|
||||
return None
|
||||
return Reader(path)
|
||||
try:
|
||||
return Reader(path)
|
||||
except OSError:
|
||||
return None
|
||||
|
||||
|
||||
GEOIP_READER = get_geoip_reader()
|
||||
|
|
|
@ -38,7 +38,9 @@ class Challenge(Serializer):
|
|||
"""Challenge that gets sent to the client based on which stage
|
||||
is currently active"""
|
||||
|
||||
type = ChoiceField(choices=list(ChallengeTypes))
|
||||
type = ChoiceField(
|
||||
choices=[(x.name, x.name) for x in ChallengeTypes],
|
||||
)
|
||||
component = CharField(required=False)
|
||||
title = CharField(required=False)
|
||||
|
||||
|
@ -90,7 +92,7 @@ class ChallengeResponse(Serializer):
|
|||
|
||||
stage: Optional["StageView"]
|
||||
|
||||
def __init__(self, instance, data, **kwargs):
|
||||
def __init__(self, instance=None, data=None, **kwargs):
|
||||
self.stage = kwargs.pop("stage", None)
|
||||
super().__init__(instance=instance, data=data, **kwargs)
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.http import HttpRequest
|
|||
from django.http.request import QueryDict
|
||||
from django.http.response import HttpResponse
|
||||
from django.views.generic.base import View
|
||||
from rest_framework.request import Request
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import DEFAULT_AVATAR, User
|
||||
|
@ -67,9 +68,9 @@ class ChallengeStageView(StageView):
|
|||
return HttpChallengeResponse(challenge)
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
def post(self, request: Request, *args, **kwargs) -> HttpResponse:
|
||||
"""Handle challenge response"""
|
||||
challenge: ChallengeResponse = self.get_response_instance(data=request.POST)
|
||||
challenge: ChallengeResponse = self.get_response_instance(data=request.data)
|
||||
if not challenge.is_valid():
|
||||
return self.challenge_invalid(challenge)
|
||||
return self.challenge_valid(challenge)
|
||||
|
|
|
@ -9,11 +9,16 @@ from django.template.response import TemplateResponse
|
|||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
||||
from django.views.generic import TemplateView, View
|
||||
from drf_yasg2.utils import no_body, swagger_auto_schema
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.views import APIView
|
||||
from structlog.stdlib import BoundLogger, get_logger
|
||||
|
||||
from authentik.core.models import USER_ATTRIBUTE_DEBUG
|
||||
from authentik.events.models import cleanse_dict
|
||||
from authentik.flows.challenge import (
|
||||
Challenge,
|
||||
ChallengeResponse,
|
||||
ChallengeTypes,
|
||||
HttpChallengeResponse,
|
||||
RedirectChallenge,
|
||||
|
@ -40,9 +45,11 @@ SESSION_KEY_GET = "authentik_flows_get"
|
|||
|
||||
|
||||
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
||||
class FlowExecutorView(View):
|
||||
class FlowExecutorView(APIView):
|
||||
"""Stage 1 Flow executor, passing requests to Stage Views"""
|
||||
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
flow: Flow
|
||||
|
||||
plan: Optional[FlowPlan] = None
|
||||
|
@ -113,8 +120,13 @@ class FlowExecutorView(View):
|
|||
self.current_stage_view.request = request
|
||||
return super().dispatch(request)
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={200: Challenge()},
|
||||
request_body=no_body,
|
||||
operation_id="flows_executor_get",
|
||||
)
|
||||
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
"""pass get request to current stage"""
|
||||
"""Get the next pending challenge from the currently active flow."""
|
||||
self._logger.debug(
|
||||
"f(exec): Passing GET",
|
||||
view_class=class_to_path(self.current_stage_view.__class__),
|
||||
|
@ -127,8 +139,13 @@ class FlowExecutorView(View):
|
|||
self._logger.exception(exc)
|
||||
return to_stage_response(request, FlowErrorResponse(request, exc))
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={200: Challenge()},
|
||||
request_body=ChallengeResponse(),
|
||||
operation_id="flows_executor_solve",
|
||||
)
|
||||
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
"""pass post request to current stage"""
|
||||
"""Solve the previously retrieved challenge and advanced to the next stage."""
|
||||
self._logger.debug(
|
||||
"f(exec): Passing POST",
|
||||
view_class=class_to_path(self.current_stage_view.__class__),
|
||||
|
@ -175,8 +192,10 @@ class FlowExecutorView(View):
|
|||
"f(exec): Continuing with next stage",
|
||||
reamining=len(self.plan.stages),
|
||||
)
|
||||
kwargs = self.kwargs
|
||||
kwargs.update({"flow_slug": self.flow.slug})
|
||||
return redirect_with_qs(
|
||||
"authentik_api:flow-executor", self.request.GET, **self.kwargs
|
||||
"authentik_api:flow-executor", self.request.GET, **kwargs
|
||||
)
|
||||
# User passed all stages
|
||||
self._logger.debug(
|
||||
|
|
|
@ -13,6 +13,7 @@ redis:
|
|||
ws_db: 2
|
||||
|
||||
debug: false
|
||||
|
||||
log_level: info
|
||||
|
||||
# Error reporting, sends stacktrace to sentry.beryju.org
|
||||
|
|
|
@ -55,13 +55,21 @@ class OutpostConsumer(AuthJsonConsumer):
|
|||
OutpostState(
|
||||
uid=self.channel_name, last_seen=datetime.now(), _outpost=self.outpost
|
||||
).save(timeout=OUTPOST_HELLO_INTERVAL * 1.5)
|
||||
LOGGER.debug("added channel to cache", channel_name=self.channel_name)
|
||||
LOGGER.debug(
|
||||
"added outpost instace to cache",
|
||||
outpost=self.outpost,
|
||||
channel_name=self.channel_name,
|
||||
)
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def disconnect(self, close_code):
|
||||
if self.outpost:
|
||||
OutpostState.for_channel(self.outpost, self.channel_name).delete()
|
||||
LOGGER.debug("removed channel from cache", channel_name=self.channel_name)
|
||||
LOGGER.debug(
|
||||
"removed outpost instance from cache",
|
||||
outpost=self.outpost,
|
||||
channel_name=self.channel_name,
|
||||
)
|
||||
|
||||
def receive_json(self, content: Data):
|
||||
msg = from_dict(WebsocketMessage, content)
|
||||
|
|
|
@ -26,5 +26,5 @@ def invalidate_policy_cache(sender, instance, **_):
|
|||
cache.delete_many(keys)
|
||||
LOGGER.debug("Invalidating policy cache", policy=instance, keys=total)
|
||||
# Also delete user application cache
|
||||
keys = cache.keys(user_app_cache_key("*"))
|
||||
keys = cache.keys(user_app_cache_key("*")) or []
|
||||
cache.delete_many(keys)
|
||||
|
|
|
@ -74,7 +74,7 @@ class SAMLFlowFinalView(ChallengeStageView):
|
|||
return super().get(
|
||||
self.request,
|
||||
**{
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-autosubmit",
|
||||
"title": "Redirecting to %(app)s..." % {"app": application.name},
|
||||
"url": provider.acs_url,
|
||||
|
|
|
@ -150,7 +150,6 @@ SWAGGER_SETTINGS = {
|
|||
REST_FRAMEWORK = {
|
||||
"DEFAULT_PAGINATION_CLASS": "authentik.api.pagination.Pagination",
|
||||
"PAGE_SIZE": 100,
|
||||
"DATETIME_FORMAT": "%s",
|
||||
"DEFAULT_FILTER_BACKENDS": [
|
||||
"rest_framework_guardian.filters.ObjectPermissionsFilter",
|
||||
"django_filters.rest_framework.DjangoFilterBackend",
|
||||
|
|
|
@ -15,9 +15,11 @@ class OAuthSourceForm(forms.ModelForm):
|
|||
self.fields["authentication_flow"].queryset = Flow.objects.filter(
|
||||
designation=FlowDesignation.AUTHENTICATION
|
||||
)
|
||||
self.fields["authentication_flow"].required = True
|
||||
self.fields["enrollment_flow"].queryset = Flow.objects.filter(
|
||||
designation=FlowDesignation.ENROLLMENT
|
||||
)
|
||||
self.fields["enrollment_flow"].required = True
|
||||
if hasattr(self.Meta, "overrides"):
|
||||
for overide_field, overide_value in getattr(self.Meta, "overrides").items():
|
||||
self.fields[overide_field].initial = overide_value
|
||||
|
|
|
@ -4,6 +4,7 @@ from typing import Any, Optional
|
|||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.http import Http404, HttpRequest, HttpResponse
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
|
@ -151,6 +152,8 @@ class OAuthCallback(OAuthClientMixin, View):
|
|||
PLAN_CONTEXT_REDIRECT: final_redirect,
|
||||
}
|
||||
)
|
||||
if not flow:
|
||||
return HttpResponseBadRequest()
|
||||
# We run the Flow planner here so we can pass the Pending user in the context
|
||||
planner = FlowPlanner(flow)
|
||||
plan = planner.plan(self.request, kwargs)
|
||||
|
@ -233,6 +236,9 @@ class OAuthCallback(OAuthClientMixin, View):
|
|||
PLAN_CONTEXT_SOURCES_OAUTH_ACCESS: access,
|
||||
}
|
||||
# We run the Flow planner here so we can pass the Pending user in the context
|
||||
if not source.enrollment_flow:
|
||||
LOGGER.warning("source has no enrollment flow", source=source)
|
||||
return HttpResponseBadRequest()
|
||||
planner = FlowPlanner(source.enrollment_flow)
|
||||
plan = planner.plan(self.request, context)
|
||||
plan.append(in_memory_stage(PostUserEnrollmentStage))
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
"""AuthenticatorStaticStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from django_otp.plugins.otp_static.models import StaticDevice
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_static.models import AuthenticatorStaticStage
|
||||
|
@ -19,3 +22,39 @@ class AuthenticatorStaticStageViewSet(ModelViewSet):
|
|||
|
||||
queryset = AuthenticatorStaticStage.objects.all()
|
||||
serializer_class = AuthenticatorStaticStageSerializer
|
||||
|
||||
|
||||
class StaticDeviceSerializer(ModelSerializer):
|
||||
"""Serializer for static authenticator devices"""
|
||||
|
||||
class Meta:
|
||||
|
||||
model = StaticDevice
|
||||
fields = ["name", "token_set"]
|
||||
depth = 2
|
||||
|
||||
|
||||
class StaticDeviceViewSet(ModelViewSet):
|
||||
"""Viewset for static authenticator devices"""
|
||||
|
||||
queryset = StaticDevice.objects.none()
|
||||
serializer_class = StaticDeviceSerializer
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
|
||||
def get_queryset(self):
|
||||
if not self.request:
|
||||
return super().get_queryset()
|
||||
return StaticDevice.objects.filter(user=self.request.user)
|
||||
|
||||
|
||||
class StaticAdminDeviceViewSet(ReadOnlyModelViewSet):
|
||||
"""Viewset for static authenticator devices (for admins)"""
|
||||
|
||||
permission_classes = [IsAdminUser]
|
||||
queryset = StaticDevice.objects.all()
|
||||
serializer_class = StaticDeviceSerializer
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
|
|
|
@ -31,7 +31,7 @@ class AuthenticatorStaticStageView(ChallengeStageView):
|
|||
tokens: list[StaticToken] = self.request.session[SESSION_STATIC_TOKENS]
|
||||
return AuthenticatorStaticChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-authenticator-static",
|
||||
"codes": [token.token for token in tokens],
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
"""AuthenticatorTOTPStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_totp.models import AuthenticatorTOTPStage
|
||||
|
@ -19,3 +22,41 @@ class AuthenticatorTOTPStageViewSet(ModelViewSet):
|
|||
|
||||
queryset = AuthenticatorTOTPStage.objects.all()
|
||||
serializer_class = AuthenticatorTOTPStageSerializer
|
||||
|
||||
|
||||
class TOTPDeviceSerializer(ModelSerializer):
|
||||
"""Serializer for totp authenticator devices"""
|
||||
|
||||
class Meta:
|
||||
|
||||
model = TOTPDevice
|
||||
fields = [
|
||||
"name",
|
||||
]
|
||||
depth = 2
|
||||
|
||||
|
||||
class TOTPDeviceViewSet(ModelViewSet):
|
||||
"""Viewset for totp authenticator devices"""
|
||||
|
||||
queryset = TOTPDevice.objects.none()
|
||||
serializer_class = TOTPDeviceSerializer
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
|
||||
def get_queryset(self):
|
||||
if not self.request:
|
||||
return super().get_queryset()
|
||||
return TOTPDevice.objects.filter(user=self.request.user)
|
||||
|
||||
|
||||
class TOTPAdminDeviceViewSet(ReadOnlyModelViewSet):
|
||||
"""Viewset for totp authenticator devices (for admins)"""
|
||||
|
||||
permission_classes = [IsAdminUser]
|
||||
queryset = TOTPDevice.objects.all()
|
||||
serializer_class = TOTPDeviceSerializer
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
|
|
|
@ -51,7 +51,7 @@ class AuthenticatorTOTPStageView(ChallengeStageView):
|
|||
device: TOTPDevice = self.request.session[SESSION_TOTP_DEVICE]
|
||||
return AuthenticatorTOTPChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-authenticator-totp",
|
||||
"config_url": device.config_url,
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ class AuthenticatorValidateStageView(ChallengeStageView):
|
|||
challenges = self.request.session["device_challenges"]
|
||||
return AuthenticatorChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-authenticator-validate",
|
||||
"device_challenges": challenges,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
"""AuthenticateWebAuthnStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_webauthn.models import AuthenticateWebAuthnStage
|
||||
from authentik.stages.authenticator_webauthn.models import (
|
||||
AuthenticateWebAuthnStage,
|
||||
WebAuthnDevice,
|
||||
)
|
||||
|
||||
|
||||
class AuthenticateWebAuthnStageSerializer(StageSerializer):
|
||||
|
@ -19,3 +24,41 @@ class AuthenticateWebAuthnStageViewSet(ModelViewSet):
|
|||
|
||||
queryset = AuthenticateWebAuthnStage.objects.all()
|
||||
serializer_class = AuthenticateWebAuthnStageSerializer
|
||||
|
||||
|
||||
class WebAuthnDeviceSerializer(ModelSerializer):
|
||||
"""Serializer for WebAuthn authenticator devices"""
|
||||
|
||||
class Meta:
|
||||
|
||||
model = WebAuthnDevice
|
||||
fields = [
|
||||
"name",
|
||||
]
|
||||
depth = 2
|
||||
|
||||
|
||||
class WebAuthnDeviceViewSet(ModelViewSet):
|
||||
"""Viewset for WebAuthn authenticator devices"""
|
||||
|
||||
queryset = WebAuthnDevice.objects.none()
|
||||
serializer_class = WebAuthnDeviceSerializer
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
|
||||
def get_queryset(self):
|
||||
if not self.request:
|
||||
return super().get_queryset()
|
||||
return WebAuthnDevice.objects.filter(user=self.request.user)
|
||||
|
||||
|
||||
class WebAuthnAdminDeviceViewSet(ReadOnlyModelViewSet):
|
||||
"""Viewset for WebAuthn authenticator devices (for admins)"""
|
||||
|
||||
permission_classes = [IsAdminUser]
|
||||
queryset = WebAuthnDevice.objects.all()
|
||||
serializer_class = WebAuthnDeviceSerializer
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
ordering = ["name"]
|
||||
|
|
|
@ -122,7 +122,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
|
|||
|
||||
return AuthenticatorWebAuthnChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-authenticator-webauthn",
|
||||
"registration": make_credential_options.registration_dict,
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ class CaptchaStageView(ChallengeStageView):
|
|||
def get_challenge(self, *args, **kwargs) -> Challenge:
|
||||
return CaptchaChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-captcha",
|
||||
"site_key": self.executor.current_stage.public_key,
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ class ConsentStageView(ChallengeStageView):
|
|||
def get_challenge(self) -> Challenge:
|
||||
challenge = ConsentChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-consent",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -24,7 +24,7 @@ class DummyStageView(ChallengeStageView):
|
|||
def get_challenge(self, *args, **kwargs) -> Challenge:
|
||||
return DummyChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "",
|
||||
"title": self.executor.current_stage.name,
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ class EmailStageView(ChallengeStageView):
|
|||
|
||||
def get_challenge(self) -> Challenge:
|
||||
challenge = EmailChallenge(
|
||||
data={"type": ChallengeTypes.native, "component": "ak-stage-email"}
|
||||
data={"type": ChallengeTypes.native.value, "component": "ak-stage-email"}
|
||||
)
|
||||
return challenge
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ class IdentificationStageView(ChallengeStageView):
|
|||
current_stage: IdentificationStage = self.executor.current_stage
|
||||
challenge = IdentificationChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-identification",
|
||||
"primary_action": _("Log in"),
|
||||
"input_type": "text",
|
||||
|
|
|
@ -78,7 +78,7 @@ class PasswordStageView(ChallengeStageView):
|
|||
def get_challenge(self) -> Challenge:
|
||||
challenge = PasswordChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-password",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -164,7 +164,7 @@ class PromptStageView(ChallengeStageView):
|
|||
fields = list(self.executor.current_stage.fields.all().order_by("order"))
|
||||
challenge = PromptChallenge(
|
||||
data={
|
||||
"type": ChallengeTypes.native,
|
||||
"type": ChallengeTypes.native.value,
|
||||
"component": "ak-stage-prompt",
|
||||
"fields": [PromptSerializer(field).data for field in fields],
|
||||
},
|
||||
|
|
|
@ -279,6 +279,7 @@ stages:
|
|||
displayName: Build static files for e2e
|
||||
inputs:
|
||||
script: |
|
||||
docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/src/api --additional-properties=typescriptThreePlus=true
|
||||
cd web
|
||||
npm i
|
||||
npm run build
|
||||
|
|
|
@ -19,7 +19,7 @@ services:
|
|||
networks:
|
||||
- internal
|
||||
server:
|
||||
image: beryju/authentik:${AUTHENTIK_TAG:-2021.3.3}
|
||||
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.3.3}
|
||||
command: server
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
|
@ -27,9 +27,11 @@ services:
|
|||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||
# AUTHENTIK_ERROR_REPORTING__ENABLED: true
|
||||
volumes:
|
||||
- ./media:/media
|
||||
- ./custom-templates:/templates
|
||||
- geoip:/geoip
|
||||
ports:
|
||||
- 8000
|
||||
networks:
|
||||
|
@ -45,7 +47,7 @@ services:
|
|||
env_file:
|
||||
- .env
|
||||
worker:
|
||||
image: beryju/authentik:${AUTHENTIK_TAG:-2021.3.3}
|
||||
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.3.3}
|
||||
command: worker
|
||||
networks:
|
||||
- internal
|
||||
|
@ -55,14 +57,16 @@ services:
|
|||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||
# AUTHENTIK_ERROR_REPORTING__ENABLED: true
|
||||
volumes:
|
||||
- ./backups:/backups
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./custom-templates:/templates
|
||||
- geoip:/geoip
|
||||
env_file:
|
||||
- .env
|
||||
static:
|
||||
image: beryju/authentik-static:${AUTHENTIK_TAG:-2021.3.3}
|
||||
image: ${AUTHENTIK_IMAGE_STATIC:-beryju/authentik-static}:${AUTHENTIK_TAG:-2021.3.3}
|
||||
networks:
|
||||
- internal
|
||||
labels:
|
||||
|
@ -91,10 +95,21 @@ services:
|
|||
- "127.0.0.1:8080:8080"
|
||||
networks:
|
||||
- internal
|
||||
geoipupdate:
|
||||
image: "maxmindinc/geoipupdate:latest"
|
||||
volumes:
|
||||
- "geoip:/usr/share/GeoIP"
|
||||
environment:
|
||||
GEOIPUPDATE_EDITION_IDS: "GeoLite2-City"
|
||||
GEOIPUPDATE_FREQUENCY: "8"
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
volumes:
|
||||
database:
|
||||
driver: local
|
||||
geoip:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
internal: {}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|-----------------------------------|-------------------------|-------------|
|
||||
| image.name | beryju/authentik | Image used to run the authentik server and worker |
|
||||
| image.name_static | beryju/authentik-static | Image used to run the authentik static server (CSS and JS Files) |
|
||||
| image.tag | 2021.3.3 | Image tag |
|
||||
| image.tag | 2021.3.3 | Image tag |
|
||||
| image.pullPolicy | IfNotPresent | Image Pull Policy used for all deployments |
|
||||
| serverReplicas | 1 | Replicas for the Server deployment |
|
||||
| workerReplicas | 1 | Replicas for the Worker deployment |
|
||||
|
@ -22,6 +22,10 @@
|
|||
| config.email.use_ssl | false | Enable SSL |
|
||||
| config.email.timeout | 10 | SMTP Timeout |
|
||||
| config.email.from | authentik@localhost | Email address authentik will send from, should have a correct @domain |
|
||||
| geoip.enabled | false | Optionally enable GeoIP |
|
||||
| geoip.accountId | | GeoIP MaxMind Account ID |
|
||||
| geoip.licenseKey | | GeoIP MaxMind License key |
|
||||
| geoip.image | maxmindinc/geoipupdate:latest | GeoIP Updater image |
|
||||
| backup.accessKey | | Optionally enable S3 Backup, Access Key |
|
||||
| backup.secretKey | | Optionally enable S3 Backup, Secret Key |
|
||||
| backup.bucket | | Optionally enable S3 Backup, Bucket |
|
||||
|
|
11
helm/templates/geoip-configmap.yaml
Normal file
11
helm/templates/geoip-configmap.yaml
Normal file
|
@ -0,0 +1,11 @@
|
|||
{{- if .Values.geoip.enabled -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "authentik.fullname" . }}-geoip-config
|
||||
data:
|
||||
GEOIPUPDATE_ACCOUNT_ID: "{{ .Values.geoip.accountId }}"
|
||||
GEOIPUPDATE_LICENSE_KEY: "{{ .Values.geoip.licenseKey }}"
|
||||
GEOIPUPDATE_EDITION_IDS: "GeoLite2-City"
|
||||
GEOIPUPDATE_FREQUENCY: "8"
|
||||
{{- end }}
|
39
helm/templates/geoip-deployment.yaml
Normal file
39
helm/templates/geoip-deployment.yaml
Normal file
|
@ -0,0 +1,39 @@
|
|||
{{- if .Values.geoip.enabled -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "authentik.fullname" . }}-geoip
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "authentik.name" . }}
|
||||
helm.sh/chart: {{ include "authentik.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
k8s.goauthentik.io/component: geoip
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "authentik.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
k8s.goauthentik.io/component: geoip
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "authentik.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
k8s.goauthentik.io/component: geoip
|
||||
spec:
|
||||
containers:
|
||||
- name: geoip
|
||||
image: "{{ .Values.geoip.image }}"
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ include "authentik.fullname" . }}-geoip-config
|
||||
volumeMounts:
|
||||
- name: geoip
|
||||
mountPath: /usr/share/GeoIP
|
||||
volumes:
|
||||
- name: geoip
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "authentik.fullname" . }}-geoip
|
||||
{{- end }}
|
17
helm/templates/geoip-pvc.yaml
Normal file
17
helm/templates/geoip-pvc.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
{{- if .Values.geoip.enabled -}}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "authentik.fullname" . }}-geoip
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "authentik.name" . }}
|
||||
helm.sh/chart: {{ include "authentik.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
{{- end }}
|
121
helm/templates/prom-rules.yaml
Normal file
121
helm/templates/prom-rules.yaml
Normal file
|
@ -0,0 +1,121 @@
|
|||
{{- if .Values.monitoring.enabled -}}
|
||||
---
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: PrometheusRule
|
||||
metadata:
|
||||
name: {{ include "authentik.fullname" . }}-static-rules
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "authentik.name" . }}
|
||||
helm.sh/chart: {{ include "authentik.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
spec:
|
||||
groups:
|
||||
- name: Aggregate request counters
|
||||
rules:
|
||||
- record: job:django_http_requests_before_middlewares_total:sum_rate30s
|
||||
expr: sum(rate(django_http_requests_before_middlewares_total[30s])) by (job)
|
||||
- record: job:django_http_requests_unknown_latency_total:sum_rate30s
|
||||
expr: sum(rate(django_http_requests_unknown_latency_total[30s])) by (job)
|
||||
- record: job:django_http_ajax_requests_total:sum_rate30s
|
||||
expr: sum(rate(django_http_ajax_requests_total[30s])) by (job)
|
||||
- record: job:django_http_responses_before_middlewares_total:sum_rate30s
|
||||
expr: sum(rate(django_http_responses_before_middlewares_total[30s])) by (job)
|
||||
- record: job:django_http_requests_unknown_latency_including_middlewares_total:sum_rate30s
|
||||
expr: sum(rate(django_http_requests_unknown_latency_including_middlewares_total[30s])) by (job)
|
||||
- record: job:django_http_requests_body_total_bytes:sum_rate30s
|
||||
expr: sum(rate(django_http_requests_body_total_bytes[30s])) by (job)
|
||||
- record: job:django_http_responses_streaming_total:sum_rate30s
|
||||
expr: sum(rate(django_http_responses_streaming_total[30s])) by (job)
|
||||
- record: job:django_http_responses_body_total_bytes:sum_rate30s
|
||||
expr: sum(rate(django_http_responses_body_total_bytes[30s])) by (job)
|
||||
- record: job:django_http_requests_total:sum_rate30s
|
||||
expr: sum(rate(django_http_requests_total_by_method[30s])) by (job)
|
||||
- record: job:django_http_requests_total_by_method:sum_rate30s
|
||||
expr: sum(rate(django_http_requests_total_by_method[30s])) by (job,method)
|
||||
- record: job:django_http_requests_total_by_transport:sum_rate30s
|
||||
expr: sum(rate(django_http_requests_total_by_transport[30s])) by (job,transport)
|
||||
- record: job:django_http_requests_total_by_view:sum_rate30s
|
||||
expr: sum(rate(django_http_requests_total_by_view_transport_method[30s])) by (job,view)
|
||||
- record: job:django_http_requests_total_by_view_transport_method:sum_rate30s
|
||||
expr: sum(rate(django_http_requests_total_by_view_transport_method[30s])) by (job,view,transport,method)
|
||||
- record: job:django_http_responses_total_by_templatename:sum_rate30s
|
||||
expr: sum(rate(django_http_responses_total_by_templatename[30s])) by (job,templatename)
|
||||
- record: job:django_http_responses_total_by_status:sum_rate30s
|
||||
expr: sum(rate(django_http_responses_total_by_status[30s])) by (job,status)
|
||||
- record: job:django_http_responses_total_by_status_name_method:sum_rate30s
|
||||
expr: sum(rate(django_http_responses_total_by_status_name_method[30s])) by (job,status,name,method)
|
||||
- record: job:django_http_responses_total_by_charset:sum_rate30s
|
||||
expr: sum(rate(django_http_responses_total_by_charset[30s])) by (job,charset)
|
||||
- record: job:django_http_exceptions_total_by_type:sum_rate30s
|
||||
expr: sum(rate(django_http_exceptions_total_by_type[30s])) by (job,type)
|
||||
- record: job:django_http_exceptions_total_by_view:sum_rate30s
|
||||
expr: sum(rate(django_http_exceptions_total_by_view[30s])) by (job,view)
|
||||
- name: Aggregate latency histograms
|
||||
rules:
|
||||
- record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s
|
||||
expr: histogram_quantile(0.50, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) by (job, le))
|
||||
labels:
|
||||
quantile: "50"
|
||||
- record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s
|
||||
expr: histogram_quantile(0.95, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) by (job, le))
|
||||
labels:
|
||||
quantile: "95"
|
||||
- record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s
|
||||
expr: histogram_quantile(0.99, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) by (job, le))
|
||||
labels:
|
||||
quantile: "99"
|
||||
- record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s
|
||||
expr: histogram_quantile(0.999, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) by (job, le))
|
||||
labels:
|
||||
quantile: "99.9"
|
||||
- record: job:django_http_requests_latency_seconds:quantile_rate30s
|
||||
expr: histogram_quantile(0.50, sum(rate(django_http_requests_latency_seconds_bucket[30s])) by (job, le))
|
||||
labels:
|
||||
quantile: "50"
|
||||
- record: job:django_http_requests_latency_seconds:quantile_rate30s
|
||||
expr: histogram_quantile(0.95, sum(rate(django_http_requests_latency_seconds_bucket[30s])) by (job, le))
|
||||
labels:
|
||||
quantile: "95"
|
||||
- record: job:django_http_requests_latency_seconds:quantile_rate30s
|
||||
expr: histogram_quantile(0.99, sum(rate(django_http_requests_latency_seconds_bucket[30s])) by (job, le))
|
||||
labels:
|
||||
quantile: "99"
|
||||
- record: job:django_http_requests_latency_seconds:quantile_rate30s
|
||||
expr: histogram_quantile(0.999, sum(rate(django_http_requests_latency_seconds_bucket[30s])) by (job, le))
|
||||
labels:
|
||||
quantile: "99.9"
|
||||
- name: Aggregate model operations
|
||||
rules:
|
||||
- record: job:django_model_inserts_total:sum_rate1m
|
||||
expr: sum(rate(django_model_inserts_total[1m])) by (job, model)
|
||||
- record: job:django_model_updates_total:sum_rate1m
|
||||
expr: sum(rate(django_model_updates_total[1m])) by (job, model)
|
||||
- record: job:django_model_deletes_total:sum_rate1m
|
||||
expr: sum(rate(django_model_deletes_total[1m])) by (job, model)
|
||||
- name: Aggregate database operations
|
||||
rules:
|
||||
- record: job:django_db_new_connections_total:sum_rate30s
|
||||
expr: sum(rate(django_db_new_connections_total[30s])) by (alias, vendor)
|
||||
- record: job:django_db_new_connection_errors_total:sum_rate30s
|
||||
expr: sum(rate(django_db_new_connection_errors_total[30s])) by (alias, vendor)
|
||||
- record: job:django_db_execute_total:sum_rate30s
|
||||
expr: sum(rate(django_db_execute_total[30s])) by (alias, vendor)
|
||||
- record: job:django_db_execute_many_total:sum_rate30s
|
||||
expr: sum(rate(django_db_execute_many_total[30s])) by (alias, vendor)
|
||||
- record: job:django_db_errors_total:sum_rate30s
|
||||
expr: sum(rate(django_db_errors_total[30s])) by (alias, vendor, type)
|
||||
- name: Aggregate migrations
|
||||
rules:
|
||||
- record: job:django_migrations_applied_total:max
|
||||
expr: max(django_migrations_applied_total) by (job, connection)
|
||||
- record: job:django_migrations_unapplied_total:max
|
||||
expr: max(django_migrations_unapplied_total) by (job, connection)
|
||||
- name: Alerts
|
||||
rules:
|
||||
- alert: UnappliedMigrations
|
||||
expr: job:django_migrations_unapplied_total:max > 0
|
||||
for: 1m
|
||||
labels:
|
||||
severity: testing
|
||||
{{- end }}
|
17
helm/templates/static-sm.yaml
Normal file
17
helm/templates/static-sm.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
{{- if .Values.monitoring.enabled -}}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "authentik.name" . }}
|
||||
helm.sh/chart: {{ include "authentik.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
name: {{ include "authentik.fullname" . }}-static-monitoring
|
||||
spec:
|
||||
endpoints:
|
||||
- port: http
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s.goauthentik.io/component: static
|
||||
{{- end }}
|
|
@ -88,9 +88,17 @@ spec:
|
|||
secretKeyRef:
|
||||
name: "{{ .Release.Name }}-postgresql"
|
||||
key: "postgresql-password"
|
||||
{{ if .Values.geoip.enabled -}}
|
||||
- name: AUTHENTIK_AUTHENTIK__GEOIP
|
||||
value: /geoip/GeoLite2-City.mmdb
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: authentik-uploads
|
||||
mountPath: /media
|
||||
{{ if .Values.geoip.enabled -}}
|
||||
- name: geoip
|
||||
mountPath: /geoip
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8000
|
||||
|
@ -116,3 +124,8 @@ spec:
|
|||
- name: authentik-uploads
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "authentik.fullname" . }}-uploads
|
||||
{{ if .Values.geoip.enabled -}}
|
||||
- name: geoip
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "authentik.fullname" . }}-geoip
|
||||
{{- end }}
|
||||
|
|
26
helm/templates/web-sm.yaml
Normal file
26
helm/templates/web-sm.yaml
Normal file
|
@ -0,0 +1,26 @@
|
|||
{{- if .Values.monitoring.enabled -}}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "authentik.name" . }}
|
||||
helm.sh/chart: {{ include "authentik.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
name: {{ include "authentik.fullname" . }}-web-monitoring
|
||||
spec:
|
||||
endpoints:
|
||||
- basicAuth:
|
||||
password:
|
||||
name: {{ include "authentik.fullname" . }}-secret-key
|
||||
key: SECRET_KEY
|
||||
username:
|
||||
name: {{ include "authentik.fullname" . }}-secret-key
|
||||
key: monitoring_username
|
||||
port: http
|
||||
path: /metrics/
|
||||
interval: 10s
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s.goauthentik.io/component: web
|
||||
{{- end }}
|
|
@ -68,6 +68,15 @@ spec:
|
|||
secretKeyRef:
|
||||
name: "{{ .Release.Name }}-postgresql"
|
||||
key: "postgresql-password"
|
||||
{{ if .Values.geoip.enabled -}}
|
||||
- name: AUTHENTIK_AUTHENTIK__GEOIP
|
||||
value: /geoip/GeoLite2-City.mmdb
|
||||
{{- end }}
|
||||
{{ if .Values.geoip.enabled -}}
|
||||
volumeMounts:
|
||||
- name: geoip
|
||||
mountPath: /geoip
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
cpu: 150m
|
||||
|
@ -75,3 +84,9 @@ spec:
|
|||
limits:
|
||||
cpu: 300m
|
||||
memory: 600M
|
||||
{{ if .Values.geoip.enabled -}}
|
||||
volumes:
|
||||
- name: geoip
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "authentik.fullname" . }}-geoip
|
||||
{{- end -}}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
image:
|
||||
tag: gh-master
|
||||
pullPolicy: Always
|
||||
|
||||
serverReplicas: 1
|
||||
workerReplicas: 1
|
||||
|
||||
config:
|
||||
# Log level used by web and worker
|
||||
# Can be either debug, info, warning, error
|
||||
logLevel: debug
|
||||
|
||||
ingress:
|
||||
hosts:
|
||||
- authentik.127.0.0.1.nip.io
|
||||
|
||||
# These values influence the bundled postgresql and redis charts, but are also used by authentik to connect
|
||||
postgresql:
|
||||
postgresqlPassword: EK-5jnKfjrGRm<77
|
||||
|
||||
redis:
|
||||
password: password
|
|
@ -14,6 +14,9 @@ workerReplicas: 1
|
|||
# Enable the Kubernetes integration which lets authentik deploy outposts into kubernetes
|
||||
kubernetesIntegration: true
|
||||
|
||||
monitoring:
|
||||
enabled: true
|
||||
|
||||
config:
|
||||
# Optionally specify fixed secret_key, otherwise generated automatically
|
||||
# secretKey: _k*@6h2u2@q-dku57hhgzb7tnx*ba9wodcb^s9g0j59@=y(@_o
|
||||
|
@ -41,6 +44,13 @@ config:
|
|||
# Email address authentik will send from, should have a correct @domain
|
||||
from: authentik@localhost
|
||||
|
||||
# Enable MaxMind GeoIP
|
||||
geoip:
|
||||
enabled: false
|
||||
accountId: ""
|
||||
licenseKey: ""
|
||||
image: maxmindinc/geoipupdate:latest
|
||||
|
||||
# Enable Database Backups to S3
|
||||
# backup:
|
||||
# accessKey: access-key
|
||||
|
|
|
@ -33,7 +33,7 @@ stages:
|
|||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: 'outpost/pkg/'
|
||||
artifact: 'swagger_client'
|
||||
artifact: 'go_swagger_client'
|
||||
publishLocation: 'pipeline'
|
||||
- stage: lint
|
||||
jobs:
|
||||
|
@ -51,7 +51,7 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'swagger_client'
|
||||
artifactName: 'go_swagger_client'
|
||||
path: "outpost/pkg/"
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
|
@ -70,7 +70,7 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'swagger_client'
|
||||
artifactName: 'go_swagger_client'
|
||||
path: "outpost/pkg/"
|
||||
- task: Go@0
|
||||
inputs:
|
||||
|
@ -89,7 +89,7 @@ stages:
|
|||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'swagger_client'
|
||||
artifactName: 'go_swagger_client'
|
||||
path: "outpost/pkg/"
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
|
|
|
@ -24,7 +24,7 @@ require (
|
|||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/cachecontrol v0.0.0-20200921180117-858c6e7e6b7e // indirect
|
||||
github.com/recws-org/recws v1.2.1
|
||||
github.com/sirupsen/logrus v1.8.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/afero v1.5.1 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
|
|
|
@ -618,6 +618,8 @@ github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM
|
|||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU=
|
||||
github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM golang:1.16.0 AS builder
|
||||
FROM golang:1.16.2 AS builder
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
|
|
971
swagger.yaml
971
swagger.yaml
File diff suppressed because it is too large
Load diff
273
tests/e2e/test_provider_oauth2_oidc_implicit.py
Normal file
273
tests/e2e/test_provider_oauth2_oidc_implicit.py
Normal file
|
@ -0,0 +1,273 @@
|
|||
"""test OAuth2 OpenID Provider flow"""
|
||||
from json import loads
|
||||
from sys import platform
|
||||
from time import sleep
|
||||
from unittest.case import skipUnless
|
||||
|
||||
from docker import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from docker.types import Healthcheck
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support import expected_conditions as ec
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import Application
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.policies.expression.models import ExpressionPolicy
|
||||
from authentik.policies.models import PolicyBinding
|
||||
from authentik.providers.oauth2.constants import (
|
||||
SCOPE_OPENID,
|
||||
SCOPE_OPENID_EMAIL,
|
||||
SCOPE_OPENID_PROFILE,
|
||||
)
|
||||
from authentik.providers.oauth2.generators import (
|
||||
generate_client_id,
|
||||
generate_client_secret,
|
||||
)
|
||||
from authentik.providers.oauth2.models import ClientTypes, OAuth2Provider, ScopeMapping
|
||||
from tests.e2e.utils import (
|
||||
USER,
|
||||
SeleniumTestCase,
|
||||
apply_migration,
|
||||
object_manager,
|
||||
retry,
|
||||
)
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
@skipUnless(platform.startswith("linux"), "requires local docker")
|
||||
class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
|
||||
"""test OAuth with OpenID Provider flow"""
|
||||
|
||||
def setUp(self):
|
||||
self.client_id = generate_client_id()
|
||||
self.client_secret = generate_client_secret()
|
||||
self.application_slug = "test"
|
||||
super().setUp()
|
||||
|
||||
def setup_client(self) -> Container:
|
||||
"""Setup client saml-sp container which we test SAML against"""
|
||||
sleep(1)
|
||||
client: DockerClient = from_env()
|
||||
container = client.containers.run(
|
||||
image="beryju/oidc-test-client",
|
||||
detach=True,
|
||||
network_mode="host",
|
||||
auto_remove=True,
|
||||
healthcheck=Healthcheck(
|
||||
test=["CMD", "wget", "--spider", "http://localhost:9009/health"],
|
||||
interval=5 * 100 * 1000000,
|
||||
start_period=1 * 100 * 1000000,
|
||||
),
|
||||
environment={
|
||||
"OIDC_CLIENT_ID": self.client_id,
|
||||
"OIDC_CLIENT_SECRET": self.client_secret,
|
||||
"OIDC_PROVIDER": f"{self.live_server_url}/application/o/{self.application_slug}/",
|
||||
},
|
||||
)
|
||||
while True:
|
||||
container.reload()
|
||||
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
||||
if status == "healthy":
|
||||
return container
|
||||
LOGGER.info("Container failed healthcheck")
|
||||
sleep(1)
|
||||
|
||||
@retry()
|
||||
@apply_migration("authentik_core", "0003_default_user")
|
||||
@apply_migration("authentik_flows", "0008_default_flows")
|
||||
@apply_migration("authentik_flows", "0010_provider_flows")
|
||||
@apply_migration("authentik_crypto", "0002_create_self_signed_kp")
|
||||
def test_redirect_uri_error(self):
|
||||
"""test OpenID Provider flow (invalid redirect URI, check error message)"""
|
||||
sleep(1)
|
||||
# Bootstrap all needed objects
|
||||
authorization_flow = Flow.objects.get(
|
||||
slug="default-provider-authorization-implicit-consent"
|
||||
)
|
||||
provider = OAuth2Provider.objects.create(
|
||||
name=self.application_slug,
|
||||
client_type=ClientTypes.CONFIDENTIAL,
|
||||
client_id=self.client_id,
|
||||
client_secret=self.client_secret,
|
||||
rsa_key=CertificateKeyPair.objects.first(),
|
||||
redirect_uris="http://localhost:9009/",
|
||||
authorization_flow=authorization_flow,
|
||||
)
|
||||
provider.property_mappings.set(
|
||||
ScopeMapping.objects.filter(
|
||||
scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE]
|
||||
)
|
||||
)
|
||||
provider.save()
|
||||
Application.objects.create(
|
||||
name=self.application_slug,
|
||||
slug=self.application_slug,
|
||||
provider=provider,
|
||||
)
|
||||
self.container = self.setup_client()
|
||||
|
||||
self.driver.get("http://localhost:9009/implicit/")
|
||||
sleep(2)
|
||||
self.assertEqual(
|
||||
self.driver.find_element(By.CLASS_NAME, "pf-c-title").text,
|
||||
"Redirect URI Error",
|
||||
)
|
||||
|
||||
@retry()
|
||||
@apply_migration("authentik_core", "0003_default_user")
|
||||
@apply_migration("authentik_flows", "0008_default_flows")
|
||||
@apply_migration("authentik_flows", "0010_provider_flows")
|
||||
@apply_migration("authentik_crypto", "0002_create_self_signed_kp")
|
||||
@object_manager
|
||||
def test_authorization_consent_implied(self):
|
||||
"""test OpenID Provider flow (default authorization flow with implied consent)"""
|
||||
sleep(1)
|
||||
# Bootstrap all needed objects
|
||||
authorization_flow = Flow.objects.get(
|
||||
slug="default-provider-authorization-implicit-consent"
|
||||
)
|
||||
provider = OAuth2Provider.objects.create(
|
||||
name=self.application_slug,
|
||||
client_type=ClientTypes.CONFIDENTIAL,
|
||||
client_id=self.client_id,
|
||||
client_secret=self.client_secret,
|
||||
rsa_key=CertificateKeyPair.objects.first(),
|
||||
redirect_uris="http://localhost:9009/implicit/",
|
||||
authorization_flow=authorization_flow,
|
||||
)
|
||||
provider.property_mappings.set(
|
||||
ScopeMapping.objects.filter(
|
||||
scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE]
|
||||
)
|
||||
)
|
||||
provider.save()
|
||||
Application.objects.create(
|
||||
name=self.application_slug,
|
||||
slug=self.application_slug,
|
||||
provider=provider,
|
||||
)
|
||||
self.container = self.setup_client()
|
||||
|
||||
self.driver.get("http://localhost:9009/implicit/")
|
||||
self.login()
|
||||
self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "pre")))
|
||||
sleep(1)
|
||||
body = loads(self.driver.find_element(By.CSS_SELECTOR, "pre").text)
|
||||
print(body)
|
||||
self.assertEqual(body["profile"]["nickname"], USER().username)
|
||||
self.assertEqual(body["profile"]["name"], USER().name)
|
||||
self.assertEqual(body["profile"]["email"], USER().email)
|
||||
|
||||
@retry()
|
||||
@apply_migration("authentik_core", "0003_default_user")
|
||||
@apply_migration("authentik_flows", "0008_default_flows")
|
||||
@apply_migration("authentik_flows", "0010_provider_flows")
|
||||
@apply_migration("authentik_crypto", "0002_create_self_signed_kp")
|
||||
@object_manager
|
||||
def test_authorization_consent_explicit(self):
|
||||
"""test OpenID Provider flow (default authorization flow with explicit consent)"""
|
||||
sleep(1)
|
||||
# Bootstrap all needed objects
|
||||
authorization_flow = Flow.objects.get(
|
||||
slug="default-provider-authorization-explicit-consent"
|
||||
)
|
||||
provider = OAuth2Provider.objects.create(
|
||||
name=self.application_slug,
|
||||
authorization_flow=authorization_flow,
|
||||
client_type=ClientTypes.CONFIDENTIAL,
|
||||
client_id=self.client_id,
|
||||
client_secret=self.client_secret,
|
||||
rsa_key=CertificateKeyPair.objects.first(),
|
||||
redirect_uris="http://localhost:9009/implicit/",
|
||||
)
|
||||
provider.property_mappings.set(
|
||||
ScopeMapping.objects.filter(
|
||||
scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE]
|
||||
)
|
||||
)
|
||||
provider.save()
|
||||
app = Application.objects.create(
|
||||
name=self.application_slug,
|
||||
slug=self.application_slug,
|
||||
provider=provider,
|
||||
)
|
||||
self.container = self.setup_client()
|
||||
|
||||
self.driver.get("http://localhost:9009/implicit/")
|
||||
self.login()
|
||||
|
||||
self.wait.until(
|
||||
ec.presence_of_element_located((By.CSS_SELECTOR, "ak-flow-executor"))
|
||||
)
|
||||
|
||||
flow_executor = self.get_shadow_root("ak-flow-executor")
|
||||
consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor)
|
||||
|
||||
self.assertIn(
|
||||
app.name,
|
||||
consent_stage.find_element(By.CSS_SELECTOR, "#header-text").text,
|
||||
)
|
||||
consent_stage.find_element(
|
||||
By.CSS_SELECTOR,
|
||||
("[type=submit]"),
|
||||
).click()
|
||||
|
||||
self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "pre")))
|
||||
sleep(1)
|
||||
body = loads(self.driver.find_element(By.CSS_SELECTOR, "pre").text)
|
||||
|
||||
self.assertEqual(body["profile"]["nickname"], USER().username)
|
||||
self.assertEqual(body["profile"]["name"], USER().name)
|
||||
self.assertEqual(body["profile"]["email"], USER().email)
|
||||
|
||||
@retry()
|
||||
@apply_migration("authentik_core", "0003_default_user")
|
||||
@apply_migration("authentik_flows", "0008_default_flows")
|
||||
@apply_migration("authentik_flows", "0010_provider_flows")
|
||||
@apply_migration("authentik_crypto", "0002_create_self_signed_kp")
|
||||
def test_authorization_denied(self):
|
||||
"""test OpenID Provider flow (default authorization with access deny)"""
|
||||
sleep(1)
|
||||
# Bootstrap all needed objects
|
||||
authorization_flow = Flow.objects.get(
|
||||
slug="default-provider-authorization-explicit-consent"
|
||||
)
|
||||
provider = OAuth2Provider.objects.create(
|
||||
name=self.application_slug,
|
||||
authorization_flow=authorization_flow,
|
||||
client_type=ClientTypes.CONFIDENTIAL,
|
||||
client_id=self.client_id,
|
||||
client_secret=self.client_secret,
|
||||
rsa_key=CertificateKeyPair.objects.first(),
|
||||
redirect_uris="http://localhost:9009/implicit/",
|
||||
)
|
||||
provider.property_mappings.set(
|
||||
ScopeMapping.objects.filter(
|
||||
scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE]
|
||||
)
|
||||
)
|
||||
provider.save()
|
||||
app = Application.objects.create(
|
||||
name=self.application_slug,
|
||||
slug=self.application_slug,
|
||||
provider=provider,
|
||||
)
|
||||
|
||||
negative_policy = ExpressionPolicy.objects.create(
|
||||
name="negative-static", expression="return False"
|
||||
)
|
||||
PolicyBinding.objects.create(target=app, policy=negative_policy, order=0)
|
||||
|
||||
self.container = self.setup_client()
|
||||
self.driver.get("http://localhost:9009/implicit/")
|
||||
self.login()
|
||||
self.wait.until(
|
||||
ec.presence_of_element_located((By.CSS_SELECTOR, "header > h1"))
|
||||
)
|
||||
self.assertEqual(
|
||||
self.driver.find_element(By.CSS_SELECTOR, "header > h1").text,
|
||||
"Permission denied",
|
||||
)
|
|
@ -3,11 +3,13 @@ from shutil import rmtree
|
|||
from tempfile import mkdtemp
|
||||
from time import sleep
|
||||
|
||||
import yaml
|
||||
from django.test import TestCase
|
||||
from docker import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from docker.types.healthcheck import Healthcheck
|
||||
|
||||
from authentik import __version__
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.outposts.apps import AuthentikOutpostConfig
|
||||
|
@ -93,3 +95,14 @@ class OutpostDockerTests(TestCase):
|
|||
controller = DockerController(self.outpost, self.service_connection)
|
||||
controller.up()
|
||||
controller.down()
|
||||
|
||||
def test_docker_static(self):
|
||||
"""test that deployment requires update"""
|
||||
controller = DockerController(self.outpost, self.service_connection)
|
||||
manifest = controller.get_static_deployment()
|
||||
compose = yaml.load(manifest, Loader=yaml.SafeLoader)
|
||||
self.assertEqual(compose["version"], "3.5")
|
||||
self.assertEqual(
|
||||
compose["services"]["authentik_proxy"]["image"],
|
||||
f"beryju/authentik-proxy:{__version__}",
|
||||
)
|
||||
|
|
108
tests/integration/test_proxy_docker.py
Normal file
108
tests/integration/test_proxy_docker.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
"""outpost tests"""
|
||||
from shutil import rmtree
|
||||
from tempfile import mkdtemp
|
||||
from time import sleep
|
||||
|
||||
import yaml
|
||||
from django.test import TestCase
|
||||
from docker import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from docker.types.healthcheck import Healthcheck
|
||||
|
||||
from authentik import __version__
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.outposts.apps import AuthentikOutpostConfig
|
||||
from authentik.outposts.models import DockerServiceConnection, Outpost, OutpostType
|
||||
from authentik.providers.proxy.controllers.docker import DockerController
|
||||
from authentik.providers.proxy.models import ProxyProvider
|
||||
|
||||
|
||||
class TestProxyDocker(TestCase):
|
||||
"""Test Docker Controllers"""
|
||||
|
||||
def _start_container(self, ssl_folder: str) -> Container:
|
||||
client: DockerClient = from_env()
|
||||
container = client.containers.run(
|
||||
image="library/docker:dind",
|
||||
detach=True,
|
||||
network_mode="host",
|
||||
remove=True,
|
||||
privileged=True,
|
||||
healthcheck=Healthcheck(
|
||||
test=["CMD", "docker", "info"],
|
||||
interval=5 * 100 * 1000000,
|
||||
start_period=5 * 100 * 1000000,
|
||||
),
|
||||
environment={"DOCKER_TLS_CERTDIR": "/ssl"},
|
||||
volumes={
|
||||
f"{ssl_folder}/": {
|
||||
"bind": "/ssl",
|
||||
}
|
||||
},
|
||||
)
|
||||
while True:
|
||||
container.reload()
|
||||
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
||||
if status == "healthy":
|
||||
return container
|
||||
sleep(1)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.ssl_folder = mkdtemp()
|
||||
self.container = self._start_container(self.ssl_folder)
|
||||
# Ensure that local connection have been created
|
||||
AuthentikOutpostConfig.init_local_connection()
|
||||
self.provider: ProxyProvider = ProxyProvider.objects.create(
|
||||
name="test",
|
||||
internal_host="http://localhost",
|
||||
external_host="http://localhost",
|
||||
authorization_flow=Flow.objects.first(),
|
||||
)
|
||||
authentication_kp = CertificateKeyPair.objects.create(
|
||||
name="docker-authentication",
|
||||
certificate_data=open(f"{self.ssl_folder}/client/cert.pem").read(),
|
||||
key_data=open(f"{self.ssl_folder}/client/key.pem").read(),
|
||||
)
|
||||
verification_kp = CertificateKeyPair.objects.create(
|
||||
name="docker-verification",
|
||||
certificate_data=open(f"{self.ssl_folder}/client/ca.pem").read(),
|
||||
)
|
||||
self.service_connection = DockerServiceConnection.objects.create(
|
||||
url="https://localhost:2376",
|
||||
tls_verification=verification_kp,
|
||||
tls_authentication=authentication_kp,
|
||||
)
|
||||
self.outpost: Outpost = Outpost.objects.create(
|
||||
name="test",
|
||||
type=OutpostType.PROXY,
|
||||
service_connection=self.service_connection,
|
||||
)
|
||||
self.outpost.providers.add(self.provider)
|
||||
self.outpost.save()
|
||||
|
||||
def tearDown(self) -> None:
|
||||
super().tearDown()
|
||||
self.container.kill()
|
||||
try:
|
||||
rmtree(self.ssl_folder)
|
||||
except PermissionError:
|
||||
pass
|
||||
|
||||
def test_docker_controller(self):
|
||||
"""test that deployment requires update"""
|
||||
controller = DockerController(self.outpost, self.service_connection)
|
||||
controller.up()
|
||||
controller.down()
|
||||
|
||||
def test_docker_static(self):
|
||||
"""test that deployment requires update"""
|
||||
controller = DockerController(self.outpost, self.service_connection)
|
||||
manifest = controller.get_static_deployment()
|
||||
compose = yaml.load(manifest, Loader=yaml.SafeLoader)
|
||||
self.assertEqual(compose["version"], "3.5")
|
||||
self.assertEqual(
|
||||
compose["services"]["authentik_proxy"]["image"],
|
||||
f"beryju/authentik-proxy:{__version__}",
|
||||
)
|
|
@ -9,7 +9,7 @@ from authentik.providers.proxy.controllers.kubernetes import ProxyKubernetesCont
|
|||
from authentik.providers.proxy.models import ProxyProvider
|
||||
|
||||
|
||||
class TestControllers(TestCase):
|
||||
class TestProxyKubernetes(TestCase):
|
||||
"""Test Controllers"""
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -4,3 +4,8 @@ node_modules
|
|||
dist
|
||||
# don't lint nyc coverage output
|
||||
coverage
|
||||
# don't lint generated code
|
||||
src/api/apis
|
||||
src/api/models
|
||||
src/api/index.ts
|
||||
src/api/runtime.ts
|
||||
|
|
|
@ -10,6 +10,25 @@ variables:
|
|||
branchName: ${{ replace(variables['Build.SourceBranchName'], 'refs/heads/', '') }}
|
||||
|
||||
stages:
|
||||
- stage: generate
|
||||
jobs:
|
||||
- job: swagger_generate
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '12.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/src/api --additional-properties=typescriptThreePlus=true
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: 'web/src/api/'
|
||||
artifact: 'ts_swagger_client'
|
||||
publishLocation: 'pipeline'
|
||||
- stage: lint
|
||||
jobs:
|
||||
- job: eslint
|
||||
|
@ -20,6 +39,11 @@ stages:
|
|||
inputs:
|
||||
versionSpec: '12.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'ts_swagger_client'
|
||||
path: "web/src/api/"
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'install'
|
||||
|
@ -37,6 +61,11 @@ stages:
|
|||
inputs:
|
||||
versionSpec: '12.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'ts_swagger_client'
|
||||
path: "web/src/api/"
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'install'
|
||||
|
@ -56,6 +85,11 @@ stages:
|
|||
inputs:
|
||||
versionSpec: '12.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'ts_swagger_client'
|
||||
path: "web/src/api/"
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'install'
|
||||
|
@ -71,16 +105,21 @@ stages:
|
|||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
python ./scripts/az_do_set_branch.py
|
||||
- task: Docker@2
|
||||
inputs:
|
||||
containerRegistry: 'beryjuorg-harbor'
|
||||
repository: 'authentik/static'
|
||||
command: 'buildAndPush'
|
||||
Dockerfile: 'web/Dockerfile'
|
||||
tags: "gh-$(branchName)"
|
||||
buildContext: 'web/'
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'ts_swagger_client'
|
||||
path: "web/src/api/"
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
python ./scripts/az_do_set_branch.py
|
||||
- task: Docker@2
|
||||
inputs:
|
||||
containerRegistry: 'beryjuorg-harbor'
|
||||
repository: 'authentik/static'
|
||||
command: 'buildAndPush'
|
||||
Dockerfile: 'web/Dockerfile'
|
||||
tags: "gh-$(branchName)"
|
||||
buildContext: 'web/'
|
||||
|
|
318
web/package-lock.json
generated
318
web/package-lock.json
generated
|
@ -103,9 +103,9 @@
|
|||
}
|
||||
},
|
||||
"@patternfly/patternfly": {
|
||||
"version": "4.87.3",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.87.3.tgz",
|
||||
"integrity": "sha512-hDNMPa7B1zKD8LWFZO4SS5hC/N+yvuci2sAn8HJd+EIbAvbMAUkRsyZ0/XO3BG3RVtpSlgq7q8x1pAHC/FTFuA=="
|
||||
"version": "4.90.5",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.90.5.tgz",
|
||||
"integrity": "sha512-Fe0C8UkzSjtacQ+fHXlFB/LHzrv/c2K4z479C6dboOgkGQE1FyB0wt1NBfxij0D++rhOy04OOYdE+Tr0JSlZKw=="
|
||||
},
|
||||
"@rollup/plugin-typescript": {
|
||||
"version": "8.2.0",
|
||||
|
@ -143,27 +143,27 @@
|
|||
}
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.2.1.tgz",
|
||||
"integrity": "sha512-OAikFZ9EimD3noxMp8tA6Cf6qJcQ2U8k5QSgTPwdx+09nZOGJzbRFteK7WWmrS93ZJdzN61lpSQbg5v+bmmfbQ==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.2.2.tgz",
|
||||
"integrity": "sha512-K5UGyEePtVPZIFMoiRafhd4Ov0M1kdozVsVKIPZrOpJyjQdPNX+fYDNL/h0nVmgOlE2S/uu4fl4mEfe/6aLShw==",
|
||||
"requires": {
|
||||
"@sentry/core": "6.2.1",
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/utils": "6.2.1",
|
||||
"@sentry/core": "6.2.2",
|
||||
"@sentry/types": "6.2.2",
|
||||
"@sentry/utils": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/types": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.2.1.tgz",
|
||||
"integrity": "sha512-h0OV1QT+fv5ojfK5/+iEXClu33HirmvbjcQC2jf05IHj9yXIOWy6EB10S8nBjuLiiFqQiAQYj3FN9Ip4eN8NJA=="
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.2.2.tgz",
|
||||
"integrity": "sha512-Y/1sRtw3a5JU4YdNBig8lLSVJ1UdYtuge+QP1CVLcLSAbq07Ok1bvF+Z+BlNcnHqle2Fl8aKuryG5Yu86enOyQ=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.2.1.tgz",
|
||||
"integrity": "sha512-6kQgM/yBPdXu+3qbJnI6HBcWztN9QfiMkH++ZiKk4ERhg9d2LYWlze478uTU5Fyo/JQYcp+McpjtjpR9QIrr0g==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.2.2.tgz",
|
||||
"integrity": "sha512-qaee6X6VDNZ8HeO83/veaKw0KuhDE7j1R+Yryme3PywFzsoTzutDrEQjb7gvcHAhBaAYX8IHUBHgxcFI9BxI+w==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/types": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
|
@ -175,48 +175,48 @@
|
|||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.2.1.tgz",
|
||||
"integrity": "sha512-jPqQEtafxxDtLONhCbTHh/Uq8mZRhsfbwJTSVYfPVEe/ELfFZLQK7tP6rOh7zEWKbTkE0mE6XcaoH3ZRAhgrqg==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.2.2.tgz",
|
||||
"integrity": "sha512-qqWbvvXtymfXh7N5eEvk97MCnMURuyFIgqWdVD4MQM6yIfDCy36CyGfuQ3ViHTLZGdIfEOhLL9/f4kzf1RzqBA==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.2.1",
|
||||
"@sentry/minimal": "6.2.1",
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/utils": "6.2.1",
|
||||
"@sentry/hub": "6.2.2",
|
||||
"@sentry/minimal": "6.2.2",
|
||||
"@sentry/types": "6.2.2",
|
||||
"@sentry/utils": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/hub": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.2.1.tgz",
|
||||
"integrity": "sha512-pG7wCQeRpzeP6t0bT4T0X029R19dbDS3/qswF8BL6bg0AI3afjfjBAZm/fqn1Uwe/uBoMHVVdbxgJDZeQ5d4rQ==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.2.2.tgz",
|
||||
"integrity": "sha512-VR6uQGRYt6RP633FHShlSLj0LUKGVrlTeSlwCoooWM5FR9lmi6akAaweuxpG78/kZvXrAWpjX6/nuYwHKGwzGA==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/utils": "6.2.1",
|
||||
"@sentry/types": "6.2.2",
|
||||
"@sentry/utils": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/minimal": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.2.1.tgz",
|
||||
"integrity": "sha512-wuSXB4Ayxv9rBEQ4pm7fnG4UU2ZPtPnnChoEfd4/mw1UthXSvmPFEn6O4pdo2G8fTkl8eqm6wT/Q7uIXMEmw+A==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.2.2.tgz",
|
||||
"integrity": "sha512-l0IgoGQgg1lTd4qDU8bQn25sbZBg8PwIHfuTLbGMlRr1flDXHOM1UXajWK/UKbAPelnU7M2JBSVzgl7PwjprzA==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.2.1",
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/hub": "6.2.2",
|
||||
"@sentry/types": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.2.1.tgz",
|
||||
"integrity": "sha512-h0OV1QT+fv5ojfK5/+iEXClu33HirmvbjcQC2jf05IHj9yXIOWy6EB10S8nBjuLiiFqQiAQYj3FN9Ip4eN8NJA=="
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.2.2.tgz",
|
||||
"integrity": "sha512-Y/1sRtw3a5JU4YdNBig8lLSVJ1UdYtuge+QP1CVLcLSAbq07Ok1bvF+Z+BlNcnHqle2Fl8aKuryG5Yu86enOyQ=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.2.1.tgz",
|
||||
"integrity": "sha512-6kQgM/yBPdXu+3qbJnI6HBcWztN9QfiMkH++ZiKk4ERhg9d2LYWlze478uTU5Fyo/JQYcp+McpjtjpR9QIrr0g==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.2.2.tgz",
|
||||
"integrity": "sha512-qaee6X6VDNZ8HeO83/veaKw0KuhDE7j1R+Yryme3PywFzsoTzutDrEQjb7gvcHAhBaAYX8IHUBHgxcFI9BxI+w==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/types": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
|
@ -228,12 +228,12 @@
|
|||
}
|
||||
},
|
||||
"@sentry/hub": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.2.1.tgz",
|
||||
"integrity": "sha512-pG7wCQeRpzeP6t0bT4T0X029R19dbDS3/qswF8BL6bg0AI3afjfjBAZm/fqn1Uwe/uBoMHVVdbxgJDZeQ5d4rQ==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.2.2.tgz",
|
||||
"integrity": "sha512-VR6uQGRYt6RP633FHShlSLj0LUKGVrlTeSlwCoooWM5FR9lmi6akAaweuxpG78/kZvXrAWpjX6/nuYwHKGwzGA==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/utils": "6.2.1",
|
||||
"@sentry/types": "6.2.2",
|
||||
"@sentry/utils": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -245,12 +245,12 @@
|
|||
}
|
||||
},
|
||||
"@sentry/minimal": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.2.1.tgz",
|
||||
"integrity": "sha512-wuSXB4Ayxv9rBEQ4pm7fnG4UU2ZPtPnnChoEfd4/mw1UthXSvmPFEn6O4pdo2G8fTkl8eqm6wT/Q7uIXMEmw+A==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.2.2.tgz",
|
||||
"integrity": "sha512-l0IgoGQgg1lTd4qDU8bQn25sbZBg8PwIHfuTLbGMlRr1flDXHOM1UXajWK/UKbAPelnU7M2JBSVzgl7PwjprzA==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.2.1",
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/hub": "6.2.2",
|
||||
"@sentry/types": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -262,14 +262,14 @@
|
|||
}
|
||||
},
|
||||
"@sentry/tracing": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.2.1.tgz",
|
||||
"integrity": "sha512-bvStY1SnL08wkSeVK3j9K5rivQQJdKFCPR2VYRFOCaUoleZ6ChPUnBvxQ/E2LXc0hk/y/wo1q4r5B0dfCCY+bQ==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.2.2.tgz",
|
||||
"integrity": "sha512-mAkPoqtofNfka/u9rOVVDQPaEoTmr0AQh654g9ZqsaqsOJLKjB4FDLVNubWs90fjeKqHiYkI3ZHPak2TzHBPkw==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.2.1",
|
||||
"@sentry/minimal": "6.2.1",
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/utils": "6.2.1",
|
||||
"@sentry/hub": "6.2.2",
|
||||
"@sentry/minimal": "6.2.2",
|
||||
"@sentry/types": "6.2.2",
|
||||
"@sentry/utils": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -281,16 +281,16 @@
|
|||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.2.1.tgz",
|
||||
"integrity": "sha512-h0OV1QT+fv5ojfK5/+iEXClu33HirmvbjcQC2jf05IHj9yXIOWy6EB10S8nBjuLiiFqQiAQYj3FN9Ip4eN8NJA=="
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.2.2.tgz",
|
||||
"integrity": "sha512-Y/1sRtw3a5JU4YdNBig8lLSVJ1UdYtuge+QP1CVLcLSAbq07Ok1bvF+Z+BlNcnHqle2Fl8aKuryG5Yu86enOyQ=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.2.1.tgz",
|
||||
"integrity": "sha512-6kQgM/yBPdXu+3qbJnI6HBcWztN9QfiMkH++ZiKk4ERhg9d2LYWlze478uTU5Fyo/JQYcp+McpjtjpR9QIrr0g==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.2.2.tgz",
|
||||
"integrity": "sha512-qaee6X6VDNZ8HeO83/veaKw0KuhDE7j1R+Yryme3PywFzsoTzutDrEQjb7gvcHAhBaAYX8IHUBHgxcFI9BxI+w==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.2.1",
|
||||
"@sentry/types": "6.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -310,12 +310,13 @@
|
|||
}
|
||||
},
|
||||
"@types/clean-css": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/clean-css/-/clean-css-4.2.2.tgz",
|
||||
"integrity": "sha512-xiTJn3bmDh1lA8c6iVJs4ZhHw+pcmxXlJQXOB6G1oULaak8rmarIeFKI4aTJ7849dEhaO612wgIualZfbxTJwA==",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/clean-css/-/clean-css-4.2.3.tgz",
|
||||
"integrity": "sha512-ET0ldU/vpXecy5vO8JRIhtJWSrk1vzXdJcp3Bjf8bARZynl6vfkhEKY/A7njfNIRlmyTGuVFuqnD6I3tOGdXpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
"@types/node": "*",
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"@types/codemirror": {
|
||||
|
@ -404,22 +405,22 @@
|
|||
}
|
||||
},
|
||||
"@types/uglify-js": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.0.tgz",
|
||||
"integrity": "sha512-I0Yd8TUELTbgRHq2K65j8rnDPAzAP+DiaF/syLem7yXwYLsHZhPd+AM2iXsWmf9P2F2NlFCgl5erZPQx9IbM9Q==",
|
||||
"version": "3.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz",
|
||||
"integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.16.1.tgz",
|
||||
"integrity": "sha512-SK777klBdlkUZpZLC1mPvyOWk9yAFCWmug13eAjVQ4/Q1LATE/NbcQL1xDHkptQkZOLnPmLUA1Y54m8dqYwnoQ==",
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.17.0.tgz",
|
||||
"integrity": "sha512-/fKFDcoHg8oNan39IKFOb5WmV7oWhQe1K6CDaAVfJaNWEhmfqlA24g+u1lqU5bMH7zuNasfMId4LaYWC5ijRLw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "4.16.1",
|
||||
"@typescript-eslint/scope-manager": "4.16.1",
|
||||
"@typescript-eslint/experimental-utils": "4.17.0",
|
||||
"@typescript-eslint/scope-manager": "4.17.0",
|
||||
"debug": "^4.1.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
|
@ -429,112 +430,55 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.16.1.tgz",
|
||||
"integrity": "sha512-0Hm3LSlMYFK17jO4iY3un1Ve9x1zLNn4EM50Lia+0EV99NdbK+cn0er7HC7IvBA23mBg3P+8dUkMXy4leL33UQ==",
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.17.0.tgz",
|
||||
"integrity": "sha512-ZR2NIUbnIBj+LGqCFGQ9yk2EBQrpVVFOh9/Kd0Lm6gLpSAcCuLLe5lUCibKGCqyH9HPwYC0GIJce2O1i8VYmWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.3",
|
||||
"@typescript-eslint/scope-manager": "4.16.1",
|
||||
"@typescript-eslint/types": "4.16.1",
|
||||
"@typescript-eslint/typescript-estree": "4.16.1",
|
||||
"@typescript-eslint/scope-manager": "4.17.0",
|
||||
"@typescript-eslint/types": "4.17.0",
|
||||
"@typescript-eslint/typescript-estree": "4.17.0",
|
||||
"eslint-scope": "^5.0.0",
|
||||
"eslint-utils": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.16.1.tgz",
|
||||
"integrity": "sha512-/c0LEZcDL5y8RyI1zLcmZMvJrsR6SM1uetskFkoh3dvqDKVXPsXI+wFB/CbVw7WkEyyTKobC1mUNp/5y6gRvXg==",
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.17.0.tgz",
|
||||
"integrity": "sha512-KYdksiZQ0N1t+6qpnl6JeK9ycCFprS9xBAiIrw4gSphqONt8wydBw4BXJi3C11ywZmyHulvMaLjWsxDjUSDwAw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "4.16.1",
|
||||
"@typescript-eslint/types": "4.16.1",
|
||||
"@typescript-eslint/typescript-estree": "4.16.1",
|
||||
"@typescript-eslint/scope-manager": "4.17.0",
|
||||
"@typescript-eslint/types": "4.17.0",
|
||||
"@typescript-eslint/typescript-estree": "4.17.0",
|
||||
"debug": "^4.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.16.1.tgz",
|
||||
"integrity": "sha512-6IlZv9JaurqV0jkEg923cV49aAn8V6+1H1DRfhRcvZUrptQ+UtSKHb5kwTayzOYTJJ/RsYZdcvhOEKiBLyc0Cw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.16.1",
|
||||
"@typescript-eslint/visitor-keys": "4.16.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.16.1.tgz",
|
||||
"integrity": "sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.16.1.tgz",
|
||||
"integrity": "sha512-m8I/DKHa8YbeHt31T+UGd/l8Kwr0XCTCZL3H4HMvvLCT7HU9V7yYdinTOv1gf/zfqNeDcCgaFH2BMsS8x6NvJg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.16.1",
|
||||
"@typescript-eslint/visitor-keys": "4.16.1",
|
||||
"debug": "^4.1.1",
|
||||
"globby": "^11.0.1",
|
||||
"is-glob": "^4.0.1",
|
||||
"semver": "^7.3.2",
|
||||
"tsutils": "^3.17.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.16.1.tgz",
|
||||
"integrity": "sha512-s/aIP1XcMkEqCNcPQtl60ogUYjSM8FU2mq1O7y5cFf3Xcob1z1iXWNB6cC43Op+NGRTFgGolri6s8z/efA9i1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.16.1",
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"globby": {
|
||||
"version": "11.0.2",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz",
|
||||
"integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
"fast-glob": "^3.1.1",
|
||||
"ignore": "^5.1.4",
|
||||
"merge2": "^1.3.0",
|
||||
"slash": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.16.1.tgz",
|
||||
"integrity": "sha512-6IlZv9JaurqV0jkEg923cV49aAn8V6+1H1DRfhRcvZUrptQ+UtSKHb5kwTayzOYTJJ/RsYZdcvhOEKiBLyc0Cw==",
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.17.0.tgz",
|
||||
"integrity": "sha512-OJ+CeTliuW+UZ9qgULrnGpPQ1bhrZNFpfT/Bc0pzNeyZwMik7/ykJ0JHnQ7krHanFN9wcnPK89pwn84cRUmYjw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.16.1",
|
||||
"@typescript-eslint/visitor-keys": "4.16.1"
|
||||
"@typescript-eslint/types": "4.17.0",
|
||||
"@typescript-eslint/visitor-keys": "4.17.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.16.1.tgz",
|
||||
"integrity": "sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA==",
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.17.0.tgz",
|
||||
"integrity": "sha512-RN5z8qYpJ+kXwnLlyzZkiJwfW2AY458Bf8WqllkondQIcN2ZxQowAToGSd9BlAUZDB5Ea8I6mqL2quGYCLT+2g==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.16.1.tgz",
|
||||
"integrity": "sha512-m8I/DKHa8YbeHt31T+UGd/l8Kwr0XCTCZL3H4HMvvLCT7HU9V7yYdinTOv1gf/zfqNeDcCgaFH2BMsS8x6NvJg==",
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.17.0.tgz",
|
||||
"integrity": "sha512-lRhSFIZKUEPPWpWfwuZBH9trYIEJSI0vYsrxbvVvNyIUDoKWaklOAelsSkeh3E2VBSZiNe9BZ4E5tYBZbUczVQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.16.1",
|
||||
"@typescript-eslint/visitor-keys": "4.16.1",
|
||||
"@typescript-eslint/types": "4.17.0",
|
||||
"@typescript-eslint/visitor-keys": "4.17.0",
|
||||
"debug": "^4.1.1",
|
||||
"globby": "^11.0.1",
|
||||
"is-glob": "^4.0.1",
|
||||
|
@ -559,12 +503,12 @@
|
|||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.16.1.tgz",
|
||||
"integrity": "sha512-s/aIP1XcMkEqCNcPQtl60ogUYjSM8FU2mq1O7y5cFf3Xcob1z1iXWNB6cC43Op+NGRTFgGolri6s8z/efA9i1w==",
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.17.0.tgz",
|
||||
"integrity": "sha512-WfuMN8mm5SSqXuAr9NM+fItJ0SVVphobWYkWOwQ1odsfC014Vdxk/92t4JwS1Q6fCA/ABfCKpa3AVtpUKTNKGQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.16.1",
|
||||
"@typescript-eslint/types": "4.17.0",
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
}
|
||||
},
|
||||
|
@ -2280,16 +2224,16 @@
|
|||
}
|
||||
},
|
||||
"minify-html-literals": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/minify-html-literals/-/minify-html-literals-1.3.2.tgz",
|
||||
"integrity": "sha512-DBdi0md84vjvwmLoo9xleFV5FkhzOwfKBqcmoVFL54c9CFlSBtG9KTKEQqiwscB+acewculqys1cDnwyrYlNtg==",
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/minify-html-literals/-/minify-html-literals-1.3.5.tgz",
|
||||
"integrity": "sha512-p8T8ryePRR8FVfJZLVFmM53WY25FL0moCCTycUDuAu6rf9GMLwy0gNjXBGNin3Yun7Y+tIWd28axOf0t2EpAlQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/html-minifier": "^3.5.3",
|
||||
"clean-css": "^4.2.1",
|
||||
"html-minifier": "^4.0.0",
|
||||
"magic-string": "^0.25.0",
|
||||
"parse-literals": "^1.2.0"
|
||||
"parse-literals": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
|
@ -2489,20 +2433,12 @@
|
|||
}
|
||||
},
|
||||
"parse-literals": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-literals/-/parse-literals-1.2.0.tgz",
|
||||
"integrity": "sha512-gh4zPwvFSXx9ginX8lu9MP3OPHN3VV12PXI8IXD6oMCklFqM82pfbU9e/PKf9r7oLpbqlDSDyHYSVlxxuq3Iew==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/parse-literals/-/parse-literals-1.2.1.tgz",
|
||||
"integrity": "sha512-Ml0w104Ph2wwzuRdxrg9booVWsngXbB4bZ5T2z6WyF8b5oaNkUmBiDtahi34yUIpXD8Y13JjAK6UyIyApJ73RQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"typescript": "^2.9.2 || ^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"typescript": {
|
||||
"version": "3.9.7",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
|
||||
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
|
||||
"dev": true
|
||||
}
|
||||
"typescript": "^2.9.2 || ^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"parse5": {
|
||||
|
@ -2717,9 +2653,9 @@
|
|||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.40.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.40.0.tgz",
|
||||
"integrity": "sha512-WiOGAPbXoHu+TOz6hyYUxIksOwsY/21TRWoO593jgYt8mvYafYqQl+axaA8y1z2HFazNUUrsMSjahV2A6/2R9A==",
|
||||
"version": "2.41.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.41.1.tgz",
|
||||
"integrity": "sha512-nepLFAW5W71/MWpS2Yr7r31eS7HRfYg2RXnxb6ehqN9zY42yACxKtEfb4xq8SmNfUohAzGMcyl6jkwdLOAiUbg==",
|
||||
"requires": {
|
||||
"fsevents": "~2.3.1"
|
||||
}
|
||||
|
@ -2801,12 +2737,12 @@
|
|||
}
|
||||
},
|
||||
"rollup-plugin-minify-html-literals": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-minify-html-literals/-/rollup-plugin-minify-html-literals-1.2.5.tgz",
|
||||
"integrity": "sha512-x4FzCnbBpYdme7MQDS3+18CvYLqakAtM/JmA3hqXplwzMeZWW3l14KU7H33RhJlHH8Klgv49hGtBRLWLfjCudw==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-minify-html-literals/-/rollup-plugin-minify-html-literals-1.2.6.tgz",
|
||||
"integrity": "sha512-JRq2fjlCTiw0zu+1Sy3ClHGCxA79dWGr4HLHWSQgd060StVW9fBVksuj8Xw/suPkNSGClJf/4xNQ1MF6JeXPaw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minify-html-literals": "^1.3.2",
|
||||
"minify-html-literals": "^1.3.5",
|
||||
"rollup-pluginutils": "^2.8.2"
|
||||
}
|
||||
},
|
||||
|
@ -3383,15 +3319,15 @@
|
|||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz",
|
||||
"integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
|
||||
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.11.0.tgz",
|
||||
"integrity": "sha512-e1KQFRCpOxnrJsJVqDUCjURq+wXvIn7cK2sRAx9XL3HYLL9aezOP4Pb1+Y3/o693EPk111Yj2Q+IUXxcpHlygQ==",
|
||||
"version": "3.13.0",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.0.tgz",
|
||||
"integrity": "sha512-TWYSWa9T2pPN4DIJYbU9oAjQx+5qdV5RUDxwARg8fmJZrD/V27Zj0JngW5xg1DFz42G0uDYl2XhzF6alSzD62w==",
|
||||
"dev": true
|
||||
},
|
||||
"union-value": {
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.15.2",
|
||||
"@patternfly/patternfly": "^4.87.3",
|
||||
"@sentry/browser": "^6.2.1",
|
||||
"@sentry/tracing": "^6.2.1",
|
||||
"@patternfly/patternfly": "^4.90.5",
|
||||
"@sentry/browser": "^6.2.2",
|
||||
"@sentry/tracing": "^6.2.2",
|
||||
"@types/chart.js": "^2.9.31",
|
||||
"@types/codemirror": "0.0.108",
|
||||
"@types/grecaptcha": "^3.0.1",
|
||||
|
@ -24,7 +24,7 @@
|
|||
"flowchart.js": "^1.15.0",
|
||||
"lit-element": "^2.4.0",
|
||||
"lit-html": "^1.3.0",
|
||||
"rollup": "^2.40.0",
|
||||
"rollup": "^2.41.1",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-cssimport": "^1.0.2",
|
||||
"rollup-plugin-external-globals": "^0.6.1",
|
||||
|
@ -33,17 +33,17 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^8.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.16.1",
|
||||
"@typescript-eslint/parser": "^4.16.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.17.0",
|
||||
"@typescript-eslint/parser": "^4.17.0",
|
||||
"eslint": "^7.21.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-lit": "^1.3.0",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-minify-html-literals": "^1.2.5",
|
||||
"rollup-plugin-minify-html-literals": "^1.2.6",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-sourcemaps": "^0.6.3",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"ts-lit-plugin": "^1.2.1",
|
||||
"typescript": "^4.2.2"
|
||||
"typescript": "^4.2.3"
|
||||
}
|
||||
}
|
||||
|
|
4
web/src/api/.gitignore
vendored
Normal file
4
web/src/api/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
apis/**
|
||||
models/**
|
||||
index.ts
|
||||
runtime.ts
|
23
web/src/api/.openapi-generator-ignore
Normal file
23
web/src/api/.openapi-generator-ignore
Normal file
|
@ -0,0 +1,23 @@
|
|||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
167
web/src/api/.openapi-generator/FILES
Normal file
167
web/src/api/.openapi-generator/FILES
Normal file
|
@ -0,0 +1,167 @@
|
|||
apis/AdminApi.ts
|
||||
apis/CoreApi.ts
|
||||
apis/CryptoApi.ts
|
||||
apis/EventsApi.ts
|
||||
apis/FlowsApi.ts
|
||||
apis/OutpostsApi.ts
|
||||
apis/PoliciesApi.ts
|
||||
apis/PropertymappingsApi.ts
|
||||
apis/ProvidersApi.ts
|
||||
apis/RootApi.ts
|
||||
apis/SourcesApi.ts
|
||||
apis/StagesApi.ts
|
||||
apis/index.ts
|
||||
index.ts
|
||||
models/Application.ts
|
||||
models/AuthenticateWebAuthnStage.ts
|
||||
models/AuthenticatorStaticStage.ts
|
||||
models/AuthenticatorTOTPStage.ts
|
||||
models/AuthenticatorValidateStage.ts
|
||||
models/Cache.ts
|
||||
models/CaptchaStage.ts
|
||||
models/CertificateData.ts
|
||||
models/CertificateKeyPair.ts
|
||||
models/Challenge.ts
|
||||
models/Config.ts
|
||||
models/ConsentStage.ts
|
||||
models/Coordinate.ts
|
||||
models/DenyStage.ts
|
||||
models/DockerServiceConnection.ts
|
||||
models/DummyPolicy.ts
|
||||
models/DummyStage.ts
|
||||
models/EmailStage.ts
|
||||
models/ErrorDetail.ts
|
||||
models/Event.ts
|
||||
models/EventMatcherPolicy.ts
|
||||
models/EventTopPerUser.ts
|
||||
models/ExpressionPolicy.ts
|
||||
models/Flow.ts
|
||||
models/FlowDiagram.ts
|
||||
models/FlowStageBinding.ts
|
||||
models/Group.ts
|
||||
models/GroupMembershipPolicy.ts
|
||||
models/HaveIBeenPwendPolicy.ts
|
||||
models/IPReputation.ts
|
||||
models/IdentificationStage.ts
|
||||
models/InlineResponse200.ts
|
||||
models/InlineResponse2001.ts
|
||||
models/InlineResponse20010.ts
|
||||
models/InlineResponse20011.ts
|
||||
models/InlineResponse20012.ts
|
||||
models/InlineResponse20013.ts
|
||||
models/InlineResponse20014.ts
|
||||
models/InlineResponse20015.ts
|
||||
models/InlineResponse20016.ts
|
||||
models/InlineResponse20017.ts
|
||||
models/InlineResponse20018.ts
|
||||
models/InlineResponse20019.ts
|
||||
models/InlineResponse2002.ts
|
||||
models/InlineResponse20020.ts
|
||||
models/InlineResponse20021.ts
|
||||
models/InlineResponse20022.ts
|
||||
models/InlineResponse20023.ts
|
||||
models/InlineResponse20024.ts
|
||||
models/InlineResponse20025.ts
|
||||
models/InlineResponse20026.ts
|
||||
models/InlineResponse20027.ts
|
||||
models/InlineResponse20028.ts
|
||||
models/InlineResponse20029.ts
|
||||
models/InlineResponse2003.ts
|
||||
models/InlineResponse20030.ts
|
||||
models/InlineResponse20031.ts
|
||||
models/InlineResponse20032.ts
|
||||
models/InlineResponse20033.ts
|
||||
models/InlineResponse20034.ts
|
||||
models/InlineResponse20035.ts
|
||||
models/InlineResponse20036.ts
|
||||
models/InlineResponse20037.ts
|
||||
models/InlineResponse20038.ts
|
||||
models/InlineResponse20039.ts
|
||||
models/InlineResponse2004.ts
|
||||
models/InlineResponse20040.ts
|
||||
models/InlineResponse20041.ts
|
||||
models/InlineResponse20042.ts
|
||||
models/InlineResponse20043.ts
|
||||
models/InlineResponse20044.ts
|
||||
models/InlineResponse20045.ts
|
||||
models/InlineResponse20046.ts
|
||||
models/InlineResponse20047.ts
|
||||
models/InlineResponse20048.ts
|
||||
models/InlineResponse20049.ts
|
||||
models/InlineResponse2005.ts
|
||||
models/InlineResponse20050.ts
|
||||
models/InlineResponse20051.ts
|
||||
models/InlineResponse20052.ts
|
||||
models/InlineResponse20053.ts
|
||||
models/InlineResponse20054.ts
|
||||
models/InlineResponse20055.ts
|
||||
models/InlineResponse20056.ts
|
||||
models/InlineResponse20057.ts
|
||||
models/InlineResponse20058.ts
|
||||
models/InlineResponse20059.ts
|
||||
models/InlineResponse2006.ts
|
||||
models/InlineResponse20060.ts
|
||||
models/InlineResponse2007.ts
|
||||
models/InlineResponse2008.ts
|
||||
models/InlineResponse2009.ts
|
||||
models/InlineResponse200Pagination.ts
|
||||
models/Invitation.ts
|
||||
models/InvitationStage.ts
|
||||
models/KubernetesServiceConnection.ts
|
||||
models/LDAPPropertyMapping.ts
|
||||
models/LDAPSource.ts
|
||||
models/LDAPSourceSyncStatus.ts
|
||||
models/LoginMetrics.ts
|
||||
models/Notification.ts
|
||||
models/NotificationRule.ts
|
||||
models/NotificationRuleGroup.ts
|
||||
models/NotificationRuleGroupParent.ts
|
||||
models/NotificationRuleTransports.ts
|
||||
models/NotificationTransport.ts
|
||||
models/NotificationTransportTest.ts
|
||||
models/OAuth2Provider.ts
|
||||
models/OAuth2ProviderSetupURLs.ts
|
||||
models/OAuthSource.ts
|
||||
models/OpenIDConnectConfiguration.ts
|
||||
models/Outpost.ts
|
||||
models/OutpostHealth.ts
|
||||
models/PasswordExpiryPolicy.ts
|
||||
models/PasswordPolicy.ts
|
||||
models/PasswordStage.ts
|
||||
models/Policy.ts
|
||||
models/PolicyBinding.ts
|
||||
models/PolicyBindingPolicy.ts
|
||||
models/PolicyBindingUser.ts
|
||||
models/PolicyBindingUserAkGroups.ts
|
||||
models/PolicyBindingUserGroups.ts
|
||||
models/PolicyBindingUserSources.ts
|
||||
models/PolicyBindingUserUserPermissions.ts
|
||||
models/Prompt.ts
|
||||
models/PromptStage.ts
|
||||
models/PropertyMapping.ts
|
||||
models/Provider.ts
|
||||
models/ProxyOutpostConfig.ts
|
||||
models/ProxyProvider.ts
|
||||
models/ReputationPolicy.ts
|
||||
models/SAMLMetadata.ts
|
||||
models/SAMLPropertyMapping.ts
|
||||
models/SAMLProvider.ts
|
||||
models/SAMLSource.ts
|
||||
models/ScopeMapping.ts
|
||||
models/ServiceConnection.ts
|
||||
models/ServiceConnectionState.ts
|
||||
models/Source.ts
|
||||
models/Stage.ts
|
||||
models/Task.ts
|
||||
models/Token.ts
|
||||
models/TokenView.ts
|
||||
models/TypeCreate.ts
|
||||
models/User.ts
|
||||
models/UserDeleteStage.ts
|
||||
models/UserLoginStage.ts
|
||||
models/UserLogoutStage.ts
|
||||
models/UserReputation.ts
|
||||
models/UserWriteStage.ts
|
||||
models/Version.ts
|
||||
models/index.ts
|
||||
runtime.ts
|
1
web/src/api/.openapi-generator/VERSION
Normal file
1
web/src/api/.openapi-generator/VERSION
Normal file
|
@ -0,0 +1 @@
|
|||
5.1.0-SNAPSHOT
|
|
@ -1,32 +0,0 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { Provider } from "./Providers";
|
||||
|
||||
export class Application {
|
||||
pk: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
provider?: Provider;
|
||||
|
||||
launch_url: string;
|
||||
meta_launch_url: string;
|
||||
meta_icon: string;
|
||||
meta_description: string;
|
||||
meta_publisher: string;
|
||||
policies: string[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(slug: string): Promise<Application> {
|
||||
return DefaultClient.fetch<Application>(["core", "applications", slug]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Application>> {
|
||||
return DefaultClient.fetch<AKResponse<Application>>(["core", "applications"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/applications/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
|
||||
export class CertificateKeyPair {
|
||||
pk: string;
|
||||
name: string;
|
||||
fingerprint: string;
|
||||
cert_expiry: number;
|
||||
cert_subject: string;
|
||||
private_key_available: boolean;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(slug: string): Promise<CertificateKeyPair> {
|
||||
return DefaultClient.fetch<CertificateKeyPair>(["crypto", "certificatekeypairs", slug]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<CertificateKeyPair>> {
|
||||
return DefaultClient.fetch<AKResponse<CertificateKeyPair>>(["crypto", "certificatekeypairs"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/crypto/certificates/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,3 @@
|
|||
import { gettext } from "django";
|
||||
import { showMessage } from "../elements/messages/MessageContainer";
|
||||
import { getCookie } from "../utils";
|
||||
import { NotFoundError, RequestError } from "./Error";
|
||||
|
||||
export const VERSION = "v2beta";
|
||||
|
||||
export interface QueryArguments {
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
|
@ -13,104 +6,27 @@ export interface QueryArguments {
|
|||
|
||||
export interface BaseInheritanceModel {
|
||||
|
||||
object_type: string;
|
||||
objectType: string;
|
||||
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
verboseName: string;
|
||||
verboseNamePlural: string;
|
||||
|
||||
}
|
||||
|
||||
export class Client {
|
||||
makeUrl(url: string[], query?: QueryArguments): string {
|
||||
let builtUrl = `/api/${VERSION}/${url.join("/")}/`;
|
||||
if (query) {
|
||||
const queryString = Object.keys(query)
|
||||
.filter((k) => query[k] !== null)
|
||||
// we default to a string in query[k] as we've filtered out the null above
|
||||
// this is just for type-hinting
|
||||
.map((k) => encodeURIComponent(k) + "=" + encodeURIComponent(query[k] || ""))
|
||||
.join("&");
|
||||
builtUrl += `?${queryString}`;
|
||||
}
|
||||
return builtUrl;
|
||||
}
|
||||
|
||||
fetch<T>(url: string[], query?: QueryArguments): Promise<T> {
|
||||
const finalUrl = this.makeUrl(url, query);
|
||||
return fetch(finalUrl)
|
||||
.then((r) => {
|
||||
if (r.status > 300) {
|
||||
switch (r.status) {
|
||||
case 404:
|
||||
throw new NotFoundError(`URL ${finalUrl} not found`);
|
||||
default:
|
||||
throw new RequestError(r.statusText);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
})
|
||||
.catch((e) => {
|
||||
showMessage({
|
||||
level_tag: "error",
|
||||
message: gettext(`Unexpected error while fetching: ${e.toString()}`),
|
||||
});
|
||||
return e;
|
||||
})
|
||||
.then((r) => r.json())
|
||||
.then((r) => <T>r);
|
||||
}
|
||||
|
||||
private writeRequest<T>(url: string[], body: T, method: string, query?: QueryArguments): Promise<T> {
|
||||
const finalUrl = this.makeUrl(url, query);
|
||||
const csrftoken = getCookie("authentik_csrf");
|
||||
const request = new Request(finalUrl, {
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRFToken": csrftoken,
|
||||
},
|
||||
});
|
||||
return fetch(request, {
|
||||
method: method,
|
||||
mode: "same-origin",
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
.then((r) => {
|
||||
if (r.status > 300) {
|
||||
switch (r.status) {
|
||||
case 404:
|
||||
throw new NotFoundError(`URL ${finalUrl} not found`);
|
||||
default:
|
||||
throw new RequestError(r.statusText);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
})
|
||||
.then((r) => r.json())
|
||||
.then((r) => <T>r);
|
||||
}
|
||||
|
||||
update<T>(url: string[], body: T, query?: QueryArguments): Promise<T> {
|
||||
return this.writeRequest(url, body, "PATCH", query);
|
||||
}
|
||||
}
|
||||
|
||||
export const DefaultClient = new Client();
|
||||
|
||||
export interface PBPagination {
|
||||
export interface AKPagination {
|
||||
next?: number;
|
||||
previous?: number;
|
||||
|
||||
count: number;
|
||||
current: number;
|
||||
total_pages: number;
|
||||
totalPages: number;
|
||||
|
||||
start_index: number;
|
||||
end_index: number;
|
||||
startIndex: number;
|
||||
endIndex: number;
|
||||
}
|
||||
|
||||
export interface AKResponse<T> {
|
||||
pagination: PBPagination;
|
||||
pagination: AKPagination;
|
||||
|
||||
results: Array<T>;
|
||||
}
|
||||
|
|
|
@ -1,42 +1,39 @@
|
|||
import { DefaultClient } from "./Client";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { Integrations } from "@sentry/tracing";
|
||||
import { VERSION } from "../constants";
|
||||
import { SentryIgnoredError } from "../common/errors";
|
||||
import { Configuration } from "./runtime";
|
||||
import { RootApi } from "./apis";
|
||||
import { Config } from ".";
|
||||
import { getCookie } from "../utils";
|
||||
|
||||
export class Config {
|
||||
branding_logo: string;
|
||||
branding_title: string;
|
||||
|
||||
error_reporting_enabled: boolean;
|
||||
error_reporting_environment: string;
|
||||
error_reporting_send_pii: boolean;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
export const DEFAULT_CONFIG = new Configuration({
|
||||
basePath: "/api/v2beta",
|
||||
headers: {
|
||||
"X-CSRFToken": getCookie("authentik_csrf"),
|
||||
}
|
||||
});
|
||||
|
||||
static get(): Promise<Config> {
|
||||
return DefaultClient.fetch<Config>(["root", "config"]).then((config) => {
|
||||
if (config.error_reporting_enabled) {
|
||||
Sentry.init({
|
||||
dsn: "https://a579bb09306d4f8b8d8847c052d3a1d3@sentry.beryju.org/8",
|
||||
release: `authentik@${VERSION}`,
|
||||
integrations: [
|
||||
new Integrations.BrowserTracing(),
|
||||
],
|
||||
tracesSampleRate: 0.6,
|
||||
environment: config.error_reporting_environment,
|
||||
beforeSend(event: Sentry.Event, hint: Sentry.EventHint) {
|
||||
if (hint.originalException instanceof SentryIgnoredError) {
|
||||
return null;
|
||||
}
|
||||
return event;
|
||||
},
|
||||
});
|
||||
console.debug("authentik/config: Sentry enabled.");
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}
|
||||
export function configureSentry(): Promise<Config> {
|
||||
return new RootApi(DEFAULT_CONFIG).rootConfigList().then((config) => {
|
||||
if (config.errorReportingEnabled) {
|
||||
Sentry.init({
|
||||
dsn: "https://a579bb09306d4f8b8d8847c052d3a1d3@sentry.beryju.org/8",
|
||||
release: `authentik@${VERSION}`,
|
||||
integrations: [
|
||||
new Integrations.BrowserTracing(),
|
||||
],
|
||||
tracesSampleRate: 0.6,
|
||||
environment: config.errorReportingEnvironment,
|
||||
beforeSend(event: Sentry.Event, hint: Sentry.EventHint) {
|
||||
if (hint.originalException instanceof SentryIgnoredError) {
|
||||
return null;
|
||||
}
|
||||
return event;
|
||||
},
|
||||
});
|
||||
console.debug("authentik/config: Sentry enabled.");
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { DefaultClient, QueryArguments, AKResponse } from "./Client";
|
||||
import { Event } from "./Events";
|
||||
|
||||
export class Notification {
|
||||
pk: string;
|
||||
severity: string;
|
||||
body: string;
|
||||
created: string;
|
||||
event?: Event;
|
||||
seen: boolean;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Notification> {
|
||||
return DefaultClient.fetch<Notification>(["events", "notifications", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Notification>> {
|
||||
return DefaultClient.fetch<AKResponse<Notification>>(["events", "notifications"], filter);
|
||||
}
|
||||
|
||||
static markSeen(pk: string): Promise<{seen: boolean}> {
|
||||
return DefaultClient.update(["events", "notifications", pk], {
|
||||
"seen": true
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import { DefaultClient, QueryArguments, AKResponse } from "./Client";
|
||||
import { Group } from "./Groups";
|
||||
|
||||
export class Rule {
|
||||
pk: string;
|
||||
name: string;
|
||||
transports: string[];
|
||||
severity: string;
|
||||
group?: Group;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Rule> {
|
||||
return DefaultClient.fetch<Rule>(["events", "rules", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Rule>> {
|
||||
return DefaultClient.fetch<AKResponse<Rule>>(["events", "rules"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/events/rules/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
import { DefaultClient, QueryArguments, AKResponse } from "./Client";
|
||||
|
||||
export class Transport {
|
||||
pk: string;
|
||||
name: string;
|
||||
mode: string;
|
||||
mode_verbose: string;
|
||||
webhook_url: string;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Transport> {
|
||||
return DefaultClient.fetch<Transport>(["events", "transports", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Transport>> {
|
||||
return DefaultClient.fetch<AKResponse<Transport>>(["events", "transports"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/events/transports/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { Event } from "./models";
|
||||
|
||||
export interface EventUser {
|
||||
pk: number;
|
||||
|
@ -11,37 +11,7 @@ export interface EventContext {
|
|||
[key: string]: EventContext | string | number | string[];
|
||||
}
|
||||
|
||||
export class Event {
|
||||
pk: string;
|
||||
export interface EventWithContext extends Event {
|
||||
user: EventUser;
|
||||
action: string;
|
||||
app: string;
|
||||
context: EventContext;
|
||||
client_ip: string;
|
||||
created: string;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Event> {
|
||||
return DefaultClient.fetch<Event>(["events", "events", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Event>> {
|
||||
return DefaultClient.fetch<AKResponse<Event>>(["events", "events"], filter);
|
||||
}
|
||||
|
||||
// events/events/top_per_user/?filter_action=authorize_application
|
||||
static topForUser(action: string): Promise<TopNEvent[]> {
|
||||
return DefaultClient.fetch<TopNEvent[]>(["events", "events", "top_per_user"], {
|
||||
"filter_action": action,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface TopNEvent {
|
||||
application: { [key: string]: string};
|
||||
counted_events: number;
|
||||
unique_users: number;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments, BaseInheritanceModel } from "./Client";
|
||||
import { TypeCreate } from "./Providers";
|
||||
|
||||
export enum ChallengeTypes {
|
||||
native = "native",
|
||||
response = "response",
|
||||
shell = "shell",
|
||||
redirect = "redirect",
|
||||
}
|
||||
import { ChallengeTypeEnum } from "./models";
|
||||
|
||||
export interface Error {
|
||||
code: string;
|
||||
|
@ -18,11 +10,12 @@ export interface ErrorDict {
|
|||
}
|
||||
|
||||
export interface Challenge {
|
||||
type: ChallengeTypes;
|
||||
type: ChallengeTypeEnum;
|
||||
component?: string;
|
||||
title?: string;
|
||||
response_errors?: ErrorDict;
|
||||
}
|
||||
|
||||
export interface WithUserInfoChallenge extends Challenge {
|
||||
pending_user: string;
|
||||
pending_user_avatar: string;
|
||||
|
@ -31,6 +24,7 @@ export interface WithUserInfoChallenge extends Challenge {
|
|||
export interface ShellChallenge extends Challenge {
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface RedirectChallenge extends Challenge {
|
||||
to: string;
|
||||
}
|
||||
|
@ -44,104 +38,3 @@ export enum FlowDesignation {
|
|||
Recovery = "recovery",
|
||||
StageConfiguration = "stage_configuration",
|
||||
}
|
||||
|
||||
export class Flow {
|
||||
pk: string;
|
||||
policybindingmodel_ptr_id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
title: string;
|
||||
designation: FlowDesignation;
|
||||
background: string;
|
||||
stages: string[];
|
||||
policies: string[];
|
||||
cache_count: number;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(slug: string): Promise<Flow> {
|
||||
return DefaultClient.fetch<Flow>(["flows", "instances", slug]);
|
||||
}
|
||||
|
||||
static diagram(slug: string): Promise<{ diagram: string }> {
|
||||
return DefaultClient.fetch<{ diagram: string }>(["flows", "instances", slug, "diagram"]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Flow>> {
|
||||
return DefaultClient.fetch<AKResponse<Flow>>(["flows", "instances"], filter);
|
||||
}
|
||||
|
||||
static cached(): Promise<number> {
|
||||
return DefaultClient.fetch<{ count: number }>(["flows", "instances", "cached"]).then(r => {
|
||||
return r.count;
|
||||
});
|
||||
}
|
||||
|
||||
static executor(slug: string): Promise<Challenge> {
|
||||
return DefaultClient.fetch(["flows", "executor", slug]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/flows/${rest}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class Stage implements BaseInheritanceModel {
|
||||
pk: string;
|
||||
name: string;
|
||||
object_type: string;
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
flow_set: Flow[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(slug: string): Promise<Stage> {
|
||||
return DefaultClient.fetch<Stage>(["stages", "all", slug]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Stage>> {
|
||||
return DefaultClient.fetch<AKResponse<Stage>>(["stages", "all"], filter);
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["stages", "all", "types"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/stages/${rest}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class FlowStageBinding {
|
||||
|
||||
pk: string;
|
||||
policybindingmodel_ptr_id: string;
|
||||
target: string;
|
||||
stage: string;
|
||||
stage_obj: Stage;
|
||||
evaluate_on_plan: boolean;
|
||||
re_evaluate_policies: boolean;
|
||||
order: number;
|
||||
policies: string[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(slug: string): Promise<FlowStageBinding> {
|
||||
return DefaultClient.fetch<FlowStageBinding>(["flows", "bindings", slug]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<FlowStageBinding>> {
|
||||
return DefaultClient.fetch<AKResponse<FlowStageBinding>>(["flows", "bindings"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/stages/bindings/${rest}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import { DefaultClient, QueryArguments, AKResponse } from "./Client";
|
||||
import { EventContext } from "./Events";
|
||||
|
||||
export class Group {
|
||||
|
||||
pk: string;
|
||||
name: string;
|
||||
is_superuser: boolean;
|
||||
attributes: EventContext;
|
||||
parent?: Group;
|
||||
users: number[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Group> {
|
||||
return DefaultClient.fetch<Group>(["core", "groups", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Group>> {
|
||||
return DefaultClient.fetch<AKResponse<Group>>(["core", "groups"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/groups/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import { DefaultClient, QueryArguments, AKResponse } from "./Client";
|
||||
import { EventContext } from "./Events";
|
||||
import { User } from "./Users";
|
||||
|
||||
export class Invitation {
|
||||
|
||||
pk: string;
|
||||
expires: number;
|
||||
fixed_date: EventContext;
|
||||
created_by: User;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Invitation> {
|
||||
return DefaultClient.fetch<Invitation>(["stages", "invitation", "invitations", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Invitation>> {
|
||||
return DefaultClient.fetch<AKResponse<Invitation>>(["stages", "invitation", "invitations"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/stages/invitations/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { Provider, TypeCreate } from "./Providers";
|
||||
|
||||
export interface OutpostHealth {
|
||||
last_seen: number;
|
||||
version: string;
|
||||
version_should: string;
|
||||
version_outdated: boolean;
|
||||
}
|
||||
|
||||
export class Outpost {
|
||||
|
||||
pk: string;
|
||||
name: string;
|
||||
providers: number[];
|
||||
providers_obj: Provider[];
|
||||
service_connection?: string;
|
||||
_config: QueryArguments;
|
||||
token_identifier: string;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Outpost> {
|
||||
return DefaultClient.fetch<Outpost>(["outposts", "outposts", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Outpost>> {
|
||||
return DefaultClient.fetch<AKResponse<Outpost>>(["outposts", "outposts"], filter);
|
||||
}
|
||||
|
||||
static health(pk: string): Promise<OutpostHealth[]> {
|
||||
return DefaultClient.fetch<OutpostHealth[]>(["outposts", "outposts", pk, "health"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/outposts/${rest}`;
|
||||
}
|
||||
}
|
||||
|
||||
export interface OutpostServiceConnectionState {
|
||||
version: string;
|
||||
healthy: boolean;
|
||||
}
|
||||
|
||||
export class OutpostServiceConnection {
|
||||
pk: string;
|
||||
name: string;
|
||||
local: boolean;
|
||||
object_type: string;
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<OutpostServiceConnection> {
|
||||
return DefaultClient.fetch<OutpostServiceConnection>(["outposts", "service_connections", "all", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<OutpostServiceConnection>> {
|
||||
return DefaultClient.fetch<AKResponse<OutpostServiceConnection>>(["outposts", "service_connections", "all"], filter);
|
||||
}
|
||||
|
||||
static state(pk: string): Promise<OutpostServiceConnectionState> {
|
||||
return DefaultClient.fetch<OutpostServiceConnectionState>(["outposts", "service_connections", "all", pk, "state"]);
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["outposts", "service_connections", "all", "types"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/outpost_service_connections/${rest}`;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
import { DefaultClient, BaseInheritanceModel, AKResponse, QueryArguments } from "./Client";
|
||||
import { TypeCreate } from "./Providers";
|
||||
|
||||
export class Policy implements BaseInheritanceModel {
|
||||
pk: string;
|
||||
name: string;
|
||||
execution_logging: boolean;
|
||||
object_type: string;
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
bound_to: number;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Policy> {
|
||||
return DefaultClient.fetch<Policy>(["policies", "all", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Policy>> {
|
||||
return DefaultClient.fetch<AKResponse<Policy>>(["policies", "all"], filter);
|
||||
}
|
||||
|
||||
static cached(): Promise<number> {
|
||||
return DefaultClient.fetch<{ count: number }>(["policies", "all", "cached"]).then(r => {
|
||||
return r.count;
|
||||
});
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["policies", "all", "types"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/policies/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { Group } from "./Groups";
|
||||
import { Policy } from "./Policies";
|
||||
import { User } from "./Users";
|
||||
|
||||
export class PolicyBinding {
|
||||
pk: string;
|
||||
policy?: Policy;
|
||||
group?: Group;
|
||||
user?: User;
|
||||
target: string;
|
||||
enabled: boolean;
|
||||
order: number;
|
||||
timeout: number;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<PolicyBinding> {
|
||||
return DefaultClient.fetch<PolicyBinding>(["policies", "bindings", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<PolicyBinding>> {
|
||||
return DefaultClient.fetch<AKResponse<PolicyBinding>>(["policies", "bindings"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/policies/bindings/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
import { DefaultClient, QueryArguments, AKResponse } from "./Client";
|
||||
import { Stage } from "./Flows";
|
||||
|
||||
export class Prompt {
|
||||
|
||||
pk: string;
|
||||
field_key: string;
|
||||
label: string;
|
||||
type: string;
|
||||
required: boolean;
|
||||
placeholder: string;
|
||||
order: number;
|
||||
promptstage_set: Stage[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Prompt> {
|
||||
return DefaultClient.fetch<Prompt>(["stages", "prompt", "prompts", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Prompt>> {
|
||||
return DefaultClient.fetch<AKResponse<Prompt>>(["stages", "prompt", "prompts"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/stages_prompts/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { TypeCreate } from "./Providers";
|
||||
|
||||
export class PropertyMapping {
|
||||
pk: string;
|
||||
name: string;
|
||||
expression: string;
|
||||
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<PropertyMapping> {
|
||||
return DefaultClient.fetch<PropertyMapping>(["propertymappings", "all", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<PropertyMapping>> {
|
||||
return DefaultClient.fetch<AKResponse<PropertyMapping>>(["propertymappings", "all"], filter);
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["propertymappings", "all", "types"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/property-mappings/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
import { BaseInheritanceModel, DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
|
||||
export interface TypeCreate {
|
||||
name: string;
|
||||
description: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
export class Provider implements BaseInheritanceModel {
|
||||
pk: number;
|
||||
name: string;
|
||||
authorization_flow: string;
|
||||
object_type: string;
|
||||
|
||||
assigned_application_slug?: string;
|
||||
assigned_application_name?: string;
|
||||
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(id: number): Promise<Provider> {
|
||||
return DefaultClient.fetch<Provider>(["providers", "all", id.toString()]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Provider>> {
|
||||
return DefaultClient.fetch<AKResponse<Provider>>(["providers", "all"], filter);
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["providers", "all", "types"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/providers/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
import { BaseInheritanceModel, DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { TypeCreate } from "./Providers";
|
||||
|
||||
export class Source implements BaseInheritanceModel {
|
||||
pk: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
enabled: boolean;
|
||||
authentication_flow: string;
|
||||
enrollment_flow: string;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
object_type: string;
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
|
||||
static get(slug: string): Promise<Source> {
|
||||
return DefaultClient.fetch<Source>(["sources", "all", slug]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Source>> {
|
||||
return DefaultClient.fetch<AKResponse<Source>>(["sources", "all"], filter);
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["sources", "all", "types"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/sources/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
import { DefaultClient, QueryArguments } from "./Client";
|
||||
|
||||
export enum TaskStatus {
|
||||
SUCCESSFUL = 1,
|
||||
WARNING = 2,
|
||||
ERROR = 4,
|
||||
}
|
||||
|
||||
export class SystemTask {
|
||||
|
||||
task_name: string;
|
||||
task_description: string;
|
||||
task_finish_timestamp: number;
|
||||
status: TaskStatus;
|
||||
messages: string[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(task_name: string): Promise<SystemTask> {
|
||||
return DefaultClient.fetch<SystemTask>(["admin", "system_tasks", task_name]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<SystemTask[]> {
|
||||
return DefaultClient.fetch<SystemTask[]>(["admin", "system_tasks"], filter);
|
||||
}
|
||||
|
||||
static retry(task_name: string): string {
|
||||
return DefaultClient.makeUrl(["admin", "system_tasks", task_name, "retry"]);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
import { AKResponse, DefaultClient, QueryArguments } from "./Client";
|
||||
import { User } from "./Users";
|
||||
|
||||
export enum TokenIntent {
|
||||
INTENT_VERIFICATION = "verification",
|
||||
INTENT_API = "api",
|
||||
INTENT_RECOVERY = "recovery",
|
||||
}
|
||||
|
||||
export class Token {
|
||||
|
||||
pk: string;
|
||||
identifier: string;
|
||||
intent: TokenIntent;
|
||||
user: User;
|
||||
description: string;
|
||||
|
||||
expires: number;
|
||||
expiring: boolean;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<User> {
|
||||
return DefaultClient.fetch<User>(["core", "tokens", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Token>> {
|
||||
return DefaultClient.fetch<AKResponse<Token>>(["core", "tokens"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/tokens/${rest}`;
|
||||
}
|
||||
|
||||
static userUrl(rest: string): string {
|
||||
return `/-/user/tokens/${rest}`;
|
||||
}
|
||||
|
||||
static getKey(identifier: string): Promise<string> {
|
||||
return DefaultClient.fetch<{ key: string }>(["core", "tokens", identifier, "view_key"]).then(
|
||||
(r) => r.key
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +1,11 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { CoreApi } from "./apis";
|
||||
import { DEFAULT_CONFIG } from "./Config";
|
||||
import { User } from "./models";
|
||||
|
||||
let _globalMePromise: Promise<User>;
|
||||
|
||||
export class User {
|
||||
pk: number;
|
||||
username: string;
|
||||
name: string;
|
||||
is_superuser: boolean;
|
||||
email: boolean;
|
||||
avatar: string;
|
||||
is_active: boolean;
|
||||
last_login: number;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<User> {
|
||||
return DefaultClient.fetch<User>(["core", "users", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<User>> {
|
||||
return DefaultClient.fetch<AKResponse<User>>(["core", "users"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/users/${rest}`;
|
||||
}
|
||||
|
||||
static me(): Promise<User> {
|
||||
if (!_globalMePromise) {
|
||||
_globalMePromise = DefaultClient.fetch<User>(["core", "users", "me"]);
|
||||
}
|
||||
return _globalMePromise;
|
||||
}
|
||||
|
||||
static count(): Promise<number> {
|
||||
return DefaultClient.fetch<AKResponse<User>>(["core", "users"], {
|
||||
"page_size": 1
|
||||
}).then(r => {
|
||||
return r.pagination.count;
|
||||
});
|
||||
export function me(): Promise<User> {
|
||||
if (!_globalMePromise) {
|
||||
_globalMePromise = new CoreApi(DEFAULT_CONFIG).coreUsersMe({});
|
||||
}
|
||||
return _globalMePromise;
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
import { DefaultClient } from "./Client";
|
||||
|
||||
export class Version {
|
||||
|
||||
version_current: string;
|
||||
version_latest: string;
|
||||
outdated: boolean;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(): Promise<Version> {
|
||||
return DefaultClient.fetch<Version>(["admin", "version"]);
|
||||
}
|
||||
|
||||
}
|
97
web/src/api/legacy.ts
Normal file
97
web/src/api/legacy.ts
Normal file
|
@ -0,0 +1,97 @@
|
|||
export class AdminURLManager {
|
||||
|
||||
static applications(rest: string): string {
|
||||
return `/administration/applications/${rest}`;
|
||||
}
|
||||
|
||||
static cryptoCertificates(rest: string): string {
|
||||
return `/administration/crypto/certificates/${rest}`;
|
||||
}
|
||||
|
||||
static policies(rest: string): string {
|
||||
return `/administration/policies/${rest}`;
|
||||
}
|
||||
|
||||
static policyBindings(rest: string): string {
|
||||
return `/administration/policies/bindings/${rest}`;
|
||||
}
|
||||
|
||||
static providers(rest: string): string {
|
||||
return `/administration/providers/${rest}`;
|
||||
}
|
||||
|
||||
static propertyMappings(rest: string): string {
|
||||
return `/administration/property-mappings/${rest}`;
|
||||
}
|
||||
|
||||
static outposts(rest: string): string {
|
||||
return `/administration/outposts/${rest}`;
|
||||
}
|
||||
|
||||
static outpostServiceConnections(rest: string): string {
|
||||
return `/administration/outpost_service_connections/${rest}`;
|
||||
}
|
||||
|
||||
static flows(rest: string): string {
|
||||
return `/administration/flows/${rest}`;
|
||||
}
|
||||
|
||||
static stages(rest: string): string {
|
||||
return `/administration/stages/${rest}`;
|
||||
}
|
||||
|
||||
static stagePrompts(rest: string): string {
|
||||
return `/administration/stages_prompts/${rest}`;
|
||||
}
|
||||
|
||||
static stageInvitations(rest: string): string {
|
||||
return `/administration/stages/invitations/${rest}`;
|
||||
}
|
||||
|
||||
static stageBindings(rest: string): string {
|
||||
return `/administration/stages/bindings/${rest}`;
|
||||
}
|
||||
|
||||
static sources(rest: string): string {
|
||||
return `/administration/sources/${rest}`;
|
||||
}
|
||||
|
||||
static tokens(rest: string): string {
|
||||
return `/administration/tokens/${rest}`;
|
||||
}
|
||||
|
||||
static eventRules(rest: string): string {
|
||||
return `/administration/events/rules/${rest}`;
|
||||
}
|
||||
|
||||
static eventTransports(rest: string): string {
|
||||
return `/administration/events/transports/${rest}`;
|
||||
}
|
||||
|
||||
static users(rest: string): string {
|
||||
return `/administration/users/${rest}`;
|
||||
}
|
||||
|
||||
static groups(rest: string): string {
|
||||
return `/administration/groups/${rest}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class UserURLManager {
|
||||
|
||||
static tokens(rest: string): string {
|
||||
return `/-/user/tokens/${rest}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AppURLManager {
|
||||
|
||||
static sourceSAML(slug: string, rest: string): string {
|
||||
return `/source/saml/${slug}/${rest}`;
|
||||
}
|
||||
static providerSAML(rest: string): string {
|
||||
return `/application/saml/${rest}`;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
import { DefaultClient } from "../Client";
|
||||
import { Provider } from "../Providers";
|
||||
|
||||
export interface OAuth2SetupURLs {
|
||||
|
||||
issuer?: string;
|
||||
authorize: string;
|
||||
token: string;
|
||||
user_info: string;
|
||||
provider_info?: string;
|
||||
logout?: string;
|
||||
|
||||
}
|
||||
|
||||
export class OAuth2Provider extends Provider {
|
||||
client_type: string
|
||||
client_id: string;
|
||||
client_secret: string;
|
||||
token_validity: string;
|
||||
include_claims_in_id_token: boolean;
|
||||
jwt_alg: string;
|
||||
rsa_key: string;
|
||||
redirect_uris: string;
|
||||
sub_mode: string;
|
||||
issuer_mode: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(id: number): Promise<OAuth2Provider> {
|
||||
return DefaultClient.fetch<OAuth2Provider>(["providers", "oauth2", id.toString()]);
|
||||
}
|
||||
|
||||
static getLaunchURls(id: number): Promise<OAuth2SetupURLs> {
|
||||
return DefaultClient.fetch(["providers", "oauth2", id.toString(), "setup_urls"]);
|
||||
}
|
||||
|
||||
static appUrl(rest: string): string {
|
||||
return `/application/oauth2/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
import { DefaultClient } from "../Client";
|
||||
import { Provider } from "../Providers";
|
||||
|
||||
export class ProxyProvider extends Provider {
|
||||
internal_host: string;
|
||||
external_host: string;
|
||||
internal_host_ssl_validation: boolean
|
||||
certificate?: string;
|
||||
skip_path_regex: string;
|
||||
basic_auth_enabled: boolean;
|
||||
basic_auth_password_attribute: string;
|
||||
basic_auth_user_attribute: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(id: number): Promise<ProxyProvider> {
|
||||
return DefaultClient.fetch<ProxyProvider>(["providers", "proxy", id.toString()]);
|
||||
}
|
||||
|
||||
static getMetadata(id: number): Promise<{ metadata: string }> {
|
||||
return DefaultClient.fetch(["providers", "proxy", id.toString(), "metadata"]);
|
||||
}
|
||||
|
||||
static appUrl(rest: string): string {
|
||||
return `/application/proxy/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
import { DefaultClient } from "../Client";
|
||||
import { Provider } from "../Providers";
|
||||
|
||||
export class SAMLProvider extends Provider {
|
||||
acs_url: string;
|
||||
audience: string;
|
||||
issuer: string;
|
||||
assertion_valid_not_before: string;
|
||||
assertion_valid_not_on_or_after: string;
|
||||
session_valid_not_on_or_after: string;
|
||||
name_id_mapping?: string;
|
||||
digest_algorithm: string;
|
||||
signature_algorithm: string;
|
||||
signing_kp?: string;
|
||||
verification_kp?: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(id: number): Promise<SAMLProvider> {
|
||||
return DefaultClient.fetch<SAMLProvider>(["providers", "saml", id.toString()]);
|
||||
}
|
||||
|
||||
static getMetadata(id: number): Promise<{ metadata: string }> {
|
||||
return DefaultClient.fetch(["providers", "saml", id.toString(), "metadata"]);
|
||||
}
|
||||
|
||||
static appUrl(rest: string): string {
|
||||
return `/application/saml/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
import { DefaultClient } from "../Client";
|
||||
import { Source } from "../Sources";
|
||||
|
||||
export class LDAPSource extends Source {
|
||||
server_uri: string;
|
||||
bind_cn: string;
|
||||
start_tls: boolean
|
||||
base_dn: string;
|
||||
additional_user_dn: string;
|
||||
additional_group_dn: string;
|
||||
user_object_filter: string;
|
||||
group_object_filter: string;
|
||||
group_membership_field: string;
|
||||
object_uniqueness_field: string;
|
||||
sync_users: boolean;
|
||||
sync_users_password: boolean;
|
||||
sync_groups: boolean;
|
||||
sync_parent_group?: string;
|
||||
property_mappings: string[];
|
||||
property_mappings_group: string[];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(slug: string): Promise<LDAPSource> {
|
||||
return DefaultClient.fetch<LDAPSource>(["sources", "ldap", slug]);
|
||||
}
|
||||
|
||||
static syncStatus(slug: string): Promise<{ last_sync?: number }> {
|
||||
return DefaultClient.fetch(["sources", "ldap", slug, "sync_status"]);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
import { DefaultClient } from "../Client";
|
||||
import { Source } from "../Sources";
|
||||
|
||||
export class OAuthSource extends Source {
|
||||
provider_type: string;
|
||||
request_token_url: string;
|
||||
authorization_url: string;
|
||||
access_token_url: string;
|
||||
profile_url: string;
|
||||
consumer_key: string;
|
||||
callback_url: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(slug: string): Promise<OAuthSource> {
|
||||
return DefaultClient.fetch<OAuthSource>(["sources", "oauth", slug]);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
import { DefaultClient } from "../Client";
|
||||
import { Source } from "../Sources";
|
||||
|
||||
export class SAMLSource extends Source {
|
||||
issuer: string;
|
||||
sso_url: string;
|
||||
slo_url: string;
|
||||
allow_idp_initiated: boolean;
|
||||
name_id_policy: string;
|
||||
binding_type: string
|
||||
signing_kp?: string;
|
||||
digest_algorithm: string;
|
||||
signature_algorithm: string;
|
||||
temporary_user_delete_after: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(slug: string): Promise<SAMLSource> {
|
||||
return DefaultClient.fetch<SAMLSource>(["sources", "saml", slug]);
|
||||
}
|
||||
|
||||
static getMetadata(slug: string): Promise<{ metadata: string }> {
|
||||
return DefaultClient.fetch(["sources", "saml", slug, "metadata"]);
|
||||
}
|
||||
|
||||
static appUrl(slug: string, rest: string): string {
|
||||
return `/source/saml/${slug}/${rest}`;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,12 @@ html {
|
|||
--pf-c-nav__link--PaddingLeft: 0.5rem;
|
||||
}
|
||||
|
||||
html > input {
|
||||
position: absolute;
|
||||
top: -2000px;
|
||||
left: -2000px;
|
||||
}
|
||||
|
||||
.pf-c-page__header {
|
||||
z-index: 0;
|
||||
}
|
||||
|
@ -83,7 +89,7 @@ select[multiple] {
|
|||
|
||||
/* ensure background on non-flow pages match */
|
||||
.pf-c-background-image::before {
|
||||
background-image: url("dist/assets/images/flow_background.jpg");
|
||||
background-image: url("/static/dist/assets/images/flow_background.jpg");
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
|
@ -157,7 +163,7 @@ ak-message {
|
|||
color: var(--ak-dark-foreground) !important;
|
||||
}
|
||||
/* tabs, vertical */
|
||||
.pf-c-tabs__link {
|
||||
.pf-c-tabs.pf-m-vertical .pf-c-tabs__link {
|
||||
background-color: var(--ak-dark-background-light);
|
||||
}
|
||||
/* table, on mobile */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue