Compare commits
55 Commits
version/0.
...
version-0.
Author | SHA1 | Date | |
---|---|---|---|
7ac870bfe5 | |||
101b973cfe | |||
d8dc1f8bb5 | |||
0f4d5bc3b0 | |||
6eed549577 | |||
be54ba4fe2 | |||
68b9c34f78 | |||
3584bdf530 | |||
e712719333 | |||
9a21c2f6bd | |||
0632d8ff37 | |||
6bfaf71c12 | |||
b6c8c319e5 | |||
4fde1b7365 | |||
412f5b9210 | |||
a9e53cd52a | |||
d0ee7908ab | |||
e69834dec4 | |||
1b9d22615c | |||
e995536a15 | |||
e6818faab1 | |||
010e834149 | |||
16d5e1d9ff | |||
a1bd6bfe17 | |||
ebe0f84460 | |||
765ae80698 | |||
bbd0ff24d8 | |||
7a403613b2 | |||
4ad184a3fb | |||
48d5f28e7a | |||
0cb48121b2 | |||
4194ffe2d4 | |||
4636fe7e64 | |||
182d714b16 | |||
540c22ce15 | |||
8c3008abce | |||
8a22c86aaa | |||
c8805cc082 | |||
db92178d0f | |||
22ce142cb8 | |||
1a292feebb | |||
09f4d812b3 | |||
ad029d3e0a | |||
b0bd68232d | |||
2bab4ebfe8 | |||
65355372ce | |||
a8647caca9 | |||
590597caf6 | |||
7b43777b22 | |||
77861b52e3 | |||
5f9c1e229c | |||
119adb3e7b | |||
5db38bd0b7 | |||
0e1587bc1a | |||
dc16a8a4c9 |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.14.0-rc1
|
current_version = 0.14.2-stable
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
||||||
|
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@ -18,11 +18,11 @@ jobs:
|
|||||||
- name: Building Docker Image
|
- name: Building Docker Image
|
||||||
run: docker build
|
run: docker build
|
||||||
--no-cache
|
--no-cache
|
||||||
-t beryju/authentik:0.14.0-rc1
|
-t beryju/authentik:0.14.2-stable
|
||||||
-t beryju/authentik:latest
|
-t beryju/authentik:latest
|
||||||
-f Dockerfile .
|
-f Dockerfile .
|
||||||
- name: Push Docker Container to Registry (versioned)
|
- name: Push Docker Container to Registry (versioned)
|
||||||
run: docker push beryju/authentik:0.14.0-rc1
|
run: docker push beryju/authentik:0.14.2-stable
|
||||||
- name: Push Docker Container to Registry (latest)
|
- name: Push Docker Container to Registry (latest)
|
||||||
run: docker push beryju/authentik:latest
|
run: docker push beryju/authentik:latest
|
||||||
build-proxy:
|
build-proxy:
|
||||||
@ -48,11 +48,11 @@ jobs:
|
|||||||
cd proxy/
|
cd proxy/
|
||||||
docker build \
|
docker build \
|
||||||
--no-cache \
|
--no-cache \
|
||||||
-t beryju/authentik-proxy:0.14.0-rc1 \
|
-t beryju/authentik-proxy:0.14.2-stable \
|
||||||
-t beryju/authentik-proxy:latest \
|
-t beryju/authentik-proxy:latest \
|
||||||
-f Dockerfile .
|
-f Dockerfile .
|
||||||
- name: Push Docker Container to Registry (versioned)
|
- name: Push Docker Container to Registry (versioned)
|
||||||
run: docker push beryju/authentik-proxy:0.14.0-rc1
|
run: docker push beryju/authentik-proxy:0.14.2-stable
|
||||||
- name: Push Docker Container to Registry (latest)
|
- name: Push Docker Container to Registry (latest)
|
||||||
run: docker push beryju/authentik-proxy:latest
|
run: docker push beryju/authentik-proxy:latest
|
||||||
build-static:
|
build-static:
|
||||||
@ -69,11 +69,11 @@ jobs:
|
|||||||
cd web/
|
cd web/
|
||||||
docker build \
|
docker build \
|
||||||
--no-cache \
|
--no-cache \
|
||||||
-t beryju/authentik-static:0.14.0-rc1 \
|
-t beryju/authentik-static:0.14.2-stable \
|
||||||
-t beryju/authentik-static:latest \
|
-t beryju/authentik-static:latest \
|
||||||
-f Dockerfile .
|
-f Dockerfile .
|
||||||
- name: Push Docker Container to Registry (versioned)
|
- name: Push Docker Container to Registry (versioned)
|
||||||
run: docker push beryju/authentik-static:0.14.0-rc1
|
run: docker push beryju/authentik-static:0.14.2-stable
|
||||||
- name: Push Docker Container to Registry (latest)
|
- name: Push Docker Container to Registry (latest)
|
||||||
run: docker push beryju/authentik-static:latest
|
run: docker push beryju/authentik-static:latest
|
||||||
test-release:
|
test-release:
|
||||||
@ -107,5 +107,5 @@ jobs:
|
|||||||
SENTRY_PROJECT: authentik
|
SENTRY_PROJECT: authentik
|
||||||
SENTRY_URL: https://sentry.beryju.org
|
SENTRY_URL: https://sentry.beryju.org
|
||||||
with:
|
with:
|
||||||
tagName: 0.14.0-rc1
|
tagName: 0.14.2-stable
|
||||||
environment: beryjuorg-prod
|
environment: beryjuorg-prod
|
||||||
|
98
Pipfile.lock
generated
98
Pipfile.lock
generated
@ -74,18 +74,18 @@
|
|||||||
},
|
},
|
||||||
"boto3": {
|
"boto3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0bb2c3159b9f5e0df50430bf06a155bd7f27f480825b6374dde807d42360a668",
|
"sha256:197926eaf0065c2c503914a15edc75f4ac259c1e5ae6d17eabd1ba5d8ebd1554",
|
||||||
"sha256:a49b3ab4bfa2f6394ba60165cfc468410797dd410f32eed47e22f61451ee986e"
|
"sha256:d6991e6fd7d0f63bf94282687700a91f5299b807e544cb3367e9b2faeeaf8c62"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.16.43"
|
"version": "==1.16.46"
|
||||||
},
|
},
|
||||||
"botocore": {
|
"botocore": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:7398c900dbd4e3d61647269215396ea3e8082f494f3e7b65d9b6aca049c1d463",
|
"sha256:85ca6915ad5471e7f6cd1b00610b74601d2970cbf8e9b1bf255697154cf621a3",
|
||||||
"sha256:795a67338cadb0c3a45014a6c81659da6af623a4e973812f87a6f9d9fb7712e9"
|
"sha256:f7d365c689070368a5a0857aa35a81d7c950556189f23065f42798f810a59cae"
|
||||||
],
|
],
|
||||||
"version": "==1.19.43"
|
"version": "==1.19.46"
|
||||||
},
|
},
|
||||||
"cachetools": {
|
"cachetools": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -152,11 +152,11 @@
|
|||||||
},
|
},
|
||||||
"channels": {
|
"channels": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:74db79c9eca616be69d38013b22083ab5d3f9ccda1ab5e69096b1bb7da2d9b18",
|
"sha256:056b72e51080a517a0f33a0a30003e03833b551d75394d6636c885d4edb8188f",
|
||||||
"sha256:f50a6e79757a64c1e45e95e144a2ac5f1e99ee44a0718ab182c501f5e5abd268"
|
"sha256:3f15bdd2138bb4796e76ea588a0a344b12a7964ea9b2e456f992fddb988a4317"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==3.0.2"
|
"version": "==3.0.3"
|
||||||
},
|
},
|
||||||
"channels-redis": {
|
"channels-redis": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -899,10 +899,10 @@
|
|||||||
},
|
},
|
||||||
"pytz": {
|
"pytz": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:3e6b7dd2d1e0a59084bcee14a17af60c5c562cdc16d828e8eba2e683d3a7e268",
|
"sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4",
|
||||||
"sha256:5c55e189b682d420be27c6995ba6edce0c0a77dd67bfbe2ae6607134d5851ffd"
|
"sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"
|
||||||
],
|
],
|
||||||
"version": "==2020.4"
|
"version": "==2020.5"
|
||||||
},
|
},
|
||||||
"pyyaml": {
|
"pyyaml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -1083,11 +1083,11 @@
|
|||||||
"standard"
|
"standard"
|
||||||
],
|
],
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:6707fa7f4dbd86fd6982a2d4ecdaad2704e4514d23a1e4278104311288b04691",
|
"sha256:1079c50a06f6338095b4f203e7861dbff318dde5f22f3a324fc6e94c7654164c",
|
||||||
"sha256:d19ca083bebd212843e01f689900e5c637a292c63bb336c7f0735a99300a5f38"
|
"sha256:ef1e0bb5f7941c6fe324e06443ddac0331e1632a776175f87891c7bd02694355"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==0.13.2"
|
"version": "==0.13.3"
|
||||||
},
|
},
|
||||||
"uvloop": {
|
"uvloop": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -1607,10 +1607,10 @@
|
|||||||
},
|
},
|
||||||
"pytz": {
|
"pytz": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:3e6b7dd2d1e0a59084bcee14a17af60c5c562cdc16d828e8eba2e683d3a7e268",
|
"sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4",
|
||||||
"sha256:5c55e189b682d420be27c6995ba6edce0c0a77dd67bfbe2ae6607134d5851ffd"
|
"sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"
|
||||||
],
|
],
|
||||||
"version": "==2020.4"
|
"version": "==2020.5"
|
||||||
},
|
},
|
||||||
"pyyaml": {
|
"pyyaml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -1741,38 +1741,38 @@
|
|||||||
},
|
},
|
||||||
"typed-ast": {
|
"typed-ast": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355",
|
"sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1",
|
||||||
"sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919",
|
"sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d",
|
||||||
"sha256:0d8110d78a5736e16e26213114a38ca35cb15b6515d535413b090bd50951556d",
|
"sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6",
|
||||||
"sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa",
|
"sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd",
|
||||||
"sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652",
|
"sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37",
|
||||||
"sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75",
|
"sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151",
|
||||||
"sha256:3742b32cf1c6ef124d57f95be609c473d7ec4c14d0090e5a5e05a15269fb4d0c",
|
"sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07",
|
||||||
"sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01",
|
"sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440",
|
||||||
"sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d",
|
"sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70",
|
||||||
"sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1",
|
"sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496",
|
||||||
"sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907",
|
"sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea",
|
||||||
"sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c",
|
"sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400",
|
||||||
"sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3",
|
"sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc",
|
||||||
"sha256:7e4c9d7658aaa1fc80018593abdf8598bf91325af6af5cce4ce7c73bc45ea53d",
|
"sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606",
|
||||||
"sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b",
|
"sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc",
|
||||||
"sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614",
|
"sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581",
|
||||||
"sha256:92c325624e304ebf0e025d1224b77dd4e6393f18aab8d829b5b7e04afe9b7a2c",
|
"sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412",
|
||||||
"sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb",
|
"sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a",
|
||||||
"sha256:b52ccf7cfe4ce2a1064b18594381bccf4179c2ecf7f513134ec2f993dd4ab395",
|
"sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2",
|
||||||
"sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b",
|
"sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787",
|
||||||
"sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41",
|
"sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f",
|
||||||
"sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6",
|
"sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937",
|
||||||
"sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34",
|
"sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64",
|
||||||
"sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe",
|
"sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487",
|
||||||
"sha256:d648b8e3bf2fe648745c8ffcee3db3ff903d0817a01a12dd6a6ea7a8f4889072",
|
"sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b",
|
||||||
"sha256:f208eb7aff048f6bea9586e61af041ddf7f9ade7caed625742af423f6bae3298",
|
"sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41",
|
||||||
"sha256:fac11badff8313e23717f3dada86a15389d0708275bddf766cca67a84ead3e91",
|
"sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a",
|
||||||
"sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4",
|
"sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3",
|
||||||
"sha256:fcf135e17cc74dbfbc05894ebca928ffeb23d9790b3167a674921db19082401f",
|
"sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166",
|
||||||
"sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"
|
"sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"
|
||||||
],
|
],
|
||||||
"version": "==1.4.1"
|
"version": "==1.4.2"
|
||||||
},
|
},
|
||||||
"typing-extensions": {
|
"typing-extensions": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -6,9 +6,9 @@ As authentik is currently in a pre-stable, only the latest "stable" version is s
|
|||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| -------- | ------------------ |
|
| -------- | ------------------ |
|
||||||
| 0.11.x | :white_check_mark: |
|
|
||||||
| 0.12.x | :white_check_mark: |
|
| 0.12.x | :white_check_mark: |
|
||||||
| 0.13.x | :white_check_mark: |
|
| 0.13.x | :white_check_mark: |
|
||||||
|
| 0.14.x | :white_check_mark: |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
"""authentik"""
|
"""authentik"""
|
||||||
__version__ = "0.14.0-rc1"
|
__version__ = "0.14.2-stable"
|
||||||
|
@ -29,7 +29,7 @@ class ApplicationCreateView(
|
|||||||
permission_required = "authentik_core.add_application"
|
permission_required = "authentik_core.add_application"
|
||||||
|
|
||||||
template_name = "generic/create.html"
|
template_name = "generic/create.html"
|
||||||
success_url = reverse_lazy("authentik_admin:applications")
|
success_url = reverse_lazy("authentik_core:shell")
|
||||||
success_message = _("Successfully created Application")
|
success_message = _("Successfully created Application")
|
||||||
|
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ class ApplicationUpdateView(
|
|||||||
permission_required = "authentik_core.change_application"
|
permission_required = "authentik_core.change_application"
|
||||||
|
|
||||||
template_name = "generic/update.html"
|
template_name = "generic/update.html"
|
||||||
success_url = reverse_lazy("authentik_admin:applications")
|
success_url = reverse_lazy("authentik_core:shell")
|
||||||
success_message = _("Successfully updated Application")
|
success_message = _("Successfully updated Application")
|
||||||
|
|
||||||
|
|
||||||
@ -60,5 +60,5 @@ class ApplicationDeleteView(
|
|||||||
permission_required = "authentik_core.delete_application"
|
permission_required = "authentik_core.delete_application"
|
||||||
|
|
||||||
template_name = "generic/delete.html"
|
template_name = "generic/delete.html"
|
||||||
success_url = reverse_lazy("authentik_admin:applications")
|
success_url = reverse_lazy("authentik_core:shell")
|
||||||
success_message = _("Successfully deleted Application")
|
success_message = _("Successfully deleted Application")
|
||||||
|
@ -25,7 +25,7 @@ urlpatterns = [
|
|||||||
name="user-tokens-delete",
|
name="user-tokens-delete",
|
||||||
),
|
),
|
||||||
# Libray
|
# Libray
|
||||||
path("library/", library.LibraryView.as_view(), name="overview"),
|
path("library", library.LibraryView.as_view(), name="overview"),
|
||||||
# Impersonation
|
# Impersonation
|
||||||
path(
|
path(
|
||||||
"-/impersonation/<int:user_id>/",
|
"-/impersonation/<int:user_id>/",
|
||||||
|
@ -48,6 +48,15 @@ class EventViewSet(ReadOnlyModelViewSet):
|
|||||||
|
|
||||||
queryset = Event.objects.all()
|
queryset = Event.objects.all()
|
||||||
serializer_class = EventSerializer
|
serializer_class = EventSerializer
|
||||||
|
ordering = ["-created"]
|
||||||
|
search_fields = [
|
||||||
|
"user",
|
||||||
|
"action",
|
||||||
|
"app",
|
||||||
|
"context",
|
||||||
|
"client_ip",
|
||||||
|
]
|
||||||
|
filterset_fields = ["action"]
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@swagger_auto_schema(
|
||||||
method="GET", responses={200: EventTopPerUserSerialier(many=True)}
|
method="GET", responses={200: EventTopPerUserSerialier(many=True)}
|
||||||
|
@ -10,7 +10,6 @@ class AuthentikEventsConfig(AppConfig):
|
|||||||
name = "authentik.events"
|
name = "authentik.events"
|
||||||
label = "authentik_events"
|
label = "authentik_events"
|
||||||
verbose_name = "authentik Events"
|
verbose_name = "authentik Events"
|
||||||
mountpoint = "events/"
|
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
import_module("authentik.events.signals")
|
import_module("authentik.events.signals")
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
{% extends "base/page.html" %}
|
|
||||||
|
|
||||||
{% load i18n %}
|
|
||||||
{% load authentik_utils %}
|
|
||||||
|
|
||||||
{% block page_content %}
|
|
||||||
<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
|
|
||||||
<section class="pf-c-page__main-section pf-m-light">
|
|
||||||
<div class="pf-c-content">
|
|
||||||
<h1>
|
|
||||||
<i class="pf-icon pf-icon-catalog"></i>
|
|
||||||
{% trans 'Event Log' %}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
|
||||||
<div class="pf-c-card">
|
|
||||||
<div class="pf-c-toolbar">
|
|
||||||
<div class="pf-c-toolbar__content">
|
|
||||||
{% include 'partials/toolbar_search.html' %}
|
|
||||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
|
||||||
{% trans 'Refresh' %}
|
|
||||||
</button>
|
|
||||||
{% include 'partials/pagination.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
|
|
||||||
<thead>
|
|
||||||
<tr role="row">
|
|
||||||
<th role="columnheader" scope="col">{% trans 'Action' %}</th>
|
|
||||||
<th role="columnheader" scope="col">{% trans 'Context' %}</th>
|
|
||||||
<th role="columnheader" scope="col">{% trans 'User' %}</th>
|
|
||||||
<th role="columnheader" scope="col">{% trans 'Creation Date' %}</th>
|
|
||||||
<th role="columnheader" scope="col">{% trans 'Client IP' %}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody role="rowgroup">
|
|
||||||
{% for entry in object_list %}
|
|
||||||
<tr role="row">
|
|
||||||
<th role="columnheader">
|
|
||||||
<div>
|
|
||||||
<div>{{ entry.action }}</div>
|
|
||||||
<small>{{ entry.app|default:'-' }}</small>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
<td role="cell">
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<code>{{ entry.context }}</code>
|
|
||||||
</div>
|
|
||||||
{% if entry.user.on_behalf_of %}
|
|
||||||
<small>
|
|
||||||
{% blocktrans with username=entry.user.on_behalf_of.username %}
|
|
||||||
On behalf of {{ username }}
|
|
||||||
{% endblocktrans %}
|
|
||||||
</small>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td role="cell">
|
|
||||||
<div>
|
|
||||||
<div>{{ entry.user.username }}</div>
|
|
||||||
<small>
|
|
||||||
{% blocktrans with pk=entry.user.pk %}
|
|
||||||
ID: {{ pk }}
|
|
||||||
{% endblocktrans %}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td role="cell">
|
|
||||||
<span>
|
|
||||||
{{ entry.created }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td role="cell">
|
|
||||||
<span>
|
|
||||||
{{ entry.client_ip }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div class="pf-c-pagination pf-m-bottom">
|
|
||||||
{% include 'partials/pagination.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
{% endblock %}
|
|
@ -1,9 +0,0 @@
|
|||||||
"""authentik events urls"""
|
|
||||||
from django.urls import path
|
|
||||||
|
|
||||||
from authentik.events.views import EventListView
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
# Event Log
|
|
||||||
path("log/", EventListView.as_view(), name="log"),
|
|
||||||
]
|
|
@ -11,6 +11,7 @@ from django.views.debug import SafeExceptionReporterFilter
|
|||||||
from guardian.utils import get_anonymous_user
|
from guardian.utils import get_anonymous_user
|
||||||
|
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
|
from authentik.policies.types import PolicyRequest
|
||||||
|
|
||||||
# Special keys which are *not* cleaned, even when the default filter
|
# Special keys which are *not* cleaned, even when the default filter
|
||||||
# is matched
|
# is matched
|
||||||
@ -74,6 +75,11 @@ def sanitize_dict(source: Dict[Any, Any]) -> Dict[Any, Any]:
|
|||||||
final_dict = {}
|
final_dict = {}
|
||||||
for key, value in source.items():
|
for key, value in source.items():
|
||||||
if is_dataclass(value):
|
if is_dataclass(value):
|
||||||
|
# Because asdict calls `copy.deepcopy(obj)` on everything thats not tuple/dict,
|
||||||
|
# and deepcopy doesn't work with HttpRequests (neither django nor rest_framework).
|
||||||
|
# Currently, the only dataclass that actually holds an http request is a PolicyRequest
|
||||||
|
if isinstance(value, PolicyRequest):
|
||||||
|
value.http_request = None
|
||||||
value = asdict(value)
|
value = asdict(value)
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
final_dict[key] = sanitize_dict(value)
|
final_dict[key] = sanitize_dict(value)
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
"""authentik Event administration"""
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
||||||
from django.views.generic import ListView
|
|
||||||
from guardian.mixins import PermissionListMixin
|
|
||||||
|
|
||||||
from authentik.admin.views.utils import SearchListMixin, UserPaginateListMixin
|
|
||||||
from authentik.events.models import Event
|
|
||||||
|
|
||||||
|
|
||||||
class EventListView(
|
|
||||||
PermissionListMixin,
|
|
||||||
LoginRequiredMixin,
|
|
||||||
SearchListMixin,
|
|
||||||
UserPaginateListMixin,
|
|
||||||
ListView,
|
|
||||||
):
|
|
||||||
"""Show list of all invitations"""
|
|
||||||
|
|
||||||
model = Event
|
|
||||||
template_name = "events/list.html"
|
|
||||||
permission_required = "authentik_events.view_event"
|
|
||||||
ordering = "-created"
|
|
||||||
|
|
||||||
search_fields = [
|
|
||||||
"user",
|
|
||||||
"action",
|
|
||||||
"app",
|
|
||||||
"context",
|
|
||||||
"client_ip",
|
|
||||||
]
|
|
@ -78,6 +78,8 @@ class FlowViewSet(ModelViewSet):
|
|||||||
queryset = Flow.objects.all()
|
queryset = Flow.objects.all()
|
||||||
serializer_class = FlowSerializer
|
serializer_class = FlowSerializer
|
||||||
lookup_field = "slug"
|
lookup_field = "slug"
|
||||||
|
search_fields = ["name", "slug", "designation", "title"]
|
||||||
|
filterset_fields = ["flow_uuid", "name", "slug", "designation"]
|
||||||
|
|
||||||
@swagger_auto_schema(responses={200: FlowDiagramSerializer()})
|
@swagger_auto_schema(responses={200: FlowDiagramSerializer()})
|
||||||
@action(detail=True, methods=["get"])
|
@action(detail=True, methods=["get"])
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
"""Base Controller"""
|
"""Base Controller"""
|
||||||
from typing import Dict, List
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from structlog import get_logger
|
from structlog import get_logger
|
||||||
from structlog.testing import capture_logs
|
from structlog.testing import capture_logs
|
||||||
@ -7,15 +7,26 @@ from structlog.testing import capture_logs
|
|||||||
from authentik.lib.sentry import SentryIgnoredException
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
from authentik.outposts.models import Outpost, OutpostServiceConnection
|
from authentik.outposts.models import Outpost, OutpostServiceConnection
|
||||||
|
|
||||||
|
FIELD_MANAGER = "goauthentik.io"
|
||||||
|
|
||||||
|
|
||||||
class ControllerException(SentryIgnoredException):
|
class ControllerException(SentryIgnoredException):
|
||||||
"""Exception raised when anything fails during controller run"""
|
"""Exception raised when anything fails during controller run"""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DeploymentPort:
|
||||||
|
"""Info about deployment's single port."""
|
||||||
|
|
||||||
|
port: int
|
||||||
|
name: str
|
||||||
|
protocol: str
|
||||||
|
|
||||||
|
|
||||||
class BaseController:
|
class BaseController:
|
||||||
"""Base Outpost deployment controller"""
|
"""Base Outpost deployment controller"""
|
||||||
|
|
||||||
deployment_ports: Dict[str, int]
|
deployment_ports: list[DeploymentPort]
|
||||||
|
|
||||||
outpost: Outpost
|
outpost: Outpost
|
||||||
connection: OutpostServiceConnection
|
connection: OutpostServiceConnection
|
||||||
@ -24,14 +35,14 @@ class BaseController:
|
|||||||
self.outpost = outpost
|
self.outpost = outpost
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
self.logger = get_logger()
|
self.logger = get_logger()
|
||||||
self.deployment_ports = {}
|
self.deployment_ports = []
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
def up(self):
|
def up(self):
|
||||||
"""Called by scheduled task to reconcile deployment/service/etc"""
|
"""Called by scheduled task to reconcile deployment/service/etc"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def up_with_logs(self) -> List[str]:
|
def up_with_logs(self) -> list[str]:
|
||||||
"""Call .up() but capture all log output and return it."""
|
"""Call .up() but capture all log output and return it."""
|
||||||
with capture_logs() as logs:
|
with capture_logs() as logs:
|
||||||
self.up()
|
self.up()
|
||||||
|
@ -68,7 +68,10 @@ class DockerController(BaseController):
|
|||||||
"image": image_name,
|
"image": image_name,
|
||||||
"name": f"authentik-proxy-{self.outpost.uuid.hex}",
|
"name": f"authentik-proxy-{self.outpost.uuid.hex}",
|
||||||
"detach": True,
|
"detach": True,
|
||||||
"ports": {x: x for _, x in self.deployment_ports.items()},
|
"ports": {
|
||||||
|
f"{port.port}/{port.protocol.lower()}": port.port
|
||||||
|
for port in self.deployment_ports
|
||||||
|
},
|
||||||
"environment": self._get_env(),
|
"environment": self._get_env(),
|
||||||
"labels": self._get_labels(),
|
"labels": self._get_labels(),
|
||||||
}
|
}
|
||||||
@ -139,7 +142,10 @@ class DockerController(BaseController):
|
|||||||
|
|
||||||
def get_static_deployment(self) -> str:
|
def get_static_deployment(self) -> str:
|
||||||
"""Generate docker-compose yaml for proxy, version 3.5"""
|
"""Generate docker-compose yaml for proxy, version 3.5"""
|
||||||
ports = [f"{x}:{x}" for _, x in self.deployment_ports.items()]
|
ports = [
|
||||||
|
f"{port.port}:{port.port}/{port.protocol.lower()}"
|
||||||
|
for port in self.deployment_ports
|
||||||
|
]
|
||||||
image_prefix = CONFIG.y("outposts.docker_image_base")
|
image_prefix = CONFIG.y("outposts.docker_image_base")
|
||||||
compose = {
|
compose = {
|
||||||
"version": "3.5",
|
"version": "3.5",
|
||||||
@ -154,6 +160,7 @@ class DockerController(BaseController):
|
|||||||
),
|
),
|
||||||
"AUTHENTIK_TOKEN": self.outpost.token.key,
|
"AUTHENTIK_TOKEN": self.outpost.token.key,
|
||||||
},
|
},
|
||||||
|
"labels": self._get_labels(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,8 @@ class KubernetesObjectReconciler(Generic[T]):
|
|||||||
def reconcile(self, current: T, reference: T):
|
def reconcile(self, current: T, reference: T):
|
||||||
"""Check what operations should be done, should be raised as
|
"""Check what operations should be done, should be raised as
|
||||||
ReconcileTrigger"""
|
ReconcileTrigger"""
|
||||||
raise NotImplementedError
|
if current.metadata.annotations != reference.metadata.annotations:
|
||||||
|
raise NeedsUpdate()
|
||||||
|
|
||||||
def create(self, reference: T):
|
def create(self, reference: T):
|
||||||
"""API Wrapper to create object"""
|
"""API Wrapper to create object"""
|
||||||
|
@ -18,6 +18,7 @@ from kubernetes.client import (
|
|||||||
|
|
||||||
from authentik import __version__
|
from authentik import __version__
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
|
from authentik.outposts.controllers.base import FIELD_MANAGER
|
||||||
from authentik.outposts.controllers.k8s.base import (
|
from authentik.outposts.controllers.k8s.base import (
|
||||||
KubernetesObjectReconciler,
|
KubernetesObjectReconciler,
|
||||||
NeedsUpdate,
|
NeedsUpdate,
|
||||||
@ -43,6 +44,7 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
|
|||||||
return f"authentik-outpost-{self.controller.outpost.uuid.hex}"
|
return f"authentik-outpost-{self.controller.outpost.uuid.hex}"
|
||||||
|
|
||||||
def reconcile(self, current: V1Deployment, reference: V1Deployment):
|
def reconcile(self, current: V1Deployment, reference: V1Deployment):
|
||||||
|
super().reconcile(current, reference)
|
||||||
if current.spec.replicas != reference.spec.replicas:
|
if current.spec.replicas != reference.spec.replicas:
|
||||||
raise NeedsUpdate()
|
raise NeedsUpdate()
|
||||||
if (
|
if (
|
||||||
@ -63,8 +65,14 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
|
|||||||
"""Get deployment object for outpost"""
|
"""Get deployment object for outpost"""
|
||||||
# Generate V1ContainerPort objects
|
# Generate V1ContainerPort objects
|
||||||
container_ports = []
|
container_ports = []
|
||||||
for port_name, port in self.controller.deployment_ports.items():
|
for port in self.controller.deployment_ports:
|
||||||
container_ports.append(V1ContainerPort(container_port=port, name=port_name))
|
container_ports.append(
|
||||||
|
V1ContainerPort(
|
||||||
|
container_port=port.port,
|
||||||
|
name=port.name,
|
||||||
|
protocol=port.protocol.upper(),
|
||||||
|
)
|
||||||
|
)
|
||||||
meta = self.get_object_meta(name=self.name)
|
meta = self.get_object_meta(name=self.name)
|
||||||
secret_name = f"authentik-outpost-{self.controller.outpost.uuid.hex}-api"
|
secret_name = f"authentik-outpost-{self.controller.outpost.uuid.hex}-api"
|
||||||
image_prefix = CONFIG.y("outposts.docker_image_base")
|
image_prefix = CONFIG.y("outposts.docker_image_base")
|
||||||
@ -118,7 +126,9 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create(self, reference: V1Deployment):
|
def create(self, reference: V1Deployment):
|
||||||
return self.api.create_namespaced_deployment(self.namespace, reference)
|
return self.api.create_namespaced_deployment(
|
||||||
|
self.namespace, reference, field_manager=FIELD_MANAGER
|
||||||
|
)
|
||||||
|
|
||||||
def delete(self, reference: V1Deployment):
|
def delete(self, reference: V1Deployment):
|
||||||
return self.api.delete_namespaced_deployment(
|
return self.api.delete_namespaced_deployment(
|
||||||
|
@ -4,6 +4,7 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
from kubernetes.client import CoreV1Api, V1Secret
|
from kubernetes.client import CoreV1Api, V1Secret
|
||||||
|
|
||||||
|
from authentik.outposts.controllers.base import FIELD_MANAGER
|
||||||
from authentik.outposts.controllers.k8s.base import (
|
from authentik.outposts.controllers.k8s.base import (
|
||||||
KubernetesObjectReconciler,
|
KubernetesObjectReconciler,
|
||||||
NeedsUpdate,
|
NeedsUpdate,
|
||||||
@ -30,6 +31,7 @@ class SecretReconciler(KubernetesObjectReconciler[V1Secret]):
|
|||||||
return f"authentik-outpost-{self.controller.outpost.uuid.hex}-api"
|
return f"authentik-outpost-{self.controller.outpost.uuid.hex}-api"
|
||||||
|
|
||||||
def reconcile(self, current: V1Secret, reference: V1Secret):
|
def reconcile(self, current: V1Secret, reference: V1Secret):
|
||||||
|
super().reconcile(current, reference)
|
||||||
for key in reference.data.keys():
|
for key in reference.data.keys():
|
||||||
if current.data[key] != reference.data[key]:
|
if current.data[key] != reference.data[key]:
|
||||||
raise NeedsUpdate()
|
raise NeedsUpdate()
|
||||||
@ -51,7 +53,9 @@ class SecretReconciler(KubernetesObjectReconciler[V1Secret]):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create(self, reference: V1Secret):
|
def create(self, reference: V1Secret):
|
||||||
return self.api.create_namespaced_secret(self.namespace, reference)
|
return self.api.create_namespaced_secret(
|
||||||
|
self.namespace, reference, field_manager=FIELD_MANAGER
|
||||||
|
)
|
||||||
|
|
||||||
def delete(self, reference: V1Secret):
|
def delete(self, reference: V1Secret):
|
||||||
return self.api.delete_namespaced_secret(
|
return self.api.delete_namespaced_secret(
|
||||||
|
@ -3,6 +3,7 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
from kubernetes.client import CoreV1Api, V1Service, V1ServicePort, V1ServiceSpec
|
from kubernetes.client import CoreV1Api, V1Service, V1ServicePort, V1ServiceSpec
|
||||||
|
|
||||||
|
from authentik.outposts.controllers.base import FIELD_MANAGER
|
||||||
from authentik.outposts.controllers.k8s.base import (
|
from authentik.outposts.controllers.k8s.base import (
|
||||||
KubernetesObjectReconciler,
|
KubernetesObjectReconciler,
|
||||||
NeedsUpdate,
|
NeedsUpdate,
|
||||||
@ -25,6 +26,7 @@ class ServiceReconciler(KubernetesObjectReconciler[V1Service]):
|
|||||||
return f"authentik-outpost-{self.controller.outpost.uuid.hex}"
|
return f"authentik-outpost-{self.controller.outpost.uuid.hex}"
|
||||||
|
|
||||||
def reconcile(self, current: V1Service, reference: V1Service):
|
def reconcile(self, current: V1Service, reference: V1Service):
|
||||||
|
super().reconcile(current, reference)
|
||||||
if len(current.spec.ports) != len(reference.spec.ports):
|
if len(current.spec.ports) != len(reference.spec.ports):
|
||||||
raise NeedsUpdate()
|
raise NeedsUpdate()
|
||||||
for port in reference.spec.ports:
|
for port in reference.spec.ports:
|
||||||
@ -35,8 +37,15 @@ class ServiceReconciler(KubernetesObjectReconciler[V1Service]):
|
|||||||
"""Get deployment object for outpost"""
|
"""Get deployment object for outpost"""
|
||||||
meta = self.get_object_meta(name=self.name)
|
meta = self.get_object_meta(name=self.name)
|
||||||
ports = []
|
ports = []
|
||||||
for port_name, port in self.controller.deployment_ports.items():
|
for port in self.controller.deployment_ports:
|
||||||
ports.append(V1ServicePort(name=port_name, port=port))
|
ports.append(
|
||||||
|
V1ServicePort(
|
||||||
|
name=port.name,
|
||||||
|
port=port.port,
|
||||||
|
protocol=port.protocol.upper(),
|
||||||
|
target_port=port.port,
|
||||||
|
)
|
||||||
|
)
|
||||||
selector_labels = DeploymentReconciler(self.controller).get_pod_meta()
|
selector_labels = DeploymentReconciler(self.controller).get_pod_meta()
|
||||||
return V1Service(
|
return V1Service(
|
||||||
metadata=meta,
|
metadata=meta,
|
||||||
@ -44,7 +53,9 @@ class ServiceReconciler(KubernetesObjectReconciler[V1Service]):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create(self, reference: V1Service):
|
def create(self, reference: V1Service):
|
||||||
return self.api.create_namespaced_service(self.namespace, reference)
|
return self.api.create_namespaced_service(
|
||||||
|
self.namespace, reference, field_manager=FIELD_MANAGER
|
||||||
|
)
|
||||||
|
|
||||||
def delete(self, reference: V1Service):
|
def delete(self, reference: V1Service):
|
||||||
return self.api.delete_namespaced_service(
|
return self.api.delete_namespaced_service(
|
||||||
|
@ -56,6 +56,7 @@ class PolicyEngine:
|
|||||||
raise ValueError(f"{pbm} is not instance of PolicyBindingModel")
|
raise ValueError(f"{pbm} is not instance of PolicyBindingModel")
|
||||||
self.__pbm = pbm
|
self.__pbm = pbm
|
||||||
self.request = PolicyRequest(user)
|
self.request = PolicyRequest(user)
|
||||||
|
self.request.obj = pbm
|
||||||
if request:
|
if request:
|
||||||
self.request.http_request = request
|
self.request.http_request = request
|
||||||
self.__cached_policies = []
|
self.__cached_policies = []
|
||||||
|
@ -93,4 +93,8 @@ class PolicyProcess(Process):
|
|||||||
span: Span
|
span: Span
|
||||||
span.set_data("policy", self.binding.policy)
|
span.set_data("policy", self.binding.policy)
|
||||||
span.set_data("request", self.request)
|
span.set_data("request", self.request)
|
||||||
self.connection.send(self.execute())
|
try:
|
||||||
|
self.connection.send(self.execute())
|
||||||
|
except Exception as exc: # pylint: disable=broad-except
|
||||||
|
LOGGER.warning(exc)
|
||||||
|
self.connection.send(PolicyResult(False, str(exc)))
|
||||||
|
@ -398,7 +398,7 @@ class AuthorizationCode(ExpiringModel, BaseGrantModel):
|
|||||||
verbose_name_plural = _("Authorization Codes")
|
verbose_name_plural = _("Authorization Codes")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{0} - {1}".format(self.provider, self.code)
|
return f"Authorization code for {self.provider} for user {self.user}"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -461,7 +461,7 @@ class RefreshToken(ExpiringModel, BaseGrantModel):
|
|||||||
self._id_token = json.dumps(asdict(value))
|
self._id_token = json.dumps(asdict(value))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.provider} - {self.access_token}"
|
return f"Refresh Token for {self.provider} for user {self.user}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def at_hash(self):
|
def at_hash(self):
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from typing import Dict
|
from typing import Dict
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from authentik.outposts.controllers.base import DeploymentPort
|
||||||
from authentik.outposts.controllers.docker import DockerController
|
from authentik.outposts.controllers.docker import DockerController
|
||||||
from authentik.outposts.models import DockerServiceConnection, Outpost
|
from authentik.outposts.models import DockerServiceConnection, Outpost
|
||||||
from authentik.providers.proxy.models import ProxyProvider
|
from authentik.providers.proxy.models import ProxyProvider
|
||||||
@ -12,10 +13,10 @@ class ProxyDockerController(DockerController):
|
|||||||
|
|
||||||
def __init__(self, outpost: Outpost, connection: DockerServiceConnection):
|
def __init__(self, outpost: Outpost, connection: DockerServiceConnection):
|
||||||
super().__init__(outpost, connection)
|
super().__init__(outpost, connection)
|
||||||
self.deployment_ports = {
|
self.deployment_ports = [
|
||||||
"http": 4180,
|
DeploymentPort(4180, "http", "tcp"),
|
||||||
"https": 4443,
|
DeploymentPort(4443, "https", "tcp"),
|
||||||
}
|
]
|
||||||
|
|
||||||
def _get_labels(self) -> Dict[str, str]:
|
def _get_labels(self) -> Dict[str, str]:
|
||||||
hosts = []
|
hosts = []
|
||||||
|
@ -15,6 +15,7 @@ from kubernetes.client.models.networking_v1beta1_ingress_rule import (
|
|||||||
NetworkingV1beta1IngressRule,
|
NetworkingV1beta1IngressRule,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from authentik.outposts.controllers.base import FIELD_MANAGER
|
||||||
from authentik.outposts.controllers.k8s.base import (
|
from authentik.outposts.controllers.k8s.base import (
|
||||||
KubernetesObjectReconciler,
|
KubernetesObjectReconciler,
|
||||||
NeedsUpdate,
|
NeedsUpdate,
|
||||||
@ -39,6 +40,7 @@ class IngressReconciler(KubernetesObjectReconciler[NetworkingV1beta1Ingress]):
|
|||||||
def reconcile(
|
def reconcile(
|
||||||
self, current: NetworkingV1beta1Ingress, reference: NetworkingV1beta1Ingress
|
self, current: NetworkingV1beta1Ingress, reference: NetworkingV1beta1Ingress
|
||||||
):
|
):
|
||||||
|
super().reconcile(current, reference)
|
||||||
# Create a list of all expected host and tls hosts
|
# Create a list of all expected host and tls hosts
|
||||||
expected_hosts = []
|
expected_hosts = []
|
||||||
expected_hosts_tls = []
|
expected_hosts_tls = []
|
||||||
@ -74,11 +76,13 @@ class IngressReconciler(KubernetesObjectReconciler[NetworkingV1beta1Ingress]):
|
|||||||
# goes to the same pod
|
# goes to the same pod
|
||||||
"nginx.ingress.kubernetes.io/affinity": "cookie",
|
"nginx.ingress.kubernetes.io/affinity": "cookie",
|
||||||
"traefik.ingress.kubernetes.io/affinity": "true",
|
"traefik.ingress.kubernetes.io/affinity": "true",
|
||||||
|
"nginx.ingress.kubernetes.io/proxy-buffers-number": "4",
|
||||||
|
"nginx.ingress.kubernetes.io/proxy-buffer-size": "16k",
|
||||||
}
|
}
|
||||||
annotations.update(
|
annotations.update(
|
||||||
self.controller.outpost.config.kubernetes_ingress_annotations
|
self.controller.outpost.config.kubernetes_ingress_annotations
|
||||||
)
|
)
|
||||||
return dict()
|
return annotations
|
||||||
|
|
||||||
def get_reference_object(self) -> NetworkingV1beta1Ingress:
|
def get_reference_object(self) -> NetworkingV1beta1Ingress:
|
||||||
"""Get deployment object for outpost"""
|
"""Get deployment object for outpost"""
|
||||||
@ -102,7 +106,7 @@ class IngressReconciler(KubernetesObjectReconciler[NetworkingV1beta1Ingress]):
|
|||||||
NetworkingV1beta1HTTPIngressPath(
|
NetworkingV1beta1HTTPIngressPath(
|
||||||
backend=NetworkingV1beta1IngressBackend(
|
backend=NetworkingV1beta1IngressBackend(
|
||||||
service_name=self.name,
|
service_name=self.name,
|
||||||
service_port=self.controller.deployment_ports["http"],
|
service_port="http",
|
||||||
),
|
),
|
||||||
path="/",
|
path="/",
|
||||||
)
|
)
|
||||||
@ -122,7 +126,9 @@ class IngressReconciler(KubernetesObjectReconciler[NetworkingV1beta1Ingress]):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create(self, reference: NetworkingV1beta1Ingress):
|
def create(self, reference: NetworkingV1beta1Ingress):
|
||||||
return self.api.create_namespaced_ingress(self.namespace, reference)
|
return self.api.create_namespaced_ingress(
|
||||||
|
self.namespace, reference, field_manager=FIELD_MANAGER
|
||||||
|
)
|
||||||
|
|
||||||
def delete(self, reference: NetworkingV1beta1Ingress):
|
def delete(self, reference: NetworkingV1beta1Ingress):
|
||||||
return self.api.delete_namespaced_ingress(
|
return self.api.delete_namespaced_ingress(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"""Proxy Provider Kubernetes Contoller"""
|
"""Proxy Provider Kubernetes Contoller"""
|
||||||
|
from authentik.outposts.controllers.base import DeploymentPort
|
||||||
from authentik.outposts.controllers.kubernetes import KubernetesController
|
from authentik.outposts.controllers.kubernetes import KubernetesController
|
||||||
from authentik.outposts.models import KubernetesServiceConnection, Outpost
|
from authentik.outposts.models import KubernetesServiceConnection, Outpost
|
||||||
from authentik.providers.proxy.controllers.k8s.ingress import IngressReconciler
|
from authentik.providers.proxy.controllers.k8s.ingress import IngressReconciler
|
||||||
@ -9,9 +10,9 @@ class ProxyKubernetesController(KubernetesController):
|
|||||||
|
|
||||||
def __init__(self, outpost: Outpost, connection: KubernetesServiceConnection):
|
def __init__(self, outpost: Outpost, connection: KubernetesServiceConnection):
|
||||||
super().__init__(outpost, connection)
|
super().__init__(outpost, connection)
|
||||||
self.deployment_ports = {
|
self.deployment_ports = [
|
||||||
"http": 4180,
|
DeploymentPort(4180, "http", "tcp"),
|
||||||
"https": 4443,
|
DeploymentPort(4443, "https", "tcp"),
|
||||||
}
|
]
|
||||||
self.reconcilers["ingress"] = IngressReconciler
|
self.reconcilers["ingress"] = IngressReconciler
|
||||||
self.reconcile_order.append("ingress")
|
self.reconcile_order.append("ingress")
|
||||||
|
@ -7,7 +7,7 @@ from authentik.providers.proxy.models import ProxyProvider
|
|||||||
|
|
||||||
|
|
||||||
class ProxyProviderForm(forms.ModelForm):
|
class ProxyProviderForm(forms.ModelForm):
|
||||||
"""Security Gateway Provider form"""
|
"""Proxy Provider form"""
|
||||||
|
|
||||||
instance: ProxyProvider
|
instance: ProxyProvider
|
||||||
|
|
||||||
|
@ -36,17 +36,17 @@ class SAMLProviderForm(forms.ModelForm):
|
|||||||
"name",
|
"name",
|
||||||
"authorization_flow",
|
"authorization_flow",
|
||||||
"acs_url",
|
"acs_url",
|
||||||
"audience",
|
|
||||||
"issuer",
|
"issuer",
|
||||||
"sp_binding",
|
"sp_binding",
|
||||||
|
"audience",
|
||||||
|
"signing_kp",
|
||||||
|
"verification_kp",
|
||||||
|
"property_mappings",
|
||||||
"assertion_valid_not_before",
|
"assertion_valid_not_before",
|
||||||
"assertion_valid_not_on_or_after",
|
"assertion_valid_not_on_or_after",
|
||||||
"session_valid_not_on_or_after",
|
"session_valid_not_on_or_after",
|
||||||
"digest_algorithm",
|
"digest_algorithm",
|
||||||
"signature_algorithm",
|
"signature_algorithm",
|
||||||
"signing_kp",
|
|
||||||
"verification_kp",
|
|
||||||
"property_mappings",
|
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
"name": forms.TextInput(),
|
"name": forms.TextInput(),
|
||||||
@ -94,6 +94,9 @@ class SAMLProviderImportForm(forms.Form):
|
|||||||
"""Create a SAML Provider from SP Metadata."""
|
"""Create a SAML Provider from SP Metadata."""
|
||||||
|
|
||||||
provider_name = forms.CharField()
|
provider_name = forms.CharField()
|
||||||
|
authorization_flow = forms.ModelChoiceField(
|
||||||
|
queryset=Flow.objects.filter(designation=FlowDesignation.AUTHORIZATION)
|
||||||
|
)
|
||||||
metadata = forms.FileField(
|
metadata = forms.FileField(
|
||||||
validators=[FileExtensionValidator(allowed_extensions=["xml"])]
|
validators=[FileExtensionValidator(allowed_extensions=["xml"])]
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 3.1.4 on 2020-12-30 21:12
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_providers_saml", "0009_auto_20201112_2016"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="samlprovider",
|
||||||
|
name="audience",
|
||||||
|
field=models.TextField(
|
||||||
|
blank=True,
|
||||||
|
default="",
|
||||||
|
help_text="Value of the audience restriction field of the asseration. When left empty, no audience restriction will be added.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -42,7 +42,13 @@ class SAMLProvider(Provider):
|
|||||||
acs_url = models.URLField(verbose_name=_("ACS URL"))
|
acs_url = models.URLField(verbose_name=_("ACS URL"))
|
||||||
audience = models.TextField(
|
audience = models.TextField(
|
||||||
default="",
|
default="",
|
||||||
help_text=_("Value of the audience restriction field of the asseration."),
|
blank=True,
|
||||||
|
help_text=_(
|
||||||
|
(
|
||||||
|
"Value of the audience restriction field of the asseration. When left empty, "
|
||||||
|
"no audience restriction will be added."
|
||||||
|
)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
issuer = models.TextField(
|
issuer = models.TextField(
|
||||||
help_text=_("Also known as EntityID"), default="authentik"
|
help_text=_("Also known as EntityID"), default="authentik"
|
||||||
|
@ -127,11 +127,14 @@ class AssertionProcessor:
|
|||||||
conditions = Element(f"{{{NS_SAML_ASSERTION}}}Conditions")
|
conditions = Element(f"{{{NS_SAML_ASSERTION}}}Conditions")
|
||||||
conditions.attrib["NotBefore"] = self._valid_not_before
|
conditions.attrib["NotBefore"] = self._valid_not_before
|
||||||
conditions.attrib["NotOnOrAfter"] = self._valid_not_on_or_after
|
conditions.attrib["NotOnOrAfter"] = self._valid_not_on_or_after
|
||||||
audience_restriction = SubElement(
|
if self.provider.audience != "":
|
||||||
conditions, f"{{{NS_SAML_ASSERTION}}}AudienceRestriction"
|
audience_restriction = SubElement(
|
||||||
)
|
conditions, f"{{{NS_SAML_ASSERTION}}}AudienceRestriction"
|
||||||
audience = SubElement(audience_restriction, f"{{{NS_SAML_ASSERTION}}}Audience")
|
)
|
||||||
audience.text = self.provider.audience
|
audience = SubElement(
|
||||||
|
audience_restriction, f"{{{NS_SAML_ASSERTION}}}Audience"
|
||||||
|
)
|
||||||
|
audience.text = self.provider.audience
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
def get_name_id(self) -> Element:
|
def get_name_id(self) -> Element:
|
||||||
|
@ -5,6 +5,7 @@ from typing import Optional
|
|||||||
import xmlsec
|
import xmlsec
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.x509 import load_pem_x509_certificate
|
from cryptography.x509 import load_pem_x509_certificate
|
||||||
|
from defusedxml.lxml import fromstring
|
||||||
from lxml import etree # nosec
|
from lxml import etree # nosec
|
||||||
from structlog import get_logger
|
from structlog import get_logger
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ LOGGER = get_logger()
|
|||||||
|
|
||||||
def format_pem_certificate(unformatted_cert: str) -> str:
|
def format_pem_certificate(unformatted_cert: str) -> str:
|
||||||
"""Format single, inline certificate into PEM Format"""
|
"""Format single, inline certificate into PEM Format"""
|
||||||
|
# Ensure that all linebreaks are gone
|
||||||
|
unformatted_cert = unformatted_cert.replace("\n", "")
|
||||||
chunks, chunk_size = len(unformatted_cert), 64
|
chunks, chunk_size = len(unformatted_cert), 64
|
||||||
lines = [PEM_HEADER]
|
lines = [PEM_HEADER]
|
||||||
for i in range(0, chunks, chunk_size):
|
for i in range(0, chunks, chunk_size):
|
||||||
@ -52,10 +55,14 @@ class ServiceProviderMetadata:
|
|||||||
provider.issuer = self.entity_id
|
provider.issuer = self.entity_id
|
||||||
provider.sp_binding = self.acs_binding
|
provider.sp_binding = self.acs_binding
|
||||||
provider.acs_url = self.acs_location
|
provider.acs_url = self.acs_location
|
||||||
if self.signing_keypair:
|
if self.signing_keypair and self.auth_n_request_signed:
|
||||||
self.signing_keypair.name = f"Provider {name} - SAML Signing Certificate"
|
self.signing_keypair.name = f"Provider {name} - SAML Signing Certificate"
|
||||||
self.signing_keypair.save()
|
self.signing_keypair.save()
|
||||||
provider.signing_kp = self.signing_keypair
|
provider.verification_kp = self.signing_keypair
|
||||||
|
if self.assertion_signed:
|
||||||
|
provider.signing_kp = CertificateKeyPair.objects.exclude(
|
||||||
|
key_data__iexact=""
|
||||||
|
).first()
|
||||||
return provider
|
return provider
|
||||||
|
|
||||||
|
|
||||||
@ -104,7 +111,7 @@ class ServiceProviderMetadataParser:
|
|||||||
|
|
||||||
def parse(self, raw_xml: str) -> ServiceProviderMetadata:
|
def parse(self, raw_xml: str) -> ServiceProviderMetadata:
|
||||||
"""Parse raw XML to ServiceProviderMetadata"""
|
"""Parse raw XML to ServiceProviderMetadata"""
|
||||||
root = etree.fromstring(raw_xml) # nosec
|
root = fromstring(raw_xml.encode())
|
||||||
|
|
||||||
entity_id = root.attrib["entityID"]
|
entity_id = root.attrib["entityID"]
|
||||||
sp_sso_descriptors = root.findall(f"{{{NS_SAML_METADATA}}}SPSSODescriptor")
|
sp_sso_descriptors = root.findall(f"{{{NS_SAML_METADATA}}}SPSSODescriptor")
|
||||||
|
@ -84,7 +84,9 @@ class TestServiceProviderMetadataParser(TestCase):
|
|||||||
provider.issuer, "http://localhost:8080/apps/user_saml/saml/metadata"
|
provider.issuer, "http://localhost:8080/apps/user_saml/saml/metadata"
|
||||||
)
|
)
|
||||||
self.assertEqual(provider.sp_binding, SAMLBindings.POST)
|
self.assertEqual(provider.sp_binding, SAMLBindings.POST)
|
||||||
self.assertEqual(provider.signing_kp.certificate_data, CERT)
|
self.assertEqual(provider.verification_kp.certificate_data, CERT)
|
||||||
|
self.assertIsNotNone(provider.signing_kp)
|
||||||
|
self.assertEqual(provider.audience, "")
|
||||||
|
|
||||||
def test_with_signing_cert_invalid_signature(self):
|
def test_with_signing_cert_invalid_signature(self):
|
||||||
"""Test Metadata with signing cert (invalid signature)"""
|
"""Test Metadata with signing cert (invalid signature)"""
|
||||||
|
@ -270,8 +270,14 @@ class MetadataImportView(LoginRequiredMixin, FormView):
|
|||||||
form.cleaned_data["metadata"].read().decode()
|
form.cleaned_data["metadata"].read().decode()
|
||||||
)
|
)
|
||||||
provider = metadata.to_provider(form.cleaned_data["provider_name"])
|
provider = metadata.to_provider(form.cleaned_data["provider_name"])
|
||||||
|
provider.authorization_flow = form.cleaned_data["authorization_flow"]
|
||||||
provider.save()
|
provider.save()
|
||||||
messages.success(self.request, _("Successfully created Provider"))
|
messages.success(self.request, _("Successfully created Provider"))
|
||||||
except ValueError:
|
except ValueError as exc:
|
||||||
messages.error(self.request, _("Failed to import Metadata."))
|
LOGGER.warning(exc)
|
||||||
|
messages.error(
|
||||||
|
self.request,
|
||||||
|
_("Failed to import Metadata: %(message)s" % {"message": str(exc)}),
|
||||||
|
)
|
||||||
|
return super().form_invalid(form)
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
@ -142,6 +142,7 @@ SWAGGER_SETTINGS = {
|
|||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
"DEFAULT_PAGINATION_CLASS": "authentik.api.pagination.Pagination",
|
"DEFAULT_PAGINATION_CLASS": "authentik.api.pagination.Pagination",
|
||||||
"PAGE_SIZE": 100,
|
"PAGE_SIZE": 100,
|
||||||
|
"DATETIME_FORMAT": "%s",
|
||||||
"DEFAULT_FILTER_BACKENDS": [
|
"DEFAULT_FILTER_BACKENDS": [
|
||||||
"rest_framework_guardian.filters.ObjectPermissionsFilter",
|
"rest_framework_guardian.filters.ObjectPermissionsFilter",
|
||||||
"django_filters.rest_framework.DjangoFilterBackend",
|
"django_filters.rest_framework.DjangoFilterBackend",
|
||||||
|
@ -19,7 +19,7 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
server:
|
server:
|
||||||
image: beryju/authentik:${AUTHENTIK_TAG:-0.14.0-rc1}
|
image: beryju/authentik:${AUTHENTIK_TAG:-0.14.2-stable}
|
||||||
command: server
|
command: server
|
||||||
environment:
|
environment:
|
||||||
AUTHENTIK_REDIS__HOST: redis
|
AUTHENTIK_REDIS__HOST: redis
|
||||||
@ -44,7 +44,7 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
worker:
|
worker:
|
||||||
image: beryju/authentik:${AUTHENTIK_TAG:-0.14.0-rc1}
|
image: beryju/authentik:${AUTHENTIK_TAG:-0.14.2-stable}
|
||||||
command: worker
|
command: worker
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
@ -60,7 +60,7 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
static:
|
static:
|
||||||
image: beryju/authentik-static:${AUTHENTIK_TAG:-0.14.0-rc1}
|
image: beryju/authentik-static:${AUTHENTIK_TAG:-0.14.2-stable}
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
labels:
|
labels:
|
||||||
|
@ -4,7 +4,7 @@ name: authentik
|
|||||||
home: https://goauthentik.io
|
home: https://goauthentik.io
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/BeryJu/authentik
|
- https://github.com/BeryJu/authentik
|
||||||
version: "0.14.0-rc1"
|
version: "0.14.2-stable"
|
||||||
icon: https://raw.githubusercontent.com/BeryJu/authentik/master/web/icons/icon.svg
|
icon: https://raw.githubusercontent.com/BeryJu/authentik/master/web/icons/icon.svg
|
||||||
dependencies:
|
dependencies:
|
||||||
- name: postgresql
|
- name: postgresql
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|-----------------------------------|-------------------------|-------------|
|
|-----------------------------------|-------------------------|-------------|
|
||||||
| image.name | beryju/authentik | Image used to run the authentik server and worker |
|
| 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.name_static | beryju/authentik-static | Image used to run the authentik static server (CSS and JS Files) |
|
||||||
| image.tag | 0.14.0-rc1 | Image tag |
|
| image.tag | 0.14.2-stable | Image tag |
|
||||||
| image.pullPolicy | IfNotPresent | Image Pull Policy used for all deployments |
|
| image.pullPolicy | IfNotPresent | Image Pull Policy used for all deployments |
|
||||||
| serverReplicas | 1 | Replicas for the Server deployment |
|
| serverReplicas | 1 | Replicas for the Server deployment |
|
||||||
| workerReplicas | 1 | Replicas for the Worker deployment |
|
| workerReplicas | 1 | Replicas for the Worker deployment |
|
||||||
|
@ -5,7 +5,7 @@ image:
|
|||||||
name: beryju/authentik
|
name: beryju/authentik
|
||||||
name_static: beryju/authentik-static
|
name_static: beryju/authentik-static
|
||||||
name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended
|
name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended
|
||||||
tag: 0.14.0-rc1
|
tag: 0.14.2-stable
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
serverReplicas: 1
|
serverReplicas: 1
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
const VERSION = "0.14.0-rc1"
|
const VERSION = "0.14.2-stable"
|
||||||
|
58
swagger.yaml
58
swagger.yaml
@ -868,6 +868,11 @@ paths:
|
|||||||
operationId: events_events_list
|
operationId: events_events_list
|
||||||
description: Event Read-Only Viewset
|
description: Event Read-Only Viewset
|
||||||
parameters:
|
parameters:
|
||||||
|
- name: action
|
||||||
|
in: query
|
||||||
|
description: ''
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
- name: ordering
|
- name: ordering
|
||||||
in: query
|
in: query
|
||||||
description: Which field to use when ordering the results.
|
description: Which field to use when ordering the results.
|
||||||
@ -919,6 +924,11 @@ paths:
|
|||||||
operationId: events_events_top_per_user
|
operationId: events_events_top_per_user
|
||||||
description: Get the top_n events grouped by user count
|
description: Get the top_n events grouped by user count
|
||||||
parameters:
|
parameters:
|
||||||
|
- name: action
|
||||||
|
in: query
|
||||||
|
description: ''
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
- name: ordering
|
- name: ordering
|
||||||
in: query
|
in: query
|
||||||
description: Which field to use when ordering the results.
|
description: Which field to use when ordering the results.
|
||||||
@ -1194,6 +1204,26 @@ paths:
|
|||||||
operationId: flows_instances_list
|
operationId: flows_instances_list
|
||||||
description: Flow Viewset
|
description: Flow Viewset
|
||||||
parameters:
|
parameters:
|
||||||
|
- name: flow_uuid
|
||||||
|
in: query
|
||||||
|
description: ''
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: name
|
||||||
|
in: query
|
||||||
|
description: ''
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: slug
|
||||||
|
in: query
|
||||||
|
description: ''
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: designation
|
||||||
|
in: query
|
||||||
|
description: ''
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
- name: ordering
|
- name: ordering
|
||||||
in: query
|
in: query
|
||||||
description: Which field to use when ordering the results.
|
description: Which field to use when ordering the results.
|
||||||
@ -7974,9 +8004,9 @@ definitions:
|
|||||||
minLength: 1
|
minLength: 1
|
||||||
audience:
|
audience:
|
||||||
title: Audience
|
title: Audience
|
||||||
description: Value of the audience restriction field of the asseration.
|
description: Value of the audience restriction field of the asseration. When
|
||||||
|
left empty, no audience restriction will be added.
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
|
||||||
issuer:
|
issuer:
|
||||||
title: Issuer
|
title: Issuer
|
||||||
description: Also known as EntityID
|
description: Also known as EntityID
|
||||||
@ -8133,6 +8163,14 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
x-nullable: true
|
x-nullable: true
|
||||||
|
verbose_name:
|
||||||
|
title: Verbose name
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name_plural:
|
||||||
|
title: Verbose name plural
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
__type__:
|
__type__:
|
||||||
title: 'type '
|
title: 'type '
|
||||||
type: string
|
type: string
|
||||||
@ -8181,6 +8219,14 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
x-nullable: true
|
x-nullable: true
|
||||||
|
verbose_name:
|
||||||
|
title: Verbose name
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name_plural:
|
||||||
|
title: Verbose name plural
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
server_uri:
|
server_uri:
|
||||||
title: Server URI
|
title: Server URI
|
||||||
type: string
|
type: string
|
||||||
@ -8296,6 +8342,14 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
x-nullable: true
|
x-nullable: true
|
||||||
|
verbose_name:
|
||||||
|
title: Verbose name
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name_plural:
|
||||||
|
title: Verbose name plural
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
provider_type:
|
provider_type:
|
||||||
title: Provider type
|
title: Provider type
|
||||||
type: string
|
type: string
|
||||||
|
138
web/package-lock.json
generated
138
web/package-lock.json
generated
@ -304,9 +304,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/codemirror": {
|
"@types/codemirror": {
|
||||||
"version": "0.0.102",
|
"version": "0.0.103",
|
||||||
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.102.tgz",
|
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.103.tgz",
|
||||||
"integrity": "sha512-WZZW8VL8BAzzAZWkiYnM5VsYz1qWYieRqHPPtC/BB015QXd3LPXtBlbRYA8lauKgM10qWYeLH8p5LsIn2SLXfA==",
|
"integrity": "sha512-dYQTrIcZal0pnYz/ODjpJB+yadKJhGHywylAlHKjE8VSzGiw2A+6S+hD6jfyXw02ToFR9DO52X+O1pvHn31sbg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/tern": "*"
|
"@types/tern": "*"
|
||||||
}
|
}
|
||||||
@ -393,13 +393,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/eslint-plugin": {
|
"@typescript-eslint/eslint-plugin": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.11.1.tgz",
|
||||||
"integrity": "sha512-x4arJMXBxyD6aBXLm3W7mSDZRiABzy+2PCLJbL7OPqlp53VXhaA1HKK7R2rTee5OlRhnUgnp8lZyVIqjnyPT6g==",
|
"integrity": "sha512-fABclAX2QIEDmTMk6Yd7Muv1CzFLwWM4505nETzRHpP3br6jfahD9UUJkhnJ/g2m7lwfz8IlswcwGGPGiq9exw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/experimental-utils": "4.11.0",
|
"@typescript-eslint/experimental-utils": "4.11.1",
|
||||||
"@typescript-eslint/scope-manager": "4.11.0",
|
"@typescript-eslint/scope-manager": "4.11.1",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"functional-red-black-tree": "^1.0.1",
|
"functional-red-black-tree": "^1.0.1",
|
||||||
"regexpp": "^3.0.0",
|
"regexpp": "^3.0.0",
|
||||||
@ -408,71 +408,71 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": {
|
"@typescript-eslint/scope-manager": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.11.1.tgz",
|
||||||
"integrity": "sha512-6VSTm/4vC2dHM3ySDW9Kl48en+yLNfVV6LECU8jodBHQOhO8adAVizaZ1fV0QGZnLQjQ/y0aBj5/KXPp2hBTjA==",
|
"integrity": "sha512-Al2P394dx+kXCl61fhrrZ1FTI7qsRDIUiVSuN6rTwss6lUn8uVO2+nnF4AvO0ug8vMsy3ShkbxLu/uWZdTtJMQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"@typescript-eslint/visitor-keys": "4.11.0"
|
"@typescript-eslint/visitor-keys": "4.11.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/types": {
|
"@typescript-eslint/types": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.11.1.tgz",
|
||||||
"integrity": "sha512-XXOdt/NPX++txOQHM1kUMgJUS43KSlXGdR/aDyEwuAEETwuPt02Nc7v+s57PzuSqMbNLclblQdv3YcWOdXhQ7g==",
|
"integrity": "sha512-5kvd38wZpqGY4yP/6W3qhYX6Hz0NwUbijVsX2rxczpY6OXaMxh0+5E5uLJKVFwaBM7PJe1wnMym85NfKYIh6CA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@typescript-eslint/visitor-keys": {
|
"@typescript-eslint/visitor-keys": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.1.tgz",
|
||||||
"integrity": "sha512-tRYKyY0i7cMk6v4UIOCjl1LhuepC/pc6adQqJk4Is3YcC6k46HvsV9Wl7vQoLbm9qADgeujiT7KdLrylvFIQ+A==",
|
"integrity": "sha512-IrlBhD9bm4bdYcS8xpWarazkKXlE7iYb1HzRuyBP114mIaj5DJPo11Us1HgH60dTt41TCZXMaTCAW+OILIYPOg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"eslint-visitor-keys": "^2.0.0"
|
"eslint-visitor-keys": "^2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/experimental-utils": {
|
"@typescript-eslint/experimental-utils": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.11.1.tgz",
|
||||||
"integrity": "sha512-1VC6mSbYwl1FguKt8OgPs8xxaJgtqFpjY/UzUYDBKq4pfQ5lBvN2WVeqYkzf7evW42axUHYl2jm9tNyFsb8oLg==",
|
"integrity": "sha512-mAlWowT4A6h0TC9F+J5pdbEhjNiEMO+kqPKQ4sc3fVieKL71dEqfkKgtcFVSX3cjSBwYwhImaQ/mXQF0oaI38g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/json-schema": "^7.0.3",
|
"@types/json-schema": "^7.0.3",
|
||||||
"@typescript-eslint/scope-manager": "4.11.0",
|
"@typescript-eslint/scope-manager": "4.11.1",
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"@typescript-eslint/typescript-estree": "4.11.0",
|
"@typescript-eslint/typescript-estree": "4.11.1",
|
||||||
"eslint-scope": "^5.0.0",
|
"eslint-scope": "^5.0.0",
|
||||||
"eslint-utils": "^2.0.0"
|
"eslint-utils": "^2.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": {
|
"@typescript-eslint/scope-manager": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.11.1.tgz",
|
||||||
"integrity": "sha512-6VSTm/4vC2dHM3ySDW9Kl48en+yLNfVV6LECU8jodBHQOhO8adAVizaZ1fV0QGZnLQjQ/y0aBj5/KXPp2hBTjA==",
|
"integrity": "sha512-Al2P394dx+kXCl61fhrrZ1FTI7qsRDIUiVSuN6rTwss6lUn8uVO2+nnF4AvO0ug8vMsy3ShkbxLu/uWZdTtJMQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"@typescript-eslint/visitor-keys": "4.11.0"
|
"@typescript-eslint/visitor-keys": "4.11.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/types": {
|
"@typescript-eslint/types": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.11.1.tgz",
|
||||||
"integrity": "sha512-XXOdt/NPX++txOQHM1kUMgJUS43KSlXGdR/aDyEwuAEETwuPt02Nc7v+s57PzuSqMbNLclblQdv3YcWOdXhQ7g==",
|
"integrity": "sha512-5kvd38wZpqGY4yP/6W3qhYX6Hz0NwUbijVsX2rxczpY6OXaMxh0+5E5uLJKVFwaBM7PJe1wnMym85NfKYIh6CA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@typescript-eslint/typescript-estree": {
|
"@typescript-eslint/typescript-estree": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.1.tgz",
|
||||||
"integrity": "sha512-eA6sT5dE5RHAFhtcC+b5WDlUIGwnO9b0yrfGa1mIOIAjqwSQCpXbLiFmKTdRbQN/xH2EZkGqqLDrKUuYOZ0+Hg==",
|
"integrity": "sha512-tC7MKZIMRTYxQhrVAFoJq/DlRwv1bnqA4/S2r3+HuHibqvbrPcyf858lNzU7bFmy4mLeIHFYr34ar/1KumwyRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"@typescript-eslint/visitor-keys": "4.11.0",
|
"@typescript-eslint/visitor-keys": "4.11.1",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"globby": "^11.0.1",
|
"globby": "^11.0.1",
|
||||||
"is-glob": "^4.0.1",
|
"is-glob": "^4.0.1",
|
||||||
@ -482,12 +482,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/visitor-keys": {
|
"@typescript-eslint/visitor-keys": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.1.tgz",
|
||||||
"integrity": "sha512-tRYKyY0i7cMk6v4UIOCjl1LhuepC/pc6adQqJk4Is3YcC6k46HvsV9Wl7vQoLbm9qADgeujiT7KdLrylvFIQ+A==",
|
"integrity": "sha512-IrlBhD9bm4bdYcS8xpWarazkKXlE7iYb1HzRuyBP114mIaj5DJPo11Us1HgH60dTt41TCZXMaTCAW+OILIYPOg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"eslint-visitor-keys": "^2.0.0"
|
"eslint-visitor-keys": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -508,41 +508,41 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/parser": {
|
"@typescript-eslint/parser": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.11.1.tgz",
|
||||||
"integrity": "sha512-NBTtKCC7ZtuxEV5CrHUO4Pg2s784pvavc3cnz6V+oJvVbK4tH9135f/RBP6eUA2KHiFKAollSrgSctQGmHbqJQ==",
|
"integrity": "sha512-BJ3jwPQu1jeynJ5BrjLuGfK/UJu6uwHxJ/di7sanqmUmxzmyIcd3vz58PMR7wpi8k3iWq2Q11KMYgZbUpRoIPw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/scope-manager": "4.11.0",
|
"@typescript-eslint/scope-manager": "4.11.1",
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"@typescript-eslint/typescript-estree": "4.11.0",
|
"@typescript-eslint/typescript-estree": "4.11.1",
|
||||||
"debug": "^4.1.1"
|
"debug": "^4.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/scope-manager": {
|
"@typescript-eslint/scope-manager": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.11.1.tgz",
|
||||||
"integrity": "sha512-6VSTm/4vC2dHM3ySDW9Kl48en+yLNfVV6LECU8jodBHQOhO8adAVizaZ1fV0QGZnLQjQ/y0aBj5/KXPp2hBTjA==",
|
"integrity": "sha512-Al2P394dx+kXCl61fhrrZ1FTI7qsRDIUiVSuN6rTwss6lUn8uVO2+nnF4AvO0ug8vMsy3ShkbxLu/uWZdTtJMQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"@typescript-eslint/visitor-keys": "4.11.0"
|
"@typescript-eslint/visitor-keys": "4.11.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/types": {
|
"@typescript-eslint/types": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.11.1.tgz",
|
||||||
"integrity": "sha512-XXOdt/NPX++txOQHM1kUMgJUS43KSlXGdR/aDyEwuAEETwuPt02Nc7v+s57PzuSqMbNLclblQdv3YcWOdXhQ7g==",
|
"integrity": "sha512-5kvd38wZpqGY4yP/6W3qhYX6Hz0NwUbijVsX2rxczpY6OXaMxh0+5E5uLJKVFwaBM7PJe1wnMym85NfKYIh6CA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@typescript-eslint/typescript-estree": {
|
"@typescript-eslint/typescript-estree": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.1.tgz",
|
||||||
"integrity": "sha512-eA6sT5dE5RHAFhtcC+b5WDlUIGwnO9b0yrfGa1mIOIAjqwSQCpXbLiFmKTdRbQN/xH2EZkGqqLDrKUuYOZ0+Hg==",
|
"integrity": "sha512-tC7MKZIMRTYxQhrVAFoJq/DlRwv1bnqA4/S2r3+HuHibqvbrPcyf858lNzU7bFmy4mLeIHFYr34ar/1KumwyRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"@typescript-eslint/visitor-keys": "4.11.0",
|
"@typescript-eslint/visitor-keys": "4.11.1",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"globby": "^11.0.1",
|
"globby": "^11.0.1",
|
||||||
"is-glob": "^4.0.1",
|
"is-glob": "^4.0.1",
|
||||||
@ -568,12 +568,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/visitor-keys": {
|
"@typescript-eslint/visitor-keys": {
|
||||||
"version": "4.11.0",
|
"version": "4.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.1.tgz",
|
||||||
"integrity": "sha512-tRYKyY0i7cMk6v4UIOCjl1LhuepC/pc6adQqJk4Is3YcC6k46HvsV9Wl7vQoLbm9qADgeujiT7KdLrylvFIQ+A==",
|
"integrity": "sha512-IrlBhD9bm4bdYcS8xpWarazkKXlE7iYb1HzRuyBP114mIaj5DJPo11Us1HgH60dTt41TCZXMaTCAW+OILIYPOg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/types": "4.11.0",
|
"@typescript-eslint/types": "4.11.1",
|
||||||
"eslint-visitor-keys": "^2.0.0"
|
"eslint-visitor-keys": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -968,9 +968,9 @@
|
|||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
},
|
},
|
||||||
"construct-style-sheets-polyfill": {
|
"construct-style-sheets-polyfill": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.6",
|
||||||
"resolved": "https://registry.npmjs.org/construct-style-sheets-polyfill/-/construct-style-sheets-polyfill-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/construct-style-sheets-polyfill/-/construct-style-sheets-polyfill-2.4.6.tgz",
|
||||||
"integrity": "sha512-ECo96zFPsdghrMJmJ0vomcHsqLOIYpudobcNCIPeMubyFzBcLCfljuY0oFA3DD7btiFqB0sZ+0szbsiE8I24VA=="
|
"integrity": "sha512-lU0to7dFDjKslMF+M5NUa4s0RQMBRVyZMXvD/vp7vmjdEPgziTkHSfZHQxfoIvVWajWRJUVJMLfrMwcx8fTh4A=="
|
||||||
},
|
},
|
||||||
"copy-descriptor": {
|
"copy-descriptor": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
"@sentry/browser": "^5.29.2",
|
"@sentry/browser": "^5.29.2",
|
||||||
"@sentry/tracing": "^5.29.2",
|
"@sentry/tracing": "^5.29.2",
|
||||||
"@types/chart.js": "^2.9.29",
|
"@types/chart.js": "^2.9.29",
|
||||||
"@types/codemirror": "0.0.102",
|
"@types/codemirror": "0.0.103",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
"codemirror": "^5.59.0",
|
"codemirror": "^5.59.0",
|
||||||
"construct-style-sheets-polyfill": "^2.4.3",
|
"construct-style-sheets-polyfill": "^2.4.6",
|
||||||
"flowchart.js": "^1.15.0",
|
"flowchart.js": "^1.15.0",
|
||||||
"lit-element": "^2.4.0",
|
"lit-element": "^2.4.0",
|
||||||
"lit-html": "^1.3.0",
|
"lit-html": "^1.3.0",
|
||||||
@ -27,8 +27,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-typescript": "^8.1.0",
|
"@rollup/plugin-typescript": "^8.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.11.0",
|
"@typescript-eslint/eslint-plugin": "^4.11.1",
|
||||||
"@typescript-eslint/parser": "^4.11.0",
|
"@typescript-eslint/parser": "^4.11.1",
|
||||||
"eslint": "^7.16.0",
|
"eslint": "^7.16.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-lit": "^1.3.0",
|
"eslint-plugin-lit": "^1.3.0",
|
||||||
|
@ -1,6 +1,37 @@
|
|||||||
import { DefaultClient } from "./Client";
|
import { DefaultClient, PBResponse, QueryArguments } from "./Client";
|
||||||
|
|
||||||
|
export interface EventUser {
|
||||||
|
pk: number;
|
||||||
|
email?: string;
|
||||||
|
username: string;
|
||||||
|
on_behalf_of?: EventUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EventContext {
|
||||||
|
[key: string]: EventContext | string | number | string[];
|
||||||
|
}
|
||||||
|
|
||||||
export class Event {
|
export class Event {
|
||||||
|
pk: string;
|
||||||
|
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<PBResponse<Event>> {
|
||||||
|
return DefaultClient.fetch<PBResponse<Event>>(["events", "events"], filter);
|
||||||
|
}
|
||||||
|
|
||||||
// events/events/top_per_user/?filter_action=authorize_application
|
// events/events/top_per_user/?filter_action=authorize_application
|
||||||
static topForUser(action: string): Promise<TopNEvent[]> {
|
static topForUser(action: string): Promise<TopNEvent[]> {
|
||||||
return DefaultClient.fetch<TopNEvent[]>(["events", "events", "top_per_user"], {
|
return DefaultClient.fetch<TopNEvent[]>(["events", "events", "top_per_user"], {
|
||||||
|
@ -137,6 +137,9 @@ select[multiple] {
|
|||||||
--pf-c-table--cell--Color: var(--ak-dark-foreground);
|
--pf-c-table--cell--Color: var(--ak-dark-foreground);
|
||||||
}
|
}
|
||||||
.pf-c-table__text {
|
.pf-c-table__text {
|
||||||
|
color: var(--ak-dark-foreground);
|
||||||
|
}
|
||||||
|
.pf-c-table__sort:not(.pf-m-selected) .pf-c-table__button .pf-c-table__text {
|
||||||
color: var(--ak-dark-foreground) !important;
|
color: var(--ak-dark-foreground) !important;
|
||||||
}
|
}
|
||||||
.pf-c-table__sort-indicator i {
|
.pf-c-table__sort-indicator i {
|
||||||
|
@ -28,4 +28,4 @@ export const ColorStyles = css`
|
|||||||
background-color: var(--pf-global--danger-color--100);
|
background-color: var(--pf-global--danger-color--100);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const VERSION = "0.14.0-rc1";
|
export const VERSION = "0.14.2-stable";
|
||||||
|
@ -115,6 +115,7 @@ export abstract class Table<T> extends LitElement {
|
|||||||
this.apiEndpoint(this.page).then((r) => {
|
this.apiEndpoint(this.page).then((r) => {
|
||||||
this.data = r;
|
this.data = r;
|
||||||
this.page = r.pagination.current;
|
this.page = r.pagination.current;
|
||||||
|
this.expandedRows = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +145,7 @@ export abstract class Table<T> extends LitElement {
|
|||||||
<tr role="row">
|
<tr role="row">
|
||||||
<td role="cell" colspan="8">
|
<td role="cell" colspan="8">
|
||||||
<div class="pf-l-bullseye">
|
<div class="pf-l-bullseye">
|
||||||
${inner ? inner : html`<ak-empty-state header="none"></ak-empty-state>`}
|
${inner ? inner : html`<ak-empty-state header="${gettext("No elements found.")}"></ak-empty-state>`}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -178,7 +179,7 @@ export abstract class Table<T> extends LitElement {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr class="pf-c-table__expandable-row ${this.expandedRows[idx] ? "pf-m-expanded" : ""}" role="row">
|
<tr class="pf-c-table__expandable-row ${this.expandedRows[idx] ? "pf-m-expanded" : ""}" role="row">
|
||||||
<td></td>
|
<td></td>
|
||||||
${this.renderExpanded(item)}
|
${this.expandedRows[idx] ? this.renderExpanded(item) : html``}
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>`;
|
</tbody>`;
|
||||||
});
|
});
|
||||||
|
@ -26,9 +26,9 @@ export class TableSearch extends LitElement {
|
|||||||
if (el.value === "") return;
|
if (el.value === "") return;
|
||||||
this.onSearch(el?.value);
|
this.onSearch(el?.value);
|
||||||
}}>
|
}}>
|
||||||
<input class="pf-c-form-control" name="search" type="search" placeholder="Search..." value="${ifDefined(this.value)}" @search=${() => {
|
<input class="pf-c-form-control" name="search" type="search" placeholder="Search..." value="${ifDefined(this.value)}" @search=${(ev: Event) => {
|
||||||
if (!this.onSearch) return;
|
if (!this.onSearch) return;
|
||||||
this.onSearch("");
|
this.onSearch((ev.target as HTMLInputElement).value);
|
||||||
}}>
|
}}>
|
||||||
<button class="pf-c-button pf-m-control" type="submit">
|
<button class="pf-c-button pf-m-control" type="submit">
|
||||||
<i class="fas fa-search" aria-hidden="true"></i>
|
<i class="fas fa-search" aria-hidden="true"></i>
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
class="pf-c-page__main"
|
class="pf-c-page__main"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
id="main-content"
|
id="main-content"
|
||||||
defaultUrl="/library/"
|
defaultUrl="/library"
|
||||||
>
|
>
|
||||||
</ak-router-outlet>
|
</ak-router-outlet>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,16 +9,16 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
|||||||
new SidebarItem("Monitor").children(
|
new SidebarItem("Monitor").children(
|
||||||
new SidebarItem("Overview", "/administration/overview"),
|
new SidebarItem("Overview", "/administration/overview"),
|
||||||
new SidebarItem("System Tasks", "/administration/tasks/"),
|
new SidebarItem("System Tasks", "/administration/tasks/"),
|
||||||
new SidebarItem("Events", "/events/log/"),
|
new SidebarItem("Events", "/events"),
|
||||||
).when((): Promise<boolean> => {
|
).when((): Promise<boolean> => {
|
||||||
return User.me().then(u => u.is_superuser);
|
return User.me().then(u => u.is_superuser);
|
||||||
}),
|
}),
|
||||||
new SidebarItem("Administration").children(
|
new SidebarItem("Administration").children(
|
||||||
new SidebarItem("Applications", "/applications").activeWhen(
|
new SidebarItem("Applications", "/applications").activeWhen(
|
||||||
`^/applications/(?<slug>${SLUG_REGEX})/$`
|
`^/applications/(?<slug>${SLUG_REGEX})$`
|
||||||
),
|
),
|
||||||
new SidebarItem("Sources", "/administration/sources/").activeWhen(
|
new SidebarItem("Sources", "/administration/sources/").activeWhen(
|
||||||
`^/sources/(?<slug>${SLUG_REGEX})/$`,
|
`^/sources/(?<slug>${SLUG_REGEX})$`,
|
||||||
),
|
),
|
||||||
new SidebarItem("Providers", "/administration/providers/"),
|
new SidebarItem("Providers", "/administration/providers/"),
|
||||||
new SidebarItem("Outposts", "/administration/outposts/"),
|
new SidebarItem("Outposts", "/administration/outposts/"),
|
||||||
|
@ -8,7 +8,7 @@ import "../elements/sidebar/SidebarHamburger";
|
|||||||
|
|
||||||
export abstract class Interface extends LitElement {
|
export abstract class Interface extends LitElement {
|
||||||
@property({type: Boolean})
|
@property({type: Boolean})
|
||||||
sidebarOpen?: boolean;
|
sidebarOpen = true;
|
||||||
|
|
||||||
abstract get sidebar(): SidebarItem[];
|
abstract get sidebar(): SidebarItem[];
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ export abstract class Interface extends LitElement {
|
|||||||
<ak-sidebar class="pf-c-page__sidebar ${this.sidebarOpen ? "pf-m-expanded" : "pf-m-collapsed"}" .items=${this.sidebar}>
|
<ak-sidebar class="pf-c-page__sidebar ${this.sidebarOpen ? "pf-m-expanded" : "pf-m-collapsed"}" .items=${this.sidebar}>
|
||||||
</ak-sidebar>
|
</ak-sidebar>
|
||||||
<main class="pf-c-page__main">
|
<main class="pf-c-page__main">
|
||||||
<ak-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/library/">
|
<ak-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/library">
|
||||||
</ak-router-outlet>
|
</ak-router-outlet>
|
||||||
</main>
|
</main>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
@ -51,7 +51,7 @@ export class ApplicationListPage extends TablePage<Application> {
|
|||||||
${item.meta_icon ?
|
${item.meta_icon ?
|
||||||
html`<img class="app-icon pf-c-avatar" src="${item.meta_icon}" alt="${gettext("Application Icon")}">` :
|
html`<img class="app-icon pf-c-avatar" src="${item.meta_icon}" alt="${gettext("Application Icon")}">` :
|
||||||
html`<i class="pf-icon pf-icon-arrow"></i>`}`,
|
html`<i class="pf-icon pf-icon-arrow"></i>`}`,
|
||||||
html`<a href="#/applications/${item.slug}/">
|
html`<a href="#/applications/${item.slug}">
|
||||||
<div>
|
<div>
|
||||||
${item.name}
|
${item.name}
|
||||||
</div>
|
</div>
|
||||||
|
139
web/src/pages/events/EventInfo.ts
Normal file
139
web/src/pages/events/EventInfo.ts
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import { gettext } from "django";
|
||||||
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
|
import { Event, EventContext } from "../../api/Events";
|
||||||
|
import { Flow } from "../../api/Flows";
|
||||||
|
import { COMMON_STYLES } from "../../common/styles";
|
||||||
|
import "../../elements/Spinner";
|
||||||
|
import { SpinnerSize } from "../../elements/Spinner";
|
||||||
|
|
||||||
|
@customElement("ak-event-info")
|
||||||
|
export class EventInfo extends LitElement {
|
||||||
|
|
||||||
|
@property({attribute: false})
|
||||||
|
event?: Event;
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return COMMON_STYLES.concat(
|
||||||
|
css`
|
||||||
|
code {
|
||||||
|
display: block;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getModelInfo(context: EventContext): TemplateResult {
|
||||||
|
return html`<ul class="pf-c-list">
|
||||||
|
<li>${gettext("UID")}: ${context.pk as string}</li>
|
||||||
|
<li>${gettext("Name")}: ${context.name as string}</li>
|
||||||
|
<li>${gettext("App")}: ${context.app as string}</li>
|
||||||
|
<li>${gettext("Model Name")}: ${context.model_name as string}</li>
|
||||||
|
</ul>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultResponse(): TemplateResult {
|
||||||
|
return html`<div class="pf-l-flex">
|
||||||
|
<div class="pf-l-flex__item">
|
||||||
|
<h3>${gettext("Context")}</h3>
|
||||||
|
<code>${JSON.stringify(this.event?.context)}</code>
|
||||||
|
</div>
|
||||||
|
<div class="pf-l-flex__item">
|
||||||
|
<h3>${gettext("User")}</h3>
|
||||||
|
<code>${JSON.stringify(this.event?.user)}</code>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
if (!this.event) {
|
||||||
|
return html`<ak-spinner size=${SpinnerSize.Medium}></ak-spinner>`;
|
||||||
|
}
|
||||||
|
switch (this.event?.action) {
|
||||||
|
case "model_created":
|
||||||
|
case "model_updated":
|
||||||
|
case "model_deleted":
|
||||||
|
return html`
|
||||||
|
<h3>${gettext("Affected model:")}</h3><hr>
|
||||||
|
${this.getModelInfo(this.event.context.model as EventContext)}
|
||||||
|
`;
|
||||||
|
case "authorize_application":
|
||||||
|
return html`<div class="pf-l-flex">
|
||||||
|
<div class="pf-l-flex__item">
|
||||||
|
<h3>${gettext("Authorized application:")}</h3><hr>
|
||||||
|
${this.getModelInfo(this.event.context.authorized_application as EventContext)}
|
||||||
|
</div>
|
||||||
|
<div class="pf-l-flex__item">
|
||||||
|
<h3>${gettext("Using flow")}</h3>
|
||||||
|
<span>${until(Flow.list({
|
||||||
|
flow_uuid: this.event.context.flow as string,
|
||||||
|
}).then(resp => {
|
||||||
|
return html`<a href="#/flows/${resp.results[0].slug}">${resp.results[0].name}</a>`;
|
||||||
|
}), html`<ak-spinner size=${SpinnerSize.Medium}></ak-spinner>`)}</span>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
case "login_failed":
|
||||||
|
return html`
|
||||||
|
<h3>${gettext(`Attempted to log in as ${this.event.context.username}`)}</h3>
|
||||||
|
`;
|
||||||
|
case "token_view":
|
||||||
|
return html`
|
||||||
|
<h3>${gettext("Token:")}</h3><hr>
|
||||||
|
${this.getModelInfo(this.event.context.token as EventContext)}
|
||||||
|
`;
|
||||||
|
case "property_mapping_exception":
|
||||||
|
case "policy_exception":
|
||||||
|
return html`<div class="pf-l-flex">
|
||||||
|
<div class="pf-l-flex__item">
|
||||||
|
<h3>${gettext("Exception")}</h3>
|
||||||
|
<code>${this.event.context.error}</code>
|
||||||
|
</div>
|
||||||
|
<div class="pf-l-flex__item">
|
||||||
|
<h3>${gettext("Expression")}</h3>
|
||||||
|
<code>${this.event.context.expression}</code>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
case "policy_execution":
|
||||||
|
return html`<div class="pf-l-flex">
|
||||||
|
<div class="pf-l-flex__item">
|
||||||
|
<h3>${gettext("Request")}</h3>
|
||||||
|
<ul class="pf-c-list">
|
||||||
|
<li>${gettext("Object")}: ${(this.event.context.request as EventContext).obj as string}</li>
|
||||||
|
<li><span>${gettext("Context")}: <code>${JSON.stringify((this.event.context.request as EventContext).context)}</code></span></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="pf-l-flex__item">
|
||||||
|
<h3>${gettext("Result")}</h3>
|
||||||
|
<ul class="pf-c-list">
|
||||||
|
<li>${gettext("Passing")}: ${(this.event.context.result as EventContext).passing}</li>
|
||||||
|
<li>${gettext("Messages")}:
|
||||||
|
<ul class="pf-c-list">
|
||||||
|
${((this.event.context.result as EventContext).messages as string[]).map(msg => {
|
||||||
|
return html`<li>${msg}</li>`;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
case "configuration_error":
|
||||||
|
return html`<h3>${this.event.context.message}</h3>`;
|
||||||
|
case "update_available":
|
||||||
|
return html`<h3>${gettext("New version available!")}</h3>
|
||||||
|
<a target="_blank" href="https://github.com/BeryJu/authentik/releases/tag/version%2F${this.event.context.new_version}">${this.event.context.new_version}</a>
|
||||||
|
`;
|
||||||
|
// Action types which typically don't record any extra context.
|
||||||
|
// If context is not empty, we fall to the default response.
|
||||||
|
case "login":
|
||||||
|
case "logout":
|
||||||
|
if (this.event.context === {}) {
|
||||||
|
return html`<span>${gettext("No additional data available.")}</span>`;
|
||||||
|
}
|
||||||
|
return this.defaultResponse();
|
||||||
|
default:
|
||||||
|
return this.defaultResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
web/src/pages/events/EventListPage.ts
Normal file
71
web/src/pages/events/EventListPage.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, html, property, TemplateResult } from "lit-element";
|
||||||
|
import { PBResponse } from "../../api/Client";
|
||||||
|
import { Event } from "../../api/Events";
|
||||||
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
|
import { TablePage } from "../../elements/table/TablePage";
|
||||||
|
import { time } from "../../utils";
|
||||||
|
import "./EventInfo";
|
||||||
|
|
||||||
|
@customElement("ak-event-list")
|
||||||
|
export class EventListPage extends TablePage<Event> {
|
||||||
|
expandable = true;
|
||||||
|
|
||||||
|
pageTitle(): string {
|
||||||
|
return "Event Log";
|
||||||
|
}
|
||||||
|
pageDescription(): string | undefined {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pageIcon(): string {
|
||||||
|
return "pf-icon pf-icon-catalog";
|
||||||
|
}
|
||||||
|
searchEnabled(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property()
|
||||||
|
order = "-created";
|
||||||
|
|
||||||
|
apiEndpoint(page: number): Promise<PBResponse<Event>> {
|
||||||
|
return Event.list({
|
||||||
|
ordering: this.order,
|
||||||
|
page: page,
|
||||||
|
search: this.search || "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
columns(): TableColumn[] {
|
||||||
|
return [
|
||||||
|
new TableColumn("Action", "action"),
|
||||||
|
new TableColumn("User", "user"),
|
||||||
|
new TableColumn("Creation Date", "created"),
|
||||||
|
new TableColumn("Client IP", "client_ip"),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
row(item: Event): TemplateResult[] {
|
||||||
|
return [
|
||||||
|
html`<div>${item.action}</div>
|
||||||
|
<small>${item.app}</small>`,
|
||||||
|
html`<div>${item.user.username}</div>
|
||||||
|
${item.user.on_behalf_of ? html`<small>
|
||||||
|
${gettext(`On behalf of ${item.user.on_behalf_of.username}`)}
|
||||||
|
</small>` : html``}`,
|
||||||
|
html`<span>${time(item.created).toLocaleString()}</span>`,
|
||||||
|
html`<span>${item.client_ip}</span>`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
renderExpanded(item: Event): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<td role="cell" colspan="4">
|
||||||
|
<div class="pf-c-table__expandable-row-content">
|
||||||
|
<ak-event-info .event=${item}></ak-event-info>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -30,6 +30,12 @@ export class SiteShell extends LitElement {
|
|||||||
::slotted(*) {
|
::slotted(*) {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
.pf-l-bullseye {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
BackdropStyle,
|
BackdropStyle,
|
||||||
BullseyeStyle,
|
BullseyeStyle,
|
||||||
|
@ -7,6 +7,7 @@ import "./pages/applications/ApplicationListPage";
|
|||||||
import "./pages/applications/ApplicationViewPage";
|
import "./pages/applications/ApplicationViewPage";
|
||||||
import "./pages/sources/SourceViewPage";
|
import "./pages/sources/SourceViewPage";
|
||||||
import "./pages/flows/FlowViewPage";
|
import "./pages/flows/FlowViewPage";
|
||||||
|
import "./pages/events/EventListPage";
|
||||||
|
|
||||||
export const ROUTES: Route[] = [
|
export const ROUTES: Route[] = [
|
||||||
// Prevent infinite Shell loops
|
// Prevent infinite Shell loops
|
||||||
@ -24,4 +25,5 @@ export const ROUTES: Route[] = [
|
|||||||
new Route(new RegExp(`^/flows/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
new Route(new RegExp(`^/flows/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
||||||
return html`<ak-flow-view .args=${args}></ak-flow-view>`;
|
return html`<ak-flow-view .args=${args}></ak-flow-view>`;
|
||||||
}),
|
}),
|
||||||
|
new Route(new RegExp("^/events$"), html`<ak-event-list></ak-event-list>`),
|
||||||
];
|
];
|
||||||
|
@ -50,3 +50,7 @@ export function loading<T>(v: T, actual: TemplateResult): TemplateResult {
|
|||||||
}
|
}
|
||||||
return actual;
|
return actual;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function time(t: string): Date {
|
||||||
|
return new Date(parseInt(t, 10) * 1000);
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ Download the latest `docker-compose.yml` from [here](https://raw.githubuserconte
|
|||||||
|
|
||||||
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
|
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
|
||||||
|
|
||||||
To optionally deploy a different version run `echo AUTHENTIK_TAG=0.14.0-rc1 >> .env`
|
To optionally deploy a different version run `echo AUTHENTIK_TAG=0.14.2-stable >> .env`
|
||||||
|
|
||||||
If this is a fresh authentik install run the following commands to generate a password:
|
If this is a fresh authentik install run the following commands to generate a password:
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ image:
|
|||||||
name: beryju/authentik
|
name: beryju/authentik
|
||||||
name_static: beryju/authentik-static
|
name_static: beryju/authentik-static
|
||||||
name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended
|
name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended
|
||||||
tag: 0.14.0-rc1
|
tag: 0.14.2-stable
|
||||||
|
|
||||||
serverReplicas: 1
|
serverReplicas: 1
|
||||||
workerReplicas: 1
|
workerReplicas: 1
|
||||||
|
66
website/docs/integrations/services/grafana/index.md
Normal file
66
website/docs/integrations/services/grafana/index.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
title: Grafana
|
||||||
|
---
|
||||||
|
|
||||||
|
## What is Grafana
|
||||||
|
|
||||||
|
From https://en.wikipedia.org/wiki/Grafana
|
||||||
|
|
||||||
|
:::note
|
||||||
|
Grafana is a multi-platform open source analytics and interactive visualization web application. It provides charts, graphs, and alerts for the web when connected to supported data sources, Grafana Enterprise version with additional capabilities is also available. It is expandable through a plug-in system.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `grafana.company` is the FQDN of the Grafana install.
|
||||||
|
- `authentik.company` is the FQDN of the authentik install.
|
||||||
|
|
||||||
|
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
|
||||||
|
|
||||||
|
- Client Type: `Confidential`
|
||||||
|
- JWT Algorithm: `RS256`
|
||||||
|
- Scopes: OpenID, Email and Profile
|
||||||
|
- RSA Key: Select any available key
|
||||||
|
- Redirect URIs: `https://grafana.company/login/generic_oauth`
|
||||||
|
|
||||||
|
Note the Client ID and Client Secret values. Create an application, using the provider you've created above. Note the slug of the application you've created.
|
||||||
|
|
||||||
|
## Grafana
|
||||||
|
|
||||||
|
If your Grafana is running in docker, set the following environment variables:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_NAME: "authentik"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: "<Client ID from above>"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: "<Client Secret from above>"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_SCOPES: "openid profile email"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_AUTH_URL: "https://authentik.company/application/o/authorize/"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: "https://authentik.company/application/o/token/"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_API_URL: "https://authentik.company/application/o/userinfo/"
|
||||||
|
GF_AUTH_SIGNOUT_REDIRECT_URL: "https://authentik.company/application/o/<Slug of the application from above>/end-session/"
|
||||||
|
# Optionally enable auto-login
|
||||||
|
GF_AUTH_OAUTH_AUTO_LOGIN: "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using a config-file instead, you have to set these options:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[auth]
|
||||||
|
signout_redirect_url = https://authentik.company/application/o/<Slug of the application from above>/end-session/
|
||||||
|
# Optionally enable auto-login
|
||||||
|
oauth_auto_login = true
|
||||||
|
|
||||||
|
[auth.generic_oauth]
|
||||||
|
name = authentik
|
||||||
|
enabled = true
|
||||||
|
client_id = <Client ID from above>
|
||||||
|
client_secret = <Client Secret from above>
|
||||||
|
scopes = openid email profile
|
||||||
|
auth_url = https://authentik.company/application/o/authorize/
|
||||||
|
token_url = https://authentik.company/application/o/token/
|
||||||
|
api_url = https://authentik.company/application/o/userinfo/
|
||||||
|
```
|
@ -17,13 +17,14 @@ The following placeholders will be used:
|
|||||||
- `harbor.company` is the FQDN of the Harbor install.
|
- `harbor.company` is the FQDN of the Harbor install.
|
||||||
- `authentik.company` is the FQDN of the authentik install.
|
- `authentik.company` is the FQDN of the authentik install.
|
||||||
|
|
||||||
Create an application in authentik. Create an OpenID provider with the following parameters:
|
Create an OAuth2/OpenID provider with the following parameters:
|
||||||
|
|
||||||
- Client Type: `Confidential`
|
- Client Type: `Confidential`
|
||||||
- Response types: `code (Authorization Code Flow)`
|
|
||||||
- JWT Algorithm: `RS256`
|
- JWT Algorithm: `RS256`
|
||||||
- Redirect URIs: `https://harbor.company/c/oidc/callback`
|
- Redirect URIs: `https://harbor.company/c/oidc/callback`
|
||||||
- Scopes: `openid`
|
- Scopes: OpenID, Email and Profile
|
||||||
|
|
||||||
|
Note the Client ID and Client Secret values. Create an application, using the provider you've created above.
|
||||||
|
|
||||||
## Harbor
|
## Harbor
|
||||||
|
|
||||||
|
@ -51,12 +51,11 @@ Under _Sources_, click _Edit_ and ensure that "Autogenerated Active Directory Ma
|
|||||||
|
|
||||||
### Step 3
|
### Step 3
|
||||||
|
|
||||||
Under _Providers_, create an OAuth2/OpenID Provider with these settings:
|
Under _Providers_, create an OAuth2/OpenID provider with these settings:
|
||||||
|
|
||||||
- Client Type: Confidential
|
- Client Type: Confidential
|
||||||
- JWT Algorithm: RS256
|
- JWT Algorithm: RS256
|
||||||
- Redirect URI: `https://vcenter.company/ui/login/oauth2/authcode`
|
- Redirect URI: `https://vcenter.company/ui/login/oauth2/authcode`
|
||||||
- Post Logout Redirect URIs: `https://vcenter.company/ui/login`
|
|
||||||
- Sub Mode: If your Email address Schema matches your UPN, select "Based on the User's Email...", otherwise select "Based on the User's UPN...".
|
- Sub Mode: If your Email address Schema matches your UPN, select "Based on the User's Email...", otherwise select "Based on the User's UPN...".
|
||||||
- Scopes: Select the Scope Mapping you've created in Step 1
|
- Scopes: Select the Scope Mapping you've created in Step 1
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ title: Release 0.14
|
|||||||
|
|
||||||
- The OAuth2 Provider has been updated to closer match the OpenID Connect Specifications
|
- The OAuth2 Provider has been updated to closer match the OpenID Connect Specifications
|
||||||
|
|
||||||
Response time now longer has to be configured manually. The issuer field can be configured now (the default behaviour is the same as pre-0.14)
|
Response type no longer has to be configured manually. The issuer field can be configured now (the default behaviour is the same as pre-0.14)
|
||||||
|
|
||||||
Authorization Codes are now generated as a JWT Token, which is not specified as spec, but seems to be a quasi-standard.
|
Authorization Codes are now generated as a JWT Token, which is not specified as spec, but seems to be a quasi-standard.
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ This release does not introduce any new requirements.
|
|||||||
|
|
||||||
### docker-compose
|
### docker-compose
|
||||||
|
|
||||||
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/BeryJu/authentik/version-0.14/docker-compose.yml) and run `docker-compose up -d`.
|
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/BeryJu/authentik/version-0.14/docker-compose.yml). Aftewards, simply run `docker-compose up -d` and then the normal upgrade command of `docker-compose run --rm server migrate`.
|
||||||
|
|
||||||
### Kubernetes
|
### Kubernetes
|
||||||
|
|
||||||
|
@ -101,6 +101,7 @@ module.exports = {
|
|||||||
"integrations/services/aws/index",
|
"integrations/services/aws/index",
|
||||||
"integrations/services/awx-tower/index",
|
"integrations/services/awx-tower/index",
|
||||||
"integrations/services/gitlab/index",
|
"integrations/services/gitlab/index",
|
||||||
|
"integrations/services/grafana/index",
|
||||||
"integrations/services/harbor/index",
|
"integrations/services/harbor/index",
|
||||||
"integrations/services/home-assistant/index",
|
"integrations/services/home-assistant/index",
|
||||||
"integrations/services/nextcloud/index",
|
"integrations/services/nextcloud/index",
|
||||||
|
@ -11,8 +11,8 @@ const features = [
|
|||||||
title: "Easy to Use",
|
title: "Easy to Use",
|
||||||
description: (
|
description: (
|
||||||
<>
|
<>
|
||||||
Identity made easy. authentik makes single-sign on, user
|
Identity made easy. authentik makes single-sign on (SSO), user
|
||||||
enrollment and access control simple.
|
enrollment, and access control simple.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -20,7 +20,7 @@ const features = [
|
|||||||
title: "Realise your workflow",
|
title: "Realise your workflow",
|
||||||
description: (
|
description: (
|
||||||
<>
|
<>
|
||||||
authentik lets you build your Workflow as you need it, no
|
authentik lets you build your workflow as you need it, no
|
||||||
limitations.
|
limitations.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
@ -109,20 +109,20 @@ function Home() {
|
|||||||
authentik is an open-source Identity Provider
|
authentik is an open-source Identity Provider
|
||||||
focused on flexibility and versatility. You
|
focused on flexibility and versatility. You
|
||||||
can use authentik in an existing environment
|
can use authentik in an existing environment
|
||||||
to add support for new protocols. authentik
|
to add support for new protocols, implement
|
||||||
is also a great solution for implementing
|
sign-up/recovery/etc. in your application so
|
||||||
signup/recovery/etc in your application, so
|
you don't have to deal with it, and many other
|
||||||
you don't have to deal with it.
|
things.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col col--5 col--offset-2 padding-vert--xl">
|
<div className="col col--5 col--offset-2 padding-vert--xl">
|
||||||
<h2>Upmost flexibility</h2>
|
<h2>Utmost flexibility</h2>
|
||||||
<p>
|
<p>
|
||||||
You can adopt authentik to your environment,
|
You can adopt authentik to your environment,
|
||||||
regardless of your requirements. Need an Active-
|
regardless of your requirements. Need an Active-Directory
|
||||||
Directory integrated SSO Provider? Do you want
|
integrated SSO Provider? Do you want
|
||||||
to implement a custom enrollment process for your
|
to implement a custom enrollment process for your
|
||||||
customers? Are you developing an application and
|
customers? Are you developing an application and
|
||||||
don't want to deal with User verification and recovery?
|
don't want to deal with User verification and recovery?
|
||||||
|
Reference in New Issue
Block a user